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/// As opposed to a Pass, a Phase does one thing at a time and does not mix with other Phase%s.
25/// They are supposed to classically run one after another.
26class Phase : public Stage {
27public:
28 /// @name Construction & Destruction
29 ///@{
30 Phase(World& world, std::string name)
31 : Stage(world, name) {}
34
35 ///@}
36
37 /// @name Getters
38 ///@{
39 bool todo() const { return todo_; }
40 ///@}
41
42 /// @name run
43 ///@{
44 virtual void run(); ///< Entry point and generates some debug output; invokes Phase::start.
45 virtual void start() = 0; ///< Actual entry.
46
47 /// Runs a single Phase.
48 template<class P, class... Args>
49 static void run(Args&&... args) {
50 P p(std::forward<Args>(args)...);
51 p.run();
52 }
53 ///@}
54
55protected:
56 /// Set to `true` to indicate that you want to rerun all Phase%es in your current fixed-point PhaseMan.
57 bool todo_ = false;
58};
59
60/// This Phase will recursively Rewriter::rewrite
61/// 1. all World::annexes() (during which Analysis::is_bootstrapping is `true`), and then
62/// 2. all World::externals() (during which Analysis::is_bootstrapping is `false`).
63/// @note You can override Rewriter::rewrite, Rewriter::rewrite_imm, Rewriter::rewrite_mut, etc.
64class Analysis : public Phase, public Rewriter {
65public:
66 /// @name Construction & Destruction
67 ///@{
68 Analysis(World& world, std::string name)
69 : Phase(world, std::move(name))
70 , Rewriter(world) {}
74
75 /// Clears all members and sets todo() to `false` for next round in a fixed-point iteration.
76 /// @sa RWPhase::analyze
77 virtual void reset();
78 ///@}
79
80 bool is_bootstrapping() const { return bootstrapping_; }
81
82 /// @name Rewrite
83 ///@{
84 virtual void rewrite_annex(flags_t, const Def*);
85 virtual void rewrite_external(Def*);
86 ///@}
87
88 /// @name Getters
89 ///@{
90 World& world() { return Phase::world(); }
91 ///@}
92
93protected:
94 void start() override;
95
96private:
97 bool bootstrapping_ = true;
98};
99
100/// Rewrites the RWPhase::old_world into the RWPhase::new_world and `swap`s them afterwards.
101/// This will destroy RWPhase::old_world leaving RWPhase::new_world which will be created here as the *current* World to
102/// work with.
103/// This Phase will recursively Rewriter::rewrite
104/// 1. all (old) World::annexes() (during which RWPhase::is_bootstrapping is `true`), and then
105/// 2. all (old) World::externals() (during which RWPhase::is_bootstrapping is `false`).
106/// All rewrites that refer to another annex have to be skipped during bootstrapping.
107/// @note You can override Rewriter::rewrite, Rewriter::rewrite_imm, Rewriter::rewrite_mut, etc.
108class RWPhase : public Phase, public Rewriter {
109public:
110 /// @name Construction
111 ///@{
112 RWPhase(World& world, std::string name, Analysis* analysis = nullptr)
113 : Phase(world, std::move(name))
114 , Rewriter(world.inherit())
115 , analysis_(analysis) {}
116 RWPhase(World& world, flags_t annex, Analysis* analysis = nullptr)
117 : Phase(world, annex)
118 , Rewriter(world.inherit())
119 , analysis_(analysis) {}
120 ///@}
121
122 /// Returns whether we are currently bootstrapping (rewriting annexes).
123 /// While bootstrapping, you have to skip rewrites that refer to other annexes, as they might not yet be available.
124 bool is_bootstrapping() const { return bootstrapping_; }
125
126 /// You can do an optional fixed-point loop on the RWPhase::old_world before rewriting.
127 /// If analysis_ is set, use this for the fixed-point loop.
128 /// @note If you don't need a fixed-point, just return `false` after the first run of analyze.
129 virtual bool analyze();
130
131 /// @name Rewrite
132 ///@{
133 virtual void rewrite_annex(flags_t, const Def*);
134 virtual void rewrite_external(Def*);
135 ///@}
136
137 /// @name World
138 /// * Phase::world is the **old** one.
139 /// * Rewriter::world is the **new** one.
140 /// * RWPhase::world is deleted to not confuse this.
141 ///@{
142 using Phase::world;
143 using Rewriter::world;
144 World& world() = delete; ///< Hides both and forbids direct access.
145 World& old_world() { return Phase::world(); } ///< Get **old** Def%s from here.
146 World& new_world() { return Rewriter::world(); } ///< Create **new** Def%s into this.
147 ///@}
148
149protected:
150 void start() override;
151
152private:
153 Analysis* analysis_;
154 bool bootstrapping_ = true;
155};
156
157/// Simple Stage that searches for a pattern and replaces it.
158/// Combine them in a ReplPhase.
159class Repl : public Stage {
160public:
163
164 virtual const Def* replace(const Def* def) = 0;
165};
166
167class ReplMan : public Repl {
168public:
171
172 void apply(Repls&&);
173 void apply(const App*) final;
174 void apply(Stage& stage) final { apply(std::move(static_cast<ReplMan&>(stage).repls_)); }
175
176 void add(std::unique_ptr<Repl>&& repl) { repls_.emplace_back(std::move(repl)); }
177 const auto& repls() const { return repls_; }
178
179private:
180 const Def* replace(const Def*) final { fe::unreachable(); }
181
182 Repls repls_;
183};
184
185#define MIM_CONCAT_INNER(a, b) a##b
186#define MIM_CONCAT(a, b) MIM_CONCAT_INNER(a, b)
187
188#define MIM_REPL(__stages, __annex, ...) MIM_REPL_IMPL(__stages, __annex, __LINE__, __VA_ARGS__)
189
190// clang-format off
191#define MIM_REPL_IMPL(__stages, __annex, __id, ...) \
192 struct MIM_CONCAT(Repl_, __id) : ::mim::Repl { \
193 MIM_CONCAT(Repl_, __id)(::mim::World & world, ::mim::flags_t annex) \
194 : Repl(world, annex) {} \
195 \
196 const ::mim::Def* replace(const ::mim::Def* def) final __VA_ARGS__ \
197 }; \
198 ::mim::Stage::hook<__annex, MIM_CONCAT(Repl_, __id)>(__stages)
199// clang-format on
200
201class ReplManPhase : public RWPhase {
202public:
203 /// @name Construction
204 ///@{
205 ReplManPhase(World& world, std::unique_ptr<ReplMan>&& man)
206 : RWPhase(world, "pass_man_phase")
207 , man_(std::move(man)) {}
210
211 void apply(const App*) final;
212 void apply(Stage&) final;
213 ///@}
214
215 const ReplMan& man() const { return *man_; }
216
217private:
218 void start() final;
219 const Def* rewrite(const Def*) final;
220
221 std::unique_ptr<ReplMan> man_;
222};
223
224/// Removes unreachable and dead code by rebuilding the whole World into a new one and `swap`ping them afterwards.
225class Cleanup : public RWPhase {
226public:
228 : RWPhase(world, "cleanup") {}
231};
232
233/// Wraps a PassMan pipeline as a Phase.
234class PassManPhase : public Phase {
235public:
236 /// @name Construction
237 ///@{
238 PassManPhase(World& world, std::unique_ptr<PassMan>&& man)
239 : Phase(world, "pass_man_phase")
240 , man_(std::move(man)) {}
243
244 void apply(const App*) final;
245 void apply(Stage&) final;
246 ///@}
247
248 const PassMan& man() const { return *man_; }
249
250private:
251 void start() final { man_->run(); }
252
253 std::unique_ptr<PassMan> man_;
254};
255
256/// Organizes several Phase%s in a a pipeline.
257/// If @p fixed_point is `true`, run PhaseMan until all Phase%s' Phase::todo_ flags yield `false`.
258class PhaseMan : public Phase {
259public:
260 /// @name Construction
261 ///@{
264
265 void apply(bool, Phases&&);
266 void apply(const App*) final;
267 void apply(Stage&) final;
268 ///@}
269
270 /// @name Getters
271 ///@{
272 bool fixed_point() const { return fixed_point_; }
273 auto& phases() { return phases_; }
274 const auto& phases() const { return phases_; }
275 ///@}
276
277private:
278 void start() final;
279
280 Phases phases_;
281 bool fixed_point_;
282};
283
284/// Transitively visits all *reachable*, [*closed*](@ref Def::is_closed) mutables in the World.
285/// * Select with `elide_empty` whether you want to visit trivial mutables without body.
286/// * If you a are only interested in specific mutables, you can pass this to @p M.
287template<class M = Def>
288class ClosedMutPhase : public Phase {
289public:
291 : Phase(world, std::move(name))
292 , elide_empty_(elide_empty) {}
296
297 bool elide_empty() const { return elide_empty_; }
298
299protected:
300 void start() override {
301 world().template for_each<M>(elide_empty(), [this](M* mut) { root_ = mut, visit(mut); });
302 }
303 virtual void visit(M*) = 0;
304 M* root() const { return root_; }
305
306private:
307 const bool elide_empty_;
308 M* root_;
309};
310
311/// Like ClosedMutPhase but computes a Nest for each NestPhase::visit.
312template<class M = Def>
313class NestPhase : public ClosedMutPhase<M> {
314public:
315 NestPhase(World& world, std::string name, bool elide_empty)
316 : ClosedMutPhase<M>(world, std::move(name), elide_empty) {}
319
320 const Nest& nest() const { return *nest_; }
321 virtual void visit(const Nest&) = 0;
322
323private:
324 void visit(M* mut) final {
325 Nest nest(mut);
326 nest_ = &nest;
327 visit(nest);
328 }
329
330 const Nest* nest_;
331};
332
333} // namespace mim
This Phase will recursively Rewriter::rewrite.
Definition phase.h:64
void start() override
Actual entry.
Definition phase.cpp:29
Analysis(World &world, std::string name)
Definition phase.h:68
World & world()
Definition phase.h:90
virtual void rewrite_external(Def *)
Definition phase.cpp:40
virtual void reset()
Clears all members and sets todo() to false for next round in a fixed-point iteration.
Definition phase.cpp:23
virtual void rewrite_annex(flags_t, const Def *)
Definition phase.cpp:39
bool is_bootstrapping() const
Definition phase.h:80
Analysis(World &world, flags_t annex)
Definition phase.h:71
Cleanup(World &world, flags_t annex)
Definition phase.h:229
Cleanup(World &world)
Definition phase.h:227
M * root() const
Definition phase.h:304
ClosedMutPhase(World &world, std::string name, bool elide_empty)
Definition phase.h:290
void start() override
Actual entry.
Definition phase.h:300
ClosedMutPhase(World &world, flags_t annex, bool elide_empty)
Definition phase.h:293
bool elide_empty() const
Definition phase.h:297
virtual void visit(M *)=0
Base class for all Defs.
Definition def.h:251
NestPhase(World &world, flags_t annex, bool elide_empty)
Definition phase.h:317
virtual void visit(const Nest &)=0
const Nest & nest() const
Definition phase.h:320
void visit(M *mut) final
Definition phase.h:324
NestPhase(World &world, std::string name, bool elide_empty)
Definition phase.h:315
Builds a nesting tree of all immutables‍/binders.
Definition nest.h:11
PassManPhase(World &world, flags_t annex)
Definition phase.h:241
PassManPhase(World &world, std::unique_ptr< PassMan > &&man)
Definition phase.h:238
void start() final
Actual entry.
Definition phase.h:251
const PassMan & man() const
Definition phase.h:248
An optimizer that combines several optimizations in an optimal way.
Definition pass.h:172
Organizes several Phases in a a pipeline.
Definition phase.h:258
PhaseMan(World &world, flags_t annex)
Definition phase.h:262
bool fixed_point() const
Definition phase.h:272
auto & phases()
Definition phase.h:273
const auto & phases() const
Definition phase.h:274
As opposed to a Pass, a Phase does one thing at a time and does not mix with other Phases.
Definition phase.h:26
bool todo_
Set to true to indicate that you want to rerun all Phasees in your current fixed-point PhaseMan.
Definition phase.h:57
Phase(World &world, std::string name)
Definition phase.h:30
static void run(Args &&... args)
Runs a single Phase.
Definition phase.h:49
Phase(World &world, flags_t annex)
Definition phase.h:32
virtual void run()
Entry point and generates some debug output; invokes Phase::start.
Definition phase.cpp:13
bool todo() const
Definition phase.h:39
virtual void start()=0
Actual entry.
virtual bool analyze()
You can do an optional fixed-point loop on the RWPhase::old_world before rewriting.
Definition phase.cpp:65
World & new_world()
Create new Defs into this.
Definition phase.h:146
RWPhase(World &world, flags_t annex, Analysis *analysis=nullptr)
Definition phase.h:116
virtual void rewrite_annex(flags_t, const Def *)
Definition phase.cpp:75
bool is_bootstrapping() const
Returns whether we are currently bootstrapping (rewriting annexes).
Definition phase.h:124
RWPhase(World &world, std::string name, Analysis *analysis=nullptr)
Definition phase.h:112
void start() override
Actual entry.
Definition phase.cpp:46
World & world()=delete
Hides both and forbids direct access.
World & old_world()
Get old Defs from here.
Definition phase.h:145
virtual void rewrite_external(Def *)
Definition phase.cpp:77
const Def * rewrite(const Def *) final
Definition phase.cpp:129
ReplManPhase(World &world, flags_t annex)
Definition phase.h:208
const ReplMan & man() const
Definition phase.h:215
void start() final
Actual entry.
Definition phase.cpp:121
ReplManPhase(World &world, std::unique_ptr< ReplMan > &&man)
Definition phase.h:205
void apply(const App *) final
Invoked if your Stage has additional args.
Definition phase.cpp:107
void apply(Stage &stage) final
Dito, but invoked by Stage::recreate.
Definition phase.h:174
const auto & repls() const
Definition phase.h:177
const Def * replace(const Def *) final
Definition phase.h:180
ReplMan(World &world, flags_t annex)
Definition phase.h:169
void add(std::unique_ptr< Repl > &&repl)
Definition phase.h:176
void apply(Repls &&)
Definition phase.cpp:86
Simple Stage that searches for a pattern and replaces it.
Definition phase.h:159
virtual const Def * replace(const Def *def)=0
Repl(World &world, flags_t annex)
Definition phase.h:161
World & world()
Definition rewrite.h:47
Rewriter(std::unique_ptr< World > &&ptr)
Definition rewrite.h:22
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:31
#define M(S, D)
Definition ast.h:14
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