MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
tensor.h
Go to the documentation of this file.
1#pragma once
2
3#include <optional>
4
5#include <fe/worklist.h>
6
7#include <mim/lam.h>
8#include <mim/tuple.h>
9#include <mim/world.h>
10
12
13namespace mim::plug::tensor {
14
15/// Recognizes the (rebuilt) `tensor_copy` combiner `(acc, ys) ↦ ys#0`: the result is exactly the
16/// single input element, so a map_reduce built on it is a pure re-indexed read of that input.
17inline bool is_copy_comb(const Def* comb) {
18 auto ret = Lam::isa_ret_arg(comb);
19 return ret && ret == comb->as_mut<Lam>()->var(0)->proj(2, 1)->proj(1, 0);
20}
21
22/// Is `post` the (rebuilt) CPS identity `tensor.id`, i.e. a lam `(x, extras) ↦ x` that returns its
23/// first argument (and hence has no epilogue inputs)?
24inline bool is_identity_post(const Def* post) {
25 auto ret = Lam::isa_ret_arg(post);
26 return ret && ret == post->as_mut<Lam>()->var(0)->proj(2, 0);
27}
28
29/// A pure re-indexed read: the source tensor, the access map into it (over the read's output
30/// coordinates), and the source's element type/rank/shape.
31struct PureRead {
32 const Def* src = nullptr;
33 const Def* map = nullptr;
34 const Def* T = nullptr;
35 const Def* R = nullptr;
36 const Def* S = nullptr;
37};
38
39/// If `value` is a pure re-indexed read — a copy-combiner map_reduce without reduction loops that
40/// writes its full loop domain through the identity output map (reshape/transpose/slice/flip/repeat
41/// lower to these) — returns its single access map and source.
42/// `fuse_tensor`'s read-through absorbs exactly these into the consuming op's access maps.
43inline std::optional<PureRead> is_pure_read(const Def* value) {
44 auto mr = Axm::isa<tensor::map_reduce_post>(value);
45 if (!mr) return {};
46 auto [nis_nps, meta, shapes, in_tys, comb_init, map_out, maps_all, is_all] = mr->uncurry_args<8>();
47
48 auto [nis, nps] = nis_nps->projs<2>();
49 // No reduction loops: the total loop count Rn equals the output rank Ro.
50 if (Lit::isa(nis) != 1 || Lit::isa(nps) != 0 || meta->proj(5, 2) != meta->proj(5, 3)) return {};
51 auto [So, Sr, sched] = shapes->projs<3>();
52 if (Sr != So) return {};
53 auto id_lam = map_out->isa_mut<Lam>();
54 if (!id_lam || !id_lam->is_set() || id_lam->body() != id_lam->var()) return {};
55 auto [comb, init, post] = comb_init->projs<3>();
56 if (!is_copy_comb(comb) || !is_identity_post(post)) return {};
57
58 auto sole = [](const Def* d, u64 n, u64 i) { return d->proj(n, i)->proj(1, 0); };
59 return PureRead{sole(is_all, 2, 0), sole(maps_all, 2, 0), sole(in_tys, 6, 0), sole(in_tys, 6, 1),
60 sole(in_tys, 6, 2)};
61}
62
63/// @note `index` comes *before* `arr` in the operand tuple, see tensor.get.
64inline const Def* op_get(const Def* T, const Def* r, const Def* s, const Def* arr, const Def* index) {
65 auto& w = arr->world();
66 return w.app(w.app(w.annex<tensor::get>(), {T, r, s}), {index, arr});
67}
68
69/// @note `index` comes *before* `arr` in the operand tuple, see tensor.get.
70inline const Def* op_set(const Def* T, const Def* r, const Def* s, const Def* arr, const Def* index, const Def* x) {
71 auto& w = arr->world();
72 return w.app(w.app(w.annex<tensor::set>(), {T, r, s}), {index, arr, x});
73}
74
75/// Counts the consumers of every def of @p world matched by @p pred.
76/// Tuples and packs are transparent argument wrappers, so a wrapped def is charged to the enclosing
77/// non-tuple consumer - a shared argument tuple charges each of its users, and a def used twice in one
78/// argument list counts twice.
79/// A phase whose world does not track uses needs this up front.
80template<class Pred>
81DefMap<u64> count_consumers(const World& world, Pred pred) {
82 auto counts = DefMap<u64>();
83 auto charge = [&](this auto&& charge, const Def* d) -> void {
84 if (pred(d))
85 ++counts[d];
86 else if (d->isa<Tuple>() || d->isa<Pack>())
87 for (auto op : d->ops())
88 if (op) charge(op);
89 };
90
91 auto wl = fe::BFSWorklist<DefSet>();
92 wl.push(world.roots());
93
94 while (!wl.empty()) {
95 auto def = wl.pop();
96 auto transparent = def->isa<Tuple>() || def->isa<Pack>();
97 for (auto op : def->ops())
98 if (op) {
99 if (!transparent) charge(op);
100 wl.push(op);
101 }
102 if (def->type()) wl.push(def->type());
103 }
104
105 return counts;
106}
107
108} // namespace mim::plug::tensor
static auto isa(const Def *def)
Definition axm.h:112
Base class for all Defs.
Definition def.h:273
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.
Definition def.cpp:623
T * as_mut() const
Asserts that this is a mutable, casts constness away and performs a static_cast to T.
Definition def.h:589
World & world() const noexcept
Definition def.h:1097
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:440
A function.
Definition lam.h:113
static const Def * isa_ret_arg(const Def *d)
Yields the y of lm (x, ret) = ret y - the argument d's body hands to its Lam::ret_var.
Definition lam.cpp:41
static std::optional< T > isa(const Def *def)
Definition def.h:937
A (possibly paramterized) Tuple.
Definition tuple.h:137
Data constructor for a Sigma.
Definition tuple.h:61
The World represents the whole program and manages creation of MimIR nodes (Defs).
Definition world.h:40
auto roots() const
annexes() + externals().muts() in this order.
Definition world.h:285
The tensor Plugin
Definition constraints.h:5
bool is_identity_post(const Def *post)
Is post the (rebuilt) CPS identity tensor.id, i.e.
Definition tensor.h:24
const Def * op_set(const Def *T, const Def *r, const Def *s, const Def *arr, const Def *index, const Def *x)
Definition tensor.h:70
std::optional< PureRead > is_pure_read(const Def *value)
If value is a pure re-indexed read — a copy-combiner map_reduce without reduction loops that writes i...
Definition tensor.h:43
bool is_copy_comb(const Def *comb)
Recognizes the (rebuilt) tensor_copy combiner (acc, ys) ↦ ys#0: the result is exactly the single inpu...
Definition tensor.h:17
const Def * op_get(const Def *T, const Def *r, const Def *s, const Def *arr, const Def *index)
Definition tensor.h:64
DefMap< u64 > count_consumers(const World &world, Pred pred)
Counts the consumers of every def of world matched by pred.
Definition tensor.h:81
A pure re-indexed read: the source tensor, the access map into it (over the read's output coordinates...
Definition tensor.h:31
GIDMap< const Def *, To > DefMap
Definition def.h:88
uint64_t u64
Definition types.h:27