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_min<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>() + 1.0L) 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 std::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 std::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) && y == T(0) && std::signbit(x) != std::signbit(y)) {
205 bool min = id == extrema::fmin || id == extrema::ieee754min;
206 result = min == std::signbit(x) ? x : y;
207 } else if constexpr (id == extrema::fmin || id == extrema::fmax) {
208 result = id == extrema::fmin ? std::fmin(x, y) : std::fmax(x, y);
209 } else if constexpr (id == extrema::ieee754min || id == extrema::ieee754max) {
210 if (std::isnan(x))
211 result = x;
212 else if (std::isnan(y))
213 result = y;
214 else
215 result = id == extrema::ieee754min ? std::fmin(x, y) : std::fmax(x, y);
216 } else {
217 static_assert(false, "missing sub tag");
218 }
219
220 return fe::bitcast_resize<u64>(result);
221 } else if constexpr (std::is_same_v<Id, pow>) {
222 return fe::bitcast_resize<u64>(static_cast<T>(std::pow(x, y)));
223 } else if constexpr (std::is_same_v<Id, cmp>) {
224 using std::isunordered;
225 bool result = false;
226 result |= ((id & cmp::u) != cmp::f) && isunordered(x, y);
227 result |= ((id & cmp::g) != cmp::f) && x > y;
228 result |= ((id & cmp::l) != cmp::f) && x < y;
229 result |= ((id & cmp::e) != cmp::f) && x == y;
230 return u64(result);
231 } else {
232 static_assert(false, "missing tag");
233 }
234}
235
236template<class Id, Id id>
237const Def* fold(World& world, const Def* type, const Def* a) {
238 if (a->isa<Bot>()) return world.bot(type);
239
240 if (auto la = Lit::isa(a))
241 if (auto width = isa_f(a->type()))
242 if (auto res = dispatch_float_width(*width, [&]<nat_t w>() { return fold_unary_lit<Id, id, w>(*la); }))
243 return world.lit(type, *res);
244
245 return nullptr;
246}
247
248// Note that @p a and @p b are passed by reference as fold also commutes if possible.
249template<class Id, Id id>
250const Def* fold(World& world, const Def* type, const Def*& a, const Def*& b) {
251 if (a->isa<Bot>() || b->isa<Bot>()) return world.bot(type);
252
253 if (auto la = Lit::isa(a))
254 if (auto lb = Lit::isa(b))
255 if (auto width = isa_f(a->type()))
256 if (auto res
257 = dispatch_float_width(*width, [&]<nat_t w>() { return fold_binary_lit<Id, id, w>(*la, *lb); }))
258 return world.lit(type, *res);
259
260 if (is_commutative(id) && Def::greater(a, b)) std::swap(a, b);
261 return nullptr;
262}
263
264/// Reassociates @p a und @p b according to following rules.
265/// We use the following naming convention while literals are prefixed with an 'l':
266/// ```
267/// a op b
268/// (x op y) op (z op w)
269///
270/// (1) la op (lz op w) -> (la op lz) op w
271/// (2) (lx op y) op (lz op w) -> (lx op lz) op (y op w)
272/// (3) a op (lz op w) -> lz op (a op w)
273/// (4) (lx op y) op b -> lx op (y op b)
274/// ```
275template<class Id>
276const Def* reassociate(Id id, World& world, [[maybe_unused]] const App* ab, const Def* a, const Def* b) {
277 if (!is_associative(id)) return nullptr;
278
279 auto xy = Axm::isa<Id>(id, a);
280 auto zw = Axm::isa<Id>(id, b);
281 auto la = a->isa<Lit>();
282 auto [x, y] = xy ? xy->template args<2>() : std::array<const Def*, 2>{nullptr, nullptr};
283 auto [z, w] = zw ? zw->template args<2>() : std::array<const Def*, 2>{nullptr, nullptr};
284 auto lx = Lit::isa(x);
285 auto lz = Lit::isa(z);
286
287 // build mode for all new ops by using the least upper bound of all involved apps
288 auto mode = std::to_underlying(Mode::bot);
289 auto check_mode = [&](const App* app) {
290 auto app_m = Lit::isa(app->decurry()->arg());
291 if (!app_m || !fe::has_flag(static_cast<Mode>(*app_m), Mode::reassoc)) return false;
292 mode &= *app_m; // least upper bound
293 return true;
294 };
295
296 if (!check_mode(ab)) return nullptr;
297 if (lx && !check_mode(xy->decurry())) return nullptr;
298 if (lz && !check_mode(zw->decurry())) return nullptr;
299
300 auto make_op = [&](const Def* a, const Def* b) { return world.call(id, mode, Defs{a, b}); };
301
302 if (la && lz) return make_op(make_op(a, z), w); // (1)
303 if (lx && lz) return make_op(make_op(x, z), make_op(y, w)); // (2)
304 if (lz) return make_op(z, make_op(a, w)); // (3)
305 if (lx) return make_op(x, make_op(y, b)); // (4)
306 return nullptr;
307}
308
309template<conv id, nat_t sw, nat_t dw>
310std::optional<u64> fold_conv_lit(u64 a) {
311 using S = w2f<sw>;
312 using D = w2f<dw>;
313 // clang-format off
314 if constexpr (false) {}
315 else if constexpr (id == conv::s2f) return fe::bitcast_resize<u64>(static_cast<D>(decode_signed<sw>(a)));
316 else if constexpr (id == conv::u2f) return fe::bitcast_resize<u64>(static_cast<D>(decode_unsigned<sw>(a)));
317 else if constexpr (id == conv::f2s) return fold_float_to_signed_bits<dw>(fe::bitcast_resize<S>(a));
318 else if constexpr (id == conv::f2u) return fold_float_to_unsigned_bits<dw>(fe::bitcast_resize<S>(a));
319 else if constexpr (id == conv::f2f) return fe::bitcast_resize<u64>(static_cast<D>(fe::bitcast_resize<S>(a)));
320 else static_assert(false, "missing sub tag");
321 // clang-format on
322}
323
324template<conv id, nat_t sw>
325std::optional<u64> fold_conv_dst(nat_t dw, u64 a) {
326 if constexpr (id == conv::s2f || id == conv::u2f || id == conv::f2f)
327 return dispatch_float_width(dw, [&]<nat_t d>() { return fold_conv_lit<id, sw, d>(a); });
328 else
329 return dispatch_int_width(dw, [&]<nat_t d>() { return fold_conv_lit<id, sw, d>(a); });
330}
331
332template<conv id>
333std::optional<u64> fold_conv(nat_t sw, nat_t dw, u64 a) {
334 if constexpr (id == conv::s2f || id == conv::u2f)
335 return dispatch_int_width(sw, [&]<nat_t s>() { return fold_conv_dst<id, s>(dw, a); });
336 else
337 return dispatch_float_width(sw, [&]<nat_t s>() { return fold_conv_dst<id, s>(dw, a); });
338}
339
340} // namespace
341
342template<arith id>
343const Def* normalize_arith(const Def* type, const Def* c, const Def* arg) {
344 auto& world = type->world();
345 auto callee = c->as<App>();
346 auto [a, b] = arg->projs<2>();
347 auto mode = callee->decurry()->arg();
348 auto lm = Lit::isa(mode);
349 auto w = isa_f(a->type());
350
351 if (auto result = fold<arith, id>(world, type, a, b)) return result;
352
353 // clang-format off
354 // TODO check mode properly
355 if (w && lm && static_cast<Mode>(*lm) == Mode::fast) {
356 auto zero = lit_f(world, *w, 0.0);
357 auto one = lit_f(world, *w, 1.0);
358 auto two = lit_f(world, *w, 2.0);
359
360 if (auto la = a->isa<Lit>()) {
361 if (zero && la == zero) {
362 switch (id) {
363 case arith::add: return b; // 0 + b -> b
364 case arith::sub: break;
365 case arith::mul: return la; // 0 * b -> 0
366 case arith::div: return la; // 0 / b -> 0
367 case arith::rem: return la; // 0 % b -> 0
368 }
369 }
370
371 if (one && la == one) {
372 switch (id) {
373 case arith::add: break;
374 case arith::sub: break;
375 case arith::mul: return b; // 1 * b -> b
376 case arith::div: break;
377 case arith::rem: break;
378 }
379 }
380 }
381
382 if (auto lb = b->isa<Lit>()) {
383 if (zero && lb == zero) {
384 switch (id) {
385 case arith::sub: return a; // a - 0 -> a
386 case arith::div: break;
387 case arith::rem: break;
388 default: std::unreachable();
389 // add, mul are commutative, the literal has been normalized to the left
390 }
391 }
392 }
393
394 if (a == b) {
395 switch (id) {
396 case arith::add: if (two ) return world.call(arith::mul, mode, Defs{two , a}); break; // a + a -> 2 * a
397 case arith::sub: if (zero) return zero; break; // a - a -> 0
398 case arith::mul: break;
399 case arith::div: if (one ) return one ; break; // a / a -> 1
400 case arith::rem: break;
401 }
402 }
403 }
404 // clang-format on
405
406 if (auto res = reassociate<arith>(id, world, callee, a, b)) return res;
407
408 return world.raw_app(type, callee, {a, b});
409}
410
411template<extrema id>
412const Def* normalize_extrema(const Def* type, const Def* c, const Def* arg) {
413 auto& world = type->world();
414 auto callee = c->as<App>();
415 auto [a, b] = arg->projs<2>();
416 auto m = callee->decurry()->arg();
417 auto lm = Lit::isa(m);
418
419 if (auto lit = fold<extrema, id>(world, type, a, b)) return lit;
420
421 if (lm && fe::has_flag(static_cast<Mode>(*lm), Mode::nnan | Mode::nsz)) {
422 switch (id) {
423 case extrema::ieee754min: return world.call(extrema::fmin, m, Defs{a, b});
424 case extrema::ieee754max: return world.call(extrema::fmax, m, Defs{a, b});
425 default: break;
426 }
427 }
428
429 return world.raw_app(type, c, {a, b});
430}
431
432template<tri id>
433const Def* normalize_tri(const Def* type, const Def*, const Def* arg) {
434 auto& world = type->world();
435 if (auto lit = fold<tri, id>(world, type, arg)) return lit;
436 return {};
437}
438
439const Def* normalize_pow(const Def* type, const Def*, const Def* arg) {
440 auto& world = type->world();
441 auto [a, b] = arg->projs<2>();
442 if (auto lit = fold<pow, /*dummy*/ pow(0)>(world, type, a, b)) return lit;
443 return {};
444}
445
446template<rt id>
447const Def* normalize_rt(const Def* type, const Def*, const Def* arg) {
448 auto& world = type->world();
449 if (auto lit = fold<rt, id>(world, type, arg)) return lit;
450 return {};
451}
452
453template<exp id>
454const Def* normalize_exp(const Def* type, const Def*, const Def* arg) {
455 auto& world = type->world();
456 if (auto lit = fold<exp, id>(world, type, arg)) return lit;
457 return {};
458}
459
460template<er id>
461const Def* normalize_er(const Def* type, const Def*, const Def* arg) {
462 auto& world = type->world();
463 if (auto lit = fold<er, id>(world, type, arg)) return lit;
464 return {};
465}
466
467template<gamma id>
468const Def* normalize_gamma(const Def* type, const Def*, const Def* arg) {
469 auto& world = type->world();
470 if (auto lit = fold<gamma, id>(world, type, arg)) return lit;
471 return {};
472}
473
474template<cmp id>
475const Def* normalize_cmp(const Def* type, const Def* c, const Def* arg) {
476 auto& world = type->world();
477 auto callee = c->as<App>();
478 auto [a, b] = arg->projs<2>();
479
480 if (auto result = fold<cmp, id>(world, type, a, b)) return result;
481 if (id == cmp::f) return world.lit_ff();
482 if (id == cmp::t) return world.lit_tt();
483
484 return world.raw_app(type, callee, {a, b});
485}
486
487template<conv id>
488const Def* normalize_conv(const Def* dst_t, const Def*, const Def* x) {
489 auto& world = dst_t->world();
490 auto s_t = x->type()->as<App>();
491 auto d_t = dst_t->as<App>();
492 auto s = s_t->arg();
493 auto d = d_t->arg();
494 auto ls = Lit::isa(s);
495 auto ld = Lit::isa(d);
496
497 if (s_t == d_t) return x;
498 if (x->isa<Bot>()) return world.bot(d_t);
499
500 constexpr bool sf = id == conv::f2f || id == conv::f2s || id == conv::f2u;
501 constexpr bool df = id == conv::f2f || id == conv::s2f || id == conv::u2f;
502
503 // Only a power-of-two Idx is an integer of its bitwidth.
504 auto int_w = [](std::optional<nat_t> l) -> std::optional<nat_t> {
505 if (l && (*l == 0 || std::has_single_bit(*l))) return Idx::size2bitwidth(*l);
506 return {};
507 };
508 auto sw = sf ? isa_f(s_t) : int_w(ls);
509 auto dw = df ? isa_f(d_t) : int_w(ld);
510
511 if (auto l = Lit::isa(x); l && sw && dw)
512 if (auto res = fold_conv<id>(*sw, *dw, *l)) return world.lit(d_t, *res);
513
514 return {};
515}
516
517const Def* normalize_abs(const Def* type, const Def*, const Def* arg) {
518 auto& world = type->world();
519 if (auto lit = fold<abs>(world, type, arg)) return lit;
520 return {};
521}
522
523template<round id>
524const Def* normalize_round(const Def* type, const Def*, const Def* arg) {
525 auto& world = type->world();
526 if (auto lit = fold<round, id>(world, type, arg)) return lit;
527 return {};
528}
529
531
532} // namespace mim::plug::math
const Def * arg() const
Definition lam.h:251
static auto isa(const Def *def)
Definition axm.h:112
Base class for all Defs.
Definition def.h:289
World & world() const noexcept
Definition def.h:1105
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
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
Definition def.h:1119
static bool greater(const Def *a, const Def *b)
Definition def.cpp:555
static constexpr nat_t size2bitwidth(nat_t n)
Definition def.h:1040
static std::optional< T > isa(const Def *def)
Definition def.h:976
#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:67
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:55
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:171
typename detail::w2s_< w >::type w2s
Definition types.h:67
constexpr bool is_associative(Id id)
Definition axm.h:177
typename detail::w2u_< w >::type w2u
Definition types.h:66
TExt< false > Bot
Definition union.h:39
uint64_t u64
Definition types.h:27
@ App
Definition def.h:125
@ Lit
Definition def.h:125
#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