7#include <absl/container/fixed_array.h>
27 auto ptr = (*ctor)(
world());
54 bootstrapping_ =
true;
58 curr_sparse_ = !dense_ && !nonlocal_ && !dirty_.empty();
60 auto seeds = fe::Vector<Def*>(dirty_.begin(), dirty_.end());
66 bootstrapping_ =
false;
67 log().v(
"sparse round: re-drain {} dirty muts", seeds.size());
74 for (
auto [concr, abstr] : lattice_)
75 if (!concr->isa_mut())
map(concr, abstr);
77 for (
auto mut : seeds)
81 for (
const auto& [flags, e] :
world().annexes())
85 bootstrapping_ =
false;
87 for (
auto mut :
world().externals().muts())
94 profile_count(curr_sparse_ ?
"rounds.sparse" :
"rounds.full");
95 profile_count(
"muts.drained", std::exchange(num_drained_,
size_t(0)));
105const Def* Analysis::repr_(
const Def* slow,
const Def* fast)
const {
106 while (slow != fast) {
107 auto next = follow(fast);
108 if (!next)
return fast;
110 if (!fast)
return next;
112 assert(slow &&
"slow lags fast, so fast already traversed slow's successor");
116 for (
auto def = follow(slow); def != slow; def = follow(def))
117 if (def->gid() < res->gid()) res = def;
127 if (
lookup(mut))
return mut;
129 worklist_.emplace_back(mut);
133void Analysis::drain() {
134 while (!worklist_.empty()) {
135 auto mut = worklist_.front();
136 worklist_.pop_front();
140 log().d(
"enter {}", mut);
141 for (
auto d : mut->deps())
154 for (uint32_t i = 0;
todo; ++i) {
155 if (i >= max_iters) fe::throwf(
"phase `{}` did not reach a fixed point after {} iterations",
name(), max_iters);
156 log().v(
"iteration {}", i);
169 bootstrapping_ =
false;
183 return analysis_->todo();
204 if (old_mut->
is_external()) new_mut->externalize();
220 if (new_def == old_mut)
return;
224 new_def->as_mut()->externalize();
229 if (
auto hole = mut->isa<
Hole>()) {
230 auto [last, op] = hole->find();
231 return op ?
rewrite(op) : last;
236 if (
auto type = mut->
type(); type &&
rewrite(type) != type) {
243 if (!mut->
is_set())
return mut;
247 if (!std::ranges::equal(new_ops, mut->
ops())) {
262 phases_ = std::move(
phases);
263 name_ += fixed_point_ ?
" tt" :
" ff";
270 for (
auto arg :
args->projs())
277 auto& man =
static_cast<PhaseMan&
>(phase);
279 for (
auto& old_phase : man.phases())
280 new_phases.emplace_back(std::unique_ptr<Phase>(
static_cast<Phase*
>(old_phase->recreate().release())));
281 apply(man.fixed_point(), std::move(new_phases));
289 auto stale = absl::FixedArray<bool>(n,
true);
290 auto ran = absl::FixedArray<bool>(n,
false);
292 auto any_stale = [&stale]() {
return std::ranges::any_of(stale, [](
bool b) {
return b; }); };
294 for (uint32_t iter = 0; any_stale(); ++iter) {
295 if (iter >= max_iters)
296 fe::throwf(
"phase `{}` did not reach a fixed point after {} iterations",
name(), max_iters);
300 for (
size_t i = 0; i != n; ++i) {
301 auto& phase =
phases()[i];
303 log().v(
"skip `{}`: World unchanged since its last quiet run", phase->name());
309 auto new_phase = std::unique_ptr<Phase>(
static_cast<Phase*
>(phase->recreate().release()));
310 swap(new_phase, phase);
320 std::ranges::fill(stale,
true);
virtual void prepare()
Run before the main analysis.
void start() override
Actual entry.
const Def * rewrite(const Def *) override
Rewrites def and then maps the result to its repr().
virtual void leave()
Called after curr_mut() has been completely dealt with.
virtual void rewrite_annex(flags_t, Sym, const Def *)
virtual void rewrite_external(Def *)
virtual void reset()
Clears the rewriter map and resets Phase::todo() and is_bootstrapping() for the next fixed-point iter...
virtual void finalize()
Run after the main analysis - only in full rounds, so it always sees the complete abstract World.
const Def * repr(const Def *def) const
The representative of def: follows def ↦ lattice(def) to the end of its chain.
Def * rewrite_mut(Def *) override
Schedules mut for a breadth-first visit of its dependencies and records mut -> mut.
static auto uncurry_args(const Def *def)
Def * set(size_t i, const Def *)
Successively set from left to right.
T * as_mut() const
Asserts that this is a mutable, casts constness away and performs a static_cast to T.
constexpr auto ops() const noexcept
T * isa_mut() const
If this is mutable, it will cast constness away and perform a dynamic_cast to T.
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
bool is_external() const noexcept
Def * unset()
Unsets all Def::ops; works even, if not set at all or only partially set.
const fe::Vector< std::string > & args(std::string_view plugin) const
Yields an empty fe::Vector if plugin has none.
fe::Profiler & profiler()
auto phase(flags_t flags)
This node is a hole in the IR that is inferred by its context later on.
const Def * rewrite_mut(Def *mut) override
void rewrite_annex(flags_t, Sym, const Def *) override
void rewrite_external(Def *) override
static T as(const Def *def)
PhaseMan(World &world, flags_t annex)
void start() final
Actual entry.
void apply(bool, Phases &&)
virtual std::unique_ptr< Phase > recreate()
Creates a new instance; needed by a fixed-point PhaseMan.
void invalidate(bool todo=true)
Signals that another round of fixed-point iteration is required, either as part of.
const fe::Log & log() const
Phase(World &world, std::string name)
static std::unique_ptr< Phase > create(const Flags2Phases &phases, const Def *def)
void profile_count(std::string_view key, uint64_t n=1)
Adds n to the custom fe::Profiler counter key of the current run; no-op unless profiling is enabled.
const fe::Vector< std::string > & args()
Command-line arguments passed to this Phase's plugin via -X <plugin>:<arg>.
virtual void run()
Entry point and generates some debug output; invokes Phase::start.
std::string_view name() const
virtual void start()=0
Actual entry.
virtual void finalize()
Run after all roots have been walked - but for an RWPhase still before the two worlds are swapped.
virtual void rewrite_external(Def *)=0
void start() override
Actual entry.
virtual bool rewrite_annexes() const =0
virtual const Def * rewrite_root(const Def *def)
Rewrites a root - i.e. an annex or an external.
virtual bool analyze()
Runs the optional pre-analysis on Phase::world, typically to a fixed point, before rewriting begins.
virtual void rewrite_annex(flags_t, Sym, const Def *)=0
World & new_world()
Create new Defs into this.
void rewrite_annex(flags_t, Sym, const Def *) override
void start() override
RWBase::start() and then swaps the two worlds.
void rewrite_external(Def *) override
World & old_world()
Get old Defs from here.
friend void swap(Rewriter &rw1, Rewriter &rw2) noexcept
virtual const Def * rewrite_mut(Def *)
virtual const Def * map(const Def *old_def, const Def *new_def)
std::deque< Def2Def > old2news_
virtual const Def * rewrite(const Def *)
auto enter(Def *new_mut)
Updates curr_mut() to new_mut and restores it at the end of the scope.
virtual const Def * lookup(const Def *old_def)
Lookup old_def by searching in reverse through the stack of maps.
const Def * reattach(flags_t flags, const Def *def)
Overwrites the Def of an already attach()ed annex, keeping its Sym.
const Def * attach(flags_t, Sym, const Def *)
The World represents the whole program and manages creation of MimIR nodes (Defs).
u32 curr_gid() const
Manage global identifier - a unique number for each Def.
World & verify()
Verifies that all externals() and annexes() are Def::is_closed(), if MIM_ENABLE_CHECKS.
const fe::Log & log() const
Log via log().e("...", args) etc.; owned by the Driver.
std::deque< std::unique_ptr< Phase > > Phases
static std::string demangle(plugin_t plugin)
Reverts an Axm::mangled plugin back to its name; never longer than Annex::Max_Plugin_Size.
static constexpr plugin_t flags2plugin(flags_t f)