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 "mim/phase.h"
4
5#include "mim/util/gid.h"
6
7namespace mim {
8
9/// Combined η-normalization: folds η-reduction and η-expansion into a single, idempotent phase.
10/// A Lam should appear either **only** in callee position (Known) or not (Unknown).
11/// A Lam that occurs in an unknown position more than once (Unknown_N) or in both positions is η-expanded
12/// (`g f -> g (λx.f x)`); a genuine η-redex `λx.f x` whose `f` does **not** want to be expanded is η-reduced.
13///
14/// The analysis is **wrapper-transparent**: a use of a wrapper `λx.f x` is counted as a use of `f` at the same
15/// position/multiplicity instead of counting `f` as Known (the wrapper's callee).
16/// This makes `f`'s classification identical whether `f` is bare or wrapped, so the canonical η-form is a genuine
17/// fixed point - the phase does not fight itself and can share one big `compile.phases tt` fixed-point loop with
18/// BetaRed and mem.seo without oscillating.
19class EtaConv : public RWPhase {
20public:
21 using RWPhase::RWPhase;
22
23private:
24 /// Known and Unknown_* are independent bits; both set means "both positions".
25 enum Lattice : u8 {
26 None = 0,
27 Known = 1 << 0,
28 Unknown_1 = 1 << 1,
29 Unknown_N = Unknown_1 | 1 << 2,
30 };
31
32 /// Two Unknown_1 uses saturate to Unknown_N.
33 static Lattice join(Lattice a, Lattice b) { return Lattice(a | b | (a & b & Unknown_1) << 1); }
34
35 Lattice lattice(const Lam* lam) const {
36 if (auto l = fe::lookup(lam2lattice_, lam)) return *l;
37 return None;
38 }
39
40 /// Does @p def want to be η-expanded - and hence keep any wrapper `λx.def x` instead of reducing it?
41 bool expand(const Def* def) const {
42 auto lam = def->isa<Lam>();
43 return lam && lattice(lam) > Unknown_1;
44 }
45
46 void join(const Lam* lam, Lattice l) {
47 auto& x = lam2lattice_[lam];
48 x = join(x, l);
49 }
50
51 bool analyze() final;
52 void analyze(const Def*);
53 void visit(const Def*, Lattice);
54
55 /// An external must keep its shape: neither η-reduce nor η-expand it.
56 void rewrite_external(Def* mut) final { rewrite_no_eta(mut)->as_mut()->externalize(); }
57 const Def* rewrite(const Def*) final;
58 const Def* rewrite_imm_App(const App*) final;
59 const Def* rewrite_imm_Var(const Var*) final;
60 /// η-reduce wrappers but never η-expand - used for callee (Known) positions, where expansion must not happen
61 /// but a wrapper `λx.f x` should still collapse to `f`.
62 const Def* rewrite_no_exp(const Def* old_def);
63 const Def* rewrite_no_eta(const Def* old_def) { return RWPhase::rewrite(old_def); }
64
65 DefSet analyzed_;
66 GIDMap<const Lam*, Lattice> lam2lattice_;
67};
68
69} // namespace mim
Base class for all Defs.
Definition def.h:289
Combined η-normalization: folds η-reduction and η-expansion into a single, idempotent phase.
Definition eta_conv.h:19
const Def * rewrite_imm_Var(const Var *) final
Definition eta_conv.cpp:70
const Def * rewrite(const Def *) final
Definition eta_conv.cpp:34
void rewrite_external(Def *mut) final
An external must keep its shape: neither η-reduce nor η-expand it.
Definition eta_conv.h:56
const Def * rewrite_imm_App(const App *) final
Definition eta_conv.cpp:65
RWPhase(World &world, std::string name, Analysis *analysis=nullptr)
Definition phase.h:334
bool analyze() final
Runs the optional pre-analysis on old_world(), typically to a fixed point, before rewriting begins.
Definition eta_conv.cpp:5
A function.
Definition lam.h:91
RWPhase(World &world, std::string name, Analysis *analysis=nullptr)
Definition phase.h:334
virtual const Def * rewrite(const Def *)
Definition rewrite.cpp:62
A variable introduced by a binder (mutable).
Definition def.h:857
Definition ast.h:16
ankerl::unordered_dense::map< K, V, GIDHash< K > > GIDMap
Definition gid.h:22
GIDSet< const Def * > DefSet
Definition def.h:94
uint8_t u8
Definition types.h:27