MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
lower_typed_clos.h
Go to the documentation of this file.
1#pragma once
2
3#include <queue>
4
5#include <mim/phase.h>
6
7#include <mim/plug/mem/mem.h>
8
10
11namespace mim::plug::clos::phase {
12
13/// This pass lowers *typed closures* to *untyped closures*.
14/// For details on typed closures, see ClosConv.
15/// In general, untyped closure have the form `(pointer-to-environment, code)` with the following exceptions:
16/// * Lam%s in callee-position should be λ-lifted and thus don't receive an environment.
17/// * External and imported (not set) Lam%s also don't receive an environment.
18/// They are appropriately η-wrapped by ClosConv.
19/// * If the environment is of integer type, it's directly stored in the environment-pointer ("unboxed").
20/// @note In theory this should work for other primitive types as well, but the LL backend does not handle the
21/// required conversion correctly.
22///
23/// Further, first class continuations are rewritten to returning functions.
24/// They receive `⊥` as a dummy continuation.
25/// Therefore Clos2SJLJ should have taken place prior to this pass.
26///
27/// This pass will heap-allocate ClosKind::esc closures and stack-allocate everything else.
28/// These annotations are introduced by LowerTypedClosPrep.
29///
30/// The rewrite carries a *mem token* along each function body (LowerTypedClos::lvm_ / LowerTypedClos::lcm_) so
31/// that the `mem.alloc`/`mem.store` it inserts for boxed environments are threaded into the mem chain.
32/// This stateful, order-sensitive threading is why LowerTypedClos::rewrite intercepts whole classes of nodes
33/// instead of relying on the per-node hooks alone.
34/// A converted Lam's body is enqueued and rewritten later, seeded with that body's own initial mem token.
35class LowerTypedClos : public RWPhase {
36public:
39
40private:
41 /// A pending body rewrite: the initial mem tokens (old @c lvm, new @c lcm) plus the old and new Lam.
42 struct Todo {
43 const Def* lvm;
44 const Def* lcm;
45 Lam* old_lam;
46 Lam* new_lam;
47 };
48
49 void rewrite_external(Def*) final;
50 void finalize() final;
51 const Def* rewrite(const Def* def) final;
52 const Def* rewrite_imm(const Def* def) final;
53 const Def* rewrite_imm_App(const App*) final;
54
55 /// Describes how the environment should be treated.
56 enum Mode {
57 Box = 0, ///< Environment is boxed (default).
58 Unbox, ///< Environment is of primitive type (currently `iN`s) and directly stored in the pointer.
59 No_Env ///< Lambda has no environment (lifted, top-level).
60 };
61
62 /// Create a new Lam stub.
63 /// @p adjust_bb_type is true if the @p lam should be rewritten to a returning function.
64 Lam* make_stub(Lam* lam, Mode mode, bool adjust_bb_type);
65
66 /// Pointer type used to represent environments.
67 const Def* env_type() { return new_world().call<mem::Ptr0>(new_world().sigma()); }
68
69 /// Dummy return continuation.
70 /// @note Not cached: `mem::M` resolves through new_world()'s annex table, which is only populated once
71 /// bootstrapping is done - and by then everything is hash-consed anyway.
72 const Def* dummy_ret() { return new_world().bot(new_world().cn(new_world().call<mem::M>(0))); }
73
74 std::queue<Todo> worklist_;
75
76 /// @name memory-tokens
77 /// The mem token threaded through the body currently being rewritten.
78 ///@{
79 const Def* lvm_ = nullptr; ///< Last visited memory token.
80 const Def* lcm_ = nullptr; ///< Last created memory token.
81 ///@}
82};
83
84} // namespace mim::plug::clos::phase
Base class for all Defs.
Definition def.h:273
A function.
Definition lam.h:113
flags_t annex() const
Definition phase.h:81
World & new_world()
Create new Defs into this.
Definition phase.h:452
RWPhase(World &world, std::string name, Analysis *analysis=nullptr)
Definition phase.h:431
World & world()=delete
Hides both and forbids direct access.
The World represents the whole program and manages creation of MimIR nodes (Defs).
Definition world.h:40
const Def * sigma(Defs ops)
Definition world.cpp:316
const Def * bot(const Def *type)
Definition world.h:591
const Def * call(const Def *callee, T &&arg, Args &&... args)
Definition world.h:662
const Def * rewrite(const Def *def) final
void finalize() final
Run after all roots have been walked - but for an RWPhase still before the two worlds are swapped.
LowerTypedClos(World &world, flags_t annex)
const Def * rewrite_imm(const Def *def) final
const Def * rewrite_imm_App(const App *) final
u64 flags_t
Definition types.h:39