10template<
class Id, Id
id, nat_t w>
14 if constexpr (std::is_same_v<Id, tri>) {
15 if constexpr (
false) {}
28 else fe::unreachable();
29 }
else if constexpr (std::is_same_v<Id, rt>) {
30 if constexpr (
false) {}
31 else if constexpr (
id ==
rt::sq)
return std::sqrt(x);
32 else if constexpr (
id ==
rt::cb)
return std::cbrt(x);
33 else []<
bool flag =
false>() {
static_assert(flag,
"missing sub tag"); }();
34 }
else if constexpr (std::is_same_v<Id, exp>) {
35 if constexpr (
false) {}
36 else if constexpr (
id ==
exp::exp )
return std::exp (x);
37 else if constexpr (
id ==
exp::exp2 )
return std::exp2 (x);
38 else if constexpr (
id ==
exp::exp10)
return std::pow(T(10), x);
39 else if constexpr (
id ==
exp::log )
return std::log (x);
40 else if constexpr (
id ==
exp::log2 )
return std::log2 (x);
41 else if constexpr (
id ==
exp::log10)
return std::log10(x);
42 else fe::unreachable();
43 }
else if constexpr (std::is_same_v<Id, er>) {
44 if constexpr (
false) {}
45 else if constexpr (
id ==
er::f )
return std::erf (x);
46 else if constexpr (
id ==
er::fc)
return std::erfc(x);
47 else []<
bool flag =
false>() {
static_assert(flag,
"missing sub tag"); }();
48 }
else if constexpr (std::is_same_v<Id, gamma>) {
49 if constexpr (
false) {}
50 else if constexpr (
id ==
gamma::t)
return std::tgamma(x);
51 else if constexpr (
id ==
gamma::l)
return std::lgamma(x);
52 else []<
bool flag =
false>() {
static_assert(flag,
"missing sub tag"); }();
53 }
else if constexpr (std::is_same_v<Id, round>) {
54 if constexpr (
false) {}
55 else if constexpr (
id ==
round::f)
return std::floor (x);
56 else if constexpr (
id ==
round::c)
return std::ceil (x);
57 else if constexpr (
id ==
round::r)
return std::round (x);
58 else if constexpr (
id ==
round::t)
return std::trunc (x);
59 else []<
bool flag =
false>() {
static_assert(flag,
"missing sub tag"); }();
61 []<
bool flag =
false>() {
static_assert(flag,
"missing tag"); }();
65template<
class Id, nat_t w>
69 if constexpr (std::is_same_v<Id, abs>) {
72 []<
bool flag =
false>() {
static_assert(flag,
"missing tag"); }();
77Ref fold(World& world, Ref type,
const Def*
a) {
78 if (
a->isa<
Bot>())
return world.bot(type);
79 auto la =
a->isa<
Lit>();
86 case i: res = fold<Id, i>(la->get()); break;
89 default: fe::unreachable();
92 return world.lit(type, *res);
98template<
class Id, Id
id, nat_t w>
102 if constexpr (std::is_same_v<Id, arith>) {
103 if constexpr (
false) {}
104 else if constexpr (
id ==
arith::add)
return x + y;
105 else if constexpr (
id ==
arith::sub)
return x - y;
106 else if constexpr (
id ==
arith::mul)
return x * y;
107 else if constexpr (
id ==
arith::div)
return x / y;
109 else []<
bool flag =
false>() {
static_assert(flag,
"missing sub tag"); }();
110 }
else if constexpr (std::is_same_v<Id, math::extrema>) {
117 if (std::isnan(x))
return x;
118 if (std::isnan(y))
return y;
121 []<
bool flag =
false>() {
static_assert(flag,
"missing sub tag"); }();
123 }
else if constexpr (std::is_same_v<Id, pow>) {
124 return std::pow(
a, b);
125 }
else if constexpr (std::is_same_v<Id, cmp>) {
126 using std::isunordered;
134 []<
bool flag =
false>() {
static_assert(flag,
"missing tag"); }();
139template<
class Id, Id
id> Ref fold(World& world, Ref type,
const Def*
a) {
140 if (
a->isa<
Bot>())
return world.bot(type);
147 case i: res = fold<Id, id, i>(*la); break;
150 default: fe::unreachable();
153 return world.lit(type, *res);
160template<
class Id, Id
id> Ref fold(World& world, Ref type,
const Def*&
a,
const Def*& b) {
161 if (
a->isa<
Bot>() || b->isa<
Bot>())
return world.bot(type);
169 case i: res = fold<Id, id, i>(*la, *lb); break;
172 default: fe::unreachable();
175 return world.lit(type, *res);
194template<
class Id> Ref reassociate(Id
id, World& world, [[maybe_unused]]
const App* ab, Ref
a, Ref b) {
199 auto la =
a->isa<
Lit>();
200 auto [x, y] = xy ? xy->template args<2>() :
std::array<const Def*, 2>{
nullptr,
nullptr};
201 auto [z,
w] = zw ? zw->template args<2>() :
std::array<const Def*, 2>{
nullptr,
nullptr};
207 auto check_mode = [&](
const App* app) {
214 if (!check_mode(ab))
return nullptr;
215 if (lx && !check_mode(xy->decurry()))
return nullptr;
216 if (lz && !check_mode(zw->decurry()))
return nullptr;
218 auto make_op = [&](Ref
a, Ref b) {
return world.call(
id,
mode,
Defs{
a, b}); };
220 if (la && lz)
return make_op(make_op(
a, z), w);
221 if (lx && lz)
return make_op(make_op(x, z), make_op(y, w));
222 if (lz)
return make_op(z, make_op(
a, w));
223 if (lx)
return make_op(x, make_op(y, b));
227template<
class Id, Id
id, nat_t sw, nat_t dw> Res fold(
u64 a) {
228 using S = std::conditional_t<id == conv::s2f, w2s<sw>, std::conditional_t<id == conv::u2f, w2u<sw>,
w2f<sw>>>;
229 using D = std::conditional_t<id == conv::f2s, w2s<dw>, std::conditional_t<id == conv::f2u, w2u<dw>,
w2f<dw>>>;
236 auto& world = type->
world();
237 auto callee =
c->as<
App>();
238 auto [
a, b] = arg->
projs<2>();
239 auto mode = callee->arg();
241 auto w =
isa_f(
a->type());
243 if (
auto result = fold<arith, id>(world, type,
a, b))
return result;
248 if (
auto la =
a->isa<
Lit>()) {
249 if (la ==
lit_f(world, *w, 0.0)) {
259 if (la ==
lit_f(world, *w, 1.0)) {
270 if (
auto lb = b->isa<
Lit>()) {
271 if (lb ==
lit_f(world, *w, 0.0)) {
276 default: fe::unreachable();
294 if (
auto res = reassociate<arith>(
id, world, callee,
a, b))
return res;
296 return world.raw_app(type, callee, {
a, b});
300 auto& world = type->
world();
301 auto callee =
c->as<
App>();
302 auto [
a, b] = arg->
projs<2>();
303 auto m = callee->arg();
306 if (
auto lit = fold<extrema, id>(world, type,
a, b))
return lit;
316 return world.raw_app(type,
c, arg);
320 auto& world = type->
world();
321 if (
auto lit = fold<tri, id>(world, type, arg))
return lit;
322 return world.raw_app(type,
c, arg);
326 auto& world = type->
world();
327 auto [
a, b] = arg->
projs<2>();
328 if (
auto lit = fold<
pow,
pow(0)>(world, type,
a, b))
return lit;
329 return world.raw_app(type,
c, arg);
333 auto& world = type->
world();
334 if (
auto lit = fold<rt, id>(world, type, arg))
return lit;
335 return world.raw_app(type,
c, arg);
339 auto& world = type->
world();
340 if (
auto lit = fold<exp, id>(world, type, arg))
return lit;
341 return world.raw_app(type,
c, arg);
345 auto& world = type->
world();
346 if (
auto lit = fold<er, id>(world, type, arg))
return lit;
347 return world.raw_app(type,
c, arg);
351 auto& world = type->
world();
352 if (
auto lit = fold<gamma, id>(world, type, arg))
return lit;
353 return world.raw_app(type,
c, arg);
357 auto& world = type->
world();
358 auto callee =
c->as<
App>();
359 auto [
a, b] = arg->
projs<2>();
361 if (
auto result = fold<cmp, id>(world, type,
a, b))
return result;
362 if (
id ==
cmp::f)
return world.lit_ff();
363 if (
id ==
cmp::t)
return world.lit_tt();
365 return world.raw_app(type, callee, {
a, b});
369 auto& world = dst_t->
world();
370 auto callee =
c->as<
App>();
371 auto s_t = x->
type()->as<
App>();
372 auto d_t = dst_t->as<
App>();
378 if (s_t == d_t)
return x;
379 if (x->isa<
Bot>())
return world.bot(d_t);
384 constexpr nat_t min_s = sf ? 16 : 1;
385 constexpr nat_t min_d = df ? 16 : 1;
394 else if (S == *sw && D == *dw) { \
395 if constexpr (S >= min_s && D >= min_d) \
396 res = fold<conv, id, S, D>(*l); \
400 M( 1, 1)
M( 1, 8)
M( 1, 16)
M( 1, 32)
M( 1, 64)
401 M( 8, 1)
M( 8, 8)
M( 8, 16)
M( 8, 32)
M( 8, 64)
402 M(16, 1)
M(16, 8)
M(16, 16)
M(16, 32)
M(16, 64)
403 M(32, 1)
M(32, 8)
M(32, 16)
M(32, 32)
M(32, 64)
404 M(64, 1)
M(64, 8)
M(64, 16)
M(64, 32)
M(64, 64)
406 else fe::unreachable();
408 return world.lit(d_t, *res);
412 return world.raw_app(dst_t, callee, x);
416 auto& world = type->
world();
417 if (
auto lit = fold<abs>(world, type, arg))
return lit;
418 return world.raw_app(type,
c, arg);
422 auto& world = type->
world();
423 if (
auto lit = fold<round, id>(world, type, arg))
return lit;
424 return world.raw_app(type,
c, arg);
auto projs(F f) const
Splits this Def via Def::projections into an Array (if A == -1_n) or std::array (otherwise).
static constexpr nat_t size2bitwidth(nat_t n)
static std::optional< T > isa(Ref def)
Helper class to retrieve Infer::arg if present.
Utility class when folding constants in normalizers.
This is a thin wrapper for std::span<T, N> with the following additional features:
Extremum. Either Top (Up) or Bottom.
#define MIM_math_NORMALIZER_IMPL
Ref normalize_rt(Ref type, Ref c, Ref arg)
const Lit * lit_f(World &w, R val)
Ref normalize_abs(Ref type, Ref c, Ref arg)
Ref normalize_exp(Ref type, Ref c, Ref arg)
Ref normalize_tri(Ref type, Ref c, Ref arg)
Ref normalize_conv(Ref dst_t, Ref c, Ref x)
Ref normalize_extrema(Ref type, Ref c, Ref arg)
Ref normalize_er(Ref type, Ref c, Ref arg)
@ reassoc
Allow reassociation transformations for floating-point operations.
@ bot
Alias for Mode::fast.
Ref normalize_round(Ref type, Ref c, Ref arg)
Ref normalize_arith(Ref type, Ref c, Ref arg)
std::optional< nat_t > isa_f(Ref def)
Ref normalize_gamma(Ref type, Ref c, Ref arg)
Ref mode(World &w, VMode m)
mim::plug::math::VMode -> Ref.
Ref normalize_cmp(Ref type, Ref c, Ref arg)
Ref normalize_pow(Ref type, Ref c, Ref arg)
D bitcast(const S &src)
A bitcast from src of type S to D.
typename detail::w2f_< w >::type w2f
void commute(const Def *&a, const Def *&b)
Swap Lit to left - or smaller Def::gid, if no lit present.
constexpr bool is_commutative(Id)
constexpr bool is_associative(Id id)