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 op : mut->deps())
167 for (auto mut : op->local_muts()) queue.push(mut);
168 }
169 }
170
171protected:
172 virtual void visit(M*) = 0;
173 M* root() const { return root_; }
174
175private:
176 bool elide_empty_;
177 M* root_;
178};
179
180/// Transitively collects all *closed* mutables (Def::is_closed) in a World.
181template<class M = Def> class ClosedCollector : public ClosedMutPhase<M> {
182public:
184 : ClosedMutPhase<M>(world, "collector", false, false) {}
185
186 virtual void visit(M* mut) { muts.emplace_back(mut); }
187
188 /// Wrapper to directly receive all *closed* mutables as Vector.
190 ClosedCollector<M> collector(world);
191 collector.run();
192 return std::move(collector.muts);
193 }
194
196};
197
198/// Like ClosedMutPhase but computes a Nest for each NestPhase::visit.
199template<class M = Def> class NestPhase : public ClosedMutPhase<M> {
200public:
201 NestPhase(World& world, std::string_view name, bool dirty, bool elide_empty)
202 : ClosedMutPhase<M>(world, name, dirty, elide_empty) {}
203
204 const Nest& nest() const { return *nest_; }
205 virtual void visit(const Nest&) = 0;
206
207private:
208 void visit(M* mut) final {
209 Nest nest(mut);
210 nest_ = &nest;
211 visit(nest);
212 }
213
214 const Nest* nest_;
215};
216
217} // namespace mim
void start() override
Actual entry.
Definition phase.cpp:25
Cleanup(World &world)
Definition phase.h:69
static Vector< M * > collect(World &world)
Wrapper to directly receive all closed mutables as Vector.
Definition phase.h:189
Vector< M * > muts
Definition phase.h:195
ClosedCollector(World &world)
Definition phase.h:183
virtual void visit(M *mut)
Definition phase.h:186
M * root() const
Definition phase.h:173
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
Defs deps() const noexcept
Definition def.cpp:441
Muts local_muts() const
Mutables reachable by following immutable deps(); mut->local_muts() is by definition the set { mut }...
Definition def.cpp:316
FPPhase(World &world, std::string_view name)
Definition phase.h:79
void start() override
Actual entry.
Definition phase.cpp:16
virtual bool analyze()=0
virtual void visit(const Nest &)=0
const Nest & nest() const
Definition phase.h:204
void visit(M *mut) final
Definition phase.h:208
NestPhase(World &world, std::string_view name, bool dirty, bool elide_empty)
Definition phase.h:201
Builds a nesting tree of all immutables‍/binders.
Definition nest.h:11
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
const auto & passes() const
Definition pass.h:115
PassPhase(World &world, Args &&... args)
Definition phase.h:90
void start() override
Actual entry.
Definition phase.h:97
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
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
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
Rewriter(World &world)
Definition rewrite.h:11
This is a thin wrapper for absl::InlinedVector<T, N, A> which is a drop-in replacement for std::vecto...
Definition vector.h:17
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:109