Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions changelog/fix5227.dd
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
fix Issue 5227 - X ^^ FP at compile-time

The pow operator `^^` can now be used by CTFE.

Adds these std.math functions to those that can be used by CTFE:

round
floor
ceil
trunc
log
log2
log10
pow
expm1
exp2
fmin
fmax
copysign
fma
151 changes: 146 additions & 5 deletions src/dmd/builtin.d
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,116 @@ extern (C++) Expression eval_ldexp(Loc loc, FuncDeclaration fd, Expressions* arg
return new RealExp(loc, CTFloat.ldexp(arg0.toReal(), cast(int) arg1.toInteger()), arg0.type);
}

extern (C++) Expression eval_log(Loc loc, FuncDeclaration fd, Expressions* arguments)
{
Expression arg0 = (*arguments)[0];
assert(arg0.op == TOK.float64);
return new RealExp(loc, CTFloat.log(arg0.toReal()), arg0.type);
}

extern (C++) Expression eval_log2(Loc loc, FuncDeclaration fd, Expressions* arguments)
{
Expression arg0 = (*arguments)[0];
assert(arg0.op == TOK.float64);
return new RealExp(loc, CTFloat.log2(arg0.toReal()), arg0.type);
}

extern (C++) Expression eval_log10(Loc loc, FuncDeclaration fd, Expressions* arguments)
{
Expression arg0 = (*arguments)[0];
assert(arg0.op == TOK.float64);
return new RealExp(loc, CTFloat.log10(arg0.toReal()), arg0.type);
}

extern (C++) Expression eval_expm1(Loc loc, FuncDeclaration fd, Expressions* arguments)
{
Expression arg0 = (*arguments)[0];
assert(arg0.op == TOK.float64);
return new RealExp(loc, CTFloat.expm1(arg0.toReal()), arg0.type);
}

extern (C++) Expression eval_exp2(Loc loc, FuncDeclaration fd, Expressions* arguments)
{
Expression arg0 = (*arguments)[0];
assert(arg0.op == TOK.float64);
return new RealExp(loc, CTFloat.exp2(arg0.toReal()), arg0.type);
}

extern (C++) Expression eval_round(Loc loc, FuncDeclaration fd, Expressions* arguments)
{
Expression arg0 = (*arguments)[0];
assert(arg0.op == TOK.float64);
return new RealExp(loc, CTFloat.round(arg0.toReal()), arg0.type);
}

extern (C++) Expression eval_floor(Loc loc, FuncDeclaration fd, Expressions* arguments)
{
Expression arg0 = (*arguments)[0];
assert(arg0.op == TOK.float64);
return new RealExp(loc, CTFloat.floor(arg0.toReal()), arg0.type);
}

extern (C++) Expression eval_ceil(Loc loc, FuncDeclaration fd, Expressions* arguments)
{
Expression arg0 = (*arguments)[0];
assert(arg0.op == TOK.float64);
return new RealExp(loc, CTFloat.ceil(arg0.toReal()), arg0.type);
}

extern (C++) Expression eval_trunc(Loc loc, FuncDeclaration fd, Expressions* arguments)
{
Expression arg0 = (*arguments)[0];
assert(arg0.op == TOK.float64);
return new RealExp(loc, CTFloat.trunc(arg0.toReal()), arg0.type);
}

extern (C++) Expression eval_copysign(Loc loc, FuncDeclaration fd, Expressions* arguments)
{
Expression arg0 = (*arguments)[0];
assert(arg0.op == TOK.float64);
Expression arg1 = (*arguments)[1];
assert(arg1.op == TOK.float64);
return new RealExp(loc, CTFloat.copysign(arg0.toReal(), arg1.toReal()), arg0.type);
}

extern (C++) Expression eval_pow(Loc loc, FuncDeclaration fd, Expressions* arguments)
{
Expression arg0 = (*arguments)[0];
assert(arg0.op == TOK.float64);
Expression arg1 = (*arguments)[1];
assert(arg1.op == TOK.float64);
return new RealExp(loc, CTFloat.pow(arg0.toReal(), arg1.toReal()), arg0.type);
}

