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 current your fixed-point PhaseMan.
57 bool todo_ = false;
58};
59
60/// Rewrites the RWPhase::old_world into the RWPhase::new_world and `swap`s them afterwards.
61/// This will destroy RWPhase::old_world leaving RWPhase::new_world which will be created here as the *current* World to
62/// work with.
63/// This Phase will recursively Rewriter::rewrite
64/// 1. all (old) World::annexes() (during which RWPhase::is_bootstrapping is `true`), and then
65/// 2. all (old) World::externals() (during which RWPhase::is_bootstrapping is `false`).
66/// @note You can override Rewriter::rewrite, Rewriter::rewrite_imm, Rewriter::rewrite_mut, etc.
67class RWPhase : public Phase, public Rewriter {
68public:
69 /// @name Construction
70 ///@{
71 RWPhase(World& world, std::string name)
72 : Phase(world, std::move(name))
73 , Rewriter(world.inherit()) {}
75 : Phase(world, annex)
76 , Rewriter(world.inherit()) {}
77 ///@}
78
79 bool is_bootstrapping() const { return bootstrapping_; }
80
81 /// You can do an optional fixed-point loop on the RWPhase::old_world before rewriting.
82 /// @note If you don't need a fixed-point, just return `false` after the first run of analyze.
83 virtual bool analyze() { return false; }
84
85 /// @name Rewrite
86 ///@{
87 virtual void rewrite_annex(flags_t, const Def*);
88 virtual void rewrite_external(Def*);
89 ///@}
90
91 /// @name World
92 /// * Phase::world is the **old** one.
93 /// * Rewriter::world is the **new** one.
94 /// * RWPhase::world is deleted to not confuse this.
95 ///@{
96 using Phase::world;
97 using Rewriter::world;
98 World& world() = delete; ///< Hides both and forbids direct access.
99 World& old_world() { return Phase::world(); } ///< Get **old** Def%s from here.
100 World& new_world() { return Rewriter::world(); } ///< Create **new** Def%s into this.
101 ///@}
102
103protected:
104 void start() override;
105
106private:
107 bool bootstrapping_ = true;
108};
109
110/// Simple Stage that searches for a pattern and replaces it.
111/// Combine them in a ReplPhase.
112class Repl : public Stage {
113public:
116
117 virtual const Def* replace(const Def* def) = 0;
118};
119
120class ReplMan : public Repl {
121public:
124
125 void apply(Repls&&);
126 void apply(const App*) final;
127 void apply(Stage& stage) final { apply(std::move(static_cast<ReplMan&>(stage).repls_)); }
128
129 void add(std::unique_ptr<Repl>&& repl) { repls_.emplace_back(std::move(repl)); }
130 const auto& repls() const { return repls_; }
131
132private:
133 const Def* replace(const Def*) final { fe::unreachable(); }
134
135 Repls repls_;
136};
137
138#define MIM_CONCAT_INNER(a, b) a##b
139#define MIM_CONCAT(a, b) MIM_CONCAT_INNER(a, b)
140
141#define MIM_REPL(__stages, __annex, ...) MIM_REPL_IMPL(__stages, __annex, __LINE__, __VA_ARGS__)
142
143// clang-format off
144#define MIM_REPL_IMPL(__stages, __annex, __id, ...) \
145 struct MIM_CONCAT(Repl_, __id) : ::mim::Repl { \
146 MIM_CONCAT(Repl_, __id)(::mim::World & world, ::mim::flags_t annex) \
147 : Repl(world, annex) {} \
148 \
149 const ::mim::Def* replace(const ::mim::Def* def) final __VA_ARGS__ \
150 }; \
151 ::mim::Stage::hook<__annex, MIM_CONCAT(Repl_, __id)>(__stages)
152// clang-format on
153
154class ReplManPhase : public RWPhase {
155public:
156 /// @name Construction
157 ///@{
158 ReplManPhase(World& world, std::unique_ptr<ReplMan>&& man)
159 : RWPhase(world, "pass_man_phase")
160 , man_(std::move(man)) {}
163
164 void apply(const App*) final;
165 void apply(Stage&) final;
166 ///@}
167
168 const ReplMan& man() const { return *man_; }
169
170private:
171 void start() final;
172 const Def* rewrite(const Def*) final;
173
174 std::unique_ptr<ReplMan> man_;
175};
176
177/// Removes unreachable and dead code by rebuilding the whole World into a new one and `swap`ping them afterwards.
178class Cleanup : public RWPhase {
179public:
181 : RWPhase(world, "cleanup") {}
184};
185
186/// Wraps a PassMan pipeline as a Phase.
187class PassManPhase : public Phase {
188public:
189 /// @name Construction
190 ///@{
191 PassManPhase(World& world, std::unique_ptr<PassMan>&& man)
192 : Phase(world, "pass_man_phase")
193 , man_(std::move(man)) {}
196
197 void apply(const App*) final;
198 void apply(Stage&) final;
199 ///@}
200
201 const PassMan& man() const { return *man_; }
202
203private:
204 void start() final { man_->run(); }
205
206 std::unique_ptr<PassMan> man_;
207};
208
209/// Organizes several Phase%s in a a pipeline.
210/// If @p fixed_point is `true`, run PhaseMan until all Phase%s' Phase::todo_ flags yield `false`.
211class PhaseMan : public Phase {
212public:
213 /// @name Construction
214 ///@{
217
218 void apply(bool, Phases&&);
219 void apply(const App*) final;
220 void apply(Stage&) final;
221 ///@}
222
223 /// @name Getters
224 ///@{
225 bool fixed_point() const { return fixed_point_; }
226 auto& phases() { return phases_; }
227 const auto& phases() const { return phases_; }
228 ///@}
229
230private:
231 void start() final;
232
233 Phases phases_;
234 bool fixed_point_;
235};
236
237/// Transitively visits all *reachable*, [*closed*](@ref Def::is_closed) mutables in the World.
238/// * Select with `elide_empty` whether you want to visit trivial mutables without body.
239/// * If you a are only interested in specific mutables, you can pass this to @p M.
240template<class M = Def>
241class ClosedMutPhase : public Phase {
242public:
244 : Phase(world, std::move(name))
245 , elide_empty_(elide_empty) {}
249
250 bool elide_empty() const { return elide_empty_; }
251
252protected:
253 void start() override {
254 world().template for_each<M>(elide_empty(), [this](M* mut) { root_ = mut, visit(mut); });
255 }
256 virtual void visit(M*) = 0;
257 M* root() const { return root_; }
258
259private:
260 const bool elide_empty_;
261 M* root_;
262};
263
264/// Like ClosedMutPhase but computes a Nest for each NestPhase::visit.
265template<class M = Def>
266class NestPhase : public ClosedMutPhase<M> {
267public:
268 NestPhase(World& world, std::string name, bool elide_empty)
269 : ClosedMutPhase<M>(world, std::move(name), elide_empty) {}
272
273 const Nest& nest() const { return *nest_; }
274 virtual void visit(const Nest&) = 0;
275
276private:
277 void visit(M* mut) final {
278 Nest nest(mut);
279 nest_ = &nest;
280 visit(nest);
281 }
282
283 const Nest* nest_;
284};
285
286} // namespace mim
Cleanup(World &world, flags_t annex)
Definition phase.h:182
Cleanup(World &world)
Definition phase.h:180
M * root() const
Definition phase.h:257
ClosedMutPhase(World &world, std::string name, bool elide_empty)
Definition phase.h:243
void start() override
Actual entry.
Definition phase.h:253
ClosedMutPhase(World &world, flags_t annex, bool elide_empty)
Definition phase.h:246
bool elide_empty() const
Definition phase.h:250
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:270
virtual void visit(const Nest &)=0
const Nest & nest() const
Definition phase.h:273
void visit(M *mut) final
Definition phase.h:277
NestPhase(World &world, std::string name, bool elide_empty)
Definition phase.h:268
Builds a nesting tree of all immutables‍/binders.
Definition nest.h:11
PassManPhase(World &world, flags_t annex)
Definition phase.h:194
PassManPhase(World &world, std::unique_ptr< PassMan > &&man)
Definition phase.h:191
void start() final
Actual entry.
Definition phase.h:204
const PassMan & man() const
Definition phase.h:201
An optimizer that combines several optimizations in an optimal way.
Definition pass.h:172
Organizes several Phases in a a pipeline.
Definition phase.h:211
PhaseMan(World &world, flags_t annex)
Definition phase.h:215
bool fixed_point() const
Definition phase.h:225
auto & phases()
Definition phase.h:226
const auto & phases() const
Definition phase.h:227
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 current your 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.
World & new_world()
Create new Defs into this.
Definition phase.h:100
RWPhase(World &world, std::string name)
Definition phase.h:71
virtual void rewrite_annex(flags_t, const Def *)
Definition phase.cpp:40
bool is_bootstrapping() const
Definition phase.h:79
void start() override
Actual entry.
Definition phase.cpp:23
World & world()=delete
Hides both and forbids direct access.
RWPhase(World &world, flags_t annex)
Definition phase.h:74
virtual bool analyze()
You can do an optional fixed-point loop on the RWPhase::old_world before rewriting.
Definition phase.h:83
World & old_world()
Get old Defs from here.
Definition phase.h:99
virtual void rewrite_external(Def *)
Definition phase.cpp:42
const Def * rewrite(const Def *) final
Definition phase.cpp:94
ReplManPhase(World &world, flags_t annex)
Definition phase.h:161
const ReplMan & man() const
Definition phase.h:168
void start() final
Actual entry.
Definition phase.cpp:86
ReplManPhase(World &world, std::unique_ptr< ReplMan > &&man)
Definition phase.h:158
void apply(const App *) final
Invoked if your Stage has additional args.
Definition phase.cpp:72
void apply(Stage &stage) final
Dito, but invoked by Stage::recreate.
Definition phase.h:127
const auto & repls() const
Definition phase.h:130
const Def * replace(const Def *) final
Definition phase.h:133
ReplMan(World &world, flags_t annex)
Definition phase.h:122
void add(std::unique_ptr< Repl > &&repl)
Definition phase.h:129
void apply(Repls &&)
Definition phase.cpp:51
Simple Stage that searches for a pattern and replaces it.
Definition phase.h:112
virtual const Def * replace(const Def *def)=0
Repl(World &world, flags_t annex)
Definition phase.h:114
World & world()
Definition rewrite.h:36
Rewriter(std::unique_ptr< World > &&ptr)
Definition rewrite.h:13
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:36
#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