MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
conv.h
Go to the documentation of this file.
1#pragma once
2
3#include <mim/def.h>
4#include <mim/phase.h>
5
6namespace mim::plug::cps {
7
8/// Full CPS conversion in one recursive rewrite.
9///
10/// Each term-level, direct-style function
11/// ```
12/// f: [a: A] → B
13/// ```
14/// becomes
15/// ```
16/// f_cps: Cn [a: A, Cn B]
17/// ```
18/// and every use of `f` is replaced by `cps.cps2ds_dep (A, λ a: B) f_cps` to remain type-correct.
19///
20/// Call sites are lifted on the fly:
21/// When the recursive rewrite encounters `App (cps.cps2ds_dep (T, U) k) arg` inside a continuation,
22/// it allocates a fresh continuation `cont` receiving the result, records the pending call `k (arg, cont)`,
23/// and uses `cont`'s variable as the value of the App.
24/// Once the enclosing Lam is done, the pending calls are wired up in encounter order - which respects
25/// data dependencies, because operands are always rewritten before their users:
26/// ```
27/// lam = k₀ (arg₀, cont₀)
28/// cont₀ = k₁ (arg₁, cont₁)
29/// ...
30/// contₙ = rewritten body of lam
31/// ```
32/// A lifted call simply lives in the Lam whose body rewriting first reaches it.
33/// Rewrites whose result mentions such a continuation variable are scoped to that Lam (see Conv::map) and
34/// re-derived - and thus re-lifted - in sibling scopes.
35class Conv : public RWPhase {
36public:
37 using RWPhase::RWPhase;
38
39private:
40 /// A lifted call `callee (arg, cont)` waiting to be wired into the body of the enclosing Lam.
41 struct Pending {
42 const Def* callee; ///< CPS callee `k: Cn [T, Cn U]`.
43 const Def* arg; ///< Rewritten argument - still without the continuation.
44 Lam* cont; ///< Fresh continuation receiving the result of the call.
45 };
46
47 /// RAII guard for rewriting the body of one mutable Lam:
48 /// fences pending_, pushes a map scope for contaminated rewrites, and tracks whether lifting is legal here.
49 class Scope {
50 public:
51 Scope(Conv& conv, bool liftable)
52 : conv_(conv)
53 , base_(conv.pending_.size())
54 , old_liftable_(conv.liftable_) {
55 conv_.push(Vars());
56 conv_.liftable_ = liftable;
57 }
58 ~Scope() {
59 assert(conv_.pending_.size() == base_ && "pending calls must have been wire()d");
60 conv_.pop();
61 conv_.liftable_ = old_liftable_;
62 }
63
64 size_t base() const { return base_; }
65
66 private:
67 Conv& conv_;
68 size_t base_;
69 bool old_liftable_;
70 };
71
72 const Def* rewrite_mut_Lam(Lam*) final;
73 const Def* rewrite_imm_App(const App*) final;
74
75 /// Converts direct-style `f: [a: A] → B` to `f_cps: Cn [a: A, Cn B]` and returns the `cps2ds_dep`-wrapped f_cps.
76 const Def* convert(Lam*);
77 /// Turns the call `k (arg, cont)` into a Pending entry and returns `cont`'s variable as call result.
78 const Def* lift(const Def* k, const Def* arg, const App* old_app);
79 /// Wires all Pending calls above @p base around @p body and returns the new body.
80 const Def* wire(size_t base, const Def* body);
81
82 fe::Vector<Pending> pending_;
83 bool liftable_ = false;
84};
85
86} // namespace mim::plug::cps
Base class for all Defs.
Definition def.h:289
A function.
Definition lam.h:91
RWPhase(World &world, std::string name, Analysis *analysis=nullptr)
Definition phase.h:334
void pop()
Definition rewrite.h:41
void push(Vars old_vars={}, Vars new_vars={})
Definition rewrite.h:40
Full CPS conversion in one recursive rewrite.
Definition conv.h:35
const Def * rewrite_mut_Lam(Lam *) final
Definition conv.cpp:15
const Def * rewrite_imm_App(const App *) final
Definition conv.cpp:64
RWPhase(World &world, std::string name, Analysis *analysis=nullptr)
Definition phase.h:334
The CPS Plugin
Definition cps.h:8
fe::Patricia< const Var, DefKey >::Set Vars
Definition def.h:115