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 "mim/def.h"
4#include "mim/nest.h"
5#include "mim/rewrite.h"
6
7#include "mim/pass/pass.h"
8
9namespace mim {
10
11class Nest;
12class World;
13
14/// As opposed to a Pass, a Phase does one thing at a time and does not mix with other Phase%s.
15/// They are supposed to classically run one after another.
16/// Phase::dirty indicates whether we may need a Cleanup afterwards.
17class Phase {
18public:
19 Phase(World& world, std::string_view name, bool dirty)
20 : world_(world)
21 , name_(name)
22 , dirty_(dirty) {}
23 virtual ~Phase() = default;
24
25 /// @name Getters
26 ///@{
27 World& world() { return world_; }
28 std::string_view name() const { return name_; }
29 bool is_dirty() const { return dirty_; }
30 ///@}
31
32 /// @name run
33 ///@{
34 virtual void run(); ///< Entry point and generates some debug output; invokes Phase::start.
35
36 /// Runs a single Phase.
37 template<class P, class... Args> static void run(Args&&... args) {
38 P p(std::forward<Args>(args)...);
39 p.run();
40 }
41 ///@}
42
43protected:
44 virtual void start() = 0; ///< Actual entry.
45 void set_name(std::string name) { name_ = name; }
46
47private:
48 World& world_;
49 std::string name_;
50 bool dirty_;
51};
52
53/// Visits the current Phase::world and constructs a new RWPhase::world along the way.
54/// It recursively **rewrites** all World::externals().
55/// @note You can override Rewriter::rewrite, Rewriter::rewrite_imm, and Rewriter::rewrite_mut.
56class RWPhase : public Phase, public Rewriter {
57public:
58 RWPhase(World& world, std::string_view name)
59 : Phase(world, name, true)
60 , Rewriter(world) {}
61
62 World& world() { return Phase::world(); }
63 void start() override;
64};
65
66/// Removes unreachable and dead code by rebuilding the whole World into a new one and `swap`ping afterwards.
67class Cleanup : public Phase {
68public:
70 : Phase(world, "cleanup", false) {}
71
72 void start() override;
73};
74
75/// Like a RWPhase but starts with a fixed-point loop of FPPhase::analyze beforehand.
76/// Inherit from this one to implement a classic data-flow analysis.
77class FPPhase : public RWPhase {
78public:
79 FPPhase(World& world, std::string_view name)
80 : RWPhase(world, name) {}
81
82 void start() override;
83 virtual bool analyze() = 0;
84};
85
86/// Wraps a Pass as a Phase.
87template<class P> class PassPhase : public Phase {
88public:
89 template<class... Args>
90 PassPhase(World& world, Args&&... args)
91 : Phase(world, {}, false)
92 , man_(world) {
93 man_.template add<P>(std::forward<Args>(args)...);
94 set_name(std::string(man_.passes().back()->name()) + ".pass_phase");
95 }
96
97 void start() override { man_.run(); }
98
99private:
100 PassMan man_;
101};
102
103/// Wraps a PassMan pipeline as a Phase.
104class PassManPhase : public Phase {
105public:
106 PassManPhase(World& world, std::unique_ptr<PassMan>&& man)
107 : Phase(world, "pass_man_phase", false)
108 , man_(std::move(man)) {}
109
110 void start() override { man_->run(); }
111
112private:
113 std::unique_ptr<PassMan> man_;
114};
115
116/// Organizes several Phase%s as a pipeline.
117class Pipeline : public Phase {
118public:
120 : Phase(world, "pipeline", true) {}
121
122 void start() override;
123
124 /// @name phases
125 ///@{
126 const auto& phases() const { return phases_; }
127
128 /// Add a Phase.
129 /// You don't need to pass the World to @p args - it will be passed automatically.
130 /// If @p P is a Pass, this method will wrap this in a PassPhase.
131 template<class P, class... Args> auto add(Args&&... args) {
132 if constexpr (std::is_base_of_v<Pass, P>) {
133 return add<PassPhase<P>>(std::forward<Args>(args)...);
134 } else {
135 auto p = std::make_unique<P>(world(), std::forward<Args&&>(args)...);
136 auto phase = p.get();
137 phases_.emplace_back(std::move(p));
138 if (phase->is_dirty()) phases_.emplace_back(std::make_unique<Cleanup>(world()));
139 return phase;
140 }
141 }
142 ///@}
143
144private:
145 std::deque<std::unique_ptr<Phase>> phases_;
146};
147
148/// Transitively visits all *reachable* closed mutables (Def::is_closed()) in World.
149/// Select with `elide_empty` whether you want to visit trivial *muts* without body.
150/// Assumes that you don't change anything - hence `dirty` flag is set to `false`.
151/// If you a are only interested in specific mutables, you can pass this to @p M.
152template<class M = Def> class ClosedMutPhase : public Phase {
153public:
154 ClosedMutPhase(World& world, std::string_view name, bool dirty, bool elide_empty)
155 : Phase(world, name, dirty)
156 , elide_empty_(elide_empty) {}
157
158 void start() override {
160 for (auto mut : world().externals()) queue.push(mut);
161
162 while (!queue.empty()) {
163 auto mut = queue.pop();
164 if (auto m = mut->isa<M>(); m && m->is_closed() && (!elide_empty_ || m->is_set())) visit(root_ = m);
165
166 for (auto local_mut : mut->mut_local_muts()) queue.push(local_mut);
167 }
168 }
169
170protected:
171 virtual void visit(M*) = 0;
172 M* root() const { return root_; }
173
174private:
175 bool elide_empty_;
176 M* root_;
177};
178
179/// Transitively collects all *closed* mutables (Def::is_closed) in a World.
180template<class M = Def> class ClosedCollector : public ClosedMutPhase<M> {
181public:
183 : ClosedMutPhase<M>(world, "collector", false, false) {}
184
185 virtual void visit(M* mut) { muts.emplace_back(mut); }
186
187 /// Wrapper to directly receive all *closed* mutables as Vector.
189 ClosedCollector<M> collector(world);
190 collector.run();
191 return std::move(collector.muts);
192 }
193
195};
196
197/// Like ClosedMutPhase but computes a Nest for each NestPhase::visit.
198template<class M = Def> class NestPhase : public ClosedMutPhase<M> {
199public:
200 NestPhase(World& world, std::string_view name, bool dirty, bool elide_empty)
201 : ClosedMutPhase<M>(world, name, dirty, elide_empty) {}
202
203 const Nest& nest() const { return *nest_; }
204 virtual void visit(const Nest&) = 0;
205
206private:
207 void visit(M* mut) final {
208 Nest nest(mut);
209 nest_ = &nest;
210 visit(nest);
211 }
212
213 const Nest* nest_;
214};
215
216} // namespace mim
Removes unreachable and dead code by rebuilding the whole World into a new one and swapping afterward...
Definition phase.h:67
void start() override
Actual entry.
Definition phase.cpp:25
Cleanup(World &world)
Definition phase.h:69
Transitively collects all closed mutables (Def::is_closed) in a World.
Definition phase.h:180
static Vector< M * > collect(World &world)
Wrapper to directly receive all closed mutables as Vector.
Definition phase.h:188
Vector< M * > muts
Definition phase.h:194
ClosedCollector(World &world)
Definition phase.h:182
virtual void visit(M *mut)
Definition phase.h:185
Transitively visits all reachable closed mutables (Def::is_closed()) in World.
Definition phase.h:152
M * root() const
Definition phase.h:172
ClosedMutPhase(World &world, std::string_view name, bool dirty, bool elide_empty)
Definition phase.h:154
void start() override
Actual entry.
Definition phase.h:158
virtual void visit(M *)=0
Like a RWPhase but starts with a fixed-point loop of FPPhase::analyze beforehand.
Definition phase.h:77
FPPhase(World &world, std::string_view name)
Definition phase.h:79
void start() override
Actual entry.
Definition phase.cpp:16
virtual bool analyze()=0
Like ClosedMutPhase but computes a Nest for each NestPhase::visit.
Definition phase.h:198
virtual void visit(const Nest &)=0
const Nest & nest() const
Definition phase.h:203
void visit(M *mut) final
Definition phase.h:207
NestPhase(World &world, std::string_view name, bool dirty, bool elide_empty)
Definition phase.h:200
Builds a nesting tree of all immutables‍/binders.
Definition nest.h:11
Wraps a PassMan pipeline as a Phase.
Definition phase.h:104
void start() override
Actual entry.
Definition phase.h:110
PassManPhase(World &world, std::unique_ptr< PassMan > &&man)
Definition phase.h:106
An optimizer that combines several optimizations in an optimal way.
Definition pass.h:107
void run()
Run all registered passes on the whole World.
Definition pass.cpp:39
const auto & passes() const
Definition pass.h:115
Wraps a Pass as a Phase.
Definition phase.h:87
PassPhase(World &world, Args &&... args)
Definition phase.h:90
void start() override
Actual entry.
Definition phase.h:97
As opposed to a Pass, a Phase does one thing at a time and does not mix with other Phases.
Definition phase.h:17
static void run(Args &&... args)
Runs a single Phase.
Definition phase.h:37
bool is_dirty() const
Definition phase.h:29
Phase(World &world, std::string_view name, bool dirty)
Definition phase.h:19
virtual void run()
Entry point and generates some debug output; invokes Phase::start.
Definition phase.cpp:5
std::string_view name() const
Definition phase.h:28
virtual void start()=0
Actual entry.
void set_name(std::string name)
Definition phase.h:45
virtual ~Phase()=default
World & world()
Definition phase.h:27
Organizes several Phases as a pipeline.
Definition phase.h:117
auto add(Args &&... args)
Add a Phase.
Definition phase.h:131
void start() override
Actual entry.
Definition phase.cpp:38
const auto & phases() const
Definition phase.h:126
Pipeline(World &world)
Definition phase.h:119
Visits the current Phase::world and constructs a new RWPhase::world along the way.
Definition phase.h:56
RWPhase(World &world, std::string_view name)
Definition phase.h:58
World & world()
Definition phase.h:62
void start() override
Actual entry.
Definition phase.cpp:11
Recurseivly rewrites part of a program into the provided World.
Definition rewrite.h:9
This is a thin wrapper for absl::InlinedVector<T, N, / A> which in turn is a drop-in replacement for ...
Definition vector.h:16
The World represents the whole program and manages creation of MimIR nodes (Defs).
Definition world.h:33
bool empty() const
Definition util.h:152
bool push(T val)
Definition util.h:144
#define M(S, D)
Definition ast.h:14
Definition span.h:104