MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
lower_aff.cpp
Go to the documentation of this file.
2
3#include "mim/axm.h"
4#include "mim/def.h"
5#include "mim/lam.h"
6
10#include "mim/plug/cps/cps.h"
12#include "mim/plug/mem/mem.h"
13
15
16namespace {
17
18/// Drops, from the (unfolded) index `idx`, the components of size-1 dimensions of `shape`
19/// (`%buffer.Buf` normalizes size-1 axes away, mirroring the folding of array types).
20const Def* fold_index(const Def* shape, const Def* idx) {
21 auto& w = shape->world();
22 auto r = shape->num_projs();
23 DefVec out;
24 bool dropped = false;
25 for (size_t i = 0; i != r; ++i)
26 if (auto l = Lit::isa<u64>(shape->proj(r, i)); l && *l == 1)
27 dropped = true;
28 else
29 out.push_back(idx->proj(r, i));
30 // Without dropped axes the tuple below would just eta-reduce back to `idx` — but only after
31 // World::tuple's pack normalization has alpha-compared the projections, which walks `idx`'s whole
32 // (mem-threaded, Var-dependent) coordinate chain per elem pair — exponentially. Return `idx` directly.
33 if (!dropped) return idx;
34 return w.tuple(out);
35}
36
37/// Builds a counting `affine.For` loop body carrying `acc` (a `{mem, …}` tuple).
38std::pair<Lam*, const Def*> counting_for(const Def* bound, const Def* acc, const Def* exit, Sym name) {
39 auto& w = bound->world();
40 auto acc_ty = acc->type();
41 auto body = w.mut_con({/* iter */ w.type_i64(), /* acc */ acc_ty, /* return */ w.cn(acc_ty)})->set(name);
42 auto for_loop = w.call<affine::For>(body, exit, Defs{w.lit_i64(0), bound, w.lit_i64(1), acc});
43 return {body, for_loop};
44}
45
46/// Pointwise scaffold shared by `pad`/`concat`: a `[mem, ins] → [mem, Buf]` fun (spliced via
47/// `%cps.cps2ds`) that allocates the output buffer, loops over `s_out` carrying `{mem, buf}`, and writes
48/// `compute`'s elem at the (identity) output coordinates.
49/// `compute(iters, ins, mem)` receives the raw i64 loop counters, the fun's inputs var, and the current
50/// mem; it returns `(mem', elem)`.
51template<class Compute>
52const Def* build_pointwise(World& w,
53 const Def* result_ty, // [%mem.M 0, %buffer.Buf (r, s_out, T)]
54 const Def* op_mem,
55 const Def* op_ins,
56 const Def* s_out,
57 u64 rn,
58 const std::string& name,
59 Compute&& compute) {
60 auto mem_ty = w.call<mem::M>(0);
61 auto fun = w.mut_fun(w.sigma({mem_ty, op_ins->type()}), result_ty)->set(name);
62 auto call = w.app(cps::op_cps2ds_dep(fun), w.tuple({op_mem, op_ins}));
63 auto [fun_mem, ins] = fun->var(0_n)->projs<2>();
64 auto cont = fun->var(1);
65
66 auto [obr, obs, obT] = Axm::isa<buffer::Buf>(result_ty->proj(1))->args<3>();
67 auto [a_mem, out_buf] = buffer::op_alloc(obr, obs, obT, fun_mem)->projs<2>();
68 const Def* acc = w.tuple({a_mem, out_buf});
69 auto current_mut = fun;
70
71 DefVec iters; // raw i64 loop counters
72 iters.reserve(rn);
73 for (u64 d = 0; d < rn; ++d) {
74 auto bound = w.call<core::bitcast>(w.type_i64(), s_out->proj(rn, d));
75 auto [body, for_call] = counting_for(bound, acc, cont, w.sym(name + "_" + std::to_string(d)));
76 auto [iter, new_acc, yield] = body->vars<3>();
77 cont = yield;
78 iters.push_back(iter);
79 acc = new_acc;
80 current_mut->set(true, for_call);
81 current_mut = body;
82 }
83 auto [loop_mem, loop_buf] = acc->projs<2>();
84
85 std::pair<const Def*, const Def*> el = compute(iters, ins, loop_mem);
86 auto [el_mem, elem] = el;
87
88 DefVec wcoords(rn);
89 for (u64 d = 0; d < rn; ++d)
90 wcoords[d] = w.call(core::conv::u, s_out->proj(rn, d), iters[d]);
91 auto [wr_mem, wr_buf]
92 = buffer::op_write(obr, obs, obT, el_mem, loop_buf, fold_index(s_out, w.tuple(wcoords)), elem)->projs<2>();
93 current_mut->app(true, cont, w.tuple({wr_mem, loop_buf}));
94 return call;
95}
96
97} // namespace
98
99const Def* LowerAff::rewrite_imm_App(const App* app) {
100 if (is_bootstrapping()) return RWPhase::rewrite_imm_App(app);
101 if (Axm::isa<matrix::map_reduce_aff>(app)) return lower_map_reduce_aff(app);
102 if (Axm::isa<matrix::broadcast>(app)) return lower_broadcast(app);
103 if (Axm::isa<matrix::pad>(app)) return lower_pad(app);
104 if (Axm::isa<matrix::concat>(app)) return lower_concat(app);
105 if (Axm::isa<buffer::constant>(app)) return lower_buffer_constant(app);
106 return RWPhase::rewrite_imm_App(app);
107}
108
109const Def* LowerAff::lower_buffer_constant(const App* app) {
110 // `%buffer.constant (r, s, T) (mem, val)` fills every elem with `val`. Emit a fill loop (via the same
111 // pointwise scaffold as pad/concat) so the store never materializes as one giant literal array. A
112 // non-literal rank has no static loop nest, so leave it for `%buffer.lower_ptr`'s monolithic fallback.
113 auto [r, s, T] = app->callee()->as<App>()->args<3>();
114 auto s_out = rewrite(s);
115 auto rn = Lit::isa<u64>(rewrite(r));
116 if (!rn) return RWPhase::rewrite_imm_App(app);
117
118 auto& w = new_world();
119 auto [mem, val] = rewrite(app->arg())->projs<2>();
120 auto result_ty = rewrite(app->type()); // [%mem.M 0, %buffer.Buf (r, s, T)]
121 // `compute` ignores the loop counters and writes the (loop-invariant) scalar `ins` everywhere.
122 return build_pointwise(
123 w, result_ty, mem, val, s_out, *rn, "constant_fill",
124 [](const DefVec&, const Def* ins, const Def* m) -> std::pair<const Def*, const Def*> { return {m, ins}; });
125}
126
127const Def* LowerAff::lower_map_reduce_aff(const App* app) {
128 auto& w = new_world();
129 auto c = rewrite(app->callee())->as<App>();
130
131 auto [nis, meta, shapes, TisRisSis, comb_init, acc_out, accs] = c->uncurry_args<7>();
132 auto [To, Ro, Rr] = meta->projs<3>();
133 auto [So, Sr] = shapes->projs<2>();
134 auto [Tis, Ris, Sis] = TisRisSis->projs<3>();
135 auto [comb, init] = comb_init->projs<2>();
136
137 // The final argument is `[mem, is]`; the result is `[mem, Buf]`.
138 auto [op_mem, op_is] = rewrite(app->arg())->projs<2>();
139 auto result_ty = rewrite(app->type()); // [%mem.M 0, %buffer.Buf (Ro, So, To)]
140
141 auto nis_l = Lit::isa<u64>(nis);
142 auto ro_l = Lit::isa<u64>(Ro), rr_l = Lit::isa<u64>(Rr);
143 if (!nis_l || !ro_l || !rr_l) {
144 WLOG("{} doesn't have lowering-time known rank counts (nis/Ro/Rr)", app);
145 return RWPhase::rewrite_imm_App(app);
146 }
147 auto nis_nat = *nis_l;
148 auto ro = *ro_l, rr = *rr_l;
149 auto nloops = ro + rr;
150 auto n = w.lit_nat(nloops);
151
152 // Builds `%affine.map @(m, n) @(sin, sout) f idxs mem`. The map is mem-threaded (its divisions consume mem),
153 // and this phase threads real memory, so the caller passes the current mem and receives `(mem', coords)`.
154 auto affine_map = [&](const Def* f, const Def* m, const Def* nn, const Def* sin, const Def* sout, const Def* idxs,
155 const Def* mem) {
156 auto a = w.app(w.annex<affine::map>(), w.tuple({m, nn}));
157 a = w.app(a, w.tuple({sin, sout}));
158 a = w.app(a, f);
159 a = w.app(a, idxs);
160 return w.app(a, mem)->projs<2>();
161 };
162
163 auto mem_ty = w.call<mem::M>(0);
164
165 // `[mem, is] → [mem, Buf]`, spliced via %cps.cps2ds and applied to the op's (mem, is).
166 auto fun = w.mut_fun(w.sigma({mem_ty, op_is->type()}), result_ty)->set("mapRedAff");
167 auto call = w.app(cps::op_cps2ds_dep(fun), w.tuple({op_mem, op_is}));
168 auto [fun_mem, new_inputs] = fun->var(0_n)->projs<2>();
169 auto cont = fun->var(1);
170
171 // Allocate the output buffer; the output loops carry `{mem, buf}`.
172 auto [obr, obs, obT] = Axm::isa<buffer::Buf>(result_ty->proj(1))->args<3>();
173 auto [a_mem, out_buf] = buffer::op_alloc(obr, obs, obT, fun_mem)->projs<2>();
174 const Def* acc = w.tuple({a_mem, out_buf});
175 auto current_mut = fun;
176
177 DefVec out_iters;
178 out_iters.reserve(ro);
179 for (u64 i = 0; i < ro; ++i) {
180 auto dim = Sr->proj(nloops, i);
181 auto bound = w.call<core::bitcast>(w.type_i64(), dim);
182 auto [body, for_call] = counting_for(bound, acc, cont, w.sym("forOut_" + std::to_string(i)));
183 auto [iter, new_acc, yield] = body->vars<3>();
184 cont = yield;
185 out_iters.push_back(w.call(core::conv::u, dim, iter));
186 acc = new_acc;
187 current_mut->set(true, for_call);
188 current_mut = body;
189 }
190 auto [wb_mem, wb_buf] = acc->projs<2>();
191
192 // Write-back continuation `Cn[mem, To]`.
193 auto write_back = mem::mut_con(To)->set("writeBack");
194 auto [wb_in_mem, elem_final] = write_back->vars<2>();
195 DefVec wb_iters = out_iters;
196 for (u64 j = 0; j < rr; ++j)
197 wb_iters.push_back(w.call(core::conv::u, Sr->proj(nloops, ro + j), w.lit(w.type_i64(), 0)));
198 auto [wc_mem, write_coords] = affine_map(acc_out, Ro, n, Sr, So, w.tuple(wb_iters), wb_in_mem);
199 auto stored = buffer::op_write(obr, obs, obT, wc_mem, wb_buf, fold_index(So, write_coords), elem_final);
200 write_back->app(true, cont, w.tuple({stored->proj(0), wb_buf}));
201
202 // Reduction loops; accumulator `{mem, elem}`.
203 acc = w.tuple({wb_mem, init});
204 cont = write_back;
205 DefVec red_iters;
206 red_iters.reserve(rr);
207 for (u64 j = 0; j < rr; ++j) {
208 auto dim = Sr->proj(nloops, ro + j);
209 auto bound = w.call<core::bitcast>(w.type_i64(), dim);
210 auto [body, for_call] = counting_for(bound, acc, cont, w.sym("forIn_" + std::to_string(j)));
211 auto [iter, new_acc, yield] = body->vars<3>();
212 cont = yield;
213 red_iters.push_back(w.call(core::conv::u, dim, iter));
214 acc = new_acc;
215 current_mut->set(true, for_call);
216 current_mut = body;
217 }
218 auto [red_mem, elem_acc] = acc->projs<2>();
219
220 DefVec iters_v = out_iters;
221 iters_v.insert(iters_v.end(), red_iters.begin(), red_iters.end());
222 auto iters = w.tuple(iters_v);
223
224 // Read one elem from each input at its affine coordinates, threading memory.
225 auto cur = red_mem;
226 DefVec input_elems(nis_nat);
227 for (u64 i = 0; i < nis_nat; ++i) {
228 auto in_buf = new_inputs->proj(nis_nat, i);
229 auto [mc_mem, coords]
230 = affine_map(accs->proj(nis_nat, i), Ris->proj(nis_nat, i), n, Sr, Sis->proj(nis_nat, i), iters, cur);
231 cur = mc_mem;
232 auto [ir, is_, iT] = Axm::isa<buffer::Buf>(in_buf->type())->args<3>();
233 auto [rd_mem, rd_val]
234 = buffer::op_read(ir, is_, iT, cur, in_buf, fold_index(Sis->proj(nis_nat, i), coords))->projs<2>();
235 cur = rd_mem;
236 input_elems[i] = rd_val;
237 }
238
239 // The combiner is mem-threaded (`Fn [mem, To, «nis; Tis»] → [mem, To]`): call it directly, its result feeds `cont`.
240 current_mut->app(true, comb, w.tuple({w.tuple({cur, elem_acc, w.tuple(input_elems)}), cont}));
241
242 return call;
243}
244
245const Def* LowerAff::lower_broadcast(const App* app) {
246 auto& w = new_world();
247 auto callee = app->callee()->as<App>(); // (broadcast {impl}) (s_in, s_out)
248 auto [s_in, s_out] = rewrite(callee->arg())->projs<2>();
249 auto [op_mem, input] = rewrite(app->arg())->projs<2>();
250 auto result_ty = rewrite(app->type()); // [%mem.M 0, %buffer.Buf (ro, so, T)]
251
252 auto r_nat = s_out->num_projs();
253
254 auto mem_ty = w.call<mem::M>(0);
255 auto fun = w.mut_fun(w.sigma({mem_ty, input->type()}), result_ty)->set("broadcast");
256 auto call = w.app(cps::op_cps2ds_dep(fun), w.tuple({op_mem, input}));
257 auto [fun_mem, in_buf] = fun->var(0_n)->projs<2>();
258 auto cont = fun->var(1);
259
260 auto [in_r, in_s, in_T] = Axm::isa<buffer::Buf>(in_buf->type())->args<3>();
261 auto [out_r, out_s, out_T] = Axm::isa<buffer::Buf>(result_ty->proj(1))->args<3>();
262
263 auto [a_mem, out_buf] = buffer::op_alloc(out_r, out_s, out_T, fun_mem)->projs<2>();
264 const Def* acc = w.tuple({a_mem, out_buf});
265 auto current_mut = fun;
266 DefVec out_iters;
267 out_iters.reserve(r_nat);
268 for (size_t i = 0; i < r_nat; ++i) {
269 auto dim = s_out->proj(r_nat, i);
270 auto bound = w.call<core::bitcast>(w.type_i64(), dim);
271 auto [body, for_call] = counting_for(bound, acc, cont, w.sym("bcast_" + std::to_string(i)));
272 auto [iter, new_acc, yield] = body->vars<3>();
273 cont = yield;
274 out_iters.push_back(w.call(core::conv::u, dim, iter));
275 acc = new_acc;
276 current_mut->set(true, for_call);
277 current_mut = body;
278 }
279 auto [loop_mem, loop_buf] = acc->projs<2>();
280
281 // Non-size-1 input dims mirror the matching output index; size-1 dims are dropped from each buffer index.
282 auto iters = w.tuple(out_iters);
283 auto [rd_mem, rd_val] = buffer::op_read(in_r, in_s, in_T, loop_mem, in_buf, fold_index(s_in, iters))->projs<2>();
284 auto [wr_mem, wr_buf]
285 = buffer::op_write(out_r, out_s, out_T, rd_mem, loop_buf, fold_index(s_out, iters), rd_val)->projs<2>();
286 current_mut->app(true, cont, w.tuple({wr_mem, loop_buf}));
287
288 return call;
289}
290
291const Def* LowerAff::lower_pad(const App* app) {
292 auto& w = new_world();
293 auto c = rewrite(app->callee())->as<App>();
294
295 // callee: pad {T, r} [s_in, s_out, mode, lo, hi]. The shapes are the logical ones; buffer reads and
296 // writes fold size-1 axes (the `Buf` handles are normalized), while the loops cover all logical dims.
297 auto [Tr, params] = c->uncurry_args<2>();
298 auto [s_in, s_out, mode, lo, hi] = params->projs<5>();
299 auto [op_mem, input, value] = rewrite(app->arg())->projs<3>();
300 auto result_ty = rewrite(app->type()); // [%mem.M 0, %buffer.Buf (r, s_out, T)]
301
302 auto r_l = Lit::isa<u64>(Tr->proj(2, 1));
303 auto mode_l = Lit::isa<u64>(mode);
304 if (!r_l || !mode_l) {
305 WLOG("{} doesn't have a lowering-time known rank/mode", app);
306 return RWPhase::rewrite_imm_App(app);
307 }
308 auto rn = *r_l;
309 auto mode_nat = *mode_l;
310 auto i64 = w.type_i64();
311
312 // select(cond, t, f) == `(f, t)#cond` (cf. %core.select); cond : Bool.
313 auto sel = [&](const Def* cond, const Def* t, const Def* f) { return w.extract(w.tuple({f, t}), cond); };
314
315 auto compute = [&](const DefVec& iters, const Def* ins, const Def* mem) -> std::pair<const Def*, const Def*> {
316 auto [in_buf, fill] = ins->projs<2>();
317 auto [ibr, ibs, ibT] = Axm::isa<buffer::Buf>(in_buf->type())->args<3>();
318 DefVec clamped(rn); // per-axis read index, kept in range, as `Idx (s_in#d)`
319 DefVec valid; // per-axis in-bounds flag (constant mode only)
320 for (u64 d = 0; d < rn; ++d) {
321 auto lo_d = w.call<core::bitcast>(i64, lo->proj(rn, d));
322 auto sin_d = w.call<core::bitcast>(i64, s_in->proj(rn, d));
323 auto in_d = w.call(core::wrap::sub, core::Mode::none, Defs{iters[d], lo_d}); // o#d − lo#d
324 const Def* idx_i64;
325 if (mode_nat == 0) { // constant: a single unsigned `<` covers both bounds (underflow wraps high)
326 auto v_d = w.call(core::icmp::ul, w.tuple({in_d, sin_d}));
327 valid.push_back(v_d);
328 idx_i64 = sel(v_d, in_d, w.lit_i64(0));
329 } else { // replicate: clamp the read to the nearest edge [0, s_in#d − 1]
330 auto sin_m1 = w.call(core::wrap::sub, core::Mode::none, Defs{sin_d, w.lit_i64(1)});
331 idx_i64 = w.call(core::extrema::smax,
332 w.tuple({w.lit_i64(0), w.call(core::extrema::smin, w.tuple({in_d, sin_m1}))}));
333 }
334 clamped[d] = w.call(core::conv::u, s_in->proj(rn, d), idx_i64);
335 }
336 auto [rd_mem, elem]
337 = buffer::op_read(ibr, ibs, ibT, mem, in_buf, fold_index(s_in, w.tuple(clamped)))->projs<2>();
338 if (mode_nat != 0) return {rd_mem, elem}; // replicate: always a (clamped) read
339 auto all_valid = valid.empty() ? w.lit_tt() : valid[0];
340 for (u64 d = 1; d < valid.size(); ++d)
341 all_valid = w.call(core::bit2::and_, w.lit_nat(2), w.tuple({all_valid, valid[d]}));
342 return {rd_mem, sel(all_valid, elem, fill)}; // constant: fill out-of-region cells with `value`
343 };
344
345 return build_pointwise(w, result_ty, op_mem, w.tuple({input, value}), s_out, rn, "pad", compute);
346}
347
348const Def* LowerAff::lower_concat(const App* app) {
349 auto& w = new_world();
350 auto c = rewrite(app->callee())->as<App>();
351
352 // callee: concat {T, nis, r} [ax] {Sis} [s_out]. The shapes are the logical ones; buffer reads and
353 // writes fold size-1 axes (the `Buf` handles are normalized), while the loops cover all logical dims.
354 auto [TnisR, ax, Sis, s_out] = c->uncurry_args<4>();
355 auto [T, nis, r] = TnisR->projs<3>();
356 auto [op_mem, op_is] = rewrite(app->arg())->projs<2>();
357 auto result_ty = rewrite(app->type()); // [%mem.M 0, %buffer.Buf (r, s_out, T)]
358
359 auto nis_l = Lit::isa<u64>(nis);
360 auto r_l = Lit::isa<u64>(r);
361 auto ax_l = Lit::isa<u64>(ax);
362 if (!nis_l || !r_l || !ax_l) {
363 WLOG("{} doesn't have lowering-time known nis/rank/axis", app);
364 return RWPhase::rewrite_imm_App(app);
365 }
366 auto nisn = *nis_l, rn = *r_l, axn = *ax_l;
367
368 // Prefix offsets along `ax`: off#i = Σ_{j<i} Sis#i#ax (literal extents required).
369 DefVec off(nisn);
370 Vector<u64> ext(nisn);
371 u64 acc_off = 0;
372 for (u64 i = 0; i < nisn; ++i) {
373 off[i] = w.lit_i64(acc_off);
374 auto ei = Lit::isa<u64>(Sis->proj(nisn, i)->proj(rn, axn));
375 if (!ei) {
376 WLOG("{} input {} has a non-literal extent along the concat axis", app, i);
377 return RWPhase::rewrite_imm_App(app);
378 }
379 ext[i] = *ei;
380 acc_off += *ei;
381 }
382
383 auto sel = [&](const Def* cond, const Def* t, const Def* f) { return w.extract(w.tuple({f, t}), cond); };
384
385 auto compute = [&](const DefVec& iters, const Def* ins, const Def* mem) -> std::pair<const Def*, const Def*> {
386 auto o_ax = iters[axn];
387 const Def* cur = mem;
388 // Read input `i` at `iters`, but with the `ax` coordinate shifted by off#i and clamped into input `i`.
389 auto read_i = [&](u64 i) -> const Def* {
390 auto in_buf = ins->proj(nisn, i);
391 auto [ibr, ibs, ibT] = Axm::isa<buffer::Buf>(in_buf->type())->args<3>();
392 auto Sis_i = Sis->proj(nisn, i);
393 auto e_i_m1 = w.lit_i64(ext[i] - 1);
394 auto loc = w.call(core::wrap::sub, core::Mode::none, Defs{o_ax, off[i]});
395 auto clamp = w.call(core::extrema::smax,
396 w.tuple({w.lit_i64(0), w.call(core::extrema::smin, w.tuple({loc, e_i_m1}))}));
397 DefVec coords(rn);
398 for (u64 d = 0; d < rn; ++d) {
399 auto idx_i64 = (d == axn) ? clamp : iters[d];
400 coords[d] = w.call(core::conv::u, Sis_i->proj(rn, d), idx_i64);
401 }
402 auto [rd_mem, rd_val]
403 = buffer::op_read(ibr, ibs, ibT, cur, in_buf, fold_index(Sis_i, w.tuple(coords)))->projs<2>();
404 cur = rd_mem;
405 return rd_val;
406 };
407 // Select chain: the highest `i` with off#i ≤ o_ax owns the cell (offsets increase, later wins).
408 auto result = read_i(0);
409 for (u64 i = 1; i < nisn; ++i) {
410 auto cond = w.call(core::icmp::uge, w.tuple({o_ax, off[i]}));
411 result = sel(cond, read_i(i), result);
412 }
413 return {cur, result};
414 };
415
416 return build_pointwise(w, result_ty, op_mem, op_is, s_out, rn, "concat", compute);
417}
418
419} // namespace mim::plug::matrix::phase
const Def * callee() const
Definition lam.h:276
const Def * arg() const
Definition lam.h:285
static auto isa(const Def *def)
Definition axm.h:107
Base class for all Defs.
Definition def.h:261
auto projs(F f) const
Splits this Def via Def::projections into an Array (if A == std::dynamic_extent) or std::array (other...
Definition def.h:402
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
Definition def.cpp:491
auto vars(F f) noexcept
Definition def.h:441
Lam * set(Filter filter, const Def *body)
Definition lam.cpp:29
static std::optional< T > isa(const Def *def)
Definition def.h:878
const Vector< std::string > & args()
Command-line arguments passed to this Phase's plugin via -X <plugin>:<arg>.
Definition phase.cpp:23
World & new_world()
Create new Defs into this.
Definition phase.h:368
bool is_bootstrapping() const
Returns whether we are currently bootstrapping (rewriting annexes).
Definition phase.h:356
virtual const Def * rewrite(const Def *)
Definition rewrite.cpp:56
const Def * rewrite_imm_App(const App *) override
Definition lower_aff.cpp:99
#define WLOG(...)
Definition log.h:89
const Def * op_write(const Def *r, const Def *s, const Def *T, const Def *mem, const Def *buf, const Def *idx, const Def *val)
buffer.write (r, s, T) (mem, buf, idx, val) ↦ [mem.M 0, buffer.Buf (r, s, T)].
Definition buffer.h:29
const Def * op_read(const Def *r, const Def *s, const Def *T, const Def *mem, const Def *buf, const Def *idx)
buffer.read (r, s, T) (mem, buf, idx) ↦ [mem.M 0, T].
Definition buffer.h:22
const Def * op_alloc(const Def *r, const Def *s, const Def *T, const Def *mem)
buffer.alloc (r, s, T) mem ↦ [mem.M 0, buffer.Buf (r, s, T)].
Definition buffer.h:16
@ none
Wrap around.
Definition core.h:16
const Def * op_cps2ds_dep(const Def *k)
Definition cps.h:16
The mem Plugin
Definition mem.h:11
Lam * mut_con(World &w, nat_t a=0)
Yields con[mem.M 0].
Definition mem.h:16
View< const Def * > Defs
Definition def.h:78
Vector< const Def * > DefVec
Definition def.h:79
uint64_t u64
Definition types.h:27
@ App
Definition def.h:109
Vector(I, I, A=A()) -> Vector< typename std::iterator_traits< I >::value_type, Default_Inlined_Size< typename std::iterator_traits< I >::value_type >, A >