MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
phase.cpp
Go to the documentation of this file.
1#include "mim/phase.h"
2
3#include <algorithm>
4#include <memory>
5#include <utility>
6
7#include <absl/container/fixed_array.h>
8
9#include "mim/driver.h"
10#include "mim/flags.h"
11
12namespace mim {
13
14/*
15 * Phase
16 */
17
19 : world_(world)
20 , annex_(annex)
21 , name_(world.annex(annex)->sym()) {}
22
26
27std::unique_ptr<Phase> Phase::recreate() {
28 auto ctor = driver().phase(annex());
29 auto ptr = (*ctor)(world());
30 ptr->apply(*this);
31 return ptr;
32}
33
34void Phase::run() {
35 auto profiling = driver().flags().profile != Flags::Profile::None;
36 if (profiling) driver().profiler().start(name());
37 world().verify().ILOG("🚀 Phase launch: `{}`", name());
38 start();
39 world().verify().ILOG("🏁 Phase finish: `{}`", name());
40 if (profiling) driver().profiler().stop();
41}
42
43void Phase::profile_count(std::string_view key, uint64_t n) {
44 if (driver().flags().profile != Flags::Profile::None) driver().profiler().count(key, n);
45}
46
47/*
48 * Analyzer
49 */
50
52 old2news_.clear();
53 worklist_.clear();
54 push();
55 todo_ = false;
56}
57
59 curr_sparse_ = !dense_ && !nonlocal_ && !dirty_.empty();
60 nonlocal_ = false;
61 auto seeds = Vector<Def*>(dirty_.begin(), dirty_.end());
62 dirty_.clear();
63
64 prepare();
65
66 if (curr_sparse_) {
67 VLOG("sparse round: re-draining {} dirty muts", seeds.size());
68 std::ranges::sort(seeds, GIDLt<Def*>()); // MutSet iteration order is nondeterministic
69
70 // Replay the lattice into the fresh rewriter map: this re-installs the substitutions that
71 // non-revisited producers wrote in earlier rounds - except for mutables, whose map entry
72 // doubles as the per-round "already scheduled" marker and would suppress their drain.
73 for (auto [concr, abstr] : lattice_)
74 if (!concr->isa_mut()) map(concr, abstr);
75
76 for (auto mut : seeds)
77 rewrite(mut);
78 drain();
79 } else {
80 for (const auto& [flags, e] : world().annexes())
81 rewrite_annex(flags, e.sym, e.def);
82 drain();
83
84 bootstrapping_ = false;
85
86 for (auto mut : world().externals().muts())
88 drain();
89
90 finalize();
91 }
92
93 profile_count(curr_sparse_ ? "rounds.sparse" : "rounds.full");
94 profile_count("muts.drained", std::exchange(num_drained_, size_t(0)));
95
96 // A quiet sparse round only certifies the muts it visited:
97 // force one full round; the fixed point counts only if that one stays quiet, too.
98 if (curr_sparse_ && !todo()) invalidate();
99}
100
101void Analysis::rewrite_annex(flags_t, Sym, const Def* def) { rewrite(def); }
103
105 if (lookup(mut)) return mut; // already scheduled this round
106 map(mut, mut);
107 worklist_.emplace_back(mut);
108 return mut;
109}
110
111void Analysis::drain() {
112 while (!worklist_.empty()) {
113 auto mut = worklist_.front();
114 worklist_.pop_front();
115 ++num_drained_;
116
117 auto _ = enter(mut);
118 DLOG("enter: {}", mut);
119 for (auto d : mut->deps())
120 rewrite(d);
121 }
122}
123
124/*
125 * RWPhase
126 */
127
129 auto max_iters = driver().flags().max_fp_iters;
130 bool todo = true;
131 for (uint32_t i = 0; todo; ++i) {
132 if (i >= max_iters) fe::throwf("phase `{}` did not reach a fixed point after {} iterations", name(), max_iters);
133 VLOG("iteration: {}", i);
134 todo = analyze();
135 }
136
137 for (const auto& [flags, e] : old_world().annexes())
138 rewrite_annex(flags, e.sym, e.def);
139
140 bootstrapping_ = false;
141
142 for (auto mut : old_world().externals().muts())
143 rewrite_external(mut);
144
146}
147
149 if (analysis_) {
150 analysis_->reset();
151 analysis_->run();
152 return analysis_->todo();
153 }
154
155 return false;
156}
157
158void RWPhase::rewrite_annex(flags_t f, Sym sym, const Def* def) { new_world().annexes().attach(f, sym, rewrite(def)); }
159
161 auto new_mut = rewrite(old_mut)->as_mut();
162 if (old_mut->is_external()) new_mut->externalize();
163}
164
165/*
166 * PhaseMan
167 */
168
169void PhaseMan::apply(bool fp, Phases&& phases) {
170 fixed_point_ = fp;
171 phases_ = std::move(phases);
172 name_ += fixed_point_ ? " tt" : " ff";
173}
174
175void PhaseMan::apply(const App* app) {
176 auto [fp, args] = app->uncurry_args<2>();
177
178 auto phases = Phases();
179 for (auto arg : args->projs())
180 if (auto phase = create(driver().phases(), arg)) phases.emplace_back(std::move(phase));
181
182 apply(Lit::as<bool>(fp), std::move(phases));
183}
184
185void PhaseMan::apply(Phase& phase) {
186 auto& man = static_cast<PhaseMan&>(phase);
187 Phases new_phases;
188 for (auto& old_phase : man.phases())
189 new_phases.emplace_back(std::unique_ptr<Phase>(static_cast<Phase*>(old_phase->recreate().release())));
190 apply(man.fixed_point(), std::move(new_phases));
191}
192
194 auto max_iters = driver().flags().max_fp_iters;
195 auto n = phases().size();
196 // A phase's run is a deterministic function of the World's content.
197 // So a phase only needs to run (again) if the World (may have) changed since its last quiet run.
198 auto stale = absl::FixedArray<bool>(n, true);
199 auto ran = absl::FixedArray<bool>(n, false);
200
201 auto any_stale = [&stale]() { return std::ranges::any_of(stale, [](bool b) { return b; }); };
202
203 for (uint32_t iter = 0; any_stale(); ++iter) {
204 if (iter >= max_iters)
205 fe::throwf("phase `{}` did not reach a fixed point after {} iterations", name(), max_iters);
206 if (fixed_point()) VLOG("🔄 fixed-point iteration: {}", iter);
207
208 bool todo = false;
209 for (size_t i = 0; i != n; ++i) {
210 auto& phase = phases()[i];
211 if (!stale[i]) {
212 VLOG("skipping `{}`: World unchanged since its last quiet run", phase->name());
213 profile_count("phases.skipped");
214 continue;
215 }
216
217 if (ran[i]) { // re-runs need a fresh instance
218 auto new_phase = std::unique_ptr<Phase>(static_cast<Phase*>(phase->recreate().release()));
219 swap(new_phase, phase);
220 }
221
222 phase->run();
223 ran[i] = true;
224 stale[i] = false;
225
226 if (phase->todo()) {
227 todo = true;
228 // The World changed: everyone - including this phase itself - gets another look.
229 std::ranges::fill(stale, true);
230 }
231 }
232
233 todo &= fixed_point();
235 if (!fixed_point()) break;
236 }
237}
238
239} // namespace mim
virtual void prepare()
Run before the main analysis.
Definition phase.h:254
void start() override
Actual entry.
Definition phase.cpp:58
virtual void rewrite_annex(flags_t, Sym, const Def *)
Definition phase.cpp:101
virtual void rewrite_external(Def *)
Definition phase.cpp:102
virtual void reset()
Clears the rewriter map and resets Phase::todo() for the next fixed-point iteration.
Definition phase.cpp:51
virtual void finalize()
Run after the main analysis - only in full rounds, so it always sees the complete abstract World.
Definition phase.h:256
Def * rewrite_mut(Def *) override
Schedules mut for a breadth-first visit of its dependencies and records mut -> mut.
Definition phase.cpp:104
World & world()
Definition phase.h:77
static auto uncurry_args(const Def *def)
Definition lam.h:329
Base class for all Defs.
Definition def.h:261
T * as_mut() const
Asserts that this is a mutable, casts constness away and performs a static_cast to T.
Definition def.h:536
bool is_external() const noexcept
Definition def.h:500
Profiler & profiler()
Definition driver.h:38
const Vector< std::string > & args(Sym plugin) const
Yields an empty Vector if plugin has none.
Definition driver.cpp:127
Flags & flags()
Definition driver.h:35
auto phase(flags_t flags)
Definition driver.h:123
static T as(const Def *def)
Definition def.h:884
PhaseMan(World &world, flags_t annex)
Definition phase.h:436
bool fixed_point() const
Definition phase.h:446
auto & phases()
Definition phase.h:447
void start() final
Actual entry.
Definition phase.cpp:193
void apply(bool, Phases &&)
Definition phase.cpp:169
virtual std::unique_ptr< Phase > recreate()
Creates a new instance; needed by a fixed-point PhaseMan.
Definition phase.cpp:27
std::string name_
Definition phase.h:123
void invalidate(bool todo=true)
Signals that another round of fixed-point iteration is required, either as part of.
Definition phase.h:98
flags_t annex() const
Definition phase.h:81
Phase(World &world, std::string name)
Definition phase.h:29
static std::unique_ptr< Phase > create(const Flags2Phases &phases, const Def *def)
Definition phase.h:50
void profile_count(std::string_view key, uint64_t n=1)
Adds n to the custom Profiler counter key of the current run; no-op unless profiling is enabled.
Definition phase.cpp:43
Driver & driver()
Definition phase.h:78
virtual void run()
Entry point and generates some debug output; invokes Phase::start.
Definition phase.cpp:34
bool todo() const
Definition phase.h:90
std::string_view name() const
Definition phase.h:80
virtual void start()=0
Actual entry.
const Vector< std::string > & args()
Command-line arguments passed to this Phase's plugin via -X <plugin>:<arg>.
Definition phase.cpp:23
World & world()
Definition phase.h:77
void stop()
Marks the end of the most recently started Phase run.
Definition profile.h:60
void start(std::string_view name)
Definition profile.h:53
void count(std::string_view key, uint64_t n=1)
Adds n to counter key of the currently running Span; no-op if no Span is running or n is 0.
Definition profile.h:67
virtual bool analyze()
Runs the optional pre-analysis on RWPhase::old_world(), typically to a fixed point,...
Definition phase.cpp:148
World & new_world()
Create new Defs into this.
Definition phase.h:368
virtual void rewrite_annex(flags_t, Sym, const Def *)
Definition phase.cpp:158
void start() override
Actual entry.
Definition phase.cpp:128
World & old_world()
Get old Defs from here.
Definition phase.h:367
virtual void rewrite_external(Def *)
Definition phase.cpp:160
friend void swap(Rewriter &rw1, Rewriter &rw2) noexcept
Definition rewrite.h:82
virtual void push()
Definition rewrite.h:38
virtual const Def * map(const Def *old_def, const Def *new_def)
Definition rewrite.h:45
std::deque< Def2Def > old2news_
Definition rewrite.h:99
virtual const Def * rewrite(const Def *)
Definition rewrite.cpp:56
auto enter(Def *new_mut)
Updates curr_mut() to new_mut and restores it at the end of the scope.
Definition rewrite.h:102
virtual const Def * lookup(const Def *old_def)
Lookup old_def by searching in reverse through the stack of maps.
Definition rewrite.h:55
This is a thin wrapper for absl::InlinedVector<T, N, A> which is a drop-in replacement for std::vecto...
Definition vector.h:18
const Def * attach(flags_t, Sym, const Def *)
Definition world.cpp:43
The World represents the whole program and manages creation of MimIR nodes (Defs).
Definition world.h:36
World & verify()
Verifies that all externals() and annexes() are Def::is_closed(), if MIM_ENABLE_CHECKS.
Definition world.cpp:755
Annexes & annexes()
Definition world.h:267
#define VLOG(...)
Definition log.h:91
#define DLOG(...)
Vaporizes to nothingness in Debug build.
Definition log.h:94
Definition ast.h:14
u64 flags_t
Definition types.h:39
std::deque< std::unique_ptr< Phase > > Phases
Definition phase.h:20
static constexpr plugin_t flags2plugin(flags_t f)
Definition plugin.h:128
static Sym demangle(Driver &, plugin_t plugin)
Reverts an Axm::mangled string to a Sym.
Definition plugin.cpp:37
@ None
No profiling.
Definition flags.h:14
uint32_t max_fp_iters
Definition flags.h:21
Profile profile
Definition flags.h:27