MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
rewrite.h
Go to the documentation of this file.
1#pragma once
2
3#include <fe/restore.h>
4
5#include "mim/check.h"
6#include "mim/def.h"
7#include "mim/lam.h"
8#include "mim/nom.h"
9#include "mim/rule.h"
10#include "mim/single.h"
11#include "mim/tuple.h"
12#include "mim/union.h"
13
14namespace mim {
15
16class World;
17
18/// Recurseivly rebuilds part of a program **into** the provided World w.r.t.\ Rewriter::map.
19/// This World may be different than the World we started with.
20/// @see @ref rewriter
21class Rewriter {
22public:
23 /// @name Construction & Destruction
24 ///@{
26 virtual ~Rewriter();
27
28 void reset();
29 ///@}
30
31 /// @name Getters
32 ///@{
33 World& world() { return *world_; }
34 ///@}
35
36 /// @name Scope
37 ///@{
38 /// Opens a scope for the mappings whose old Def depends on @p old_vars or whose new Def depends on @p new_vars.
39 /// The root scope takes all others.
40 void push(Vars old_vars = {}, Vars new_vars = {}) { scopes_.emplace_back(old_vars, new_vars); }
41 void pop() { scopes_.pop_back(); }
42 /// Adds the old @p var - if any - to the innermost scope.
43 void bind_old(const Var* var);
44 /// Adds the new @p var - if any - to the innermost scope.
45 void bind_new(const Var* var);
46 void bind(const Var* old_var, const Var* new_var) {
47 bind_old(old_var);
48 bind_new(new_var);
49 }
50 ///@}
51
52 /// @name Map / Lookup
53 /// Map @p old_def to @p new_def and returns @p new_def.
54 ///@{
55 /// Records the mapping in the innermost push() scope it depends on.
56 const Def* map(const Def* old_def, const Def* new_def);
57
58 // clang-format off
59 const Def* map(const Def* old_def , Defs new_defs);
60 const Def* map(Defs old_defs, const Def* new_def );
61 const Def* map(Defs old_defs, Defs new_defs);
62 // clang-format on
63
64 /// Lookup `old_def` by searching in reverse through the stack of maps.
65 /// @returns `nullptr` if nothing was found.
66 virtual const Def* lookup(const Def* old_def) {
67 for (const auto& scope : scopes_ | std::views::reverse)
68 if (auto new_def = fe::lookup(scope.old2new, old_def)) return new_def;
69 return nullptr;
70 }
71 ///@}
72
73 /// @name rewrite
74 /// Recursively rewrite old Def%s.
75 ///@{
76 virtual const Def* rewrite(const Def*);
77 virtual const Def* rewrite_imm(const Def*);
78 virtual const Def* rewrite_mut(Def*);
79 virtual const Def* rewrite_stub(Def*, Def*);
80 /// Like above, but @p new_mut may have a *different* number of ops than @p old_mut:
81 /// `new_mut->op(i)` is rewritten from `old_mut->op(new2old[i])`.
82 /// This is what a Phase needs that reshapes an aggregate; @see Sieve.
83 const Def* rewrite_stub(Def* old_mut, Def* new_mut, fe::View<size_t> new2old);
84 virtual DefVec rewrite(Defs);
85
86#define CODE_IMM(N) virtual const Def* rewrite_imm_##N(const N*);
87#define CODE_MUT(N) virtual const Def* rewrite_mut_##N(N*);
90#undef CODE_IMM
91#undef CODE_MUT
92
93 virtual const Def* rewrite_imm_Seq(const Seq* seq);
94 virtual const Def* rewrite_mut_Seq(Seq* seq);
95 ///@}
96
97 template<class D = Def>
98 D* curr_mut() const {
99 return curr_mut_ ? curr_mut_->template isa<D>() : nullptr;
100 }
101
102protected:
103 /// The map of the innermost push() scope.
104 Def2Def& old2new() { return scopes_.back().old2new; }
105
106 /// Does @p old_def depend on the old Vars of any scope?
107 bool has_intersection(const Def* old_def) {
108 // Def::has_free_vars_in avoids materializing old_def's merged free_vars() - once per level, at that.
109 for (const auto& scope : scopes_ | std::views::reverse)
110 if (old_def->has_free_vars_in(scope.old_vars)) return true;
111 return false;
112 }
113
114 /// Updates curr_mut() to @p new_mut and restores it at the end of the scope.
115 [[nodiscard]] auto enter(Def* new_mut) { return fe::Restore(curr_mut_, new_mut); }
116
117 /// The tail of rewrite_stub: immutabilizes @p new_mut in hindsight, as rewriting may have made it vacuous.
118 /// A stub that already has users stays mutable, as the users captured it during its own rewrite.
119 /// Only needed if you fill a stub yourself instead of going through rewrite_stub.
120 const Def* seal(Def* old_mut, Def* new_mut);
121
122 struct Scope {
123 Vars old_vars; ///< Only mappings depending on these go here; the root's are VarRewriter's substitutions.
126 };
127 fe::Vector<Scope> scopes_;
128
129private:
130 World* world_;
131 Def* curr_mut_ = nullptr;
132
133 friend void swap(Rewriter& rw1, Rewriter& rw2) noexcept {
134 using std::swap;
135 swap(rw1.scopes_, rw2.scopes_);
136 // Do NOT swap world_: it is a back pointer!
137 }
138};
139
140/// Extends Rewriter for variable substitution.
141/// @see @ref rewriter
142class VarRewriter : public Rewriter {
143public:
144 /// @name Construction
145 ///@{
148 VarRewriter(const Var* var, const Def* arg)
149 : Rewriter(arg->world()) {
150 add(var, arg);
151 }
152
153 /// Substitutes @p arg for @p var.
154 VarRewriter& add(const Var* var, const Def* arg) {
155 map(var, arg);
156 bind_old(var);
157 return *this;
158 }
159 ///@}
160
161 /// @name rewrite
162 ///@{
163 const Def* rewrite(const Def*) final;
164 const Def* rewrite_mut(Def*) final;
165 ///@}
166
167 friend void swap(VarRewriter& vrw1, VarRewriter& vrw2) noexcept {
168 using std::swap;
169 swap(static_cast<Rewriter&>(vrw1), static_cast<Rewriter&>(vrw2));
170 }
171};
172
173class Zonker : public Rewriter {
174public:
175 /// @name C'tor
176 ///@{
179 ///@}
180
181 const Def* lookup(const Def* old_def) final;
182
183 /// @name rewrite
184 ///@{
185 const Def* rewrite(const Def*) final;
186 const Def* rewrite_mut(Def* mut) final { return map(mut, mut); }
187 const Def* rewire_mut(Def*);
188 ///@}
189
190 friend void swap(Zonker& z1, Zonker& z2) noexcept {
191 using std::swap;
192 swap(static_cast<Rewriter&>(z1), static_cast<Rewriter&>(z2));
193 }
194};
195
196/// Imports from Driver::library: an annex therein is looked up via World::annex, so it is imported only once.
197class Importer : public Rewriter {
198public:
201
202 const Def* import(const Def* root) { return Rewriter::rewrite(root); }
203 const Def* rewrite(const Def*) final;
204
205 friend void swap(Importer& i1, Importer& i2) noexcept {
206 using std::swap;
207 swap(static_cast<Rewriter&>(i1), static_cast<Rewriter&>(i2));
208 }
209};
210
211} // namespace mim
Base class for all Defs.
Definition def.h:289
bool has_free_vars_in(Vars) const
Same as vars.has_intersection(free_vars()).
Definition def.cpp:285
const Def * rewrite(const Def *) final
Definition rewrite.cpp:349
friend void swap(Importer &i1, Importer &i2) noexcept
Definition rewrite.h:205
Importer(World &world)
Definition rewrite.h:199
fe::Vector< Scope > scopes_
Definition rewrite.h:127
friend void swap(Rewriter &rw1, Rewriter &rw2) noexcept
Definition rewrite.h:133
bool has_intersection(const Def *old_def)
Does old_def depend on the old Vars of any scope?
Definition rewrite.h:107
void bind_old(const Var *var)
Adds the old var - if any - to the innermost scope.
Definition rewrite.cpp:40
void pop()
Definition rewrite.h:41
virtual const Def * rewrite_imm_Seq(const Seq *seq)
Definition rewrite.cpp:230
virtual const Def * rewrite_mut_Seq(Seq *seq)
Definition rewrite.cpp:236
Vars old_vars
Only mappings depending on these go here; the root's are VarRewriter's substitutions.
Definition rewrite.h:123
World & world()
Definition rewrite.h:33
virtual const Def * rewrite_mut(Def *)
Definition rewrite.cpp:83
D * curr_mut() const
Definition rewrite.h:98
void bind(const Var *old_var, const Var *new_var)
Definition rewrite.h:46
virtual const Def * rewrite_stub(Def *, Def *)
Definition rewrite.cpp:257
const Def * map(const Def *old_def, const Def *new_def)
Definition rewrite.cpp:29
Rewriter(World &world)
Definition rewrite.cpp:16
virtual ~Rewriter()
void bind_new(const Var *var)
Adds the new var - if any - to the innermost scope.
Definition rewrite.cpp:44
const Def * seal(Def *old_mut, Def *new_mut)
The tail of rewrite_stub: immutabilizes new_mut in hindsight, as rewriting may have made it vacuous.
Definition rewrite.cpp:280
void reset()
Definition rewrite.cpp:23
virtual const Def * rewrite_imm(const Def *)
Definition rewrite.cpp:74
virtual const Def * rewrite(const Def *)
Definition rewrite.cpp:62
auto enter(Def *new_mut)
Updates curr_mut() to new_mut and restores it at the end of the scope.
Definition rewrite.h:115
void push(Vars old_vars={}, Vars new_vars={})
Definition rewrite.h:40
Def2Def & old2new()
The map of the innermost push() scope.
Definition rewrite.h:104
virtual const Def * lookup(const Def *old_def)
Lookup old_def by searching in reverse through the stack of maps.
Definition rewrite.h:66
Base class for Arr and Pack.
Definition tuple.h:267
VarRewriter & add(const Var *var, const Def *arg)
Substitutes arg for var.
Definition rewrite.h:154
const Def * rewrite_mut(Def *) final
Definition rewrite.cpp:302
VarRewriter(World &world)
Definition rewrite.h:146
friend void swap(VarRewriter &vrw1, VarRewriter &vrw2) noexcept
Definition rewrite.h:167
const Def * rewrite(const Def *) final
Definition rewrite.cpp:291
VarRewriter(const Var *var, const Def *arg)
Definition rewrite.h:148
A variable introduced by a binder (mutable).
Definition def.h:857
The World represents the whole program and manages creation of MimIR nodes (Defs).
Definition world.h:43
const Def * rewire_mut(Def *)
Definition rewrite.cpp:329
friend void swap(Zonker &z1, Zonker &z2) noexcept
Definition rewrite.h:190
const Def * lookup(const Def *old_def) final
Lookup old_def by searching in reverse through the stack of maps.
Definition rewrite.cpp:311
const Def * rewrite(const Def *) final
Definition rewrite.cpp:320
Zonker(World &world)
Definition rewrite.h:177
const Def * rewrite_mut(Def *mut) final
Definition rewrite.h:186
#define MIM_MUT_NODE(X)
Definition def.h:65
#define MIM_IMM_NODE(X)
Definition def.h:47
Definition ast.h:16
DefMap< const Def * > Def2Def
Definition def.h:95
fe::View< const Def * > Defs
Definition def.h:96
fe::Vector< const Def * > DefVec
Definition def.h:98
fe::Patricia< const Var, DefKey >::Set Vars
Definition def.h:115
#define CODE_MUT(N)
Definition phase.h:288
#define CODE_IMM(N)
Definition rewrite.h:86