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();
307 if (
auto lit = fold<extrema, id>(world, type,
a, b))
return lit;
317 return world.raw_app(type,
c, {
a, b});
321 auto& world = type->
world();
322 if (
auto lit = fold<tri, id>(world, type, arg))
return lit;
327 auto& world = type->
world();
328 auto [
a, b] = arg->
projs<2>();
329 if (
auto lit = fold<
pow,
pow(0)>(world, type,
a, b))
return lit;
334 auto& world = type->
world();
335 if (
auto lit = fold<rt, id>(world, type, arg))
return lit;
340 auto& world = type->
world();
341 if (
auto lit = fold<exp, id>(world, type, arg))
return lit;
346 auto& world = type->
world();
347 if (
auto lit = fold<er, id>(world, type, arg))
return lit;
352 auto& world = type->
world();
353 if (
auto lit = fold<gamma, id>(world, type, arg))
return lit;
358 auto& world = type->
world();
359 auto callee =
c->as<
App>();
360 auto [
a, b] = arg->
projs<2>();
362 if (
auto result = fold<cmp, id>(world, type,
a, b))
return result;
363 if (
id ==
cmp::f)
return world.lit_ff();
364 if (
id ==
cmp::t)
return world.lit_tt();
366 return world.raw_app(type, callee, {
a, b});
370 auto& world = dst_t->
world();
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);
416 auto& world = type->
world();
417 if (
auto lit = fold<abs>(world, type, arg))
return lit;
422 auto& world = type->
world();
423 if (
auto lit = fold<round, id>(world, type, arg))
return lit;
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...
Ref type() const noexcept
Yields the raw type of this Def, i.e. maybe nullptr.
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_er(Ref type, Ref, Ref arg)
Ref normalize_pow(Ref type, Ref, Ref arg)
const Lit * lit_f(World &w, R val)
Ref normalize_gamma(Ref type, Ref, Ref arg)
Ref normalize_conv(Ref dst_t, Ref, Ref x)
Ref normalize_extrema(Ref type, Ref c, Ref arg)
Ref normalize_round(Ref type, Ref, Ref arg)
Ref normalize_rt(Ref type, Ref, Ref arg)
Ref normalize_exp(Ref type, Ref, Ref arg)
Ref normalize_abs(Ref type, Ref, Ref arg)
@ reassoc
Allow reassociation transformations for floating-point operations.
@ bot
Alias for Mode::fast.
Ref normalize_tri(Ref type, Ref, Ref arg)
Ref normalize_arith(Ref type, Ref c, Ref arg)
std::optional< nat_t > isa_f(Ref def)
Ref mode(World &w, VMode m)
mim::plug::math::VMode -> Ref.
Ref normalize_cmp(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)