MimIR
0.5-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
/// `Extract` / `Insert` 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 writing into a `buffer.alloc`ed destination,
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 plus the
27
/// values a `tensor.buf` annotation nominates, and only those types are rewritten to `Buf` — and only at
28
/// function boundaries, never as a global type rewrite.
29
class
LowerToMem
:
public
RWPhase
{
30
public
:
31
using
RWPhase::RWPhase
;
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
const
Def
*
rewrite_imm_Extract
(
const
Extract
*)
override
;
39
const
Def
*
rewrite_imm_Insert
(
const
Insert
*)
override
;
40
41
/// The type of @p lam with its tensor-typed domain converted.
42
const
Pi
* conv_type(
Lam
* lam);
43
44
/// Splits the Extract @p d into the recorded tensor it reads and its *rewritten* index.
45
/// A size-1 axis folds out of the array type, so the index is already the folded one `buffer` expects.
46
/// Yields a null base if @p d does not read a tensor.
47
std::pair<const Def*, const Def*> peel_tensor(
const
Def
*);
48
const
Def
* lower_splat(
const
App
*);
49
const
Def
* lower_generate(
const
App
*);
50
const
Def
* lower_broadcast(
const
App
*);
51
const
Def
* lower_map_reduce(
const
App
*);
52
const
Def
* lower_pad(
const
App
*);
53
const
Def
* lower_concat(
const
App
*);
54
const
Def
* lower_gather(
const
App
*);
55
const
Def
* lower_scatter(
const
App
*);
56
57
/// Adapts a call to a bufferized function: materializes value-world tensor arguments into buffers;
58
/// continuation arguments pass through (their domains are converted by `rewrite_mut_Lam`).
59
const
Def
* lower_call(
const
App
*,
Lam
* old_callee);
60
61
/// Converts an argument to a converted parameter type: tensor values become buffers (via `buffer.init`
62
/// on a `⊥` memory), recursing through sigmas; anything else is `rewrite`d.
63
const
Def
* materialize(
const
Def
* old_ty,
const
Def
* old_arg);
64
65
/// The already rewritten @p val as a `buffer.Buf`, materializing a value-world tensor (e.g. a literal)
66
/// from its old-world @p old.
67
/// The result is *not* a buffer if @p old's type was not recorded as a tensor type.
68
const
Def
* to_buffer(
const
Def
* val,
const
Def
* old);
69
70
/// LowerToMem::materialize of @p old_arg as a buffer.
71
/// A non-buffer value is wrapped in a `buffer.lit` of rank @p r and shape @p shape.
72
const
Def
* make_buffer(
const
Def
* old_arg,
const
Def
* r,
const
Def
*
shape
);
73
74
/// LowerToMem::to_buffer on each element of an `«n; …»` operand list, re-tupled so the tuple type is
75
/// re-inferred from the converted elements; `nullptr` if one element is not a recorded tensor type.
76
const
Def
* buffer_list(
const
Def
* list,
const
Def
* old_list,
const
Def
* n);
77
78
/// Fills a fresh buffer of (old) array type `arr_ty` with the (already rewritten) scalar `scalar`, via
79
/// `buffer.lit`. `btensor.lower_map_reduce` turns that into a fill loop, so it never materializes as a
80
/// monolithic `mem.store` of a giant literal array (which the LLVM backend cannot digest).
81
/// Used for constant splats `‹s; c›` and scalar `tensor.broadcast`s.
82
const
Def
* splat_buffer(
const
Def
* arr_ty,
const
Def
* scalar);
83
84
/// Pre-pass: records every array type used as a tensor operand/result and the set of bufferized
85
/// functions; hard-errors on program shapes the conversion cannot handle (there is no value-semantics
86
/// fallback in the default pipeline).
87
void
collect_tensor_types();
88
89
/// Builds the `buffer.Buf` type for an old tensor array type `«s; T»` (peeling the nested `Arr`s).
90
const
Def
* buf_of(
const
Def
* arr_ty);
91
92
/// Converts a boundary type: tensor array types become `buffer.Buf`, recursing through (immutable) sigmas
93
/// so that grouped parameters like `[«s; T», Idx s]` are converted as well; anything else is `rewrite`d.
94
const
Def
* conv_boundary(
const
Def
* t);
95
96
/// A `⊥: mem.M 0` placeholder consumed by emitted buffer operations; AddMem replaces it with the
97
/// scheduler-placed current memory.
98
/// Shared by every op whose result is a pure function of its value operands, so that genuinely equal
99
/// ops still collapse into one (e.g. a weight literal materialized at many sites).
100
const
Def
* bot_mem();
101
102
/// A *fresh* `mem.M 0` for one emitted buffer/btensor operation: the var of a newly minted continuation
103
/// `con fresh_mem(mem: mem.M 0)` that receives its memory once LowerToMem::wrap_fresh_mem has chained it
104
/// in front of the enclosing lam's body.
105
/// Required by every op that allocates a buffer it then writes into, for two independent reasons:
106
/// 1. Immutable Def%s are hash-consed, so two `buffer.alloc`s agreeing on `(r, s, T)` and sharing one
107
/// placeholder collapse into a single allocation - two distinct tensors would alias one buffer.
108
/// 2. AddMem is a memoizing Rewriter, so two operations sharing one argument tuple
109
/// `(⊥: mem.M 0, …)` - which happens whenever they differ only in their curried callee - are threaded
110
/// from the *same* current memory, and the resulting parallel mem chains collapse in `cps.conv`.
111
/// Mutables are never hash-consed, so the continuations' vars are distinct by construction - no
112
/// distinguishing tag required.
113
const
Def
* fresh_mem();
114
115
/// Chains the LowerToMem::pending_ continuations in front of the freshly rewritten @p body:
116
/// yields `mem.fresh (0, k₁)` with `k₁ ↦ mem.fresh (0, k₂)`, …, and the last one carries @p body.
117
/// AddMem resolves each request by jumping to the continuation with the scheduler-placed current memory,
118
/// and the `tt` filter beta-reduces the continuations away again as soon as that happens.
119
const
Def
* wrap_fresh_mem(
const
Def
* body);
120
121
/// The fresh-memory continuations minted while the current lam's body is being rewritten.
122
fe::Vector<Lam*> pending_;
123
124
/// Per-lam memo for the ops that consume a fresh memory (see LowerToMem::rewrite).
125
DefMap<const Def*>
fresh_memo_;
126
127
/// A function is bufferized iff it is external, set, and mentions a tensor type in its domain.
128
bool
is_tensor_fn(
Lam
*)
const
;
129
130
/// Whether a type is a tensor or (recursively, through sigmas and continuation domains) contains one.
131
/// Never descends into `Arr` elements (so an index/shape array is not mistaken for a tensor).
132
bool
mentions_tensor(
const
Def
*)
const
;
133
134
DefSet
tensor_ty_;
135
136
/// Whether the program contains any (fully applied) tensor-plugin operation.
137
/// Ops without any bufferized function boundary still lower: their value-world operands are
138
/// materialized into buffers (see `materialize`).
139
bool
ops_seen_ =
false
;
140
141
/// Old-world functions that get bufferized (external, signature mentions a tensor).
142
/// Call sites of these functions must be adapted (see `lower_call`).
143
LamSet
tensor_fns_;
144
145
/// Lams passed inside a tensor op's curry chain (combiners, affine index maps): they stay element-level —
146
/// they receive element values, never buffers — even when a parameter type incidentally collides with a
147
/// tensor type (pure type-based role tracking aliases, e.g. an `(x y: I32)` group *is* `«2; I32»`).
148
LamSet
op_args_;
149
};
150
151
}
// namespace mim::plug::tensor::phase
mim::App
Definition
lam.h:215
mim::Def
Base class for all Defs.
Definition
def.h:289
mim::Extract
Extracts from a Sigma or Array-typed Extract::tuple the element at position Extract::index.
Definition
tuple.h:360
mim::Insert
Creates a new Tuple / Pack by inserting Insert::value at position Insert::index into Insert::tuple.
Definition
tuple.h:385
mim::Lam
A function.
Definition
lam.h:91
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:334
mim::plug::tensor::phase::LowerToMem
Bufferizes the low-level tensor axioms onto the shared buffer layer.
Definition
lower_to_mem.h:29
mim::plug::tensor::phase::LowerToMem::rewrite_imm_Insert
const Def * rewrite_imm_Insert(const Insert *) override
Definition
lower_to_mem.cpp:523
mim::plug::tensor::phase::LowerToMem::rewrite_mut_Lam
const Def * rewrite_mut_Lam(Lam *) override
Definition
lower_to_mem.cpp:354
mim::plug::tensor::phase::LowerToMem::rewrite
const Def * rewrite(const Def *) override
Definition
lower_to_mem.cpp:312
mim::plug::tensor::phase::LowerToMem::RWPhase
RWPhase(World &world, std::string name, Analysis *analysis=nullptr)
Definition
phase.h:334
mim::plug::tensor::phase::LowerToMem::start
void start() override
Actual entry.
Definition
lower_to_mem.cpp:274
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::rewrite_imm_Extract
const Def * rewrite_imm_Extract(const Extract *) override
Definition
lower_to_mem.cpp:508
def.h
lam.h
mim::plug::tensor::phase
Definition
constraints.h:5
mim::plug::tensor::shape
shape
Definition
autogen.h:43
mim::LamSet
GIDSet< Lam * > LamSet
Definition
lam.h:211
mim::DefMap
GIDMap< const Def *, To > DefMap
Definition
def.h:93
mim::DefSet
GIDSet< const Def * > DefSet
Definition
def.h:94
phase.h
include
mim
plug
tensor
phase
lower_to_mem.h
Generated by
1.18.0