28const Def* LowerMapReduce::lower_buffer_lit(
const App* app) {
43 result_ty, a_mem, buf, val, s_out, *rn,
"constant_fill",
44 [](
const DefVec&,
const Def* ins,
const Def* m) -> std::pair<const Def*, const Def*> {
return {m, ins}; });
47const Def* LowerMapReduce::lower_map_reduce_post(
const App* app) {
50 auto ranks = mr.ranks();
52 log().w(
"rank counts (nis/nps/Ro/Rn) of {} are not known at lowering time", app);
57 impl = w.app(impl, mr.nis_nps);
58 impl = w.app(impl, {mr.To, mr.Tp, mr.Ro, w.lit_nat(ranks->rr)});
59 impl =
w.app(impl, mr.shapes);
60 impl =
w.app(impl, {mr.Tis, mr.Tps});
61 impl =
w.app(impl, {mr.comb, mr.init, mr.post});
62 impl =
w.app(impl, mr.map_out);
65 auto [read_inputs_ty, read_post_ty, write_output_ty] = impl->type()->as<
Pi>()->dom()->projs<3>();
68 auto reader = [&](
const Def*
type,
const char*
name,
u64 num,
const Def* rank,
const Def* bounds,
const Def* rs,
69 const Def* ss,
const Def* maps,
const Def* buffers) {
70 auto fun =
w.mut_lam(
type->as<Pi>())->set(
name);
71 auto [
args, ret] = fun->vars<2>();
72 auto [m, indices] =
args->projs<2>();
74 for (
u64 i = 0; i != num; ++i) {
75 auto si = ss->proj(num, i);
77 =
op_affine_map(maps->proj(num, i), rs->proj(num, i), rank, bounds, si, indices, m)->
projs<2>();
82 fun->app(
true, ret, {m,
w.tuple(values)});
85 auto read_inputs = reader(read_inputs_ty,
"readInputs", ranks->nis, mr.Rn, mr.Sr, mr.Ris, mr.Sis, mr.maps, inputs);
87 = reader(read_post_ty,
"readPost", ranks->nps, mr.Ro, mr.So, mr.Rps, mr.Sps, mr.post_maps, post_inputs);
89 auto write_output =
w.mut_lam(write_output_ty->as<Pi>())->set(
"writeOutput");
91 auto [
args, ret] = write_output->vars<2>();
92 auto [m, output, coords, value] =
args->projs<4>();
94 write_output->app(
true, ret, stored->proj(2, 0));
97 impl =
w.app(impl, {read_inputs, read_post, write_output});
98 return w.app(impl, {mem, dst});
101const Def* LowerMapReduce::lower_broadcast(
const App* app) {
103 auto callee = app->callee()->as<
App>();
104 auto [s_in, s_out] =
rewrite(callee->arg())->
projs<2>();
105 auto [op_mem, dst, input] =
rewrite(app->arg())->
projs<3>();
106 auto result_ty =
rewrite(app->type());
108 auto r_l =
Lit::isa(s_out->arity());
110 log().w(
"rank of {} is not known at lowering time", app);
115 auto compute = [&](
const DefVec& iters,
const Def* in_buf,
const Def* mem) -> std::pair<const Def*, const Def*> {
116 auto idxs =
w.tuple(
to_idxs(w, s_out->projs(*r_l), iters));
118 return {rd_mem, rd_val};
121 return build_pointwise(result_ty, op_mem, dst, input, s_out, *r_l,
"broadcast", compute);
124const Def* LowerMapReduce::lower_pad(
const App* app) {
130 auto [Tr, s_in, params, s_out] =
c->uncurry_args<4>();
131 auto [
mode, lo, hi] = params->projs<3>();
132 auto [op_mem, dst, input, val] =
rewrite(app->arg())->
projs<4>();
133 auto result_ty =
rewrite(app->type());
137 if (!r_l || !mode_l) {
138 log().w(
"rank/mode of {} is not known at lowering time", app);
142 auto compute = [&](
const DefVec& iters,
const Def* ins,
const Def* mem) -> std::pair<const Def*, const Def*> {
143 auto [in_buf, fill] = ins->projs<2>();
144 auto [coords, valid] =
pad_coords(iters, lo, s_in, *mode_l != 0);
146 return {rd_mem, valid ?
w.select(valid, elem, fill) : elem};
149 return build_pointwise(result_ty, op_mem, dst,
w.tuple({input, val}), s_out, *r_l,
"pad", compute);
152const Def* LowerMapReduce::lower_concat(
const App* app) {
157 auto [TnisR, ax, Sis, s_out] =
c->uncurry_args<4>();
158 auto [T, nis,
r] = TnisR->projs<3>();
159 auto [op_mem, dst, op_is] =
rewrite(app->arg())->
projs<3>();
160 auto result_ty =
rewrite(app->type());
165 if (!nis_l || !r_l || !ax_l) {
166 log().w(
"nis/rank/axis of {} are not known at lowering time", app);
169 auto nisn = *nis_l, rn = *r_l, axn = *ax_l;
173 log().w(
"an extent of {} along the concat axis is not known at lowering time", app);
177 auto compute = [&](
const DefVec& iters,
const Def* ins,
const Def* mem) -> std::pair<const Def*, const Def*> {
178 const Def* cur = mem;
179 auto read = [&](
u64 i,
const Def* ax_idx) {
181 coords[axn] = ax_idx;
182 auto [rd_mem, rd_val]
188 return {cur, result};
191 return build_pointwise(result_ty, op_mem, dst, op_is, s_out, rn,
"concat", compute);
194const Def* LowerMapReduce::lower_gather(
const App* app) {
198 auto [Tr, shapes, dim] =
c->uncurry_args<3>();
199 auto [T,
r] = Tr->projs<2>();
200 auto [s_src, s_idx] = shapes->projs<2>();
202 auto result_ty =
rewrite(app->type());
206 if (!r_l || !dim_l) {
207 log().w(
"{} doesn't have lowering-time known rank/axis", app);
211 auto compute = [&](
const DefVec& iters,
const Def* ins,
const Def* mem) -> std::pair<const Def*, const Def*> {
212 auto [in_buf, idx_buf] = ins->projs<2>();
217 return {read_mem, val};
219 return build_pointwise(result_ty, op_mem, dst,
w.tuple({input, idx}), s_idx, *r_l,
"gather", compute);
222const Def* LowerMapReduce::lower_scatter(
const App* app) {
226 auto [Tr, shapes, dim] =
c->uncurry_args<3>();
227 auto [T,
r] = Tr->projs<2>();
228 auto [s_src, s_idx, s_updates] = shapes->projs<3>();
229 auto [op_mem, op_dst, input,
idx, updates] =
rewrite(app->arg())->
projs<5>();
230 auto result_ty =
rewrite(app->type());
234 if (!r_l || !dim_l) {
235 log().w(
"{} doesn't have lowering-time known rank/axis", app);
239 auto [fun, call] =
ds_splice(
w.tuple({op_mem, op_dst, input, idx, updates}), result_ty,
"scatter");
240 auto [fun_mem, out_buf, in_buf, idx_buf, update_buf] = fun->var(2, 0)->projs<5>();
241 const Def* cont = fun->var(2, 1);
243 const Def* acc =
w.tuple({
buffer::op_copy(fun_mem, out_buf, in_buf), out_buf});
246 auto [loop_mem, loop_buf] = acc->projs<2>();
253 current->app(
true, cont,
w.tuple({write_mem, loop_buf}));
const Def * callee() const
static auto isa(const Def *def)
const Def * proj(nat_t a, nat_t i) const
Similar to World::extract while assuming an arity of a, but also works on Sigmas and Arrays.
auto projs(Projector auto f) const
Splits this Def via Def::projections into an Array (if A == std::dynamic_extent) or std::array (other...
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
static std::optional< T > isa(const Def *def)
const fe::Log & log() const
const fe::Vector< std::string > & args()
Command-line arguments passed to this Phase's plugin via -X <plugin>:<arg>.
std::string_view name() const
World & new_world()
Create new Defs into this.
World & old_world()
Get old Defs from here.
const Def * rewrite_imm_App(const App *) override
virtual const Def * rewrite(const Def *)
constexpr Shape() noexcept=default
const Def * rewrite_imm_App(const App *) override
DefVec counting_nest(Lam *&cur, const Def *&exit, const Def *&acc, Defs dims, std::string_view name)
Nests one counting loop per bound of dims inside cur, threading cur, exit and acc down to the innermo...
const Def * op_affine_map(const Def *f, const Def *m, const Def *n, const Def *s_in, const Def *s_out, const Def *idxs, const Def *mem)
affine.map @(m, n) @(s_in, s_out) f idxs as mem with the address space as of mem ↦ [mem',...
std::optional< fe::Vector< u64 > > concat_extents(const Def *Sis, u64 nis, u64 r, u64 ax)
The literal extents of the nis input shapes Sis along the concat axis ax; std::nullopt if one is not ...
DefVec to_idxs(World &w, Defs extents, Defs iters)
Converts the raw i64 loop counters iters into indices Idx extents[d].
const Def * build_pointwise(const Def *result_ty, const Def *mem, const Def *dst, const Def *ins, const Def *s_out, u64 rn, const std::string &name, auto compute)
A [mem, dst, ins] → [mem, Buf] fun spliced via cps.cps2ds_dep that loops over s_out carrying [mem,...
std::pair< DefVec, const Def * > pad_coords(Defs iters, const Def *lo, const Def *s_in, bool replicate)
The read coordinates o#d − lo#d of a pad into Idx s_in#d - clamped to the nearest edge if replicate,...
const Def * folded_idx(const Def *shape, Defs iters)
The raw i64 loop counters iters as a buffer index into shape, with its literal size-1 axes folded awa...
const Def * concat_select(const Def *o_ax, const fe::Vector< u64 > &exts, auto read)
The concat cell at the i64 axis coordinate o_ax: read(i, loc) of the input i owning it - the highest ...
std::pair< Lam *, const Def * > ds_splice(const Def *arg, const Def *codom, std::string name)
A fresh fun: Fn arg->type() → codom named name, spliced into direct style as cps.cps2ds_dep fun arg.
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)].
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].
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)].
const Def * op_copy(const Def *r, const Def *s, const Def *T, const Def *mem, const Def *dst, const Def *src)
buffer.copy (r, s, T) (mem, dst, src) ↦ mem.M 0 (copies the whole buffer src into dst).
fe::Vector< const Def * > DefVec
static MapRedPost of(const App *callee)