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