MimIR
MimIR is my Intermediate Representation
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
8
9/// Bufferizes the low-level tensor axioms onto the shared `buffer` layer.
10/// `get` / `set` become `%buffer.read` / `%buffer.write`, `map_reduce` / `broadcast` / `pad` / `concat`
11/// become their buffer-world `%matrix.*` counterparts,
12/// and tensor array values `«s; T»` become `%buffer.Buf (r, s, T)` handles.
13/// Afterwards `%buffer.lower_ptr` lowers the buffer layer to `%mem.Ptr` + `%mem.lea` / `%mem.load` / `%mem.store`.
14///
15/// This phase is *conversion-only*: it rewrites types and operations but does not thread the `%mem.M`
16/// memory monad itself. Emitted buffer operations consume a `⊥: %mem.M 0` placeholder (or a short local
17/// chain), and the SSA value dependencies keep them anchored and ordered. The `%mem.add_mem` phase
18/// (mim::plug::mem::phase::AddMem), scheduled right after this one in the pipeline, then mem-extends all
19/// continuations and rewires every memory operand to the scheduler-placed current memory — handling returns,
20/// error continuations, join points, branch arms, and interleaving with a caller's own memory operations
21/// uniformly.
22///
23/// Which array types denote tensors (as opposed to index/shape arrays that share the `Arr` structure) is
24/// determined by *role*: a pre-pass collects the array operand/result types of the tensor operations, and only
25/// those types are rewritten to `Buf` — and only at function boundaries, never as a global type rewrite.
26class LowerToMem : public RWPhase {
27public:
30
31private:
32 void start() override;
33 const Def* rewrite_mut_Lam(Lam*) override;
34 const Def* rewrite_imm_App(const App*) override;
35
36 const Def* lower_get(const App*);
37 const Def* lower_set(const App*);
38 const Def* lower_broadcast(const App*);
39 const Def* lower_map_reduce(const App*);
40 const Def* lower_pad(const App*);
41 const Def* lower_concat(const App*);
42
43 /// Adapts a call to a bufferized function: materializes value-world tensor arguments into buffers;
44 /// continuation arguments pass through (their domains are converted by `rewrite_mut_Lam`).
45 const Def* lower_call(const App*, Lam* old_callee);
46
47 /// Converts an argument to a converted parameter type: tensor values become buffers (via `%buffer.init`
48 /// on a `⊥` memory), recursing through sigmas; anything else is `rewrite`d.
49 const Def* materialize(const Def* old_ty, const Def* old_arg);
50
51 /// Fills a fresh buffer of (old) array type `arr_ty` with the (already rewritten) scalar `scalar`, via
52 /// `%buffer.constant`. `%matrix.lower_aff` turns that into a fill loop, so it never materializes as a
53 /// monolithic `%mem.store` of a giant literal array (which the LLVM backend cannot digest).
54 /// Used for constant splats `‹s; c›` and scalar `%tensor.broadcast`s.
55 const Def* splat_buffer(const Def* arr_ty, const Def* scalar);
56
57 /// Buffer-reuse policy. `false` (the initial *always-allocate-and-copy* policy) is always sound.
58 /// A future liveness-based policy may return `true` to write into the source buffer in place.
59 bool reuse_in_place(const App*) const { return false; }
60
61 /// Pre-pass: records every array type used as a tensor operand/result and the set of bufferized
62 /// functions; hard-errors on program shapes the conversion cannot handle (there is no value-semantics
63 /// fallback in the default pipeline).
64 void collect_tensor_types();
65
66 /// Builds the `%buffer.Buf` type for an old tensor array type `«s; T»` (peeling the nested `Arr`s).
67 const Def* buf_of(const Def* arr_ty);
68
69 /// Converts a boundary type: tensor array types become `%buffer.Buf`, recursing through (immutable) sigmas
70 /// so that grouped parameters like `[«s; T», Idx s]` are converted as well; anything else is `rewrite`d.
71 const Def* conv_boundary(const Def* t);
72
73 /// Drops, from the (unfolded) index `idx`, the components of size-1 dimensions of `shape`.
74 /// MimIR folds size-1 dimensions out of array/buffer types (`«3,1;T»` ≡ `«3;T»`), so an index addressing a
75 /// buffer must match the folded shape.
76 const Def* fold_index(const Def* shape, const Def* idx);
77
78 /// A `⊥: %mem.M 0` placeholder consumed by emitted buffer operations; AddMem replaces it with the
79 /// scheduler-placed current memory.
80 const Def* bot_mem();
81
82 /// A function is bufferized iff it is external, set, and mentions a tensor type in its domain.
83 bool is_tensor_fn(Lam*) const;
84
85 /// Whether a type is a tensor or (recursively, through sigmas and continuation domains) contains one.
86 /// Never descends into `Arr` elements (so an index/shape array is not mistaken for a tensor).
87 bool mentions_tensor(const Def*) const;
88
89 DefSet tensor_ty_;
90
91 /// Whether the program contains any (fully applied) tensor-plugin operation.
92 /// Ops without any bufferized function boundary still lower: their value-world operands are
93 /// materialized into buffers (see `materialize`).
94 bool ops_seen_ = false;
95
96 /// Old-world functions that get bufferized (external, signature mentions a tensor).
97 /// Call sites of these functions must be adapted (see `lower_call`).
98 LamSet tensor_fns_;
99
100 /// Lams passed inside a tensor op's curry chain (combiners, affine index maps): they stay element-level —
101 /// they receive element values, never buffers — even when a parameter type incidentally collides with a
102 /// tensor type (pure type-based role tracking aliases, e.g. an `(x y: I32)` group *is* `«2; I32»`).
103 LamSet op_args_;
104
105};
106
107} // namespace mim::plug::tensor::phase
Base class for all Defs.
Definition def.h:261
A function.
Definition lam.h:110
flags_t annex() const
Definition phase.h:81
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 * rewrite_mut_Lam(Lam *) override
void start() override
Actual entry.
const Def * rewrite_imm_App(const App *) override
LowerToMem(World &world, flags_t annex)
GIDSet< Lam * > LamSet
Definition lam.h:220
u64 flags_t
Definition types.h:39
GIDSet< const Def * > DefSet
Definition def.h:76