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
8#include "mim/plug/mem/mem.h"
9
10namespace mim::plug::clos::phase {
11
12/// This pass lowers *typed closures* to *untyped closures*.
13/// For details on typed closures, see ClosConv.
14/// In general, untyped closure have the form `(pointer-to-environment, code)` with the following exceptions:
15/// * Lam%s in callee-position should be λ-lifted and thus don't receive an environment.
16/// * External and imported (not set) Lam%s also don't receive an environment.
17/// They are appropriately η-wrapped by ClosConv.
18/// * If the environment is of integer type, it's directly stored in the environment-pointer ("unboxed").
19/// @note In theory this should work for other primitive types as well, but the LL backend does not handle the
20/// required conversion correctly.
21///
22/// Further, first class continuations are rewritten to returning functions.
23/// They receive `⊥` as a dummy continuation.
24/// Therefore Clos2SJLJ should have taken place prior to this pass.
25///
26/// This pass will heap-allocate ClosKind::esc closures and stack-allocate everything else.
27/// These annotations are introduced by LowerTypedClosPrep.
28///
29/// The rewrite carries a *mem token* along each function body (LowerTypedClos::lvm_ / LowerTypedClos::lcm_) so
30/// that the `%mem.alloc`/`%mem.store` it inserts for boxed environments are threaded into the mem chain.
31/// This stateful, order-sensitive threading is why LowerTypedClos::rewrite is overridden as a whole rather than
32/// via the per-node hooks.
33/// A converted Lam's body is enqueued and rewritten later, seeded with that body's own initial mem token.
34class LowerTypedClos : public RWPhase {
35public:
38
39private:
40 /// A pending body rewrite: the initial mem tokens (old @c lvm, new @c lcm) plus the old and new Lam.
41 struct Todo {
42 const Def* lvm;
43 const Def* lcm;
44 Lam* old_lam;
45 Lam* new_lam;
46 };
47
48 void start() override;
49 const Def* rewrite(const Def* def) final;
50
51 /// Describes how the environment should be treated.
52 enum Mode {
53 Box = 0, ///< Environment is boxed (default).
54 Unbox, ///< Environment is of primitive type (currently `iN`s) and directly stored in the pointer.
55 No_Env ///< Lambda has no environment (lifted, top-level).
56 };
57
58 /// Create a new Lam stub.
59 /// @p adjust_bb_type is true if the @p lam should be rewritten to a returning function.
60 Lam* make_stub(Lam* lam, Mode mode, bool adjust_bb_type);
61
62 /// Pointer type used to represent environments.
63 const Def* env_type() { return new_world().call<mem::Ptr0>(new_world().sigma()); }
64
65 std::queue<Todo> worklist_;
66
67 const Def* dummy_ret_ = nullptr; ///< dummy return continuation
68 bool converting_ = false; ///< `false` while bootstrapping annexes; `true` once actually converting.
69
70 /// @name memory-tokens
71 /// The mem token threaded through the body currently being rewritten.
72 ///@{
73 const Def* lvm_ = nullptr; ///< Last visited memory token.
74 const Def* lcm_ = nullptr; ///< Last created memory token.
75 ///@}
76};
77
78} // namespace mim::plug::clos::phase
Base class for all Defs.
Definition def.h:261
A function.
Definition lam.h:110
flags_t annex() const
Definition phase.h:81
World & new_world()
Create new Defs into this.
Definition phase.h:368
RWPhase(World &world, std::string name, Analysis *analysis=nullptr)
Definition phase.h:316
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:36
const Def * sigma(Defs ops)
Definition world.cpp:298
const Def * call(const Def *callee, T &&arg, Args &&... args)
Definition world.h:641
const Def * rewrite(const Def *def) final
LowerTypedClos(World &world, flags_t annex)
u64 flags_t
Definition types.h:39