extern (C++) Expression eval_fmin(Loc loc, FuncDeclaration fd, Expressions* arguments)
{
Expression arg0 = (*arguments)[0];
assert(arg0.op == TOK.float64);
Expression arg1 = (*arguments)[1];
assert(arg1.op == TOK.float64);
return new RealExp(loc, CTFloat.fmin(arg0.toReal(), arg1.toReal()), arg0.type);
}

extern (C++) Expression eval_fmax(Loc loc, FuncDeclaration fd, Expressions* arguments)
{
Expression arg0 = (*arguments)[0];
assert(arg0.op == TOK.float64);
Expression arg1 = (*arguments)[1];
assert(arg1.op == TOK.float64);
return new RealExp(loc, CTFloat.fmax(arg0.toReal(), arg1.toReal()), arg0.type);
}

extern (C++) Expression eval_fma(Loc loc, FuncDeclaration fd, Expressions* arguments)
{
Expression arg0 = (*arguments)[0];
assert(arg0.op == TOK.float64);
Expression arg1 = (*arguments)[1];
assert(arg1.op == TOK.float64);
Expression arg2 = (*arguments)[2];
assert(arg2.op == TOK.float64);
return new RealExp(loc, CTFloat.fma(arg0.toReal(), arg1.toReal(), arg2.toReal()), arg0.type);
}

