MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
normalizers.cpp
Go to the documentation of this file.
1#include <fe/bitset.h>
2
3#include <mim/tuple.h>
4#include <mim/world.h>
5
7
8#include "mim/plug/vec/vec.h"
9
10namespace mim::plug::vec {
11
12namespace {
13
14/// The elements of the `n`-vector @p vec, if they are known.
15std::optional<DefVec> elems(const Def* n, const Def* vec) {
16 auto l = Lit::isa(n);
17 if (l == 0) return DefVec();
18 if (l == 1) return DefVec{vec}; // `«1; E»` ≡ `E`, even if `E` is itself an aggregate
19 if (auto tuple = vec->isa<Tuple>()) return DefVec(tuple->ops().begin(), tuple->ops().end());
20 if (auto seq = vec->isa<Seq>(); seq && !seq->shape().is_fused())
21 if (auto a = Lit::isa(seq->arity())) return seq->projs(*a);
22 return {};
23}
24
25} // namespace
26
27template<fold id>
28const Def* normalize_fold(const Def*, const Def* c, const Def* arg) {
29 auto& w = c->world();
30 auto [_, n, f] = App::uncurry_args<3>(c);
31 auto [acc, vec] = arg->projs<2>();
32 if constexpr (id == fold::r) std::swap(acc, vec);
33
34 auto es = elems(n, vec);
35 if (!es) return nullptr;
36
37 if constexpr (id == fold::l)
38 for (auto e : *es)
39 acc = w.app(f, {acc, e});
40 else // fold::r
41 for (auto e : *es | std::views::reverse)
42 acc = w.app(f, {e, acc});
43 return acc;
44}
45
46const Def* normalize_zip(const Def* type, const Def* c, const Def* arg) {
47 if (arg->is_open()) return {};
48 auto& w = type->world();
49 auto [ni_n, _, f] = App::uncurry_args<3>(c);
50 auto [ni, n] = ni_n->projs<2>([](const Def* def) { return Lit::isa(def); });
51
52 if (!ni || !n) return {};
53 if (ni >= w.flags().scalarize_threshold || n >= w.flags().scalarize_threshold) return {};
54
55 auto res = fe::Vector<const Def*, 32>(*n);
56 auto tup = fe::Vector<const Def*, 32>(*ni);
57
58 for (size_t j = 0; j != n; ++j) {
59 for (size_t i = 0; i != ni; ++i)
60 tup[i] = arg->proj(*ni, i)->proj(*n, j);
61
62 res[j] = w.app(f, tup);
63 }
64
65 return w.tuple(res);
66}
67
68template<scan id>
69const Def* normalize_scan(const Def*, const Def* c, const Def* vec) {
70 auto& w = c->world();
71 auto [_, n, p] = App::uncurry_args<3>(c);
72 if (Lit::isa(n) == 1) return w.app(p, vec);
73
74 // All elements of `‹s; x›` are `x`, so besides `p x` only whether `s` is empty matters.
75 if (auto pack = vec->isa_imm<Pack>()) {
76 auto shape = pack->shape();
77 auto r = shape.rank();
78 if (!r) return nullptr;
79
80 auto res = w.app(p, pack->body());
81 for (nat_t i = 0; i != *r; ++i) {
82 // World::seq folds literal-`0` extents away.
83 if (Lit::isa(shape[i])) continue;
84 auto cmp = w.call(id == scan::exists ? core::ncmp::ne : core::ncmp::e, Defs{shape[i], w.lit_nat_0()});
85 res = w.call(id == scan::exists ? core::bit2::and_ : core::bit2::or_, 0_n, Defs{cmp, res});
86 }
87 return res;
88 }
89
90 auto es = elems(n, vec);
91 if (!es) return nullptr;
92
93 const Def* acc = w.lit_bool(id != scan::exists);
94 for (auto e : *es)
95 acc = w.call(id == scan::exists ? core::bit2::or_ : core::bit2::and_, 0_n, Defs{acc, w.app(p, e)});
96 return acc;
97}
98
99const Def* normalize_is_unique(const Def*, const Def* callee, const Def* vec) {
100 auto& w = vec->world();
101 auto n = Lit::isa(callee->as<App>()->arg());
102 if (n && *n <= 1) return w.lit_tt();
103
104 if (auto tuple = vec->isa<Tuple>(); tuple && n) {
105 auto seen = DefSet();
106 for (auto op : tuple->ops()) {
107 auto [_, ins] = seen.emplace(op);
108 if (!ins) return w.lit_ff();
109 }
110 return tuple->is_closed() ? w.lit_tt() : nullptr;
111 }
112
113 if (auto pack = vec->isa_imm<Pack>()) {
114 if (Lit::isa(pack->arity())) return w.lit_ff();
115 }
116
117 return nullptr;
118}
119
120const Def* normalize_cat(const Def*, const Def* callee, const Def* arg) {
121 auto [a, b] = arg->projs<2>();
122 auto [n, m] = callee->as<App>()->decurry()->args<2>([](auto def) { return Lit::isa(def); });
123 if (n && *n == 0) return b;
124 if (m && *m == 0) return a;
125 return n && m ? Tuple::cat(*n, *m, a, b) : nullptr;
126}
127
128const Def* normalize_diff(const Def* type, const Def* c, const Def* arg) {
129 if (auto arr = type->isa<Arr>()) {
130 if (arr->arity()->isa<Bot>()) return nullptr; // ack error
131 }
132
133 auto& w = type->world();
134 auto callee = c->as<App>();
135 auto [n, m] = callee->args<2>([](auto def) { return Lit::isa(def); });
136 auto [vec, is] = arg->projs<2>();
137
138 if (!n || !m) return nullptr;
139 if (n == 1 && m == 1) return w.tuple();
140
141 if (auto tup_vec = vec->isa<Tuple>()) {
142 if (auto tup_is = is->isa<Tuple>(); tup_is && tup_is->is_closed()) {
143 auto defs = DefVec();
144 auto drop = fe::Bitset();
145 for (auto opi : tup_is->ops())
146 drop.set(Lit::as(opi));
147
148 for (size_t i = 0, e = tup_vec->num_ops(); i != e; ++i)
149 if (!drop.test(i)) defs.emplace_back(tup_vec->op(i));
150 return w.tuple(defs);
151 }
152 if (auto lit_is = Lit::isa(is)) {
153 auto defs = DefVec();
154
155 for (size_t i = 0, e = tup_vec->num_ops(); i != e; ++i)
156 if (i != lit_is) defs.emplace_back(tup_vec->op(i));
157 return w.tuple(defs);
158 }
159 }
160
161 if (auto tup_pack = vec->isa_imm<Pack>()) return w.pack(*n - *m, tup_pack->body());
162
163 return nullptr;
164}
165
167
168} // namespace mim::plug::vec
auto args(Projector auto f) const noexcept
Definition lam.h:252
auto uncurry_args() const
Definition lam.h:275
const Def * arg() const
Definition lam.h:251
A (possibly paramterized) Array.
Definition tuple.h:305
Base class for all Defs.
Definition def.h:289
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:647
bool is_open() const
Same as has_free_vars().
Definition def.h:534
auto projs(Projector auto f) const
Splits this Def via Def::projections into an Array (if A == std::dynamic_extent) or std::array (other...
Definition def.h:457
bool is_closed() const
Same as !has_free_vars().
Definition def.cpp:357
static std::optional< T > isa(const Def *def)
Definition def.h:976
static T as(const Def *def)
Definition def.h:982
A (possibly paramterized) Tuple.
Definition tuple.h:332
Base class for Arr and Pack.
Definition tuple.h:267
Shape shape() const
Definition tuple.h:279
bool is_fused() const
Does this span several axes? Also true for a dynamic rank.
Definition tuple.h:211
Data constructor for a Sigma.
Definition tuple.h:84
static const Def * cat(nat_t n, nat_t m, const Def *a, const Def *b)
Definition tuple.h:92
The tuple Plugin
The vec Plugin
const Def * normalize_scan(const Def *, const Def *c, const Def *vec)
const Def * normalize_is_unique(const Def *, const Def *callee, const Def *vec)
const Def * normalize_cat(const Def *, const Def *callee, const Def *arg)
const Def * normalize_diff(const Def *type, const Def *c, const Def *arg)
const Def * normalize_fold(const Def *, const Def *c, const Def *arg)
const Def * normalize_zip(const Def *type, const Def *c, const Def *arg)
u64 nat_t
Definition types.h:37
fe::View< const Def * > Defs
Definition def.h:96
fe::Vector< const Def * > DefVec
Definition def.h:98
GIDSet< const Def * > DefSet
Definition def.h:94
TExt< false > Bot
Definition union.h:39
#define MIM_vec_NORMALIZER_IMPL
Definition autogen.h:91