MimIR 0.1
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
phase.h
Go to the documentation of this file.
1#pragma once
2
3#include <memory>
4
5#include <fe/assert.h>
6#include <fe/cast.h>
7
8#include "mim/def.h"
9#include "mim/nest.h"
10#include "mim/pass.h"
11#include "mim/rewrite.h"
12
13namespace mim {
14
15class Nest;
16class Phase;
17class PhaseMan;
18class Repl;
19class World;
20
21using Repls = std::deque<std::unique_ptr<Repl>>;
22using Phases = std::deque<std::unique_ptr<Phase>>;
23
24/// Unlike a Pass, a Phase performs one self-contained task and does not
25/// interleave with other phases. Phases are intended to run in a classical sequence, one after another.
26/// @see @ref phases_phase
27class Phase : public Stage {
28public:
29 /// @name Construction & Destruction
30 ///@{
31 Phase(World& world, std::string name)
32 : Stage(world, name) {}
35
36 ///@}
37
38 /// @name Fixed-Point Handling
39 ///@{
40 bool todo() const { return todo_; }
41
42 /// Signals that another round of fixed-point iteration is required, either
43 /// as part of
44 /// - a pipeline managed by PhaseMan, or
45 /// - the optional pre-analysis of an RWPhase.
46 ///
47 /// Calling `invalidate(todo)` bitwise-ORs @p todo into the internal `todo_` flag.
48 void invalidate(bool todo = true) { todo_ |= todo; }
49 ///@}
50
51 /// @name run
52 ///@{
53 virtual void run(); ///< Entry point and generates some debug output; invokes Phase::start.
54 virtual void start() = 0; ///< Actual entry.
55
56 /// Runs a single Phase.
57 template<class P, class... Args>
58 static void run(Args&&... args) {
59 P p(std::forward<Args>(args)...);
60 p.run();
61 }
62 ///@}
63
64private:
65 bool todo_ = false;
66
67 friend class Analysis;
68};
69
70/// Traverses the current World using Rewriter infrastructure while staying in the same world.
71///
72/// It recursively rewrites
73/// 1. all World::annexes() (during which Analysis::is_bootstrapping() is `true`), and then
74/// 2. all World::externals() (during which it is `false`).
75///
76/// Analysis provides a reusable lattice() mapping old Def%s to abstract values, represented as ordinary MimIR Def%s.
77/// @note You can override
78/// - Rewriter::rewrite(),
79/// - Rewriter::rewrite_imm(),
80/// - Rewriter::rewrite_mut(), etc.
81/// @see @ref phases_analysis
82class Analysis : public Phase, public Rewriter {
83public:
84 /// @name Construction & Destruction
85 ///@{
86 Analysis(World& world, std::string name)
87 : Phase(world, std::move(name))
88 , Rewriter(world) {}
92
93 /// Clears rewriter state, analysis state, and resets Phase::todo() for the next fixed-point iteration.
94 /// @see RWPhase::analyze
95 virtual void reset();
96 ///@}
97
98 /// @name Getters
99 ///@{
100 auto& lattice() { return lattice_; }
101 const auto& lattice() const { return lattice_; }
102 bool is_bootstrapping() const { return bootstrapping_; }
103 ///@}
104
105 /// @name Rewrite
106 ///@{
107 virtual void rewrite_annex(flags_t, const Def*);
108 virtual void rewrite_external(Def*);
109 Def* rewrite_mut(Def*) override; ///< Keeps old muts/vars.
110 ///@}
111
112 /// @name Getters
113 ///@{
114 World& world() { return Phase::world(); }
115 ///@}
116
117protected:
118 void start() override;
119
121
122private:
123 bool bootstrapping_ = true;
124};
125
126/// Rebuilds old_world() into new_world() and then swaps them.
127///
128/// It recursively rewrites
129/// 1. all old World::annexes() (during which RWPhase::is_bootstrapping() is `true`, and then
130/// 2. all old World::externals() (during which it is `false`).
131///
132/// During bootstrapping, rewrites that depend on other annexes may need to be skipped,
133/// since those annexes might not yet exist in the new world.
134///
135/// If an associated Analysis is provided, the rewrite can query its abstract results through lattice().
136///
137/// @note You can override
138/// - Rewriter::rewrite(),
139/// - Rewriter::rewrite_imm(),
140/// - Rewriter::rewrite_mut(), etc.
141/// @see @ref phases_rwphase
142class RWPhase : public Phase, public Rewriter {
143public:
144 /// @name Construction
145 ///@{
146 RWPhase(World& world, std::string name, Analysis* analysis = nullptr)
147 : Phase(world, std::move(name))
148 , Rewriter(world.inherit())
149 , analysis_(analysis) {}
151 : Phase(world, annex)
152 , Rewriter(world.inherit())
153 , analysis_(analysis) {}
154 ///@}
155
156 /// @name Analysis
157 ///@{
158 Analysis* analysis() { return analysis_; }
159 const Analysis* analysis() const { return analysis_; }
160
161 /// Returns the abstract value computed by the associated Analysis for the given old-world Def, or `nullptr` if no
162 /// value is available.
163 const Def* lattice(const Def* old_def) {
164 if (auto i = analysis_->lattice().find(old_def); i != analysis_->lattice().end()) return i->second;
165 return nullptr;
166 }
167
168 /// Runs the optional pre-analysis on RWPhase::old_world(), typically to a fixed point,
169 /// before rewriting begins.
170 ///
171 /// If analysis() is set, this is the natural place to iterate until Phase::todo() becomes `false`.
172 /// If no Analysis is needed, simply return `false`.
173 virtual bool analyze();
174 ///@}
175
176 /// @name Rewrite
177 ///@{
178 virtual void rewrite_annex(flags_t, const Def*);
179 virtual void rewrite_external(Def*);
180
181 /// Returns whether we are currently bootstrapping (rewriting annexes).
182 /// While bootstrapping, you have to skip rewrites that refer to other annexes, as they might not yet be available.
183 bool is_bootstrapping() const { return bootstrapping_; }
184 ///@}
185
186 /// @name World
187 /// * Phase::world is the **old** one.
188 /// * Rewriter::world is the **new** one.
189 /// * RWPhase::world is deleted to not confuse this.
190 ///@{
191 using Phase::world;
192 using Rewriter::world;
193 World& world() = delete; ///< Hides both and forbids direct access.
194 World& old_world() { return Phase::world(); } ///< Get **old** Def%s from here.
195 World& new_world() { return Rewriter::world(); } ///< Create **new** Def%s into this.
196 ///@}
197
198protected:
199 void start() override;
200
201private:
202 Analysis* analysis_;
203 bool bootstrapping_ = true;
204};
205
206/// Simple Stage that searches for a pattern and replaces it.
207/// Combine them in a ReplPhase.
208class Repl : public Stage {
209public:
212
213 virtual const Def* replace(const Def* def) = 0;
214};
215
216class ReplMan : public Repl {
217public:
220
221 void apply(Repls&&);
222 void apply(const App*) final;
223 void apply(Stage& stage) final { apply(std::move(static_cast<ReplMan&>(stage).repls_)); }
224
225 void add(std::unique_ptr<Repl>&& repl) { repls_.emplace_back(std::move(repl)); }
226 const auto& repls() const { return repls_; }
227
228private:
229 const Def* replace(const Def*) final { fe::unreachable(); }
230
231 Repls repls_;
232};
233
234#define MIM_CONCAT_INNER(a, b) a##b
235#define MIM_CONCAT(a, b) MIM_CONCAT_INNER(a, b)
236
237#define MIM_REPL(__stages, __annex, ...) MIM_REPL_IMPL(__stages, __annex, __LINE__, __VA_ARGS__)
238
239// clang-format off
240#define MIM_REPL_IMPL(__stages, __annex, __id, ...) \
241 struct MIM_CONCAT(Repl_, __id) : ::mim::Repl { \
242 MIM_CONCAT(Repl_, __id)(::mim::World & world, ::mim::flags_t annex) \
243 : Repl(world, annex) {} \
244 \
245 const ::mim::Def* replace(const ::mim::Def* def) final __VA_ARGS__ \
246 }; \
247 ::mim::Stage::hook<__annex, MIM_CONCAT(Repl_, __id)>(__stages)
248// clang-format on
249
250class ReplManPhase : public RWPhase {
251public:
252 /// @name Construction
253 ///@{
254 ReplManPhase(World& world, std::unique_ptr<ReplMan>&& man)
255 : RWPhase(world, "pass_man_phase")
256 , man_(std::move(man)) {}
259
260 void apply(const App*) final;
261 void apply(Stage&) final;
262 ///@}
263
264 const ReplMan& man() const { return *man_; }
265
266private:
267 void start() final;
268 const Def* rewrite(const Def*) final;
269
270 std::unique_ptr<ReplMan> man_;
271};
272
273/// Removes unreachable and dead code by rebuilding the whole World into a new one and `swap`ping them afterwards.
274/// @see @ref phases_rwphase
275class Cleanup : public RWPhase {
276public:
278 : RWPhase(world, "cleanup") {}
281};
282
283/// Wraps a PassMan pipeline as a Phase.
284class PassManPhase : public Phase {
285public:
286 /// @name Construction
287 ///@{
288 PassManPhase(World& world, std::unique_ptr<PassMan>&& man)
289 : Phase(world, "pass_man_phase")
290 , man_(std::move(man)) {}
293
294 void apply(const App*) final;
295 void apply(Stage&) final;
296 ///@}
297
298 const PassMan& man() const { return *man_; }
299
300private:
301 void start() final { man_->run(); }
302
303 std::unique_ptr<PassMan> man_;
304};
305
306/// Organizes several Phase%s into a pipeline.
307/// If fixed_point() is `true`, rerun the whole pipeline until all Phase::todo()%s flags remain `false`.
308/// @see @ref phases_phase_man
309class PhaseMan : public Phase {
310public:
311 /// @name Construction
312 ///@{
315
316 void apply(bool, Phases&&);
317 void apply(const App*) final;
318 void apply(Stage&) final;
319 ///@}
320
321 /// @name Getters
322 ///@{
323 bool fixed_point() const { return fixed_point_; }
324 auto& phases() { return phases_; }
325 const auto& phases() const { return phases_; }
326 ///@}
327
328private:
329 void start() final;
330
331 Phases phases_;
332 bool fixed_point_;
333};
334
335/// Transitively visits all *reachable*, [*closed*](@ref Def::is_closed) mutables in the World.
336/// * Select with `elide_empty` whether you want to visit trivial mutables without body.
337/// * If you are only interested in specific mutables, you can pass this to @p M.
338/// @see @ref phases_closed_mut_phase
339template<class M = Def>
340class ClosedMutPhase : public Phase {
341public:
343 : Phase(world, std::move(name))
344 , elide_empty_(elide_empty) {}
348
349 bool elide_empty() const { return elide_empty_; }
350
351protected:
352 void start() override {
353 world().template for_each<M>(elide_empty(), [this](M* mut) { root_ = mut, visit(mut); });
354 }
355 virtual void visit(M*) = 0;
356 M* root() const { return root_; }
357
358private:
359 const bool elide_empty_;
360 M* root_;
361};
362
363/// Like ClosedMutPhase but computes a Nest for each NestPhase::visit.
364/// @see @ref phases_nest_phase
365template<class M = Def>
366class NestPhase : public ClosedMutPhase<M> {
367public:
368 NestPhase(World& world, std::string name, bool elide_empty)
369 : ClosedMutPhase<M>(world, std::move(name), elide_empty) {}
372
373 const Nest& nest() const { return *nest_; }
374 virtual void visit(const Nest&) = 0;
375
376private:
377 void visit(M* mut) final {
378 Nest nest(mut);
379 nest_ = &nest;
380 visit(nest);
381 }
382
383 const Nest* nest_;
384};
385
386} // namespace mim
Traverses the current World using Rewriter infrastructure while staying in the same world.
Definition phase.h:82
void start() override
Actual entry.
Definition phase.cpp:29
Analysis(World &world, std::string name)
Definition phase.h:86
World & world()
Definition phase.h:114
Def2Def lattice_
Definition phase.h:120
virtual void rewrite_external(Def *)
Definition phase.cpp:40
auto & lattice()
Definition phase.h:100
virtual void reset()
Clears rewriter state, analysis state, and resets Phase::todo() for the next fixed-point iteration.
Definition phase.cpp:23
const auto & lattice() const
Definition phase.h:101
virtual void rewrite_annex(flags_t, const Def *)
Definition phase.cpp:39
bool is_bootstrapping() const
Definition phase.h:102
Analysis(World &world, flags_t annex)
Definition phase.h:89
Def * rewrite_mut(Def *) override
Keeps old muts/vars.
Definition phase.cpp:42
Cleanup(World &world, flags_t annex)
Definition phase.h:279
Cleanup(World &world)
Definition phase.h:277
M * root() const
Definition phase.h:356
ClosedMutPhase(World &world, std::string name, bool elide_empty)
Definition phase.h:342
void start() override
Actual entry.
Definition phase.h:352
ClosedMutPhase(World &world, flags_t annex, bool elide_empty)
Definition phase.h:345
bool elide_empty() const
Definition phase.h:349
virtual void visit(M *)=0
Base class for all Defs.
Definition def.h:252
NestPhase(World &world, flags_t annex, bool elide_empty)
Definition phase.h:370
virtual void visit(const Nest &)=0
const Nest & nest() const
Definition phase.h:373
void visit(M *mut) final
Definition phase.h:377
NestPhase(World &world, std::string name, bool elide_empty)
Definition phase.h:368
Builds a nesting tree of all mutables‍/binders.
Definition nest.h:12
PassManPhase(World &world, flags_t annex)
Definition phase.h:291
PassManPhase(World &world, std::unique_ptr< PassMan > &&man)
Definition phase.h:288
void start() final
Actual entry.
Definition phase.h:301
const PassMan & man() const
Definition phase.h:298
An optimizer that combines several optimizations in an optimal way.
Definition pass.h:172
Organizes several Phases into a pipeline.
Definition phase.h:309
PhaseMan(World &world, flags_t annex)
Definition phase.h:313
bool fixed_point() const
Definition phase.h:323
auto & phases()
Definition phase.h:324
const auto & phases() const
Definition phase.h:325
Unlike a Pass, a Phase performs one self-contained task and does not interleave with other phases.
Definition phase.h:27
friend class Analysis
Definition phase.h:67
void invalidate(bool todo=true)
Signals that another round of fixed-point iteration is required, either as part of.
Definition phase.h:48
Phase(World &world, std::string name)
Definition phase.h:31
static void run(Args &&... args)
Runs a single Phase.
Definition phase.h:58
Phase(World &world, flags_t annex)
Definition phase.h:33
virtual void run()
Entry point and generates some debug output; invokes Phase::start.
Definition phase.cpp:13
bool todo() const
Definition phase.h:40
virtual void start()=0
Actual entry.
virtual bool analyze()
Runs the optional pre-analysis on RWPhase::old_world(), typically to a fixed point,...
Definition phase.cpp:84
World & new_world()
Create new Defs into this.
Definition phase.h:195
RWPhase(World &world, flags_t annex, Analysis *analysis=nullptr)
Definition phase.h:150
virtual void rewrite_annex(flags_t, const Def *)
Definition phase.cpp:94
Analysis * analysis()
Definition phase.h:158
bool is_bootstrapping() const
Returns whether we are currently bootstrapping (rewriting annexes).
Definition phase.h:183
RWPhase(World &world, std::string name, Analysis *analysis=nullptr)
Definition phase.h:146
void start() override
Actual entry.
Definition phase.cpp:65
const Def * lattice(const Def *old_def)
Returns the abstract value computed by the associated Analysis for the given old-world Def,...
Definition phase.h:163
World & world()=delete
Hides both and forbids direct access.
const Analysis * analysis() const
Definition phase.h:159
World & old_world()
Get old Defs from here.
Definition phase.h:194
virtual void rewrite_external(Def *)
Definition phase.cpp:96
const Def * rewrite(const Def *) final
Definition phase.cpp:148
ReplManPhase(World &world, flags_t annex)
Definition phase.h:257
const ReplMan & man() const
Definition phase.h:264
void start() final
Actual entry.
Definition phase.cpp:140
ReplManPhase(World &world, std::unique_ptr< ReplMan > &&man)
Definition phase.h:254
void apply(const App *) final
Invoked if your Stage has additional args.
Definition phase.cpp:126
void apply(Stage &stage) final
Dito, but invoked by Stage::recreate.
Definition phase.h:223
const auto & repls() const
Definition phase.h:226
const Def * replace(const Def *) final
Definition phase.h:229
ReplMan(World &world, flags_t annex)
Definition phase.h:218
void add(std::unique_ptr< Repl > &&repl)
Definition phase.h:225
void apply(Repls &&)
Definition phase.cpp:105
Simple Stage that searches for a pattern and replaces it.
Definition phase.h:208
virtual const Def * replace(const Def *def)=0
Repl(World &world, flags_t annex)
Definition phase.h:210
World & world()
Definition rewrite.h:48
Rewriter(std::unique_ptr< World > &&ptr)
Definition rewrite.h:23
Common base for Phase and Pass.
Definition pass.h:26
World & world()
Definition pass.h:64
std::string_view name() const
Definition pass.h:67
Stage(World &world, std::string name)
Definition pass.h:30
flags_t annex() const
Definition pass.h:68
The World represents the whole program and manages creation of MimIR nodes (Defs).
Definition world.h:34
#define M(S, D)
Definition ast.h:14
DefMap< const Def * > Def2Def
Definition def.h:76
u64 flags_t
Definition types.h:46
std::deque< std::unique_ptr< Repl > > Repls
Definition phase.h:21
std::deque< std::unique_ptr< Phase > > Phases
Definition phase.h:22
Definition span.h:122