extern (C++) Expression eval_isnan(Loc loc, FuncDeclaration fd, Expressions* arguments)
{
Expression arg0 = (*arguments)[0];
Expand Down Expand Up @@ -226,15 +336,14 @@ public extern (C++) void builtin_init()
add_builtin("_D4core4math4sqrtFNaNbNiNfeZe", &eval_sqrt);
add_builtin("_D4core4math4fabsFNaNbNiNfeZe", &eval_fabs);
add_builtin("_D4core4math5expm1FNaNbNiNfeZe", &eval_unimp);
add_builtin("_D4core4math4exp21FNaNbNiNfeZe", &eval_unimp);
add_builtin("_D4core4math4exp2FNaNbNiNfeZe", &eval_unimp);
Copy link
Contributor

@kinke kinke Mar 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

&eval_unimp => &eval_exp2 (likewise for expm1 above)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There isn't an exp2 function in core.math. We could add to it, but that discussion is beyond the scope of this PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So you noticed the wrong mangle & fixed it instead of just removing that useless entry?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. I don't know why the eval_unimp entries are there, I didn't write that code. But I felt it was beyond the scope of this PR to address that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, the same goes for the @trusted/@safe overloads, the functions are all @safe IIRC.

// @trusted @nogc pure nothrow real function(real)
add_builtin("_D4core4math3sinFNaNbNiNeeZe", &eval_sin);
add_builtin("_D4core4math3cosFNaNbNiNeeZe", &eval_cos);
add_builtin("_D4core4math3tanFNaNbNiNeeZe", &eval_tan);
add_builtin("_D4core4math4sqrtFNaNbNiNeeZe", &eval_sqrt);
add_builtin("_D4core4math4fabsFNaNbNiNeeZe", &eval_fabs);
add_builtin("_D4core4math5expm1FNaNbNiNeeZe", &eval_unimp);
add_builtin("_D4core4math4exp21FNaNbNiNeeZe", &eval_unimp);
// @safe @nogc pure nothrow double function(double)
add_builtin("_D4core4math4sqrtFNaNbNiNfdZd", &eval_sqrt);
// @safe @nogc pure nothrow float function(float)
Expand Down Expand Up @@ -266,15 +375,14 @@ public extern (C++) void builtin_init()
add_builtin("_D3std4math4sqrtFNaNbNiNfeZe", &eval_sqrt);
add_builtin("_D3std4math4fabsFNaNbNiNfeZe", &eval_fabs);
add_builtin("_D3std4math5expm1FNaNbNiNfeZe", &eval_unimp);
add_builtin("_D3std4math4exp21FNaNbNiNfeZe", &eval_unimp);
// @trusted @nogc pure nothrow real function(real)
add_builtin("_D3std4math3sinFNaNbNiNeeZe", &eval_sin);
add_builtin("_D3std4math3cosFNaNbNiNeeZe", &eval_cos);
add_builtin("_D3std4math3tanFNaNbNiNeeZe", &eval_tan);
add_builtin("_D3std4math4sqrtFNaNbNiNeeZe", &eval_sqrt);
add_builtin("_D3std4math4fabsFNaNbNiNeeZe", &eval_fabs);
add_builtin("_D3std4math5expm1FNaNbNiNeeZe", &eval_unimp);
add_builtin("_D3std4math4exp21FNaNbNiNeeZe", &eval_unimp);
add_builtin("_D3std4math5expm1FNaNbNiNeeZe", &eval_expm1);
add_builtin("_D3std4math4exp2FNaNbNiNeeZe", &eval_exp2);
// @safe @nogc pure nothrow double function(double)
add_builtin("_D3std4math4sqrtFNaNbNiNfdZd", &eval_sqrt);
// @safe @nogc pure nothrow float function(float)
Expand Down Expand Up @@ -306,6 +414,39 @@ public extern (C++) void builtin_init()
add_builtin("_D3std4math5ldexpFNaNbNiNfdiZd", &eval_ldexp);
add_builtin("_D3std4math5ldexpFNaNbNiNffiZf", &eval_ldexp);

add_builtin("_D3std4math3logFNaNbNiNfeZe", &eval_log);

add_builtin("_D3std4math4log2FNaNbNiNfeZe", &eval_log2);

add_builtin("_D3std4math5log10FNaNbNiNfeZe", &eval_log10);

add_builtin("_D3std4math5roundFNbNiNeeZe", &eval_round);
add_builtin("_D3std4math5roundFNaNbNiNeeZe", &eval_round);

add_builtin("_D3std4math5floorFNaNbNiNefZf", &eval_floor);
add_builtin("_D3std4math5floorFNaNbNiNedZd", &eval_floor);
add_builtin("_D3std4math5floorFNaNbNiNeeZe", &eval_floor);

add_builtin("_D3std4math4ceilFNaNbNiNefZf", &eval_ceil);
add_builtin("_D3std4math4ceilFNaNbNiNedZd", &eval_ceil);
add_builtin("_D3std4math4ceilFNaNbNiNeeZe", &eval_ceil);

add_builtin("_D3std4math5truncFNaNbNiNeeZe", &eval_trunc);

add_builtin("_D3std4math4fminFNaNbNiNfeeZe", &eval_fmin);

add_builtin("_D3std4math4fmaxFNaNbNiNfeeZe", &eval_fmax);

add_builtin("_D3std4math__T8copysignTfTfZQoFNaNbNiNeffZf", &eval_copysign);
add_builtin("_D3std4math__T8copysignTdTdZQoFNaNbNiNeddZd", &eval_copysign);
add_builtin("_D3std4math__T8copysignTeTeZQoFNaNbNiNeeeZe", &eval_copysign);

add_builtin("_D3std4math__T3powTfTfZQjFNaNbNiNeffZf", &eval_pow);
add_builtin("_D3std4math__T3powTdTdZQjFNaNbNiNeddZd", &eval_pow);
add_builtin("_D3std4math__T3powTeTeZQjFNaNbNiNeeeZe", &eval_pow);

add_builtin("_D3std4math3fmaFNaNbNiNfeeeZe", &eval_fma);

// @trusted @nogc pure nothrow bool function(T)
add_builtin("_D3std4math__T5isNaNTeZQjFNaNbNiNeeZb", &eval_isnan);
add_builtin("_D3std4math__T5isNaNTdZQjFNaNbNiNedZb", &eval_isnan);
Expand Down
53 changes: 41 additions & 12 deletions src/dmd/root/ctfloat.d
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/**
/***
* Compiler implementation of the
* $(LINK2 http://www.dlang.org, D programming language).
*
Expand Down Expand Up @@ -42,28 +42,23 @@ private
extern (C++) struct CTFloat
{
nothrow:
version(DigitalMars)
{
static __gshared bool yl2x_supported = true;
static __gshared bool yl2xp1_supported = true;
}
version (GNU)
enum yl2x_supported = false;
else
{
static __gshared bool yl2x_supported = false;
static __gshared bool yl2xp1_supported = false;
}
enum yl2x_supported = __traits(compiles, core.math.yl2x(1.0L, 2.0L));
enum yl2xp1_supported = yl2x_supported;

static void yl2x(const real_t* x, const real_t* y, real_t* res)
{
version(DigitalMars)
static if (yl2x_supported)
*res = core.math.yl2x(*x, *y);
else
assert(0);
}

static void yl2xp1(const real_t* x, const real_t* y, real_t* res)
{
version(DigitalMars)
static if (yl2xp1_supported)
*res = core.math.yl2xp1(*x, *y);
else
assert(0);
Expand All @@ -88,6 +83,40 @@ extern (C++) struct CTFloat
static real_t ldexp(real_t n, int exp) { return core.math.ldexp(n, exp); }
}

static if (!is(real_t == real))
{
static real_t round(real_t x) { return real_t(cast(double)core.stdc.math.roundl(cast(double)x)); }
static real_t floor(real_t x) { return real_t(cast(double)core.stdc.math.floor(cast(double)x)); }
static real_t ceil(real_t x) { return real_t(cast(double)core.stdc.math.ceil(cast(double)x)); }
static real_t trunc(real_t x) { return real_t(cast(double)core.stdc.math.trunc(cast(double)x)); }
static real_t log(real_t x) { return real_t(cast(double)core.stdc.math.logl(cast(double)x)); }
static real_t log2(real_t x) { return real_t(cast(double)core.stdc.math.log2l(cast(double)x)); }
static real_t log10(real_t x) { return real_t(cast(double)core.stdc.math.log10l(cast(double)x)); }
static real_t pow(real_t x, real_t y) { return real_t(cast(double)core.stdc.math.powl(cast(double)x, cast(double)y)); }
static real_t expm1(real_t x) { return real_t(cast(double)core.stdc.math.expm1l(cast(double)x)); }
static real_t exp2(real_t x) { return real_t(cast(double)core.stdc.math.exp2l(cast(double)x)); }
static real_t copysign(real_t x, real_t s) { return real_t(cast(double)core.stdc.math.copysignl(cast(double)x, cast(double)s)); }
}
else
{
static real_t round(real_t x) { return core.stdc.math.roundl(x); }
static real_t floor(real_t x) { return core.stdc.math.floor(x); }
static real_t ceil(real_t x) { return core.stdc.math.ceil(x); }
static real_t trunc(real_t x) { return core.stdc.math.trunc(x); }
static real_t log(real_t x) { return core.stdc.math.logl(x); }
static real_t log2(real_t x) { return core.stdc.math.log2l(x); }
static real_t log10(real_t x) { return core.stdc.math.log10l(x); }
static real_t pow(real_t x, real_t y) { return core.stdc.math.powl(x, y); }
static real_t expm1(real_t x) { return core.stdc.math.expm1l(x); }
static real_t exp2(real_t x) { return core.stdc.math.exp2l(x); }
static real_t copysign(real_t x, real_t s) { return core.stdc.math.copysignl(x, s); }
}

static real_t fmin(real_t x, real_t y) { return x < y ? x : y; }
static real_t fmax(real_t x, real_t y) { return x > y ? x : y; }

static real_t fma(real_t x, real_t y, real_t z) { return (x * y) + z; }

static bool isIdentical(real_t a, real_t b)
{
// don't compare pad bytes in extended precision
Expand Down
17 changes: 17 additions & 0 deletions src/dmd/root/ctfloat.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,23 @@ struct CTFloat
static real_t fabs(real_t x);
static real_t ldexp(real_t n, int exp);

static real_t round(real_t x);
static real_t floor(real_t x);
static real_t ceil(real_t x);
static real_t trunc(real_t x);
static real_t log(real_t x);
static real_t log2(real_t x);
static real_t log10(real_t x);
static real_t pow(real_t x, real_t y);
static real_t expm1(real_t x);
static real_t exp2(real_t x);

static real_t fmin(real_t x, real_t y);
static real_t fmax(real_t x, real_t y);
static real_t copysign(real_t x, real_t s);

static real_t fma(real_t x, real_t y, real_t z);

static bool isIdentical(real_t a, real_t b);
static bool isNaN(real_t r);
static bool isSNaN(real_t r);
Expand Down
Loading