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>
const Def* fold(World& world,
const Def* 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>
const Def* fold(World& world,
const Def* 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);
195const Def* reassociate(Id
id, World& world, [[maybe_unused]]
const App* ab,
const Def*
a,
const Def* b) {
200 auto la =
a->isa<
Lit>();
201 auto [x, y] = xy ? xy->template args<2>() : std::array<const Def*, 2>{
nullptr,
nullptr};
202 auto [z,
w] = zw ? zw->template args<2>() : std::array<const Def*, 2>{
nullptr,
nullptr};
208 auto check_mode = [&](
const App* app) {
215 if (!check_mode(ab))
return nullptr;
216 if (lx && !check_mode(xy->decurry()))
return nullptr;
217 if (lz && !check_mode(zw->decurry()))
return nullptr;
219 auto make_op = [&](
const Def*
a,
const Def* b) {
return world.call(
id,
mode,
Defs{
a, b}); };
221 if (la && lz)
return make_op(make_op(
a, z), w);
222 if (lx && lz)
return make_op(make_op(x, z), make_op(y, w));
223 if (lz)
return make_op(z, make_op(
a, w));
224 if (lx)
return make_op(x, make_op(y, b));
228template<
class Id, Id
id, nat_t sw, nat_t dw> Res fold(
u64 a) {
229 using S = std::conditional_t<id == conv::s2f, w2s<sw>, std::conditional_t<id == conv::u2f, w2u<sw>,
w2f<sw>>>;
230 using D = std::conditional_t<id == conv::f2s, w2s<dw>, std::conditional_t<id == conv::f2u, w2u<dw>,
w2f<dw>>>;
237 auto& world = type->
world();
238 auto callee =
c->as<
App>();
239 auto [
a, b] = arg->
projs<2>();
240 auto mode = callee->arg();
242 auto w =
isa_f(
a->type());
244 if (
auto result = fold<arith, id>(world, type,
a, b))
return result;
249 if (
auto la =
a->isa<
Lit>()) {
250 if (la ==
lit_f(world, *w, 0.0)) {
260 if (la ==
lit_f(world, *w, 1.0)) {
271 if (
auto lb = b->isa<
Lit>()) {
272 if (lb ==
lit_f(world, *w, 0.0)) {
277 default: fe::unreachable();
295 if (
auto res = reassociate<arith>(
id, world, callee,
a, b))
return res;
297 return world.raw_app(type, callee, {
a, b});
301 auto& world = type->
world();
302 auto callee =
c->as<
App>();
303 auto [
a, b] = arg->
projs<2>();
304 auto m = callee->arg();
308 if (
auto lit = fold<extrema, id>(world, type,
a, b))
return lit;
318 return world.raw_app(type,
c, {
a, b});
322 auto& world = type->
world();
323 if (
auto lit = fold<tri, id>(world, type, arg))
return lit;
328 auto& world = type->
world();
329 auto [
a, b] = arg->
projs<2>();
330 if (
auto lit = fold<
pow,
pow(0)>(world, type,
a, b))
return lit;
335 auto& world = type->
world();
336 if (
auto lit = fold<rt, id>(world, type, arg))
return lit;
341 auto& world = type->
world();
342 if (
auto lit = fold<exp, id>(world, type, arg))
return lit;
347 auto& world = type->
world();
348 if (
auto lit = fold<er, id>(world, type, arg))
return lit;
353 auto& world = type->
world();
354 if (
auto lit = fold<gamma, id>(world, type, arg))
return lit;
359 auto& world = type->
world();
360 auto callee =
c->as<
App>();
361 auto [
a, b] = arg->
projs<2>();
363 if (
auto result = fold<cmp, id>(world, type,
a, b))
return result;
364 if (
id ==
cmp::f)
return world.lit_ff();
365 if (
id ==
cmp::t)
return world.lit_tt();
367 return world.raw_app(type, callee, {
a, b});
371 auto& world = dst_t->
world();
372 auto s_t = x->
type()->as<
App>();
373 auto d_t = dst_t->as<
App>();
379 if (s_t == d_t)
return x;
380 if (x->isa<
Bot>())
return world.bot(d_t);
385 constexpr nat_t min_s = sf ? 16 : 1;
386 constexpr nat_t min_d = df ? 16 : 1;
395 else if (S == *sw && D == *dw) { \
396 if constexpr (S >= min_s && D >= min_d) \
397 res = fold<conv, id, S, D>(*l); \
401 M( 1, 1)
M( 1, 8)
M( 1, 16)
M( 1, 32)
M( 1, 64)
402 M( 8, 1)
M( 8, 8)
M( 8, 16)
M( 8, 32)
M( 8, 64)
403 M(16, 1)
M(16, 8)
M(16, 16)
M(16, 32)
M(16, 64)
404 M(32, 1)
M(32, 8)
M(32, 16)
M(32, 32)
M(32, 64)
405 M(64, 1)
M(64, 8)
M(64, 16)
M(64, 32)
M(64, 64)
407 else fe::unreachable();
409 return world.lit(d_t, *res);
417 auto& world = type->
world();
418 if (
auto lit = fold<abs>(world, type, arg))
return lit;
423 auto& world = type->
world();
424 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...
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
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
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)
auto match(const Def *def)
constexpr bool is_associative(Id id)