MimIR 0.1
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
pass.h
Go to the documentation of this file.
1#pragma once
2
3#include <stack>
4#include <typeindex>
5
6#include "mim/world.h"
7
8namespace mim {
9
10class PassMan;
11/// @name Undo
12/// Used by FPPass::analyze to indicate where to backtrack to.
13///@{
14using undo_t = size_t;
15static constexpr undo_t No_Undo = std::numeric_limits<undo_t>::max();
16///@}
17
18/// All Pass%es that want to be registered in the PassMan must implement this interface.
19/// * Inherit from RWPass if your pass does **not** need state and a fixed-point iteration.
20/// * Inherit from FPPass if you **do** need state and a fixed-point.
21/// * If you do not rely on interaction between different Pass%es, consider using Phase instead.
22class Pass {
23public:
24 Pass(PassMan&, std::string_view name);
25 virtual ~Pass() = default;
26
27 /// @name Getters
28 ///@{
29 World& world();
30 PassMan& man() { return man_; }
31 const PassMan& man() const { return man_; }
32 std::string_view name() const { return name_; }
33 size_t index() const { return index_; }
34 ///@}
35
36 /// @name Rewrite Hook for the PassMan
37 /// Rewrites an *immutable* @p def within PassMan::curr_mut.
38 /// @returns the replacement.
39 ///@{
40 virtual Ref rewrite(Ref def) { return def; }
41 virtual Ref rewrite(const Var* var) { return var; }
42 virtual Ref rewrite(const Proxy* proxy) { return proxy; }
43 ///@}
44
45 /// @name Analyze Hook for the PassMan
46 /// Invoked after the PassMan has finished Pass::rewrite%ing PassMan::curr_mut to analyze the Def.
47 /// Will only be invoked if Pass::fixed_point() yields `true` - which will be the case for FPPass%es.
48 /// @returns mim::No_Undo or the state to roll back to.
49 ///@{
50 virtual undo_t analyze(Ref) { return No_Undo; }
51 virtual undo_t analyze(const Var*) { return No_Undo; }
52 virtual undo_t analyze(const Proxy*) { return No_Undo; }
53 ///@}
54
55 /// @name Further Hooks for the PassMan
56 ///@{
57 virtual bool fixed_point() const { return false; }
58
59 /// Should the PassMan even consider this pass?
60 virtual bool inspect() const = 0;
61
62 /// Invoked just before Pass::rewrite%ing PassMan::curr_mut's body.
63 /// @note This is invoked when seeing the *inside* of a mutable the first time.
64 /// This is often too late, as you usually want to do something when you see a mutable the first time from the
65 /// *outside*. This means that this PassMan::curr_mut has already been encountered elsewhere. Otherwise, we wouldn't
66 /// have seen PassMan::curr_mut to begin with (unless it is Def::is_external).
67 virtual void enter() {}
68
69 /// Invoked **once** before entering the main rewrite loop.
70 virtual void prepare() {}
71 ///@}
72
73 /// @name proxy
74 ///@{
75 const Proxy* proxy(Ref type, Defs ops, u32 tag = 0) { return world().proxy(type, ops, index(), tag); }
76 /// Check whether given @p def is a Proxy whose Proxy::pass matches this Pass's @p IPass::index.
77 const Proxy* isa_proxy(Ref def, u32 tag = 0) {
78 if (auto proxy = def->isa<Proxy>(); proxy != nullptr && proxy->pass() == index() && proxy->tag() == tag)
79 return proxy;
80 return nullptr;
81 }
82 const Proxy* as_proxy(Ref def, u32 tag = 0) {
83 auto proxy = def->as<Proxy>();
84 assert_unused(proxy->pass() == index() && proxy->tag() == tag);
85 return proxy;
86 }
87 ///@}
88
89private:
90 /// @name Memory Management
91 ///@{
92 virtual void* alloc() { return nullptr; } ///< Default constructor.
93 virtual void* copy(const void*) { return nullptr; } ///< Copy constructor.
94 virtual void dealloc(void*) {} ///< Destructor.
95 ///@}
96
97 PassMan& man_;
98 std::string name_;
99 size_t index_;
100
101 friend class PassMan;
102};
103
104/// An optimizer that combines several optimizations in an optimal way.
105/// This is loosely based upon:
106/// "Composing dataflow analyses and transformations" by Lerner, Grove, Chambers.
107class PassMan {
108public:
110 : world_(world) {}
111
112 /// @name Getters
113 ///@{
114 World& world() const { return world_; }
115 const auto& passes() const { return passes_; }
116 bool fixed_point() const { return fixed_point_; }
117 Def* curr_mut() const { return curr_mut_; }
118 ///@}
119
120 /// @name Create and run Passes
121 ///@{
122 void run(); ///< Run all registered passes on the whole World.
123
124 /// Add a pass to this PassMan.
125 /// If a pass of the same class has been added already, returns the earlier added instance.
126 template<class P, class... Args> P* add(Args&&... args) {
127 auto key = std::type_index(typeid(P));
128 if (auto it = registry_.find(key); it != registry_.end()) return static_cast<P*>(it->second);
129 auto p = std::make_unique<P>(*this, std::forward<Args>(args)...);
130 auto res = p.get();
131 fixed_point_ |= res->fixed_point();
132 passes_.emplace_back(std::move(p));
133 registry_.emplace(key, res);
134 return res;
135 }
136
137 /// Runs a single Pass.
138 template<class P, class... Args> static void run(World& world, Args&&... args) {
139 PassMan man(world);
140 man.add<P>(std::forward<Args>(args)...);
141 man.run();
142 }
143 ///@}
144
145private:
146 /// @name State
147 ///@{
148 struct State {
149 State() = default;
150 State(const State&) = delete;
151 State(State&&) = delete;
152 State& operator=(State) = delete;
153 State(size_t num)
154 : data(num) {}
155
156 Def* curr_mut = nullptr;
157 DefVec old_ops;
158 std::stack<Def*> stack;
159 MutMap<undo_t> mut2visit;
160 Vector<void*> data;
161 Def2Def old2new;
162 DefSet analyzed;
163 };
164
165 void push_state();
166 void pop_states(undo_t undo);
167 State& curr_state() {
168 assert(!states_.empty());
169 return states_.back();
170 }
171 const State& curr_state() const {
172 assert(!states_.empty());
173 return states_.back();
174 }
175 undo_t curr_undo() const { return states_.size() - 1; }
176 ///@}
177
178 /// @name rewriting
179 ///@{
180 Ref rewrite(Ref);
181
182 Ref map(Ref old_def, Ref new_def) {
183 curr_state().old2new[old_def] = new_def;
184 curr_state().old2new.emplace(new_def, new_def);
185 return new_def;
186 }
187
188 std::optional<Ref> lookup(Ref old_def) {
189 for (auto& state : states_ | std::ranges::views::reverse)
190 if (auto i = state.old2new.find(old_def); i != state.old2new.end()) return i->second;
191 return {};
192 }
193 ///@}
194
195 /// @name analyze
196 ///@{
197 undo_t analyze(Ref);
198 bool analyzed(Ref def) {
199 for (auto& state : states_ | std::ranges::views::reverse)
200 if (state.analyzed.contains(def)) return true;
201 curr_state().analyzed.emplace(def);
202 return false;
203 }
204 ///@}
205
206 World& world_;
207 std::deque<std::unique_ptr<Pass>> passes_;
208 absl::flat_hash_map<std::type_index, Pass*> registry_;
209 std::deque<State> states_;
210 Def* curr_mut_ = nullptr;
211 bool fixed_point_ = false;
212 bool proxy_ = false;
213
214 template<class P, class M> friend class FPPass;
215};
216
217/// Inherit from this class using [CRTP](https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern),
218/// if your Pass does **not** need state and a fixed-point iteration.
219/// If you a are only interested in specific mutables, you can pass this to @p M.
220template<class P, class M = Def> class RWPass : public Pass {
221public:
222 RWPass(PassMan& man, std::string_view name)
223 : Pass(man, name) {}
224
225 bool inspect() const override {
226 if constexpr (std::is_same<M, Def>::value)
227 return man().curr_mut();
228 else
229 return man().curr_mut()->template isa<M>();
230 }
231
232 M* curr_mut() const {
233 if constexpr (std::is_same<M, Def>::value)
234 return man().curr_mut();
235 else
236 return man().curr_mut()->template as<M>();
237 }
238};
239
240/// Inherit from this class using [CRTP](https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern),
241/// if you **do** need a Pass with a state and a fixed-point.
242template<class P, class M = Def> class FPPass : public RWPass<P, M> {
243public:
245 using Data = std::tuple<>; ///< Default.
246
247 FPPass(PassMan& man, std::string_view name)
248 : Super(man, name) {}
249
250 bool fixed_point() const override { return true; }
251
252protected:
253 /// @name State-related Getters
254 ///@{
255 const auto& states() const { return Super::man().states_; }
256 auto& states() { return Super::man().states_; }
257 auto& data() {
258 assert(!states().empty());
259 return *static_cast<typename P::Data*>(states().back().data[Super::index()]);
260 }
261 template<size_t I> auto& data() { return std::get<I>(data()); }
262 /// Use this for your convenience if `P::Data` is a map.
263 template<class K> auto& data(const K& key) { return data()[key]; }
264 /// Use this for your convenience if `P::Data<I>` is a map.
265 template<size_t I, class K> auto& data(const K& key) { return data<I>()[key]; }
266 ///@}
267
268 /// @name undo
269 ///@{
270 undo_t curr_undo() const { return Super::man().curr_undo(); } ///< Current undo point.
271
272 /// Retrieves the point to backtrack to just **before** @p mut was seen the very first time.
273 undo_t undo_visit(Def* mut) const {
274 const auto& mut2visit = Super::man().curr_state().mut2visit;
275 if (auto i = mut2visit.find(mut); i != mut2visit.end()) return i->second;
276 return No_Undo;
277 }
278
279 /// Retrieves the point to backtrack to just **before** rewriting @p mut%'s body.
280 undo_t undo_enter(Def* mut) const {
281 for (auto i = states().size(); i-- != 0;)
282 if (states()[i].curr_mut == mut) return i;
283 return No_Undo;
284 }
285 ///@}
286
287private:
288 /// @name Memory Management for State
289 ///@{
290 void* alloc() override { return new typename P::Data(); }
291 void* copy(const void* p) override { return new typename P::Data(*static_cast<const typename P::Data*>(p)); }
292 void dealloc(void* state) override { delete static_cast<typename P::Data*>(state); }
293 ///@}
294};
295
296inline World& Pass::world() { return man().world(); }
297
298} // namespace mim
Base class for all Defs.
Definition def.h:223
Inherit from this class using CRTP, if you do need a Pass with a state and a fixed-point.
Definition pass.h:242
void dealloc(void *state) override
Destructor.
Definition pass.h:292
auto & data()
Definition pass.h:261
auto & data()
Definition pass.h:257
undo_t undo_visit(Def *mut) const
Retrieves the point to backtrack to just before mut was seen the very first time.
Definition pass.h:273
auto & data(const K &key)
Use this for your convenience if P::Data is a map.
Definition pass.h:263
FPPass(PassMan &man, std::string_view name)
Definition pass.h:247
void * copy(const void *p) override
Copy constructor.
Definition pass.h:291
undo_t curr_undo() const
Current undo point.
Definition pass.h:270
const auto & states() const
Definition pass.h:255
bool fixed_point() const override
Definition pass.h:250
std::tuple<> Data
Default.
Definition pass.h:245
void * alloc() override
Default constructor.
Definition pass.h:290
auto & data(const K &key)
Use this for your convenience if P::Data<I> is a map.
Definition pass.h:265
auto & states()
Definition pass.h:256
undo_t undo_enter(Def *mut) const
Retrieves the point to backtrack to just before rewriting mut's body.
Definition pass.h:280
An optimizer that combines several optimizations in an optimal way.
Definition pass.h:107
Def * curr_mut() const
Definition pass.h:117
void run()
Run all registered passes on the whole World.
Definition pass.cpp:41
static void run(World &world, Args &&... args)
Runs a single Pass.
Definition pass.h:138
PassMan(World &world)
Definition pass.h:109
World & world() const
Definition pass.h:114
const auto & passes() const
Definition pass.h:115
P * add(Args &&... args)
Add a pass to this PassMan.
Definition pass.h:126
bool fixed_point() const
Definition pass.h:116
All Passes that want to be registered in the PassMan must implement this interface.
Definition pass.h:22
virtual void enter()
Invoked just before Pass::rewriteing PassMan::curr_mut's body.
Definition pass.h:67
World & world()
Definition pass.h:296
virtual undo_t analyze(const Proxy *)
Definition pass.h:52
size_t index() const
Definition pass.h:33
const PassMan & man() const
Definition pass.h:31
virtual Ref rewrite(const Proxy *proxy)
Definition pass.h:42
virtual Ref rewrite(Ref def)
Definition pass.h:40
Pass(PassMan &, std::string_view name)
Definition pass.cpp:10
virtual void * alloc()
Default constructor.
Definition pass.h:92
const Proxy * isa_proxy(Ref def, u32 tag=0)
Check whether given def is a Proxy whose Proxy::pass matches this Pass's IPass::index.
Definition pass.h:77
virtual void dealloc(void *)
Destructor.
Definition pass.h:94
virtual undo_t analyze(const Var *)
Definition pass.h:51
const Proxy * as_proxy(Ref def, u32 tag=0)
Definition pass.h:82
virtual ~Pass()=default
virtual void prepare()
Invoked once before entering the main rewrite loop.
Definition pass.h:70
virtual void * copy(const void *)
Copy constructor.
Definition pass.h:93
virtual undo_t analyze(Ref)
Definition pass.h:50
virtual bool fixed_point() const
Definition pass.h:57
virtual bool inspect() const =0
Should the PassMan even consider this pass?
PassMan & man()
Definition pass.h:30
virtual Ref rewrite(const Var *var)
Definition pass.h:41
std::string_view name() const
Definition pass.h:32
const Proxy * proxy(Ref type, Defs ops, u32 tag=0)
Definition pass.h:75
u32 pass() const
IPass::index within PassMan.
Definition def.h:831
u32 tag() const
Definition def.h:832
Inherit from this class using CRTP, if your Pass does not need state and a fixed-point iteration.
Definition pass.h:220
RWPass(PassMan &man, std::string_view name)
Definition pass.h:222
bool inspect() const override
Should the PassMan even consider this pass?
Definition pass.h:225
M * curr_mut() const
Definition pass.h:232
Helper class to retrieve Infer::arg if present.
Definition def.h:86
This is a thin wrapper for std::span<T, N> with the following additional features:
Definition span.h:28
The World represents the whole program and manages creation of MimIR nodes (Defs).
Definition world.h:33
const Proxy * proxy(Ref type, Defs ops, u32 index, u32 tag)
Definition world.h:218
#define M(S, D)
Definition cfg.h:11
DefMap< const Def * > Def2Def
Definition def.h:60
Vector< const Def * > DefVec
Definition def.h:62
GIDSet< const Def * > DefSet
Definition def.h:59
size_t undo_t
Definition pass.h:14
uint32_t u32
Definition types.h:34
static constexpr undo_t No_Undo
Definition pass.h:15
constexpr decltype(auto) get(mim::Span< T, N > span)
Definition span.h:113