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