MimIR
0.4-dev
MimIR is my Intermediate Representation
Toggle main menu visibility
Loading...
Searching...
No Matches
lower_to_mem.h
Go to the documentation of this file.
1
#pragma once
2
3
#include <
mim/def.h
>
4
#include <
mim/lam.h
>
5
#include <
mim/phase.h
>
6
7
namespace
mim::plug::tensor::phase
{
8
9
/// Bufferizes the low-level tensor axioms onto the shared `buffer` layer.
10
/// `get` / `set` become `buffer.read` / `buffer.write`, `generate` becomes an allocating fill loop,
11
/// `map_reduce` / `broadcast` / `pad` / `concat` /
12
/// `gather` / `scatter` become their buffer-world `btensor.*` counterparts,
13
/// and tensor array values `«s; T»` become `buffer.Buf (r, s, T)` handles.
14
/// Afterwards `buffer.lower_ptr` lowers the buffer layer to `mem.Ptr` + `mem.lea` / `mem.load` / `mem.store`.
15
///
16
/// This phase is *conversion-only*: it rewrites types and operations but does not thread the `mem.M`
17
/// memory monad itself. Emitted buffer operations consume a `⊥: mem.M 0` placeholder (or a short local
18
/// chain rooted in a LowerToMem::fresh_mem continuation's var), and the SSA value dependencies keep them
19
/// anchored and ordered. The `mem.add_mem` phase
20
/// (mim::plug::mem::phase::AddMem), scheduled right after this one in the pipeline, then mem-extends all
21
/// continuations and rewires every memory operand to the scheduler-placed current memory — handling returns,
22
/// error continuations, join points, branch arms, and interleaving with a caller's own memory operations
23
/// uniformly.
24
///
25
/// Which array types denote tensors (as opposed to index/shape arrays that share the `Arr` structure) is
26
/// determined by *role*: a pre-pass collects the array operand/result types of the tensor operations, and only
27
/// those types are rewritten to `Buf` — and only at function boundaries, never as a global type rewrite.
28
class
LowerToMem
:
public
RWPhase
{
29
public
:
30
LowerToMem
(
World
&
world
,
flags_t
annex
)
31
:
RWPhase
(
world
,
annex
) {}
32
33
private
:
34
void
start
()
override
;
35
const
Def
*
rewrite
(
const
Def
*)
override
;
36
const
Def
*
rewrite_mut_Lam
(
Lam
*)
override
;
37
const
Def
*
rewrite_imm_App
(
const
App
*)
override
;
38
39
/// The conversion part of LowerToMem::rewrite_mut_Lam (boundary conversion, local continuations, or the
40
/// generic RWPhase rewrite); the override itself only scopes the fresh-memory bookkeeping around it.
41
const
Def
* conv_mut_Lam(
Lam
*);
42
43
const
Def
* lower_get(
const
App
*);
44
const
Def
* lower_set(
const
App
*);
45
const
Def
* lower_splat(
const
App
*);
46
const
Def
* lower_generate(
const
App
*);
47
const
Def
* lower_broadcast(
const
App
*);
48
const
Def
*
lower_map_reduce
(
const
App
*);
49
const
Def
* lower_pad(
const
App
*);
50
const
Def
* lower_concat(
const
App
*);
51
const
Def
* lower_gather(
const
App
*);
52
const
Def
* lower_scatter(
const
App
*);
53
54
/// Adapts a call to a bufferized function: materializes value-world tensor arguments into buffers;
55
/// continuation arguments pass through (their domains are converted by `rewrite_mut_Lam`).
56
const
Def
* lower_call(
const
App
*,
Lam
* old_callee);
57
58
/// Converts an argument to a converted parameter type: tensor values become buffers (via `buffer.init`
59
/// on a `⊥` memory), recursing through sigmas; anything else is `rewrite`d.
60
const
Def
*
materialize
(
const
Def
* old_ty,
const
Def
* old_arg);
61
62
/// The already rewritten @p val as a `buffer.Buf`, materializing a value-world tensor (e.g. a literal)
63
/// from its old-world @p old.
64
/// The result is *not* a buffer if @p old's type was not recorded as a tensor type.
65
const
Def
* to_buffer(
const
Def
* val,
const
Def
* old);
66
67
/// LowerToMem::to_buffer on each element of an `«n; …»` operand list, re-tupled so the tuple type is
68
/// re-inferred from the converted elements; `nullptr` if one element is not a recorded tensor type.
69
const
Def
* buffer_list(
const
Def
* list,
const
Def
* old_list,
const
Def
* n);
70
71
/// Fills a fresh buffer of (old) array type `arr_ty` with the (already rewritten) scalar `scalar`, via
72
/// `buffer.lit`. `btensor.lower_map_reduce` turns that into a fill loop, so it never materializes as a
73
/// monolithic `mem.store` of a giant literal array (which the LLVM backend cannot digest).
74
/// Used for constant splats `‹s; c›` and scalar `tensor.broadcast`s.
75
const
Def
* splat_buffer(
const
Def
* arr_ty,
const
Def
* scalar);
76
77
/// Buffer-reuse policy. `false` (the initial *always-allocate-and-copy* policy) is always sound.
78
/// A future liveness-based policy may return `true` to write into the source buffer in place.
79
bool
reuse_in_place(
const
App
*)
const
{
return
false
; }
80
81
/// Pre-pass: records every array type used as a tensor operand/result and the set of bufferized
82
/// functions; hard-errors on program shapes the conversion cannot handle (there is no value-semantics
83
/// fallback in the default pipeline).
84
void
collect_tensor_types();
85
86
/// Builds the `buffer.Buf` type for an old tensor array type `«s; T»` (peeling the nested `Arr`s).
87
const
Def
* buf_of(
const
Def
* arr_ty);
88
89
/// Converts a boundary type: tensor array types become `buffer.Buf`, recursing through (immutable) sigmas
90
/// so that grouped parameters like `[«s; T», Idx s]` are converted as well; anything else is `rewrite`d.
91
const
Def
* conv_boundary(
const
Def
* t);
92
93
/// Drops, from the (unfolded) index `idx`, the components of size-1 dimensions of `shape`.
94
/// MimIR folds size-1 dimensions out of array/buffer types (`«3,1;T»` ≡ `«3;T»`), so an index addressing a
95
/// buffer must match the folded shape.
96
const
Def
* fold_index(
const
Def
*
shape
,
const
Def
* idx);
97
98
/// A `⊥: mem.M 0` placeholder consumed by emitted buffer operations; AddMem replaces it with the
99
/// scheduler-placed current memory.
100
/// Shared by every op whose result is a pure function of its value operands, so that genuinely equal
101
/// ops still collapse into one (e.g. a weight literal materialized at many sites).
102
const
Def
* bot_mem();
103
104
/// A *fresh* `mem.M 0` for one emitted buffer/btensor operation: the var of a newly minted continuation
105
/// `con fresh_mem(mem: mem.M 0)` that receives its memory once LowerToMem::wrap_fresh_mem has chained it
106
/// in front of the enclosing lam's body.
107
/// Required by every op that allocates a buffer it then writes into, for two independent reasons:
108
/// 1. Immutable Def%s are hash-consed, so two `buffer.alloc`s agreeing on `(r, s, T)` and sharing one
109
/// placeholder collapse into a single allocation - two distinct tensors would alias one buffer.
110
/// 2. AddMem is a memoizing Rewriter, so two operations sharing one argument tuple
111
/// `(⊥: mem.M 0, …)` - which happens whenever they differ only in their curried callee - are threaded
112
/// from the *same* current memory, and the resulting parallel mem chains collapse in `cps.conv`.
113
/// Mutables are never hash-consed, so the continuations' vars are distinct by construction - no
114
/// distinguishing tag required.
115
const
Def
* fresh_mem();
116
117
/// Chains the LowerToMem::pending_ continuations in front of @p new_lam's freshly rewritten body:
118
/// `new_lam ↦ mem.fresh (0, k₁)`, `k₁ ↦ mem.fresh (0, k₂)`, …, and the last one carries the body.
119
/// AddMem resolves each request by jumping to the continuation with the scheduler-placed current memory,
120
/// and the `tt` filter beta-reduces the continuations away again as soon as that happens.
121
void
wrap_fresh_mem(
Lam
* new_lam);
122
123
/// The fresh-memory continuations minted while the current lam's body is being rewritten.
124
fe::Vector<Lam*> pending_;
125
126
/// Per-lam memo for the ops that consume a fresh memory (see LowerToMem::rewrite).
127
DefMap<const Def*>
fresh_memo_;
128
129
/// A function is bufferized iff it is external, set, and mentions a tensor type in its domain.
130
bool
is_tensor_fn(
Lam
*)
const
;
131
132
/// Whether a type is a tensor or (recursively, through sigmas and continuation domains) contains one.
133
/// Never descends into `Arr` elements (so an index/shape array is not mistaken for a tensor).
134
bool
mentions_tensor(
const
Def
*)
const
;
135
136
DefSet
tensor_ty_;
137
138
/// Whether the program contains any (fully applied) tensor-plugin operation.
139
/// Ops without any bufferized function boundary still lower: their value-world operands are
140
/// materialized into buffers (see `materialize`).
141
bool
ops_seen_ =
false
;
142
143
/// Old-world functions that get bufferized (external, signature mentions a tensor).
144
/// Call sites of these functions must be adapted (see `lower_call`).
145
LamSet
tensor_fns_;
146
147
/// Lams passed inside a tensor op's curry chain (combiners, affine index maps): they stay element-level —
148
/// they receive element values, never buffers — even when a parameter type incidentally collides with a
149
/// tensor type (pure type-based role tracking aliases, e.g. an `(x y: I32)` group *is* `«2; I32»`).
150
LamSet
op_args_;
151
};
152
153
}
// namespace mim::plug::tensor::phase
mim::App
Definition
lam.h:224
mim::Def
Base class for all Defs.
Definition
def.h:273
mim::Lam
A function.
Definition
lam.h:113
mim::Phase::annex
flags_t annex() const
Definition
phase.h:81
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::tensor::phase::LowerToMem::rewrite_mut_Lam
const Def * rewrite_mut_Lam(Lam *) override
Definition
lower_to_mem.cpp:348
mim::plug::tensor::phase::LowerToMem::rewrite
const Def * rewrite(const Def *) override
Definition
lower_to_mem.cpp:306
mim::plug::tensor::phase::LowerToMem::start
void start() override
Actual entry.
Definition
lower_to_mem.cpp:253
mim::plug::tensor::phase::LowerToMem::rewrite_imm_App
const Def * rewrite_imm_App(const App *) override
Definition
lower_to_mem.cpp:395
mim::plug::tensor::phase::LowerToMem::LowerToMem
LowerToMem(World &world, flags_t annex)
Definition
lower_to_mem.h:30
def.h
lam.h
mim::plug::tensor::phase
Definition
constraints.h:5
mim::plug::tensor::materialize
materialize
Definition
autogen.h:251
mim::plug::tensor::shape
shape
Definition
autogen.h:44
mim::plug::tensor::lower_map_reduce
lower_map_reduce
Definition
autogen.h:426
mim::LamSet
GIDSet< Lam * > LamSet
Definition
lam.h:220
mim::flags_t
u64 flags_t
Definition
types.h:39
mim::DefMap
GIDMap< const Def *, To > DefMap
Definition
def.h:88
mim::DefSet
GIDSet< const Def * > DefSet
Definition
def.h:89
phase.h
include
mim
plug
tensor
phase
lower_to_mem.h
Generated by
1.18.0