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"); }();
77const Def*
fold(World& world,
const Def* 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>
140const Def*
fold(World& world,
const Def* type,
const Def*
a) {
141 if (
a->isa<
Bot>())
return world.bot(type);
148 case i: res = fold<Id, id, i>(*la); break;
151 default: fe::unreachable();
154 return world.lit(type, *res);
161template<
class Id, Id
id>
162const Def*
fold(World& world,
const Def* type,
const Def*&
a,
const Def*& b) {
163 if (
a->isa<
Bot>() || b->isa<
Bot>())
return world.bot(type);
171 case i: res = fold<Id, id, i>(*la, *lb); break;
174 default: fe::unreachable();
177 return world.lit(type, *res);
197const Def* reassociate(Id
id, World& world, [[maybe_unused]]
const App* ab,
const Def*
a,
const Def* b) {
202 auto la =
a->isa<
Lit>();
203 auto [x, y] = xy ? xy->template args<2>() : std::array<const Def*, 2>{
nullptr,
nullptr};
204 auto [z,
w] = zw ? zw->template args<2>() : std::array<const Def*, 2>{
nullptr,
nullptr};
210 auto check_mode = [&](
const App* app) {
217 if (!check_mode(ab))
return nullptr;
218 if (lx && !check_mode(xy->decurry()))
return nullptr;
219 if (lz && !check_mode(zw->decurry()))
return nullptr;
221 auto make_op = [&](
const Def*
a,
const Def* b) {
return world.call(
id,
mode,
Defs{
a, b}); };
223 if (la && lz)
return make_op(make_op(
a, z), w);
224 if (lx && lz)
return make_op(make_op(x, z), make_op(y, w));
225 if (lz)
return make_op(z, make_op(
a, w));
226 if (lx)
return make_op(x, make_op(y, b));
230template<
class Id, Id
id, nat_t sw, nat_t dw>
232 using S = std::conditional_t<id == conv::s2f, w2s<sw>, std::conditional_t<id == conv::u2f, w2u<sw>,
w2f<sw>>>;
233 using D = std::conditional_t<id == conv::f2s, w2s<dw>, std::conditional_t<id == conv::f2u, w2u<dw>,
w2f<dw>>>;
241 auto& world = type->world();
242 auto callee =
c->as<
App>();
243 auto [
a, b] = arg->
projs<2>();
244 auto mode = callee->arg();
246 auto w =
isa_f(
a->type());
248 if (
auto result = fold<arith, id>(world, type,
a, b))
return result;
253 if (
auto la =
a->isa<
Lit>()) {
254 if (la ==
lit_f(world, *w, 0.0)) {
264 if (la ==
lit_f(world, *w, 1.0)) {
275 if (
auto lb = b->isa<
Lit>()) {
276 if (lb ==
lit_f(world, *w, 0.0)) {
281 default: fe::unreachable();
299 if (
auto res = reassociate<arith>(
id, world, callee,
a, b))
return res;
301 return world.raw_app(type, callee, {
a, b});
306 auto& world = type->world();
307 auto callee =
c->as<
App>();
308 auto [
a, b] = arg->
projs<2>();
309 auto m = callee->arg();
313 if (
auto lit = fold<extrema, id>(world, type,
a, b))
return lit;
323 return world.raw_app(type,
c, {
a, b});
328 auto& world = type->world();
329 if (
auto lit = fold<tri, id>(world, type, arg))
return lit;
334 auto& world = type->world();
335 auto [
a, b] = arg->
projs<2>();
336 if (
auto lit = fold<
pow,
pow(0)>(world, type,
a, b))
return lit;
342 auto& world = type->world();
343 if (
auto lit = fold<rt, id>(world, type, arg))
return lit;
349 auto& world = type->world();
350 if (
auto lit = fold<exp, id>(world, type, arg))
return lit;
356 auto& world = type->world();
357 if (
auto lit = fold<er, id>(world, type, arg))
return lit;
363 auto& world = type->world();
364 if (
auto lit = fold<gamma, id>(world, type, arg))
return lit;
370 auto& world = type->world();
371 auto callee =
c->as<
App>();
372 auto [
a, b] = arg->
projs<2>();
374 if (
auto result = fold<cmp, id>(world, type,
a, b))
return result;
375 if (
id ==
cmp::f)
return world.lit_ff();
376 if (
id ==
cmp::t)
return world.lit_tt();
378 return world.raw_app(type, callee, {
a, b});
383 auto& world = dst_t->
world();
384 auto s_t = x->
type()->as<
App>();
385 auto d_t = dst_t->as<
App>();
391 if (s_t == d_t)
return x;
392 if (x->isa<
Bot>())
return world.bot(d_t);
397 constexpr nat_t min_s = sf ? 16 : 1;
398 constexpr nat_t min_d = df ? 16 : 1;
407 else if (S == *sw && D == *dw) { \
408 if constexpr (S >= min_s && D >= min_d) \
409 res = fold<conv, id, S, D>(*l); \
413 M( 1, 1)
M( 1, 8)
M( 1, 16)
M( 1, 32)
M( 1, 64)
414 M( 8, 1)
M( 8, 8)
M( 8, 16)
M( 8, 32)
M( 8, 64)
415 M(16, 1)
M(16, 8)
M(16, 16)
M(16, 32)
M(16, 64)
416 M(32, 1)
M(32, 8)
M(32, 16)
M(32, 32)
M(32, 64)
417 M(64, 1)
M(64, 8)
M(64, 16)
M(64, 32)
M(64, 64)
419 else fe::unreachable();
421 return world.lit(d_t, *res);
429 auto& world = type->world();
430 if (
auto lit = fold<abs>(world, type, arg))
return lit;
436 auto& world = type->world();
437 if (
auto lit = fold<round, id>(world, type, arg))
return lit;
static auto isa(const Def *def)
World & world() const noexcept
auto projs(F f) const
Splits this Def via Def::projections into an Array (if A == std::dynamic_extent) or std::array (other...
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
static bool greater(const Def *a, const Def *b)
static constexpr nat_t size2bitwidth(nat_t n)
static std::optional< T > isa(const Def *def)
Utility class when folding constants in normalizers.
#define MIM_math_NORMALIZER_IMPL
const Def * normalize_extrema(const Def *type, const Def *c, const Def *arg)
const Lit * lit_f(World &w, R val)
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)
@ reassoc
Allow reassociation transformations for floating-point operations.
@ bot
Alias for Mode::fast.
const Def * mode(World &w, VMode m)
mim::plug::math::VMode -> const Def*.
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)
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)
D bitcast(const S &src)
A bitcast from src of type S to D.
typename detail::w2f_< w >::type w2f
constexpr bool is_commutative(Id)
constexpr bool is_associative(Id id)