MimIR
0.4-dev
MimIR is my Intermediate Representation
Toggle main menu visibility
Loading...
Searching...
No Matches
clos_conv.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
9
#include "
mim/plug/clos/clos.h
"
10
11
namespace
mim::plug::clos::phase
{
12
13
/// Computes, on demand and with memoization, the free Def%s that a Lam must capture in its closure environment.
14
///
15
/// A referenced nested mutable does not become a free def itself; instead it contributes *its* free defs, since it
16
/// will be closure-converted too.
17
/// This makes the free-def sets of (mutually) recursive Lam%s inter-dependent, so they are solved to a fixed point
18
/// over a little dependency graph: an edge `pred → node` means `node` must include all of `pred`'s free defs.
19
///
20
/// Mutables are only treated as free defs directly if annotated with clos::attr::free_bb / clos::attr::fstclass_bb;
21
/// immutables carrying free vars are broken down to their relevant leaves.
22
class
FreeDefAna
{
23
public
:
24
FreeDefAna
(
World
& world)
25
: world_(world) {}
26
27
/// Returns the free defs @p lam has to capture; see the class description.
28
const
DefSet
&
run
(
Lam
* lam);
29
30
private
:
31
/// A memoized free-def set together with its dependency edges in the fixed-point graph.
32
struct
Node
{
33
Def
* mut;
34
DefSet
fvs;
35
fe::Vector<Node*> preds;
///< Nodes whose free defs must flow into this one.
36
fe::Vector<Node*> succs;
///< Reverse of preds; used to re-enqueue dependents when fvs grow.
37
unsigned
pass = 0;
///< 0 = uninitialized; otherwise the pass that last touched this node.
38
39
auto
add_fvs(
const
Def
* def) {
40
assert(!
Axm::isa<mem::M>
(def->
type
()));
41
return
fvs.emplace(def);
42
}
43
};
44
45
using
NodeQueue = std::queue<Node*>;
46
47
bool
is_bot(
Node
* node)
const
{
return
node->pass == 0; }
///< Not yet initialized?
48
bool
is_done(
Node
* node)
const
{
return
!is_bot(node) && node->pass < cur_pass_; }
///< Settled in an earlier pass?
49
void
mark(Node* node) { node->pass = cur_pass_; }
50
51
/// Classifies a free def of @p node, either adding it as a captured fv or spawning/linking a predecessor Node.
52
/// @p spawned_pred is set if this created a fresh (uninitialized) predecessor Node.
53
void
classify(Node* node,
const
Def* fd,
bool
& spawned_pred, NodeQueue& worklist);
54
55
std::pair<Node*, bool> build_node(Def* mut, NodeQueue& worklist);
56
void
propagate(NodeQueue& worklist);
57
58
World& world() {
return
world_; }
59
60
World& world_;
61
unsigned
cur_pass_ = 1;
62
DefMap<std::unique_ptr<Node>
> lam2node_;
63
};
64
65
/// Performs *typed closure conversion*, rebuilding the old world into a new one.
66
/// This is based on the [Simply Typed Closure Conversion](https://dl.acm.org/doi/abs/10.1145/237721.237791).
67
/// Closures are represented using tuples: `[Env: *, Cn [Env, Args..], Env]`.
68
/// In general only *continuations* are converted; different kinds of Lam%s are treated differently:
69
/// - *returning continuations* ("functions"), *join-points* and *branches* are fully closure converted.
70
/// - *return continuations* are not closure converted.
71
/// - *first-class continuations* get a "dummy" closure; they still have free variables.
72
///
73
/// This phase relies on ClosConvPrep to introduce annotations for these cases.
74
///
75
/// A converted Lam is first stubbed (ClosConv::make_stub) and packed at each use site, while its body is
76
/// enqueued and rewritten later (ClosConv::rewrite_body) in its own fresh substitution scope.
77
/// This isolation is essential: inside a closure's body its free defs are replaced by projections of *its own*
78
/// environment, and those substitutions must not leak into the enclosing scope where the closure was packed.
79
///
80
/// @note Direct-style Def%s are not rewritten, which can be a problem for certain Axm%s such as
81
/// `ax : (B : *, int → B) → (int → B)`.
82
/// There is also no machinery for free variables in a Lam's type, which may break polymorphic functions.
83
class
ClosConv
:
public
RWPhase
{
84
public
:
85
ClosConv
(
World
&
world
,
flags_t
annex
)
86
:
RWPhase
(
world
,
annex
)
87
, fva_(
world
) {}
// the FVA operates on the old world
88
89
private
:
90
/// A closure-converted Lam: the code part @p fn capturing the free defs @p fvs of @p old_fn.
91
struct
Stub {
92
Lam
* old_fn;
93
/// The captured free defs.
94
/// Do not recover them from the env tuple's ops: World::tuple may normalize it (η-reduction back to the
95
/// underlying def, unary tuple, uniform Pack).
96
DefVec
fvs;
97
Lam
* fn;
98
};
99
100
/// @name Rewrite hooks
101
///@{
102
void
rewrite_external
(
Def
*)
final
;
103
void
finalize
() final;
104
const
Def
*
rewrite_imm_Pi
(const
Pi
*) final;
105
const
Def
*
rewrite_mut_Pi
(
Pi
*) final;
106
const
Def
*
rewrite_mut_Lam
(
Lam
*) final;
107
const
Def
*
rewrite_imm_App
(const
App
*) final;
108
const
Def
*
rewrite_imm_Extract
(const
Extract
*) final;
109
const
Def
*
rewrite_mut_Global
(
Global
*) final;
110
///@}
111
112
/// Handles the `clos.attr.{returning,free_bb,fstclass_bb}` wrappers; returns `nullptr` if @p a is none of these.
113
const
Def
* rewrite_attr(
Axm
::IsA<
attr
,
App
> a);
114
115
Stub make_stub(const
DefSet
& fvs,
Lam
* old_lam);
116
Stub make_stub(
Lam
* old_lam);
117
void
rewrite_body(const Stub&);
118
119
/// Builds the closure type for the `Cn` @p pi; with @p env_type, the bare code `Cn` instead of the Sigma.
120
const
Def
* clos_type_of(const
Pi
* pi, const
Def
* env_type =
nullptr
);
121
/// Rewrites a return continuation's type: stays a plain `Cn`, but its domains are closure-converted.
122
const
Pi
* rewrite_ret_cn(const
Pi
*);
123
124
FreeDefAna fva_;
125
DefMap
<Stub> closures_;
///< old_fn *and* new fn ↦ Stub.
126
127
/// Muts that must be rewritten uniformly across the whole module: closure types and globals.
128
/// Such muts must not depend on defs living inside the scope of a continuation.
129
Def2Def
glob_muts_;
130
131
std::queue<
Lam
*> body_worklist_;
///< New fns whose bodies are yet to be rewritten.
132
};
133
134
}
// namespace mim::plug::clos::phase
mim::App
Definition
lam.h:224
mim::Axm
Definition
axm.h:9
mim::Axm::isa
static auto isa(const Def *def)
Definition
axm.h:112
mim::Def
Base class for all Defs.
Definition
def.h:273
mim::Def::type
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
Definition
def.h:1111
mim::Extract
Extracts from a Sigma or Array-typed Extract::tuple the element at position Extract::index.
Definition
tuple.h:161
mim::Global
Definition
def.h:1061
mim::Lam
A function.
Definition
lam.h:113
mim::Phase::annex
flags_t annex() const
Definition
phase.h:81
mim::Pi
A dependent function type.
Definition
lam.h:14
mim::RWPhase::RWPhase
RWPhase(World &world, std::string name, Analysis *analysis=nullptr)
Definition
phase.h:431
mim::RWPhase::world
World & world()=delete
Hides both and forbids direct access.
mim::World
The World represents the whole program and manages creation of MimIR nodes (Defs).
Definition
world.h:40
mim::plug::clos::phase::ClosConv::rewrite_mut_Global
const Def * rewrite_mut_Global(Global *) final
Definition
clos_conv.cpp:224
mim::plug::clos::phase::ClosConv::rewrite_external
void rewrite_external(Def *) final
Definition
clos_conv.cpp:122
mim::plug::clos::phase::ClosConv::rewrite_imm_Extract
const Def * rewrite_imm_Extract(const Extract *) final
Definition
clos_conv.cpp:209
mim::plug::clos::phase::ClosConv::rewrite_mut_Pi
const Def * rewrite_mut_Pi(Pi *) final
Definition
clos_conv.cpp:148
mim::plug::clos::phase::ClosConv::ClosConv
ClosConv(World &world, flags_t annex)
Definition
clos_conv.h:85
mim::plug::clos::phase::ClosConv::rewrite_imm_App
const Def * rewrite_imm_App(const App *) final
Definition
clos_conv.cpp:167
mim::plug::clos::phase::ClosConv::rewrite_imm_Pi
const Def * rewrite_imm_Pi(const Pi *) final
Definition
clos_conv.cpp:143
mim::plug::clos::phase::ClosConv::finalize
void finalize() final
Run after all roots have been walked - but for an RWPhase still before the two worlds are swapped.
Definition
clos_conv.cpp:132
mim::plug::clos::phase::ClosConv::rewrite_mut_Lam
const Def * rewrite_mut_Lam(Lam *) final
Definition
clos_conv.cpp:153
mim::plug::clos::phase::FreeDefAna::FreeDefAna
FreeDefAna(World &world)
Definition
clos_conv.h:24
mim::plug::clos::phase::FreeDefAna::run
const DefSet & run(Lam *lam)
Returns the free defs lam has to capture; see the class description.
Definition
clos_conv.cpp:108
clos.h
mem.h
mim::plug::clos::phase
Definition
branch_clos_elim.h:5
mim::plug::clos::attr
attr
Definition
autogen.h:42
mim::Def2Def
DefMap< const Def * > Def2Def
Definition
def.h:90
mim::flags_t
u64 flags_t
Definition
types.h:39
mim::DefMap
GIDMap< const Def *, To > DefMap
Definition
def.h:88
mim::DefVec
fe::Vector< const Def * > DefVec
Definition
def.h:93
mim::DefSet
GIDSet< const Def * > DefSet
Definition
def.h:89
mim::Node
Node
Definition
def.h:120
phase.h
include
mim
plug
clos
phase
clos_conv.h
Generated by
1.18.0