MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
beta_red.cpp
Go to the documentation of this file.
2
3namespace mim {
4
5static bool is_trivial(Lam* lam) {
6 if (auto var = lam->has_var()) {
7 if (auto app = lam->body()->isa<App>()) {
8 if (lam->ret_var() == app->callee() || !app->callee()->has_free_var(var))
9 return std::ranges::all_of(app->targs(), [&](const Def* arg) {
10 if (auto ex = arg->isa<Extract>(); ex && ex->tuple() == var) return true;
11 return arg == var || !arg->has_free_var(var);
12 });
13 }
14 return false;
15 }
16 return true;
17}
18
20 for (auto def : old_world().externals().muts())
21 visit(def, false);
22
23 // Inlining a trivial Lam at several call sites duplicates its callee's occurrence.
24 auto worklist = std::deque<Lam*>();
25 for (auto [lam, once] : once_)
26 if (!once && trivial_.contains(lam) && !cyclic_.contains(lam)) worklist.emplace_back(lam);
27
28 while (!worklist.empty()) {
29 auto lam = worklist.front();
30 worklist.pop_front();
31 if (auto callee = lam->forwardee()) {
32 if (auto& once = once_[callee]; once) {
33 once = false;
34 if (trivial_.contains(callee) && !cyclic_.contains(callee)) worklist.emplace_back(callee);
35 }
36 }
37 }
38
39 return false; // no fixed-point nccessary
40}
41
42void BetaRed::analyze(const Def* def) {
43 if (auto [_, ins] = analyzed_.emplace(def); !ins) {
44 // Back edge: this shared occurrence lies within the Lam%s it calls, so inlining it makes no progress.
45 if (on_stack_.contains(def))
46 for (auto mut : def->local_muts())
47 if (auto lam = mut->isa<Lam>()) cyclic_.emplace(lam);
48 return;
49 }
50
51 on_stack_.emplace(def);
52 for (auto d : def->deps())
53 visit(d, true);
54 on_stack_.erase(def);
55}
56
57void BetaRed::visit(const Def* def, bool candidate) {
58 if (auto lam = def->isa_mut<Lam>()) {
59 if (auto [i, ins] = once_.emplace(lam, candidate); !ins)
60 i->second = false;
61 else if (lam->is_set() && is_trivial(lam))
62 trivial_.emplace(lam);
63 }
64 analyze(def);
65}
66
67const Def* BetaRed::rewrite_imm_App(const App* app) {
68 if (auto old_lam = app->callee()->isa_mut<Lam>(); old_lam && old_lam->is_set() && is_candidate(old_lam))
69 return reduce(old_lam, app->arg());
70 return RWPhase::rewrite_imm_App(app);
71}
72
73const Def* BetaRed::reduce(Lam* old_lam, const Def* old_arg) {
74 profile_count("β-reduction");
75 log().d("β-reduction `{}`", old_lam);
76 invalidate();
77
78 if (auto var = old_lam->has_var(); var && is_once(old_lam)) {
79 map(var, rewrite(old_arg));
80 return rewrite(old_lam->body());
81 }
82
83 // The old body may already be memoized for a rebuilt copy of old_lam, so reduce in the old world.
84 return rewrite(old_lam->reduce_body(old_arg));
85}
86
87} // namespace mim
const Def * callee() const
Definition lam.h:237
const Def * arg() const
Definition lam.h:251
const Def * rewrite_imm_App(const App *) final
Definition beta_red.cpp:67
bool analyze() final
Runs the optional pre-analysis on old_world(), typically to a fixed point, before rewriting begins.
Definition beta_red.cpp:19
Base class for all Defs.
Definition def.h:289
bool is_set() const
Definition def.h:396
Defs deps() const noexcept
Definition def.cpp:486
T * isa_mut() const
If this is mutable, it will cast constness away and perform a dynamic_cast to T.
Definition def.h:588
bool has_free_var(const Var *) const
Same as free_vars().contains(var).
Definition def.cpp:277
Muts local_muts() const
Mutables reachable by following immutable deps(); mut->local_muts() is by definition the set { mut }...
Definition def.h:520
const Var * has_var()
Only returns not nullptr, if Var of this mutable has ever been created.
Definition def.h:496
A function.
Definition lam.h:91
const Def * body() const
Definition lam.h:104
const Def * reduce_body(const Def *arg) const
Definition lam.h:173
const Def * ret_var()
Yields the Lam::var of the Lam::ret_pi.
Definition lam.h:136
void invalidate(bool todo=true)
Signals that another round of fixed-point iteration is required, either as part of.
Definition phase.h:79
const fe::Log & log() const
Definition phase.h:60
void profile_count(std::string_view key, uint64_t n=1)
Adds n to the custom fe::Profiler counter key of the current run; no-op unless profiling is enabled.
Definition phase.cpp:60
World & old_world()
Get old Defs from here.
Definition phase.h:378
const Def * rewrite_imm_App(const App *) override
Definition phase.cpp:223
const Def * map(const Def *old_def, const Def *new_def)
Definition rewrite.cpp:29
virtual const Def * rewrite(const Def *)
Definition rewrite.cpp:62
Definition ast.h:16
static bool is_trivial(Lam *lam)
Definition beta_red.cpp:5