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/// @note You can override Rewriter::rewrite, Rewriter::rewrite_imm, Rewriter::rewrite_mut, etc.
107class RWPhase : public Phase, public Rewriter {
108public:
109 /// @name Construction
110 ///@{
111 RWPhase(World& world, std::string name, Analysis* analysis = nullptr)
112 : Phase(world, std::move(name))
113 , Rewriter(world.inherit())
114 , analysis_(analysis) {}
115 RWPhase(World& world, flags_t annex, Analysis* analysis = nullptr)
116 : Phase(world, annex)
117 , Rewriter(world.inherit())
118 , analysis_(analysis) {}
119 ///@}
120
121 bool is_bootstrapping() const { return bootstrapping_; }
122
123 /// You can do an optional fixed-point loop on the RWPhase::old_world before rewriting.
124 /// If analysis_ is set, use this for the fixed-point loop.
125 /// @note If you don't need a fixed-point, just return `false` after the first run of analyze.
126 virtual bool analyze();
127
128 /// @name Rewrite
129 ///@{
130 virtual void rewrite_annex(flags_t, const Def*);
131 virtual void rewrite_external(Def*);
132 ///@}
133
134 /// @name World
135 /// * Phase::world is the **old** one.
136 /// * Rewriter::world is the **new** one.
137 /// * RWPhase::world is deleted to not confuse this.
138 ///@{
139 using Phase::world;
140 using Rewriter::world;
141 World& world() = delete; ///< Hides both and forbids direct access.
142 World& old_world() { return Phase::world(); } ///< Get **old** Def%s from here.
143 World& new_world() { return Rewriter::world(); } ///< Create **new** Def%s into this.
144 ///@}
145
146protected:
147 void start() override;
148
149private:
150 Analysis* analysis_;
151 bool bootstrapping_ = true;
152};
153
154/// Simple Stage that searches for a pattern and replaces it.
155/// Combine them in a ReplPhase.
156class Repl : public Stage {
157public:
160
161 virtual const Def* replace(const Def* def) = 0;
162};
163
164class ReplMan : public Repl {
165public:
168
169 void apply(Repls&&);
170 void apply(const App*) final;
171 void apply(Stage& stage) final { apply(std::move(static_cast<ReplMan&>(stage).repls_)); }
172
173 void add(std::unique_ptr<Repl>&& repl) { repls_.emplace_back(std::move(repl)); }
174 const auto& repls() const { return repls_; }
175
176private:
177 const Def* replace(const Def*) final { fe::unreachable(); }
178
179 Repls repls_;
180};
181
182#define MIM_CONCAT_INNER(a, b) a##b
183#define MIM_CONCAT(a, b) MIM_CONCAT_INNER(a, b)
184
185#define MIM_REPL(__stages, __annex, ...) MIM_REPL_IMPL(__stages, __annex, __LINE__, __VA_ARGS__)
186
187// clang-format off
188#define MIM_REPL_IMPL(__stages, __annex, __id, ...) \
189 struct MIM_CONCAT(Repl_, __id) : ::mim::Repl { \
190 MIM_CONCAT(Repl_, __id)(::mim::World & world, ::mim::flags_t annex) \
191 : Repl(world, annex) {} \
192 \
193 const ::mim::Def* replace(const ::mim::Def* def) final __VA_ARGS__ \
194 }; \
195 ::mim::Stage::hook<__annex, MIM_CONCAT(Repl_, __id)>(__stages)
196// clang-format on
197
198class ReplManPhase : public RWPhase {
199public:
200 /// @name Construction
201 ///@{
202 ReplManPhase(World& world, std::unique_ptr<ReplMan>&& man)
203 : RWPhase(world, "pass_man_phase")
204 , man_(std::move(man)) {}
207
208 void apply(const App*) final;
209 void apply(Stage&) final;
210 ///@}
211
212 const ReplMan& man() const { return *man_; }
213
214private:
215 void start() final;
216 const Def* rewrite(const Def*) final;
217
218 std::unique_ptr<ReplMan> man_;
219};
220
221/// Removes unreachable and dead code by rebuilding the whole World into a new one and `swap`ping them afterwards.
222class Cleanup : public RWPhase {
223public:
225 : RWPhase(world, "cleanup") {}
228};
229
230/// Wraps a PassMan pipeline as a Phase.
231class PassManPhase : public Phase {
232public:
233 /// @name Construction
234 ///@{
235 PassManPhase(World& world, std::unique_ptr<PassMan>&& man)
236 : Phase(world, "pass_man_phase")
237 , man_(std::move(man)) {}
240
241 void apply(const App*) final;
242 void apply(Stage&) final;
243 ///@}
244
245 const PassMan& man() const { return *man_; }
246
247private:
248 void start() final { man_->run(); }
249
250 std::unique_ptr<PassMan> man_;
251};
252
253/// Organizes several Phase%s in a a pipeline.
254/// If @p fixed_point is `true`, run PhaseMan until all Phase%s' Phase::todo_ flags yield `false`.
255class PhaseMan : public Phase {
256public:
257 /// @name Construction
258 ///@{
261
262 void apply(bool, Phases&&);
263 void apply(const App*) final;
264 void apply(Stage&) final;
265 ///@}
266
267 /// @name Getters
268 ///@{
269 bool fixed_point() const { return fixed_point_; }
270 auto& phases() { return phases_; }
271 const auto& phases() const { return phases_; }
272 ///@}
273
274private:
275 void start() final;
276
277 Phases phases_;
278 bool fixed_point_;
279};
280
281/// Transitively visits all *reachable*, [*closed*](@ref Def::is_closed) mutables in the World.
282/// * Select with `elide_empty` whether you want to visit trivial mutables without body.
283/// * If you a are only interested in specific mutables, you can pass this to @p M.
284template<class M = Def>
285class ClosedMutPhase : public Phase {
286public:
288 : Phase(world, std::move(name))
289 , elide_empty_(elide_empty) {}
293
294 bool elide_empty() const { return elide_empty_; }
295
296protected:
297 void start() override {
298 world().template for_each<M>(elide_empty(), [this](M* mut) { root_ = mut, visit(mut); });
299 }
300 virtual void visit(M*) = 0;
301 M* root() const { return root_; }
302
303private:
304 const bool elide_empty_;
305 M* root_;
306};
307
308/// Like ClosedMutPhase but computes a Nest for each NestPhase::visit.
309template<class M = Def>
310class NestPhase : public ClosedMutPhase<M> {
311public:
312 NestPhase(World& world, std::string name, bool elide_empty)
313 : ClosedMutPhase<M>(world, std::move(name), elide_empty) {}
316
317 const Nest& nest() const { return *nest_; }
318 virtual void visit(const Nest&) = 0;
319
320private:
321 void visit(M* mut) final {
322 Nest nest(mut);
323 nest_ = &nest;
324 visit(nest);
325 }
326
327 const Nest* nest_;
328};
329
330} // 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:226
Cleanup(World &world)
Definition phase.h:224
M * root() const
Definition phase.h:301
ClosedMutPhase(World &world, std::string name, bool elide_empty)
Definition phase.h:287
void start() override
Actual entry.
Definition phase.h:297
ClosedMutPhase(World &world, flags_t annex, bool elide_empty)
Definition phase.h:290
bool elide_empty() const
Definition phase.h:294
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:314
virtual void visit(const Nest &)=0
const Nest & nest() const
Definition phase.h:317
void visit(M *mut) final
Definition phase.h:321
NestPhase(World &world, std::string name, bool elide_empty)
Definition phase.h:312
Builds a nesting tree of all immutables‍/binders.
Definition nest.h:11
PassManPhase(World &world, flags_t annex)
Definition phase.h:238
PassManPhase(World &world, std::unique_ptr< PassMan > &&man)
Definition phase.h:235
void start() final
Actual entry.
Definition phase.h:248
const PassMan & man() const
Definition phase.h:245
An optimizer that combines several optimizations in an optimal way.
Definition pass.h:172
Organizes several Phases in a a pipeline.
Definition phase.h:255
PhaseMan(World &world, flags_t annex)
Definition phase.h:259
bool fixed_point() const
Definition phase.h:269
auto & phases()
Definition phase.h:270
const auto & phases() const
Definition phase.h:271
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:63
World & new_world()
Create new Defs into this.
Definition phase.h:143
RWPhase(World &world, flags_t annex, Analysis *analysis=nullptr)
Definition phase.h:115
virtual void rewrite_annex(flags_t, const Def *)
Definition phase.cpp:73
bool is_bootstrapping() const
Definition phase.h:121
RWPhase(World &world, std::string name, Analysis *analysis=nullptr)
Definition phase.h:111
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:142
virtual void rewrite_external(Def *)
Definition phase.cpp:75
const Def * rewrite(const Def *) final
Definition phase.cpp:127
ReplManPhase(World &world, flags_t annex)
Definition phase.h:205
const ReplMan & man() const
Definition phase.h:212
void start() final
Actual entry.
Definition phase.cpp:119
ReplManPhase(World &world, std::unique_ptr< ReplMan > &&man)
Definition phase.h:202
void apply(const App *) final
Invoked if your Stage has additional args.
Definition phase.cpp:105
void apply(Stage &stage) final
Dito, but invoked by Stage::recreate.
Definition phase.h:171
const auto & repls() const
Definition phase.h:174
const Def * replace(const Def *) final
Definition phase.h:177
ReplMan(World &world, flags_t annex)
Definition phase.h:166
void add(std::unique_ptr< Repl > &&repl)
Definition phase.h:173
void apply(Repls &&)
Definition phase.cpp:84
Simple Stage that searches for a pattern and replaces it.
Definition phase.h:156
virtual const Def * replace(const Def *def)=0
Repl(World &world, flags_t annex)
Definition phase.h:158
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:45
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