MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
eta_conv.h
Go to the documentation of this file.
1#pragma once
2
3#include <fe/assert.h>
4
5#include "mim/phase.h"
6
7#include "mim/util/util.h"
8
9namespace mim {
10
11/// Combined η-normalization: folds η-reduction and η-expansion into a single, idempotent phase.
12/// A Lam should appear either **only** in callee position (Known) or not (Unknown).
13/// A Lam that occurs in an unknown position more than once (Unknown_N) or in both positions (Both) is η-expanded
14/// (`g f -> g (λx.f x)`); a genuine η-redex `λx.f x` whose `f` does **not** want to be expanded is η-reduced.
15///
16/// The analysis is **wrapper-transparent**: a use of a wrapper `λx.f x` is counted as a use of `f` at the same
17/// position/multiplicity instead of counting `f` as Known (the wrapper's callee).
18/// This makes `f`'s classification identical whether `f` is bare or wrapped, so the canonical η-form is a genuine
19/// fixed point - the phase does not fight itself and can share one big `%%compile.phases tt` fixed-point loop with
20/// BetaRed and %%mem.seo without oscillating.
21class EtaConv : public RWPhase {
22public:
24 : RWPhase(world, "EtaConv") {}
27
28private:
29 enum Lattice : u8 {
30 None = 0,
31 Known = 1,
32 Unknown_1 = 2,
33 Unknown_N = 3,
34 Both = 4,
35 };
36
37 static Lattice join(Lattice l1, Lattice l2) {
38 if (l1 == Unknown_1 && l2 == Unknown_1) return Unknown_N;
39 if (l1 == l2) return l1;
40 if (l1 == None) return l2;
41 if (l2 == None) return l1;
42 if (l1 == Both || l2 == Both) return Both;
43 if (l1 == Known && (l2 == Unknown_1 || l2 == Unknown_N)) return Both;
44 if (l2 == Known && (l1 == Unknown_1 || l1 == Unknown_N)) return Both;
45 if (l1 == Unknown_1 && l2 == Unknown_N) return Unknown_N;
46 if (l2 == Unknown_1 && l1 == Unknown_N) return Unknown_N;
47 fe::unreachable();
48 }
49
50 Lattice lattice(const Lam* lam) {
51 if (auto i = lam2lattice_.find(lam); i != lam2lattice_.end()) return i->second;
52 return None;
53 }
54
55 static bool eta_expand(Lattice l) { return l != Known && l != Unknown_1 && l != None; }
56 bool eta_expand(const Lam* lam) { return eta_expand(lattice(lam)); }
57
58 /// Should a wrapper `λx.f x` be kept (because `f` wants to be expanded) instead of reduced?
59 bool keep_wrapper(const Def* f) {
60 auto lam = f->isa<Lam>();
61 return lam && eta_expand(lattice(lam));
62 }
63
64 void join(const Lam* lam, Lattice l) {
65 if (auto [i, ins] = lam2lattice_.emplace(lam, l); !ins) i->second = join(i->second, l);
66 }
67
68 bool analyze() final;
69 void analyze(const Def*);
70 void visit(const Def*, Lattice);
71
72 void rewrite_annex(flags_t, Sym, const Def*) final;
73 void rewrite_external(Def*) final;
74 const Def* rewrite(const Def*) final;
75 const Def* rewrite_imm_App(const App*) final;
76 const Def* rewrite_imm_Var(const Var*) final;
77 /// η-reduce wrappers but never η-expand - used for callee (Known) positions, where expansion must not happen
78 /// but a wrapper `λx.f x` should still collapse to `f` (just as the standalone EtaRed did everywhere).
79 const Def* rewrite_no_exp(const Def* old_def);
80 const Def* rewrite_no_eta(const Def* old_def) { return RWPhase::rewrite(old_def); }
81
82 DefSet analyzed_;
83 GIDMap<const Lam*, Lattice> lam2lattice_;
84};
85
86} // namespace mim
EtaConv(World &world)
Definition eta_conv.h:23
const Def * rewrite_imm_Var(const Var *) final
Definition eta_conv.cpp:84
const Def * rewrite(const Def *) final
Definition eta_conv.cpp:43
void rewrite_annex(flags_t, Sym, const Def *) final
Definition eta_conv.cpp:34
void rewrite_external(Def *) final
Definition eta_conv.cpp:38
const Def * rewrite_imm_App(const App *) final
Definition eta_conv.cpp:79
EtaConv(World &world, flags_t annex)
Definition eta_conv.h:25
bool analyze() final
Runs the optional pre-analysis on RWPhase::old_world(), typically to a fixed point,...
Definition eta_conv.cpp:5
flags_t annex() const
Definition phase.h:81
RWPhase(World &world, std::string name, Analysis *analysis=nullptr)
Definition phase.h:316
World & world()=delete
Hides both and forbids direct access.
virtual const Def * rewrite(const Def *)
Definition rewrite.cpp:56
The World represents the whole program and manages creation of MimIR nodes (Defs).
Definition world.h:36
Definition ast.h:14
u64 flags_t
Definition types.h:39
absl::flat_hash_map< K, V, GIDHash< K > > GIDMap
Definition util.h:168
GIDSet< const Def * > DefSet
Definition def.h:76
uint8_t u8
Definition types.h:27
@ Lam
Definition def.h:109
@ Var
Definition def.h:109
@ App
Definition def.h:109