MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
normalizers.cpp
Go to the documentation of this file.
2
3namespace mim::plug::math {
4
5namespace {
6
7template<class F>
8std::optional<u64> dispatch_float_width(nat_t width, F&& f) {
9 switch (width) {
10#define CODE(i) \
11 case i: return f.template operator()<i>();
13#undef CODE
14 default: return {};
15 }
16}
17
18template<class F>
19std::optional<u64> dispatch_int_width(nat_t width, F&& f) {
20 switch (width) {
21#define CODE(i) \
22 case i: return f.template operator()<i>();
24#undef CODE
25 default: return {};
26 }
27}
28
29template<nat_t w, class F>
30std::optional<u64> fold_float_unary_bits(u64 a, F&& f) {
31 using T = w2f<w>;
32 auto x = bitcast_resize<T>(a);
33 return bitcast_resize<u64>(static_cast<T>(f(x)));
34}
35
36template<nat_t w, class F>
37std::optional<u64> fold_float_binary_bits(u64 a, u64 b, F&& f) {
38 using T = w2f<w>;
39 auto x = bitcast_resize<T>(a);
40 auto y = bitcast_resize<T>(b);
41 return bitcast_resize<u64>(static_cast<T>(f(x, y)));
42}
43
44template<nat_t w>
45constexpr long double signed_min() {
46 if constexpr (w == 1)
47 return -1.0L;
48 else
49 return static_cast<long double>(std::numeric_limits<w2s<w>>::min());
50}
51
52template<nat_t w>
53constexpr long double signed_max() {
54 if constexpr (w == 1)
55 return 0.0L;
56 else
57 return static_cast<long double>(std::numeric_limits<w2s<w>>::max());
58}
59
60template<nat_t w>
61constexpr long double unsigned_max() {
62 return static_cast<long double>(std::numeric_limits<w2u<w>>::max());
63}
64
65template<nat_t w>
66std::optional<u64> encode_signed(long double x) {
67 if constexpr (w == 1) {
68 if (x == -1.0L) return 1_u64;
69 if (x == 0.0L) return 0_u64;
70 return {};
71 } else {
72 return bitcast_resize<u64>(static_cast<w2s<w>>(x));
73 }
74}
75
76template<nat_t w>
77std::optional<u64> encode_unsigned(long double x) {
78 return bitcast_resize<u64>(static_cast<w2u<w>>(x));
79}
80
81template<nat_t w>
82long double decode_signed(u64 a) {
83 if constexpr (w == 1)
84 return bitcast_resize<bool>(a) ? -1.0L : 0.0L;
85 else
86 return static_cast<long double>(bitcast_resize<w2s<w>>(a));
87}
88
89template<nat_t w>
90long double decode_unsigned(u64 a) {
91 return static_cast<long double>(bitcast_resize<w2u<w>>(a));
92}
93
94template<nat_t w, class F>
95std::optional<u64> fold_float_to_signed_bits(F x) {
96 if (!std::isfinite(x)) return {};
97
98 auto truncated = std::trunc(static_cast<long double>(x));
99 if (truncated < signed_min<w>() || truncated > signed_max<w>()) return {};
100 return encode_signed<w>(truncated);
101}
102
103template<nat_t w, class F>
104std::optional<u64> fold_float_to_unsigned_bits(F x) {
105 if (!std::isfinite(x)) return {};
106
107 auto truncated = std::trunc(static_cast<long double>(x));
108 if (truncated < 0.0L || truncated > unsigned_max<w>()) return {};
109 return encode_unsigned<w>(truncated);
110}
111
112// clang-format off
113template<class Id, Id id, nat_t w>
114std::optional<u64> fold_unary_lit(u64 a) {
115 if constexpr (std::is_same_v<Id, tri>) {
116 if constexpr (false) {}
117 else if constexpr (id == tri:: sin ) return fold_float_unary_bits<w>(a, [](auto x) { return std:: sin (x); });
118 else if constexpr (id == tri:: cos ) return fold_float_unary_bits<w>(a, [](auto x) { return std:: cos (x); });
119 else if constexpr (id == tri:: tan ) return fold_float_unary_bits<w>(a, [](auto x) { return std:: tan (x); });
120 else if constexpr (id == tri:: sinh) return fold_float_unary_bits<w>(a, [](auto x) { return std:: sinh(x); });
121 else if constexpr (id == tri:: cosh) return fold_float_unary_bits<w>(a, [](auto x) { return std:: cosh(x); });
122 else if constexpr (id == tri:: tanh) return fold_float_unary_bits<w>(a, [](auto x) { return std:: tanh(x); });
123 else if constexpr (id == tri::asin ) return fold_float_unary_bits<w>(a, [](auto x) { return std::asin (x); });
124 else if constexpr (id == tri::acos ) return fold_float_unary_bits<w>(a, [](auto x) { return std::acos (x); });
125 else if constexpr (id == tri::atan ) return fold_float_unary_bits<w>(a, [](auto x) { return std::atan (x); });
126 else if constexpr (id == tri::asinh) return fold_float_unary_bits<w>(a, [](auto x) { return std::asinh(x); });
127 else if constexpr (id == tri::acosh) return fold_float_unary_bits<w>(a, [](auto x) { return std::acosh(x); });
128 else if constexpr (id == tri::atanh) return fold_float_unary_bits<w>(a, [](auto x) { return std::atanh(x); });
129 else fe::unreachable();
130 } else if constexpr (std::is_same_v<Id, rt>) {
131 if constexpr (false) {}
132 else if constexpr (id == rt::sq) return fold_float_unary_bits<w>(a, [](auto x) { return std::sqrt(x); });
133 else if constexpr (id == rt::cb) return fold_float_unary_bits<w>(a, [](auto x) { return std::cbrt(x); });
134 else static_assert(false, "missing sub tag");
135 } else if constexpr (std::is_same_v<Id, exp>) {
136 if constexpr (false) {}
137 else if constexpr (id == exp::exp) return fold_float_unary_bits<w>(a, [](auto x) { return std::exp(x); });
138 else if constexpr (id == exp::exp2) return fold_float_unary_bits<w>(a, [](auto x) { return std::exp2(x); });
139 else if constexpr (id == exp::exp10) return fold_float_unary_bits<w>(a, [](auto x) { return std::pow(decltype(x)(10), x); });
140 else if constexpr (id == exp::log) return fold_float_unary_bits<w>(a, [](auto x) { return std::log(x); });
141 else if constexpr (id == exp::log2) return fold_float_unary_bits<w>(a, [](auto x) { return std::log2(x); });
142 else if constexpr (id == exp::log10) return fold_float_unary_bits<w>(a, [](auto x) { return std::log10(x); });
143 else fe::unreachable();
144 } else if constexpr (std::is_same_v<Id, er>) {
145 if constexpr (false) {}
146 else if constexpr (id == er::f ) return fold_float_unary_bits<w>(a, [](auto x) { return std::erf (x); });
147 else if constexpr (id == er::fc) return fold_float_unary_bits<w>(a, [](auto x) { return std::erfc(x); });
148 else static_assert(false, "missing sub tag");
149 } else if constexpr (std::is_same_v<Id, gamma>) {
150 if constexpr (false) {}
151 else if constexpr (id == gamma::t) return fold_float_unary_bits<w>(a, [](auto x) { return std::tgamma(x); });
152 else if constexpr (id == gamma::l) return fold_float_unary_bits<w>(a, [](auto x) { return std::lgamma(x); });
153 else static_assert(false, "missing sub tag");
154 } else if constexpr (std::is_same_v<Id, round>) {
155 if constexpr (false) {}
156 else if constexpr (id == round::f) return fold_float_unary_bits<w>(a, [](auto x) { return std::floor(x); });
157 else if constexpr (id == round::c) return fold_float_unary_bits<w>(a, [](auto x) { return std::ceil(x); });
158 else if constexpr (id == round::r) return fold_float_unary_bits<w>(a, [](auto x) { return std::round(x); });
159 else if constexpr (id == round::t) return fold_float_unary_bits<w>(a, [](auto x) { return std::trunc(x); });
160 else static_assert(false, "missing sub tag");
161 } else {
162 static_assert(false, "missing tag");
163 }
164}
165// clang-format on
166
167template<class Id, nat_t w>
168std::optional<u64> fold_unary_lit(u64 a) {
169 if constexpr (std::is_same_v<Id, abs>)
170 return fold_float_unary_bits<w>(a, [](auto x) { return std::abs(x); });
171 else
172 static_assert(false, "missing tag");
173}
174
175template<class Id>
176const Def* fold(World& world, const Def* type, const Def* a) {
177 if (a->isa<Bot>()) return world.bot(type);
178
179 if (auto la = Lit::isa(a))
180 if (auto width = isa_f(a->type()))
181 if (auto res = dispatch_float_width(*width, [&]<nat_t w>() { return fold_unary_lit<Id, w>(*la); }))
182 return world.lit(type, *res);
183
184 return nullptr;
185}
186
187template<class Id, Id id, nat_t w>
188std::optional<u64> fold_binary_lit(u64 a, u64 b) {
189 using T = w2f<w>;
190 auto x = bitcast_resize<T>(a);
191 auto y = bitcast_resize<T>(b);
192
193 if constexpr (std::is_same_v<Id, arith>) {
194 // clang-format off
195 if constexpr (false) {}
196 else if constexpr (id == arith::add) return bitcast_resize<u64>(static_cast<T>(x + y));
197 else if constexpr (id == arith::sub) return bitcast_resize<u64>(static_cast<T>(x - y));
198 else if constexpr (id == arith::mul) return bitcast_resize<u64>(static_cast<T>(x * y));
199 else if constexpr (id == arith::div) return bitcast_resize<u64>(static_cast<T>(x / y));
200 else if constexpr (id == arith::rem) return bitcast_resize<u64>(static_cast<T>(rem(x, y)));
201 else static_assert(false, "missing sub tag");
202 // clang-format on
203 } else if constexpr (std::is_same_v<Id, math::extrema>) {
204 T result;
205
206 if (x == T(-0.0) && y == T(+0.0)) {
207 result = (id == extrema::fmin || id == extrema::ieee754min) ? x : y;
208 } else if (x == T(+0.0) && y == T(-0.0)) {
209 result = (id == extrema::fmin || id == extrema::ieee754min) ? y : x;
210 } else if constexpr (id == extrema::fmin || id == extrema::fmax) {
211 result = id == extrema::fmin ? std::fmin(x, y) : std::fmax(x, y);
212 } else if constexpr (id == extrema::ieee754min || id == extrema::ieee754max) {
213 if (std::isnan(x))
214 result = x;
215 else if (std::isnan(y))
216 result = y;
217 else
218 result = id == extrema::ieee754min ? std::fmin(x, y) : std::fmax(x, y);
219 } else {
220 static_assert(false, "missing sub tag");
221 }
222
223 return bitcast_resize<u64>(result);
224 } else if constexpr (std::is_same_v<Id, pow>) {
225 return bitcast_resize<u64>(static_cast<T>(std::pow(x, y)));
226 } else if constexpr (std::is_same_v<Id, cmp>) {
227 using std::isunordered;
228 bool result = false;
229 result |= ((id & cmp::u) != cmp::f) && isunordered(x, y);
230 result |= ((id & cmp::g) != cmp::f) && x > y;
231 result |= ((id & cmp::l) != cmp::f) && x < y;
232 result |= ((id & cmp::e) != cmp::f) && x == y;
233 return u64(result);
234 } else {
235 static_assert(false, "missing tag");
236 }
237}
238
239template<class Id, Id id>
240const Def* fold(World& world, const Def* type, const Def* a) {
241 if (a->isa<Bot>()) return world.bot(type);
242
243 if (auto la = Lit::isa(a))
244 if (auto width = isa_f(a->type()))
245 if (auto res = dispatch_float_width(*width, [&]<nat_t w>() { return fold_unary_lit<Id, id, w>(*la); }))
246 return world.lit(type, *res);
247
248 return nullptr;
249}
250
251// Note that @p a and @p b are passed by reference as fold also commutes if possible.
252template<class Id, Id id>
253const Def* fold(World& world, const Def* type, const Def*& a, const Def*& b) {
254 if (a->isa<Bot>() || b->isa<Bot>()) return world.bot(type);
255
256 if (auto la = Lit::isa(a))
257 if (auto lb = Lit::isa(b))
258 if (auto width = isa_f(a->type()))
259 if (auto res
260 = dispatch_float_width(*width, [&]<nat_t w>() { return fold_binary_lit<Id, id, w>(*la, *lb); }))
261 return world.lit(type, *res);
262
263 if (is_commutative(id) && Def::greater(a, b)) std::swap(a, b);
264 return nullptr;
265}
266
267/// Reassociates @p a und @p b according to following rules.
268/// We use the following naming convention while literals are prefixed with an 'l':
269/// ```
270/// a op b
271/// (x op y) op (z op w)
272///
273/// (1) la op (lz op w) -> (la op lz) op w
274/// (2) (lx op y) op (lz op w) -> (lx op lz) op (y op w)
275/// (3) a op (lz op w) -> lz op (a op w)
276/// (4) (lx op y) op b -> lx op (y op b)
277/// ```
278template<class Id>
279const Def* reassociate(Id id, World& world, [[maybe_unused]] const App* ab, const Def* a, const Def* b) {
280 if (!is_associative(id)) return nullptr;
281
282 auto xy = Axm::isa<Id>(id, a);
283 auto zw = Axm::isa<Id>(id, b);
284 auto la = a->isa<Lit>();
285 auto [x, y] = xy ? xy->template args<2>() : std::array<const Def*, 2>{nullptr, nullptr};
286 auto [z, w] = zw ? zw->template args<2>() : std::array<const Def*, 2>{nullptr, nullptr};
287 auto lx = Lit::isa(x);
288 auto lz = Lit::isa(z);
289
290 // build mode for all new ops by using the least upper bound of all involved apps
291 auto mode = std::to_underlying(Mode::bot);
292 auto check_mode = [&](const App* app) {
293 auto app_m = Lit::isa(app->arg(0));
294 if (!app_m || !fe::has_flag(static_cast<Mode>(*app_m), Mode::reassoc)) return false;
295 mode &= *app_m; // least upper bound
296 return true;
297 };
298
299 if (!check_mode(ab)) return nullptr;
300 if (lx && !check_mode(xy->decurry())) return nullptr;
301 if (lz && !check_mode(zw->decurry())) return nullptr;
302
303 auto make_op = [&](const Def* a, const Def* b) { return world.call(id, mode, Defs{a, b}); };
304
305 if (la && lz) return make_op(make_op(a, z), w); // (1)
306 if (lx && lz) return make_op(make_op(x, z), make_op(y, w)); // (2)
307 if (lz) return make_op(z, make_op(a, w)); // (3)
308 if (lx) return make_op(x, make_op(y, b)); // (4)
309 return nullptr;
310}
311
312template<conv id, nat_t sw, nat_t dw>
313std::optional<u64> fold_conv_lit(u64 a) {
314 using S = w2f<sw>;
315 using D = w2f<dw>;
316 // clang-format off
317 if constexpr (false) {}
318 else if constexpr (id == conv::s2f) return bitcast_resize<u64>(static_cast<D>(decode_signed<sw>(a)));
319 else if constexpr (id == conv::u2f) return bitcast_resize<u64>(static_cast<D>(decode_unsigned<sw>(a)));
320 else if constexpr (id == conv::f2s) return fold_float_to_signed_bits<dw>(bitcast_resize<S>(a));
321 else if constexpr (id == conv::f2u) return fold_float_to_unsigned_bits<dw>(bitcast_resize<S>(a));
322 else if constexpr (id == conv::f2f) return bitcast_resize<u64>(static_cast<D>(bitcast_resize<S>(a)));
323 else static_assert(false, "missing sub tag");
324 // clang-format on
325}
326
327template<conv id, nat_t sw>
328std::optional<u64> fold_conv_dst(nat_t dw, u64 a) {
329 if constexpr (id == conv::s2f || id == conv::u2f || id == conv::f2f)
330 return dispatch_float_width(dw, [&]<nat_t d>() { return fold_conv_lit<id, sw, d>(a); });
331 else
332 return dispatch_int_width(dw, [&]<nat_t d>() { return fold_conv_lit<id, sw, d>(a); });
333}
334
335template<conv id>
336std::optional<u64> fold_conv(nat_t sw, nat_t dw, u64 a) {
337 if constexpr (id == conv::s2f || id == conv::u2f)
338 return dispatch_int_width(sw, [&]<nat_t s>() { return fold_conv_dst<id, s>(dw, a); });
339 else
340 return dispatch_float_width(sw, [&]<nat_t s>() { return fold_conv_dst<id, s>(dw, a); });
341}
342
343} // namespace
344
345template<arith id>
346const Def* normalize_arith(const Def* type, const Def* c, const Def* arg) {
347 auto& world = type->world();
348 auto callee = c->as<App>();
349 auto [a, b] = arg->projs<2>();
350 auto mode = callee->arg();
351 auto lm = Lit::isa(mode);
352 auto w = isa_f(a->type());
353
354 if (auto result = fold<arith, id>(world, type, a, b)) return result;
355
356 // clang-format off
357 // TODO check mode properly
358 if (w && lm && static_cast<Mode>(*lm) == Mode::fast) {
359 auto zero = lit_f(world, *w, 0.0);
360 auto one = lit_f(world, *w, 1.0);
361 auto two = lit_f(world, *w, 2.0);
362
363 if (auto la = a->isa<Lit>()) {
364 if (zero && la == zero) {
365 switch (id) {
366 case arith::add: return b; // 0 + b -> b
367 case arith::sub: break;
368 case arith::mul: return la; // 0 * b -> 0
369 case arith::div: return la; // 0 / b -> 0
370 case arith::rem: return la; // 0 % b -> 0
371 }
372 }
373
374 if (one && la == one) {
375 switch (id) {
376 case arith::add: break;
377 case arith::sub: break;
378 case arith::mul: return b; // 1 * b -> b
379 case arith::div: break;
380 case arith::rem: break;
381 }
382 }
383 }
384
385 if (auto lb = b->isa<Lit>()) {
386 if (zero && lb == zero) {
387 switch (id) {
388 case arith::sub: return a; // a - 0 -> a
389 case arith::div: break;
390 case arith::rem: break;
391 default: fe::unreachable();
392 // add, mul are commutative, the literal has been normalized to the left
393 }
394 }
395 }
396
397 if (a == b) {
398 switch (id) {
399 case arith::add: if (two ) return world.call(arith::mul, mode, Defs{two , a}); break; // a + a -> 2 * a
400 case arith::sub: if (zero) return zero; break; // a - a -> 0
401 case arith::mul: break;
402 case arith::div: if (one ) return one ; break; // a / a -> 1
403 case arith::rem: break;
404 }
405 }
406 }
407 // clang-format on
408
409 if (auto res = reassociate<arith>(id, world, callee, a, b)) return res;
410
411 return world.raw_app(type, callee, {a, b});
412}
413
414template<extrema id>
415const Def* normalize_extrema(const Def* type, const Def* c, const Def* arg) {
416 auto& world = type->world();
417 auto callee = c->as<App>();
418 auto [a, b] = arg->projs<2>();
419 auto m = callee->arg();
420 auto lm = Lit::isa(m);
421 // TODO commute
422
423 if (auto lit = fold<extrema, id>(world, type, a, b)) return lit;
424
425 if (lm && (fe::has_flag(static_cast<Mode>(*lm), Mode::nnan) || fe::has_flag(static_cast<Mode>(*lm), Mode::nsz))) {
426 switch (id) {
427 case extrema::ieee754min: return world.call(extrema::fmin, m, Defs{a, b});
428 case extrema::ieee754max: return world.call(extrema::fmax, m, Defs{a, b});
429 default: break;
430 }
431 }
432
433 return world.raw_app(type, c, {a, b});
434}
435
436template<tri id>
437const Def* normalize_tri(const Def* type, const Def*, const Def* arg) {
438 auto& world = type->world();
439 if (auto lit = fold<tri, id>(world, type, arg)) return lit;
440 return {};
441}
442
443const Def* normalize_pow(const Def* type, const Def*, const Def* arg) {
444 auto& world = type->world();
445 auto [a, b] = arg->projs<2>();
446 if (auto lit = fold<pow, /*dummy*/ pow(0)>(world, type, a, b)) return lit;
447 return {};
448}
449
450template<rt id>
451const Def* normalize_rt(const Def* type, const Def*, const Def* arg) {
452 auto& world = type->world();
453 if (auto lit = fold<rt, id>(world, type, arg)) return lit;
454 return {};
455}
456
457template<exp id>
458const Def* normalize_exp(const Def* type, const Def*, const Def* arg) {
459 auto& world = type->world();
460 if (auto lit = fold<exp, id>(world, type, arg)) return lit;
461 return {};
462}
463
464template<er id>
465const Def* normalize_er(const Def* type, const Def*, const Def* arg) {
466 auto& world = type->world();
467 if (auto lit = fold<er, id>(world, type, arg)) return lit;
468 return {};
469}
470
471template<gamma id>
472const Def* normalize_gamma(const Def* type, const Def*, const Def* arg) {
473 auto& world = type->world();
474 if (auto lit = fold<gamma, id>(world, type, arg)) return lit;
475 return {};
476}
477
478template<cmp id>
479const Def* normalize_cmp(const Def* type, const Def* c, const Def* arg) {
480 auto& world = type->world();
481 auto callee = c->as<App>();
482 auto [a, b] = arg->projs<2>();
483
484 if (auto result = fold<cmp, id>(world, type, a, b)) return result;
485 if (id == cmp::f) return world.lit_ff();
486 if (id == cmp::t) return world.lit_tt();
487
488 return world.raw_app(type, callee, {a, b});
489}
490
491template<conv id>
492const Def* normalize_conv(const Def* dst_t, const Def*, const Def* x) {
493 auto& world = dst_t->world();
494 auto s_t = x->type()->as<App>();
495 auto d_t = dst_t->as<App>();
496 auto s = s_t->arg();
497 auto d = d_t->arg();
498 auto ls = Lit::isa(s);
499 auto ld = Lit::isa(d);
500
501 if (s_t == d_t) return x;
502 if (x->isa<Bot>()) return world.bot(d_t);
503
504 constexpr bool sf = id == conv::f2f || id == conv::f2s || id == conv::f2u;
505 constexpr bool df = id == conv::f2f || id == conv::s2f || id == conv::u2f;
506
507 auto sw = sf ? isa_f(s_t) : (ls ? Idx::size2bitwidth(*ls) : std::optional<nat_t>());
508 auto dw = df ? isa_f(d_t) : (ld ? Idx::size2bitwidth(*ld) : std::optional<nat_t>());
509
510 if (auto l = Lit::isa(x); l && sw && dw)
511 if (auto res = fold_conv<id>(*sw, *dw, *l)) return world.lit(d_t, *res);
512
513 return {};
514}
515
516const Def* normalize_abs(const Def* type, const Def*, const Def* arg) {
517 auto& world = type->world();
518 if (auto lit = fold<abs>(world, type, arg)) return lit;
519 return {};
520}
521
522template<round id>
523const Def* normalize_round(const Def* type, const Def*, const Def* arg) {
524 auto& world = type->world();
525 if (auto lit = fold<round, id>(world, type, arg)) return lit;
526 return {};
527}
528
530
531} // namespace mim::plug::math
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:246
World & world() const noexcept
Definition def.cpp:444
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:386
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
Definition def.cpp:452
static bool greater(const Def *a, const Def *b)
Definition def.cpp:555
static constexpr nat_t size2bitwidth(nat_t n)
Definition def.h:905
static std::optional< T > isa(const Def *def)
Definition def.h:838
#define MIM_math_NORMALIZER_IMPL
Definition autogen.h:376
The math Plugin
Definition math.h:8
const Def * normalize_extrema(const Def *type, const Def *c, const Def *arg)
const Lit * lit_f(World &w, R val)
Definition math.h:90
const Def * normalize_er(const Def *type, const Def *, const Def *arg)
const Def * normalize_cmp(const Def *type, const Def *c, const Def *arg)
const Def * normalize_abs(const Def *type, const Def *, const Def *arg)
const Def * normalize_gamma(const Def *type, const Def *, const Def *arg)
Mode
Allowed optimizations for a specific operation.
Definition math.h:14
@ fast
All flags.
Definition math.h:35
@ reassoc
Allow reassociation transformations for floating-point operations.
Definition math.h:31
@ nsz
No Signed Zeros.
Definition math.h:23
@ nnan
No NaNs.
Definition math.h:17
@ bot
Alias for Mode::fast.
Definition math.h:38
const Def * mode(World &w, VMode m)
mim::plug::math::VMode -> const Def*.
Definition math.h:46
const Def * normalize_arith(const Def *type, const Def *c, const Def *arg)
const Def * normalize_round(const Def *type, const Def *, const Def *arg)
std::optional< nat_t > isa_f(const Def *def)
Definition math.h:77
const Def * normalize_tri(const Def *type, const Def *, const Def *arg)
const Def * normalize_exp(const Def *type, const Def *, const Def *arg)
const Def * normalize_rt(const Def *type, const Def *, const Def *arg)
const Def * normalize_pow(const Def *type, const Def *, const Def *arg)
const Def * normalize_conv(const Def *dst_t, const Def *, const Def *x)
View< const Def * > Defs
Definition def.h:78
u64 nat_t
Definition types.h:37
typename detail::w2f_< w >::type w2f
Definition types.h:68
constexpr bool is_commutative(Id)
Definition axm.h:153
typename detail::w2s_< w >::type w2s
Definition types.h:67
constexpr bool is_associative(Id id)
Definition axm.h:159
typename detail::w2u_< w >::type w2u
Definition types.h:66
TExt< false > Bot
Definition lattice.h:171
uint64_t u64
Definition types.h:27
constexpr D bitcast_resize(const S &src) noexcept
A bitcast from src of type S to D, supporting different sizes.
Definition util.h:31
@ App
Definition def.h:109
@ Lit
Definition def.h:109
#define CODE(name,...)
Definition tok.h:39
#define MIM_F16_32_64(X)
Definition types.h:18
#define MIM_1_8_16_32_64(X)
Definition types.h:13