Skip to content

Instantly share code, notes, and snippets.

@joakim-noah
Last active August 12, 2016 11:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joakim-noah/eff6d4ccca7975f32c3c35eb85f29554 to your computer and use it in GitHub Desktop.
Save joakim-noah/eff6d4ccca7975f32c3c35eb85f29554 to your computer and use it in GitHub Desktop.
LDC for Android/ARM, applied to the release-1.0.0 branch 2.070
diff --git a/ddmd/builtin.d b/ddmd/builtin.d
index 6923794..fffa73e 100644
--- a/ddmd/builtin.d
+++ b/ddmd/builtin.d
@@ -17,7 +17,7 @@ import ddmd.expression;
import ddmd.func;
import ddmd.globals;
import ddmd.mtype;
-import ddmd.root.port;
+import ddmd.root.ctfloat;
import ddmd.root.stringtable;
import ddmd.tokens;
version(IN_LLVM) {
@@ -51,35 +51,35 @@ extern (C++) Expression eval_sin(Loc loc, FuncDeclaration fd, Expressions* argum
{
Expression arg0 = (*arguments)[0];
assert(arg0.op == TOKfloat64);
- return new RealExp(loc, sinl(arg0.toReal()), arg0.type);
+ return new RealExp(loc, CTFloat.sin(arg0.toReal()), arg0.type);
}
extern (C++) Expression eval_cos(Loc loc, FuncDeclaration fd, Expressions* arguments)
{
Expression arg0 = (*arguments)[0];
assert(arg0.op == TOKfloat64);
- return new RealExp(loc, cosl(arg0.toReal()), arg0.type);
+ return new RealExp(loc, CTFloat.cos(arg0.toReal()), arg0.type);
}
extern (C++) Expression eval_tan(Loc loc, FuncDeclaration fd, Expressions* arguments)
{
Expression arg0 = (*arguments)[0];
assert(arg0.op == TOKfloat64);
- return new RealExp(loc, tanl(arg0.toReal()), arg0.type);
+ return new RealExp(loc, CTFloat.tan(arg0.toReal()), arg0.type);
}
extern (C++) Expression eval_sqrt(Loc loc, FuncDeclaration fd, Expressions* arguments)
{
Expression arg0 = (*arguments)[0];
assert(arg0.op == TOKfloat64);
- return new RealExp(loc, Port.sqrt(arg0.toReal()), arg0.type);
+ return new RealExp(loc, CTFloat.sqrt(arg0.toReal()), arg0.type);
}
extern (C++) Expression eval_fabs(Loc loc, FuncDeclaration fd, Expressions* arguments)
{
Expression arg0 = (*arguments)[0];
assert(arg0.op == TOKfloat64);
- return new RealExp(loc, fabsl(arg0.toReal()), arg0.type);
+ return new RealExp(loc, CTFloat.fabs(arg0.toReal()), arg0.type);
}
version(IN_LLVM)
@@ -132,7 +132,7 @@ extern (C++) Expression eval_llvmsin(Loc loc, FuncDeclaration fd, Expressions *a
Type type = getTypeOfOverloadedIntrinsic(fd);
Expression arg0 = (*arguments)[0];
assert(arg0.op == TOKfloat64);
- return new RealExp(loc, sinl(arg0.toReal()), type);
+ return new RealExp(loc, CTFloat.sin(arg0.toReal()), type);
}
extern (C++) Expression eval_llvmcos(Loc loc, FuncDeclaration fd, Expressions *arguments)
@@ -140,7 +140,7 @@ extern (C++) Expression eval_llvmcos(Loc loc, FuncDeclaration fd, Expressions *a
Type type = getTypeOfOverloadedIntrinsic(fd);
Expression arg0 = (*arguments)[0];
assert(arg0.op == TOKfloat64);
- return new RealExp(loc, cosl(arg0.toReal()), type);
+ return new RealExp(loc, CTFloat.cos(arg0.toReal()), type);
}
extern (C++) Expression eval_llvmsqrt(Loc loc, FuncDeclaration fd, Expressions *arguments)
@@ -148,7 +148,7 @@ extern (C++) Expression eval_llvmsqrt(Loc loc, FuncDeclaration fd, Expressions *
Type type = getTypeOfOverloadedIntrinsic(fd);
Expression arg0 = (*arguments)[0];
assert(arg0.op == TOKfloat64);
- return new RealExp(loc, sqrtl(arg0.toReal()), type);
+ return new RealExp(loc, CTFloat.sqrt(arg0.toReal()), type);
}
extern (C++) Expression eval_llvmlog(Loc loc, FuncDeclaration fd, Expressions *arguments)
@@ -156,7 +156,7 @@ extern (C++) Expression eval_llvmlog(Loc loc, FuncDeclaration fd, Expressions *a
Type type = getTypeOfOverloadedIntrinsic(fd);
Expression arg0 = (*arguments)[0];
assert(arg0.op == TOKfloat64);
- return new RealExp(loc, logl(arg0.toReal()), type);
+ return new RealExp(loc, CTFloat.log(arg0.toReal()), type);
}
extern (C++) Expression eval_llvmfabs(Loc loc, FuncDeclaration fd, Expressions *arguments)
@@ -164,7 +164,7 @@ extern (C++) Expression eval_llvmfabs(Loc loc, FuncDeclaration fd, Expressions *
Type type = getTypeOfOverloadedIntrinsic(fd);
Expression arg0 = (*arguments)[0];
assert(arg0.op == TOKfloat64);
- return new RealExp(loc, fabsl(arg0.toReal()), type);
+ return new RealExp(loc, CTFloat.fabs(arg0.toReal()), type);
}
extern (C++) Expression eval_llvmminnum(Loc loc, FuncDeclaration fd, Expressions *arguments)
@@ -174,7 +174,7 @@ extern (C++) Expression eval_llvmminnum(Loc loc, FuncDeclaration fd, Expressions
assert(arg0.op == TOKfloat64);
Expression arg1 = (*arguments)[1];
assert(arg1.op == TOKfloat64);
- return new RealExp(loc, fminl(arg0.toReal(), arg1.toReal()), type);
+ return new RealExp(loc, CTFloat.fmin(arg0.toReal(), arg1.toReal()), type);
}
extern (C++) Expression eval_llvmmaxnum(Loc loc, FuncDeclaration fd, Expressions *arguments)
@@ -184,7 +184,7 @@ extern (C++) Expression eval_llvmmaxnum(Loc loc, FuncDeclaration fd, Expressions
assert(arg0.op == TOKfloat64);
Expression arg1 = (*arguments)[1];
assert(arg1.op == TOKfloat64);
- return new RealExp(loc, fmaxl(arg0.toReal(), arg1.toReal()), type);
+ return new RealExp(loc, CTFloat.fmax(arg0.toReal(), arg1.toReal()), type);
}
extern (C++) Expression eval_llvmfloor(Loc loc, FuncDeclaration fd, Expressions *arguments)
@@ -192,7 +192,7 @@ extern (C++) Expression eval_llvmfloor(Loc loc, FuncDeclaration fd, Expressions
Type type = getTypeOfOverloadedIntrinsic(fd);
Expression arg0 = (*arguments)[0];
assert(arg0.op == TOKfloat64);
- return new RealExp(loc, floor(arg0.toReal()), type);
+ return new RealExp(loc, CTFloat.floor(arg0.toReal()), type);
}
extern (C++) Expression eval_llvmceil(Loc loc, FuncDeclaration fd, Expressions *arguments)
@@ -200,7 +200,7 @@ extern (C++) Expression eval_llvmceil(Loc loc, FuncDeclaration fd, Expressions *
Type type = getTypeOfOverloadedIntrinsic(fd);
Expression arg0 = (*arguments)[0];
assert(arg0.op == TOKfloat64);
- return new RealExp(loc, ceil(arg0.toReal()), type);
+ return new RealExp(loc, CTFloat.ceil(arg0.toReal()), type);
}
extern (C++) Expression eval_llvmtrunc(Loc loc, FuncDeclaration fd, Expressions *arguments)
@@ -208,7 +208,7 @@ extern (C++) Expression eval_llvmtrunc(Loc loc, FuncDeclaration fd, Expressions
Type type = getTypeOfOverloadedIntrinsic(fd);
Expression arg0 = (*arguments)[0];
assert(arg0.op == TOKfloat64);
- return new RealExp(loc, trunc(arg0.toReal()), type);
+ return new RealExp(loc, CTFloat.trunc(arg0.toReal()), type);
}
extern (C++) Expression eval_llvmround(Loc loc, FuncDeclaration fd, Expressions *arguments)
@@ -216,7 +216,7 @@ extern (C++) Expression eval_llvmround(Loc loc, FuncDeclaration fd, Expressions
Type type = getTypeOfOverloadedIntrinsic(fd);
Expression arg0 = (*arguments)[0];
assert(arg0.op == TOKfloat64);
- return new RealExp(loc, round(arg0.toReal()), type);
+ return new RealExp(loc, CTFloat.round(arg0.toReal()), type);
}
extern (C++) Expression eval_cttz(Loc loc, FuncDeclaration fd, Expressions *arguments)
@@ -399,10 +399,10 @@ extern (C++) Expression eval_yl2x(Loc loc, FuncDeclaration fd, Expressions* argu
assert(arg0.op == TOKfloat64);
Expression arg1 = (*arguments)[1];
assert(arg1.op == TOKfloat64);
- real x = arg0.toReal();
- real y = arg1.toReal();
- real result;
- Port.yl2x_impl(&x, &y, &result);
+ const x = arg0.toReal();
+ const y = arg1.toReal();
+ real_t result = 0;
+ CTFloat.yl2x(&x, &y, &result);
return new RealExp(loc, result, arg0.type);
}
@@ -412,10 +412,10 @@ extern (C++) Expression eval_yl2xp1(Loc loc, FuncDeclaration fd, Expressions* ar
assert(arg0.op == TOKfloat64);
Expression arg1 = (*arguments)[1];
assert(arg1.op == TOKfloat64);
- real x = arg0.toReal();
- real y = arg1.toReal();
- real result;
- Port.yl2xp1_impl(&x, &y, &result);
+ const x = arg0.toReal();
+ const y = arg1.toReal();
+ real_t result = 0;
+ CTFloat.yl2xp1(&x, &y, &result);
return new RealExp(loc, result, arg0.type);
}
@@ -451,7 +451,7 @@ else
add_builtin("_D4core4math4sqrtFNaNbNiNffZf", &eval_sqrt);
// @safe @nogc pure nothrow real function(real, real)
add_builtin("_D4core4math5atan2FNaNbNiNfeeZe", &eval_unimp);
- if (Port.yl2x_supported)
+ if (CTFloat.yl2x_supported)
{
add_builtin("_D4core4math4yl2xFNaNbNiNfeeZe", &eval_yl2x);
}
@@ -459,7 +459,7 @@ else
{
add_builtin("_D4core4math4yl2xFNaNbNiNfeeZe", &eval_unimp);
}
- if (Port.yl2xp1_supported)
+ if (CTFloat.yl2xp1_supported)
{
add_builtin("_D4core4math6yl2xp1FNaNbNiNfeeZe", &eval_yl2xp1);
}
@@ -491,7 +491,7 @@ else
add_builtin("_D3std4math4sqrtFNaNbNiNffZf", &eval_sqrt);
// @safe @nogc pure nothrow real function(real, real)
add_builtin("_D3std4math5atan2FNaNbNiNfeeZe", &eval_unimp);
- if (Port.yl2x_supported)
+ if (CTFloat.yl2x_supported)
{
add_builtin("_D3std4math4yl2xFNaNbNiNfeeZe", &eval_yl2x);
}
@@ -499,7 +499,7 @@ else
{
add_builtin("_D3std4math4yl2xFNaNbNiNfeeZe", &eval_unimp);
}
- if (Port.yl2xp1_supported)
+ if (CTFloat.yl2xp1_supported)
{
add_builtin("_D3std4math6yl2xp1FNaNbNiNfeeZe", &eval_yl2xp1);
}
diff --git a/ddmd/complex.d b/ddmd/complex.d
index d64578b..def4aac 100644
--- a/ddmd/complex.d
+++ b/ddmd/complex.d
@@ -8,26 +8,21 @@
module ddmd.complex;
+import ddmd.root.ctfloat;
+
struct complex_t
{
- version(IN_LLVM_MSVC)
- {
- double re = 0;
- double im = 0;
- }
- else
- {
- real re = 0;
- real im = 0;
- }
+ real_t re;
+ real_t im;
+
+ this() @disable;
- this(real re)
+ this(real_t re)
{
- this.re = re;
- this.im = 0;
+ this(re, real_t(0));
}
- this(real re, real im)
+ this(real_t re, real_t im)
{
this.re = re;
this.im = im;
@@ -35,26 +30,17 @@ struct complex_t
complex_t opAdd(complex_t y)
{
- complex_t r;
- r.re = re + y.re;
- r.im = im + y.im;
- return r;
+ return complex_t(re + y.re, im + y.im);
}
complex_t opSub(complex_t y)
{
- complex_t r;
- r.re = re - y.re;
- r.im = im - y.im;
- return r;
+ return complex_t(re - y.re, im - y.im);
}
complex_t opNeg()
{
- complex_t r;
- r.re = -re;
- r.im = -im;
- return r;
+ return complex_t(-re, -im);
}
complex_t opMul(complex_t y)
@@ -62,37 +48,33 @@ struct complex_t
return complex_t(re * y.re - im * y.im, im * y.re + re * y.im);
}
- complex_t opMul_r(real x)
+ complex_t opMul_r(real_t x)
{
return complex_t(x) * this;
}
- complex_t opMul(real y)
+ complex_t opMul(real_t y)
{
return this * complex_t(y);
}
- complex_t opDiv(real y)
+ complex_t opDiv(real_t y)
{
return this / complex_t(y);
}
complex_t opDiv(complex_t y)
{
- real abs_y_re = y.re < 0 ? -y.re : y.re;
- real abs_y_im = y.im < 0 ? -y.im : y.im;
- real r, den;
-
- if (abs_y_re < abs_y_im)
+ if (CTFloat.fabs(y.re) < CTFloat.fabs(y.im))
{
- r = y.re / y.im;
- den = y.im + r * y.re;
+ const r = y.re / y.im;
+ const den = y.im + r * y.re;
return complex_t((re * r + im) / den, (im * r - re) / den);
}
else
{
- r = y.im / y.re;
- den = y.re + r * y.im;
+ const r = y.im / y.re;
+ const den = y.re + r * y.im;
return complex_t((re + r * im) / den, (im - r * re) / den);
}
}
@@ -108,12 +90,12 @@ struct complex_t
}
}
-extern (C++) real creall(complex_t x)
+extern (C++) real_t creall(complex_t x)
{
return x.re;
}
-extern (C++) real cimagl(complex_t x)
+extern (C++) real_t cimagl(complex_t x)
{
return x.im;
}
diff --git a/ddmd/complex_t.h b/ddmd/complex_t.h
index 12f2048..5e940e9 100644
--- a/ddmd/complex_t.h
+++ b/ddmd/complex_t.h
@@ -12,42 +12,37 @@
#ifndef DMD_COMPLEX_T_H
#define DMD_COMPLEX_T_H
+#include "ctfloat.h"
+
/* Roll our own complex type for compilers that don't support complex
*/
struct complex_t
{
- longdouble re;
- longdouble im;
-
- complex_t() { this->re = 0; this->im = 0; }
- complex_t(longdouble re) { this->re = re; this->im = 0; }
- complex_t(double re) { this->re = re; this->im = 0; }
- complex_t(longdouble re, longdouble im) { this->re = re; this->im = im; }
- complex_t(double re, double im) { this->re = re; this->im = im; }
-
- complex_t operator + (complex_t y) { complex_t r; r.re = re + y.re; r.im = im + y.im; return r; }
- complex_t operator - (complex_t y) { complex_t r; r.re = re - y.re; r.im = im - y.im; return r; }
- complex_t operator - () { complex_t r; r.re = -re; r.im = -im; return r; }
+ real_t re;
+ real_t im;
+
+ complex_t(real_t re) : re(re), im(0) {}
+ complex_t(real_t re, real_t im) : re(re), im(im) {}
+
+ complex_t operator + (complex_t y) { return complex_t(re + y.re, im + y.im); }
+ complex_t operator - (complex_t y) { return complex_t(re - y.re, im - y.im); }
+ complex_t operator - () { return complex_t(-re, -im); }
complex_t operator * (complex_t y) { return complex_t(re * y.re - im * y.im, im * y.re + re * y.im); }
complex_t operator / (complex_t y)
{
- longdouble abs_y_re = y.re < 0 ? -y.re : y.re;
- longdouble abs_y_im = y.im < 0 ? -y.im : y.im;
- longdouble r, den;
-
- if (abs_y_re < abs_y_im)
+ if (CTFloat::fabsImpl(y.re) < CTFloat::fabsImpl(y.im))
{
- r = y.re / y.im;
- den = y.im + r * y.re;
+ real_t r = y.re / y.im;
+ real_t den = y.im + r * y.re;
return complex_t((re * r + im) / den,
(im * r - re) / den);
}
else
{
- r = y.im / y.re;
- den = y.re + r * y.im;
+ real_t r = y.im / y.re;
+ real_t den = y.re + r * y.im;
return complex_t((re + r * im) / den,
(im - r * re) / den);
}
@@ -57,19 +52,22 @@ struct complex_t
int operator == (complex_t y) { return re == y.re && im == y.im; }
int operator != (complex_t y) { return re != y.re || im != y.im; }
+
+private:
+ complex_t() : re(0), im(0) {}
};
-inline complex_t operator * (longdouble x, complex_t y) { return complex_t(x) * y; }
-inline complex_t operator * (complex_t x, longdouble y) { return x * complex_t(y); }
-inline complex_t operator / (complex_t x, longdouble y) { return x / complex_t(y); }
+inline complex_t operator * (real_t x, complex_t y) { return complex_t(x) * y; }
+inline complex_t operator * (complex_t x, real_t y) { return x * complex_t(y); }
+inline complex_t operator / (complex_t x, real_t y) { return x / complex_t(y); }
-inline longdouble creall(complex_t x)
+inline real_t creall(complex_t x)
{
return x.re;
}
-inline longdouble cimagl(complex_t x)
+inline real_t cimagl(complex_t x)
{
return x.im;
}
diff --git a/ddmd/constfold.d b/ddmd/constfold.d
index e75e3c3..35be9a0 100644
--- a/ddmd/constfold.d
+++ b/ddmd/constfold.d
@@ -21,10 +21,10 @@ import ddmd.expression;
import ddmd.func;
import ddmd.globals;
import ddmd.mtype;
-import ddmd.root.longdouble;
-import ddmd.root.port;
+import ddmd.root.ctfloat;
import ddmd.root.rmem;
import ddmd.sideeffect;
+import ddmd.target;
import ddmd.tokens;
import ddmd.utf;
@@ -147,13 +147,13 @@ extern (C++) UnionExp Add(Loc loc, Type type, Expression e1, Expression e2)
{
// This rigamarole is necessary so that -0.0 doesn't get
// converted to +0.0 by doing an extraneous add with +0.0
- complex_t c1;
- real_t r1 = ldouble(0.0);
- real_t i1 = ldouble(0.0);
- complex_t c2;
- real_t r2 = ldouble(0.0);
- real_t i2 = ldouble(0.0);
- complex_t v;
+ auto c1 = complex_t(real_t(0));
+ real_t r1 = 0;
+ real_t i1 = 0;
+ auto c2 = complex_t(real_t(0));
+ real_t r2 = 0;
+ real_t i2 = 0;
+ auto v = complex_t(real_t(0));
int x;
if (e1.type.isreal())
{
@@ -187,7 +187,7 @@ extern (C++) UnionExp Add(Loc loc, Type type, Expression e1, Expression e2)
switch (x)
{
case 0 + 0:
- v = complex_t(r1 + r2, 0);
+ v = complex_t(r1 + r2);
break;
case 0 + 1:
v = complex_t(r1, i2);
@@ -199,7 +199,7 @@ extern (C++) UnionExp Add(Loc loc, Type type, Expression e1, Expression e2)
v = complex_t(r2, i1);
break;
case 3 + 1:
- v = complex_t(0, i1 + i2);
+ v = complex_t(real_t(0), i1 + i2);
break;
case 3 + 2:
v = complex_t(creall(c2), i1 + cimagl(c2));
@@ -250,13 +250,13 @@ extern (C++) UnionExp Min(Loc loc, Type type, Expression e1, Expression e2)
{
// This rigamarole is necessary so that -0.0 doesn't get
// converted to +0.0 by doing an extraneous add with +0.0
- complex_t c1;
- real_t r1 = ldouble(0.0);
- real_t i1 = ldouble(0.0);
- complex_t c2;
- real_t r2 = ldouble(0.0);
- real_t i2 = ldouble(0.0);
- complex_t v;
+ auto c1 = complex_t(real_t(0));
+ real_t r1 = 0;
+ real_t i1 = 0;
+ auto c2 = complex_t(real_t(0));
+ real_t r2 = 0;
+ real_t i2 = 0;
+ auto v = complex_t(real_t(0));
int x;
if (e1.type.isreal())
{
@@ -290,7 +290,7 @@ extern (C++) UnionExp Min(Loc loc, Type type, Expression e1, Expression e2)
switch (x)
{
case 0 + 0:
- v = complex_t(r1 - r2, 0);
+ v = complex_t(r1 - r2);
break;
case 0 + 1:
v = complex_t(r1, -i2);
@@ -302,7 +302,7 @@ extern (C++) UnionExp Min(Loc loc, Type type, Expression e1, Expression e2)
v = complex_t(-r2, i1);
break;
case 3 + 1:
- v = complex_t(0, i1 - i2);
+ v = complex_t(real_t(0), i1 - i2);
break;
case 3 + 2:
v = complex_t(-creall(c2), i1 - cimagl(c2));
@@ -339,8 +339,8 @@ extern (C++) UnionExp Mul(Loc loc, Type type, Expression e1, Expression e2)
UnionExp ue;
if (type.isfloating())
{
- complex_t c;
- d_float80 r;
+ auto c = complex_t(real_t(0));
+ real_t r = 0;
if (e1.type.isreal())
{
r = e1.toReal();
@@ -388,8 +388,7 @@ extern (C++) UnionExp Div(Loc loc, Type type, Expression e1, Expression e2)
UnionExp ue;
if (type.isfloating())
{
- complex_t c;
- d_float80 r;
+ auto c = complex_t(real_t(0));
//e1->type->print();
//e2->type->print();
if (e2.type.isreal())
@@ -403,8 +402,8 @@ extern (C++) UnionExp Div(Loc loc, Type type, Expression e1, Expression e2)
// https://issues.dlang.org/show_bug.cgi?id=14952
// This can be removed once compiling with DMD 2.068 or
// older is no longer supported.
- d_float80 r1 = e1.toReal();
- d_float80 r2 = e2.toReal();
+ const r1 = e1.toReal();
+ const r2 = e2.toReal();
emplaceExp!(RealExp)(&ue, loc, r1 / r2, type);
}
else
@@ -413,13 +412,13 @@ extern (C++) UnionExp Div(Loc loc, Type type, Expression e1, Expression e2)
}
return ue;
}
- r = e2.toReal();
+ const r = e2.toReal();
c = e1.toComplex();
c = complex_t(creall(c) / r, cimagl(c) / r);
}
else if (e2.type.isimaginary())
{
- r = e2.toImaginary();
+ const r = e2.toImaginary();
c = e1.toComplex();
c = complex_t(cimagl(c) / r, -creall(c) / r);
}
@@ -427,6 +426,7 @@ extern (C++) UnionExp Div(Loc loc, Type type, Expression e1, Expression e2)
{
c = e1.toComplex() / e2.toComplex();
}
+
if (type.isreal())
emplaceExp!(RealExp)(&ue, loc, creall(c), type);
else if (type.isimaginary())
@@ -462,16 +462,16 @@ extern (C++) UnionExp Mod(Loc loc, Type type, Expression e1, Expression e2)
UnionExp ue;
if (type.isfloating())
{
- complex_t c;
+ auto c = complex_t(real_t(0));
if (e2.type.isreal())
{
- real_t r2 = e2.toReal();
- c = complex_t(Port.fmodl(e1.toReal(), r2), Port.fmodl(e1.toImaginary(), r2));
+ const r2 = e2.toReal();
+ c = complex_t(e1.toReal() % r2, e1.toImaginary() % r2);
}
else if (e2.type.isimaginary())
{
- real_t i2 = e2.toImaginary();
- c = complex_t(Port.fmodl(e1.toReal(), i2), Port.fmodl(e1.toImaginary(), i2));
+ const i2 = e2.toImaginary();
+ c = complex_t(e1.toReal() % i2, e1.toImaginary() % i2);
}
else
assert(0);
@@ -544,12 +544,12 @@ extern (C++) UnionExp Pow(Loc loc, Type type, Expression e1, Expression e2)
if (e1.type.iscomplex())
{
emplaceExp!(ComplexExp)(&ur, loc, e1.toComplex(), e1.type);
- emplaceExp!(ComplexExp)(&uv, loc, complex_t(1.0, 0.0), e1.type);
+ emplaceExp!(ComplexExp)(&uv, loc, complex_t(real_t(1)), e1.type);
}
else if (e1.type.isfloating())
{
emplaceExp!(RealExp)(&ur, loc, e1.toReal(), e1.type);
- emplaceExp!(RealExp)(&uv, loc, ldouble(1.0), e1.type);
+ emplaceExp!(RealExp)(&uv, loc, real_t(1), e1.type);
}
else
{
@@ -573,7 +573,7 @@ extern (C++) UnionExp Pow(Loc loc, Type type, Expression e1, Expression e2)
{
// ue = 1.0 / v
UnionExp one;
- emplaceExp!(RealExp)(&one, loc, ldouble(1.0), v.type);
+ emplaceExp!(RealExp)(&one, loc, real_t(1), v.type);
uv = Div(loc, v.type, one.exp(), v);
}
if (type.iscomplex())
@@ -586,9 +586,9 @@ extern (C++) UnionExp Pow(Loc loc, Type type, Expression e1, Expression e2)
else if (e2.type.isfloating())
{
// x ^^ y for x < 0 and y not an integer is not defined; so set result as NaN
- if (e1.toReal() < 0.0)
+ if (e1.toReal() < real_t(0))
{
- emplaceExp!(RealExp)(&ue, loc, Port.ldbl_nan, type);
+ emplaceExp!(RealExp)(&ue, loc, Target.RealProperties.nan, type);
}
else
emplaceExp!(CTFEExp)(&ue, TOKcantexp);
@@ -719,8 +719,8 @@ extern (C++) UnionExp Equal(TOK op, Loc loc, Type type, Expression e1, Expressio
{
UnionExp ue;
int cmp = 0;
- real_t r1;
- real_t r2;
+ real_t r1 = 0;
+ real_t r2 = 0;
//printf("Equal(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
assert(op == TOKequal || op == TOKnotequal);
if (e1.op == TOKnull)
@@ -892,7 +892,7 @@ extern (C++) UnionExp Equal(TOK op, Loc loc, Type type, Expression e1, Expressio
r1 = e1.toImaginary();
r2 = e2.toImaginary();
L1:
- if (Port.isNan(r1) || Port.isNan(r2)) // if unordered
+ if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered
{
cmp = 0;
}
@@ -970,8 +970,8 @@ extern (C++) UnionExp Cmp(TOK op, Loc loc, Type type, Expression e1, Expression
{
UnionExp ue;
dinteger_t n;
- real_t r1;
- real_t r2;
+ real_t r1 = 0;
+ real_t r2 = 0;
//printf("Cmp(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
if (e1.op == TOKstring && e2.op == TOKstring)
{
@@ -1090,18 +1090,18 @@ extern (C++) UnionExp Cast(Loc loc, Type type, Type to, Expression e1)
switch (typeb.ty)
{
case Tint8:
- result = cast(d_int8)r;
+ result = cast(d_int8)cast(sinteger_t)r;
break;
case Tchar:
case Tuns8:
- result = cast(d_uns8)r;
+ result = cast(d_uns8)cast(dinteger_t)r;
break;
case Tint16:
- result = cast(d_int16)r;
+ result = cast(d_int16)cast(sinteger_t)r;
break;
case Twchar:
case Tuns16:
- result = cast(d_uns16)r;
+ result = cast(d_uns16)cast(dinteger_t)r;
break;
case Tint32:
result = cast(d_int32)r;
diff --git a/ddmd/ctfeexpr.d b/ddmd/ctfeexpr.d
index b5d6b0b..4a712c2 100644
--- a/ddmd/ctfeexpr.d
+++ b/ddmd/ctfeexpr.d
@@ -26,9 +26,8 @@ import ddmd.globals;
import ddmd.hdrgen;
import ddmd.id;
import ddmd.mtype;
-import ddmd.root.longdouble;
+import ddmd.root.ctfloat;
import ddmd.root.outbuffer;
-import ddmd.root.port;
import ddmd.root.rmem;
import ddmd.target;
import ddmd.tokens;
@@ -1106,7 +1105,7 @@ extern (C++) int intSignedCmp(TOK op, sinteger_t n1, sinteger_t n2)
extern (C++) int realCmp(TOK op, real_t r1, real_t r2)
{
// Don't rely on compiler, handle NAN arguments separately
- if (Port.isNan(r1) || Port.isNan(r2)) // if unordered
+ if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered
{
switch (op)
{
@@ -1294,8 +1293,8 @@ extern (C++) int ctfeRawCmp(Loc loc, Expression e1, Expression e2)
{
return e1.toInteger() != e2.toInteger();
}
- real_t r1;
- real_t r2;
+ real_t r1 = 0;
+ real_t r2 = 0;
if (e1.type.isreal())
{
r1 = e1.toReal();
@@ -1307,7 +1306,7 @@ extern (C++) int ctfeRawCmp(Loc loc, Expression e1, Expression e2)
r1 = e1.toImaginary();
r2 = e2.toImaginary();
L1:
- if (Port.isNan(r1) || Port.isNan(r2)) // if unordered
+ if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered
{
return 1;
}
diff --git a/ddmd/dcast.d b/ddmd/dcast.d
index 66290b3..e9789eb 100644
--- a/ddmd/dcast.d
+++ b/ddmd/dcast.d
@@ -30,7 +30,7 @@ import ddmd.init;
import ddmd.intrange;
import ddmd.mtype;
import ddmd.opover;
-import ddmd.root.longdouble;
+import ddmd.root.ctfloat;
import ddmd.root.outbuffer;
import ddmd.root.rmem;
import ddmd.root.rootobject;
@@ -434,17 +434,16 @@ extern (C++) MATCH implicitConvTo(Expression e, Type t)
}
case Tfloat80:
{
- real f;
if (e.type.isunsigned())
{
- f = ldouble(value);
- if (f != value) // isn't this a noop, because the compiler prefers ld
+ const f = real_t(value);
+ if (cast(dinteger_t)f != value) // isn't this a noop, because the compiler prefers ld
return;
}
else
{
- f = ldouble(cast(sinteger_t)value);
- if (f != cast(sinteger_t)value)
+ const f = real_t(cast(sinteger_t)value);
+ if (cast(sinteger_t)f != cast(sinteger_t)value)
return;
}
break;
diff --git a/ddmd/dmangle.d b/ddmd/dmangle.d
index 0e5b2b9..5bd613c 100644
--- a/ddmd/dmangle.d
+++ b/ddmd/dmangle.d
@@ -26,9 +26,8 @@ import ddmd.func;
import ddmd.globals;
import ddmd.id;
import ddmd.mtype;
-import ddmd.root.longdouble;
+import ddmd.root.ctfloat;
import ddmd.root.outbuffer;
-import ddmd.root.port;
import ddmd.utf;
import ddmd.visitor;
@@ -628,17 +627,17 @@ public:
* -0X1.1BC18BA997B95P+79 => N11BC18BA997B95P79
* 0X1.9P+2 => 19P2
*/
- if (Port.isNan(value))
+ if (CTFloat.isNaN(value))
buf.writestring("NAN"); // no -NAN bugs
- else if (Port.isInfinity(value))
- buf.writestring(value < 0 ? "NINF" : "INF");
+ else if (CTFloat.isInfinity(value))
+ buf.writestring(value < real_t(0) ? "NINF" : "INF");
else
{
- const(size_t) BUFFER_LEN = 36;
+ enum BUFFER_LEN = 36;
char[BUFFER_LEN] buffer;
- size_t n = Port.ld_sprint(buffer.ptr, 'A', value);
+ const n = CTFloat.sprint(buffer.ptr, 'A', value);
assert(n < BUFFER_LEN);
- for (size_t i = 0; i < n; i++)
+ for (int i = 0; i < n; i++)
{
char c = buffer[i];
switch (c)
diff --git a/ddmd/expression.d b/ddmd/expression.d
index 3bd883f..8fc3f51 100644
--- a/ddmd/expression.d
+++ b/ddmd/expression.d
@@ -56,11 +56,10 @@ import ddmd.opover;
import ddmd.optimize;
import ddmd.parse;
import ddmd.root.aav;
+import ddmd.root.ctfloat;
import ddmd.root.file;
import ddmd.root.filename;
-import ddmd.root.longdouble;
import ddmd.root.outbuffer;
-import ddmd.root.port;
import ddmd.root.rmem;
import ddmd.root.rootobject;
import ddmd.sideeffect;
@@ -1931,7 +1930,10 @@ private:
char[__traits(classInstanceSize, IndexExp)] indexexp;
char[__traits(classInstanceSize, SliceExp)] sliceexp;
// Ensure that the union is suitably aligned.
- real for_alignment_only;
+ version(IN_LLVM)
+ long for_alignment_only;
+ else
+ real_t for_alignment_only;
}
__AnonStruct__u u;
@@ -1944,7 +1946,7 @@ private:
*/
extern (C++) int RealEquals(real_t x1, real_t x2)
{
- return (Port.isNan(x1) && Port.isNan(x2)) || Port.fequal(x1, x2);
+ return (CTFloat.isNaN(x1) && CTFloat.isNaN(x2)) || CTFloat.isIdentical(x1, x2);
}
/************************ TypeDotIdExp ************************************/
@@ -2489,19 +2491,19 @@ public:
real_t toReal()
{
error("floating point constant expression expected instead of %s", toChars());
- return ldouble(0);
+ return real_t(0);
}
real_t toImaginary()
{
error("floating point constant expression expected instead of %s", toChars());
- return ldouble(0);
+ return real_t(0);
}
complex_t toComplex()
{
error("floating point constant expression expected instead of %s", toChars());
- return cast(complex_t)0.0;
+ return complex_t(real_t(0));
}
StringExp toStringExp()
@@ -3219,19 +3221,19 @@ public:
normalize(); // necessary until we fix all the paints of 'type'
Type t = type.toBasetype();
if (t.ty == Tuns64)
- return ldouble(cast(d_uns64)value);
+ return real_t(cast(d_uns64)value);
else
- return ldouble(cast(d_int64)value);
+ return real_t(cast(d_int64)value);
}
override real_t toImaginary()
{
- return ldouble(0);
+ return real_t(0);
}
override complex_t toComplex()
{
- return cast(complex_t)toReal();
+ return complex_t(toReal());
}
override bool isBool(bool result)
@@ -3394,12 +3396,12 @@ public:
override real_t toReal()
{
- return type.isreal() ? value : ldouble(0);
+ return type.isreal() ? value : real_t(0);
}
override real_t toImaginary()
{
- return type.isreal() ? ldouble(0) : value;
+ return type.isreal() ? real_t(0) : value;
}
override complex_t toComplex()
@@ -3409,7 +3411,7 @@ public:
override bool isBool(bool result)
{
- return result ? (value != 0) : (value == 0);
+ return result ? cast(bool)value : !cast(bool)value;
}
override void accept(Visitor v)
@@ -7410,7 +7412,7 @@ public:
{
// x/iv = i(-x/v)
// Therefore, the result is 0
- e2 = new CommaExp(loc, e2, new RealExp(loc, ldouble(0.0), t1));
+ e2 = new CommaExp(loc, e2, new RealExp(loc, real_t(0), t1));
e2.type = t1;
Expression e = new AssignExp(loc, e1, e2);
e.type = t1;
@@ -13661,7 +13663,7 @@ public:
sinteger_t intpow = 0;
if (e2.op == TOKint64 && (cast(sinteger_t)e2.toInteger() == 2 || cast(sinteger_t)e2.toInteger() == 3))
intpow = e2.toInteger();
- else if (e2.op == TOKfloat64 && (e2.toReal() == cast(sinteger_t)e2.toReal()))
+ else if (e2.op == TOKfloat64 && (e2.toReal() == real_t(cast(sinteger_t)e2.toReal())))
intpow = cast(sinteger_t)e2.toReal();
// Deal with x^^2, x^^3 immediately, since they are of practical importance.
if (intpow == 2 || intpow == 3)
@@ -13694,7 +13696,7 @@ public:
return this;
}
e = new ScopeExp(loc, mmath);
- if (e2.op == TOKfloat64 && e2.toReal() == 0.5)
+ if (e2.op == TOKfloat64 && e2.toReal() == real_t(0.5))
{
// Replace e1 ^^ 0.5 with .std.math.sqrt(x)
e = new CallExp(loc, new DotIdExp(loc, e, Id._sqrt), e1);
diff --git a/ddmd/expression.h b/ddmd/expression.h
index 2fb9d18..99abef3 100644
--- a/ddmd/expression.h
+++ b/ddmd/expression.h
@@ -1626,7 +1626,11 @@ private:
char sliceexp [sizeof(SliceExp)];
// Ensure that the union is suitably aligned.
- longdouble for_alignment_only;
+#ifdef IN_LLVM
+ alignas(alignof(real_t)) int for_alignment_only;
+#else
+ real_t for_alignment_only;
+#endif
} u;
};
diff --git a/ddmd/globals.d b/ddmd/globals.d
index 56c981e..01d3729 100644
--- a/ddmd/globals.d
+++ b/ddmd/globals.d
@@ -407,17 +407,6 @@ alias d_int32 = int32_t;
alias d_uns32 = uint32_t;
alias d_int64 = int64_t;
alias d_uns64 = uint64_t;
-alias d_float32 = float;
-alias d_float64 = double;
-alias d_float80 = real;
-version(IN_LLVM_MSVC)
-{
- alias real_t = double;
-}
-else
-{
- alias real_t = real;
-}
// file location
struct Loc
diff --git a/ddmd/globals.h b/ddmd/globals.h
index 7ce0c54..717ab3e 100644
--- a/ddmd/globals.h
+++ b/ddmd/globals.h
@@ -16,7 +16,7 @@
#pragma once
#endif
-#include "longdouble.h"
+#include "ctfloat.h"
#include "outbuffer.h"
#include "filename.h"
@@ -306,16 +306,6 @@ typedef uint32_t d_uns32;
typedef int64_t d_int64;
typedef uint64_t d_uns64;
-typedef float d_float32;
-typedef double d_float64;
-typedef longdouble d_float80;
-
-#if IN_LLVM && _MSC_VER
-typedef double real_t;
-#else
-typedef longdouble real_t;
-#endif
-
// file location
struct Loc
{
diff --git a/ddmd/hdrgen.d b/ddmd/hdrgen.d
index 7beba54..1629af0 100644
--- a/ddmd/hdrgen.d
+++ b/ddmd/hdrgen.d
@@ -39,9 +39,8 @@ import ddmd.mars;
import ddmd.mtype;
import ddmd.nspace;
import ddmd.parse;
-import ddmd.root.longdouble;
+import ddmd.root.ctfloat;
import ddmd.root.outbuffer;
-import ddmd.root.port;
import ddmd.root.rootobject;
import ddmd.statement;
import ddmd.staticassert;
@@ -2200,15 +2199,13 @@ public:
Plus one for rounding. */
const(size_t) BUFFER_LEN = value.sizeof * 3 + 8 + 1 + 1;
char[BUFFER_LEN] buffer;
- Port.ld_sprint(buffer.ptr, 'g', value);
+ CTFloat.sprint(buffer.ptr, 'g', value);
assert(strlen(buffer.ptr) < BUFFER_LEN);
- // IN_LLVM MSVC: LLVM's APFloat is used for strtold, which asserts for certain special float inputs
- if (!IN_LLVM_MSVC || (!Port.isNan(value) && !Port.isInfinity(value)))
if (hgs.hdrgen)
{
- real_t r = Port.strtold(buffer.ptr, null);
+ real_t r = CTFloat.parse(buffer.ptr);
if (r != value) // if exact duplication
- Port.ld_sprint(buffer.ptr, 'a', value);
+ CTFloat.sprint(buffer.ptr, 'a', value);
}
buf.writestring(buffer.ptr);
if (type)
diff --git a/ddmd/lexer.d b/ddmd/lexer.d
index 7b547c1..13edc1e 100644
--- a/ddmd/lexer.d
+++ b/ddmd/lexer.d
@@ -20,7 +20,7 @@ import ddmd.errors;
import ddmd.globals;
import ddmd.id;
import ddmd.identifier;
-import ddmd.root.longdouble;
+import ddmd.root.ctfloat;
import ddmd.root.outbuffer;
import ddmd.root.port;
import ddmd.root.rmem;
@@ -2130,25 +2130,20 @@ public:
++pstart;
}
stringbuffer.writeByte(0);
+ auto sbufptr = cast(const(char)*)stringbuffer.data;
TOK result;
- t.float80value = Port.strtold(cast(char*)stringbuffer.data, null);
- errno = 0;
+ bool isOutOfRange = false;
+ t.floatvalue = CTFloat.parse(sbufptr, &isOutOfRange);
switch (*p)
{
case 'F':
case 'f':
- // Only interested in errno return
- cast(void)Port.strtof(cast(char*)stringbuffer.data, null);
+ isOutOfRange = (isOutOfRange || Port.isFloat32LiteralOutOfRange(sbufptr));
result = TOKfloat32v;
p++;
break;
default:
- /* Should do our own strtod(), since dmc and linux gcc
- * accept 2.22507e-308, while apple gcc will only take
- * 2.22508e-308. Not sure who is right.
- */
- // Only interested in errno return
- cast(void)Port.strtod(cast(char*)stringbuffer.data, null);
+ isOutOfRange = (isOutOfRange || Port.isFloat64LiteralOutOfRange(sbufptr));
result = TOKfloat64v;
break;
case 'l':
@@ -2178,7 +2173,8 @@ public:
break;
}
}
- if (errno == ERANGE)
+ const isLong = (result == TOKfloat80v || result == TOKimaginary80v);
+ if (isOutOfRange && !isLong)
{
const(char)* suffix = (result == TOKfloat32v || result == TOKimaginary32v) ? "f" : "";
error(scanloc, "number '%s%s' is not representable", cast(char*)stringbuffer.data, suffix);
diff --git a/ddmd/mars.h b/ddmd/mars.h
index 5c66444..5c25141 100644
--- a/ddmd/mars.h
+++ b/ddmd/mars.h
@@ -81,7 +81,7 @@ struct OutBuffer;
#include "globals.h"
-#include "longdouble.h"
+#include "ctfloat.h"
#include "complex_t.h"
diff --git a/ddmd/mtype.d b/ddmd/mtype.d
index 6c02349..436adcc 100644
--- a/ddmd/mtype.d
+++ b/ddmd/mtype.d
@@ -10,7 +10,6 @@
module ddmd.mtype;
import core.checkedint;
-import core.stdc.float_;
import core.stdc.stdarg;
import core.stdc.stdio;
import core.stdc.stdlib;
@@ -46,9 +45,8 @@ import ddmd.identifier;
import ddmd.imphint;
import ddmd.init;
import ddmd.opover;
-import ddmd.root.longdouble;
+import ddmd.root.ctfloat;
import ddmd.root.outbuffer;
-import ddmd.root.port;
import ddmd.root.rmem;
import ddmd.root.rootobject;
import ddmd.root.stringtable;
@@ -3505,7 +3503,7 @@ version(IN_LLVM)
{
Expression e;
dinteger_t ivalue;
- d_float80 fvalue;
+ real_t fvalue = 0;
//printf("TypeBasic::getProperty('%s')\n", ident->toChars());
if (ident == Id.max)
{
@@ -3550,17 +3548,17 @@ version(IN_LLVM)
case Tcomplex32:
case Timaginary32:
case Tfloat32:
- fvalue = FLT_MAX;
+ fvalue = Target.FloatProperties.max;
goto Lfvalue;
case Tcomplex64:
case Timaginary64:
case Tfloat64:
- fvalue = DBL_MAX;
+ fvalue = Target.DoubleProperties.max;
goto Lfvalue;
case Tcomplex80:
case Timaginary80:
case Tfloat80:
- fvalue = Port.ldbl_max;
+ fvalue = Target.RealProperties.max;
goto Lfvalue;
default:
break;
@@ -3629,20 +3627,17 @@ version(IN_LLVM)
case Tcomplex32:
case Timaginary32:
case Tfloat32:
- fvalue = FLT_MIN;
+ fvalue = Target.FloatProperties.min_normal;
goto Lfvalue;
case Tcomplex64:
case Timaginary64:
case Tfloat64:
- fvalue = DBL_MIN;
+ fvalue = Target.DoubleProperties.min_normal;
goto Lfvalue;
case Tcomplex80:
case Timaginary80:
case Tfloat80:
-version(IN_LLVM)
- fvalue = Port.ldbl_min_normal;
-else
- fvalue = LDBL_MIN;
+ fvalue = Target.RealProperties.min_normal;
goto Lfvalue;
default:
break;
@@ -3661,10 +3656,8 @@ else
case Tfloat32:
case Tfloat64:
case Tfloat80:
- {
- fvalue = Port.ldbl_nan;
- goto Lfvalue;
- }
+ fvalue = Target.RealProperties.nan;
+ goto Lfvalue;
default:
break;
}
@@ -3682,7 +3675,7 @@ else
case Tfloat32:
case Tfloat64:
case Tfloat80:
- fvalue = Port.ldbl_infinity;
+ fvalue = Target.RealProperties.infinity;
goto Lfvalue;
default:
break;
@@ -3695,20 +3688,17 @@ else
case Tcomplex32:
case Timaginary32:
case Tfloat32:
- ivalue = FLT_DIG;
+ ivalue = Target.FloatProperties.dig;
goto Lint;
case Tcomplex64:
case Timaginary64:
case Tfloat64:
- ivalue = DBL_DIG;
+ ivalue = Target.DoubleProperties.dig;
goto Lint;
case Tcomplex80:
case Timaginary80:
case Tfloat80:
-version(IN_LLVM)
- ivalue = Port.ldbl_dig;
-else
- ivalue = LDBL_DIG;
+ ivalue = Target.RealProperties.dig;
goto Lint;
default:
break;
@@ -3721,20 +3711,17 @@ else
case Tcomplex32:
case Timaginary32:
case Tfloat32:
- fvalue = FLT_EPSILON;
+ fvalue = Target.FloatProperties.epsilon;
goto Lfvalue;
case Tcomplex64:
case Timaginary64:
case Tfloat64:
- fvalue = DBL_EPSILON;
+ fvalue = Target.DoubleProperties.epsilon;
goto Lfvalue;
case Tcomplex80:
case Timaginary80:
case Tfloat80:
-version(IN_LLVM)
- fvalue = Port.ldbl_epsilon;
-else
- fvalue = LDBL_EPSILON;
+ fvalue = Target.RealProperties.epsilon;
goto Lfvalue;
default:
break;
@@ -3747,20 +3734,17 @@ else
case Tcomplex32:
case Timaginary32:
case Tfloat32:
- ivalue = FLT_MANT_DIG;
+ ivalue = Target.FloatProperties.mant_dig;
goto Lint;
case Tcomplex64:
case Timaginary64:
case Tfloat64:
- ivalue = DBL_MANT_DIG;
+ ivalue = Target.DoubleProperties.mant_dig;
goto Lint;
case Tcomplex80:
case Timaginary80:
case Tfloat80:
-version(IN_LLVM)
- ivalue = Port.ldbl_mant_dig;
-else
- ivalue = LDBL_MANT_DIG;
+ ivalue = Target.RealProperties.mant_dig;
goto Lint;
default:
break;
@@ -3773,20 +3757,17 @@ else
case Tcomplex32:
case Timaginary32:
case Tfloat32:
- ivalue = FLT_MAX_10_EXP;
+ ivalue = Target.FloatProperties.max_10_exp;
goto Lint;
case Tcomplex64:
case Timaginary64:
case Tfloat64:
- ivalue = DBL_MAX_10_EXP;
+ ivalue = Target.DoubleProperties.max_10_exp;
goto Lint;
case Tcomplex80:
case Timaginary80:
case Tfloat80:
-version(IN_LLVM)
- ivalue = Port.ldbl_max_10_exp;
-else
- ivalue = LDBL_MAX_10_EXP;
+ ivalue = Target.RealProperties.max_10_exp;
goto Lint;
default:
break;
@@ -3799,20 +3780,17 @@ else
case Tcomplex32:
case Timaginary32:
case Tfloat32:
- ivalue = FLT_MAX_EXP;
+ ivalue = Target.FloatProperties.max_exp;
goto Lint;
case Tcomplex64:
case Timaginary64:
case Tfloat64:
- ivalue = DBL_MAX_EXP;
+ ivalue = Target.DoubleProperties.max_exp;
goto Lint;
case Tcomplex80:
case Timaginary80:
case Tfloat80:
-version(IN_LLVM)
- ivalue = Port.ldbl_max_exp;
-else
- ivalue = LDBL_MAX_EXP;
+ ivalue = Target.RealProperties.max_exp;
goto Lint;
default:
break;
@@ -3825,20 +3803,17 @@ else
case Tcomplex32:
case Timaginary32:
case Tfloat32:
- ivalue = FLT_MIN_10_EXP;
+ ivalue = Target.FloatProperties.min_10_exp;
goto Lint;
case Tcomplex64:
case Timaginary64:
case Tfloat64:
- ivalue = DBL_MIN_10_EXP;
+ ivalue = Target.DoubleProperties.min_10_exp;
goto Lint;
case Tcomplex80:
case Timaginary80:
case Tfloat80:
-version(IN_LLVM)
- ivalue = Port.ldbl_min_10_exp;
-else
- ivalue = LDBL_MIN_10_EXP;
+ ivalue = Target.RealProperties.min_10_exp;
goto Lint;
default:
break;
@@ -3851,20 +3826,17 @@ else
case Tcomplex32:
case Timaginary32:
case Tfloat32:
- ivalue = FLT_MIN_EXP;
+ ivalue = Target.FloatProperties.min_exp;
goto Lint;
case Tcomplex64:
case Timaginary64:
case Tfloat64:
- ivalue = DBL_MIN_EXP;
+ ivalue = Target.DoubleProperties.min_exp;
goto Lint;
case Tcomplex80:
case Timaginary80:
case Tfloat80:
-version(IN_LLVM)
- ivalue = Port.ldbl_min_exp;
-else
- ivalue = LDBL_MIN_EXP;
+ ivalue = Target.RealProperties.min_exp;
goto Lint;
default:
break;
@@ -3879,9 +3851,7 @@ else
e = new RealExp(loc, fvalue, this);
else
{
- complex_t cvalue;
- cvalue.re = fvalue;
- cvalue.im = fvalue;
+ const cvalue = complex_t(fvalue, fvalue);
//for (int i = 0; i < 20; i++)
// printf("%02x ", ((unsigned char *)&cvalue)[i]);
//printf("\n");
@@ -3930,7 +3900,7 @@ else
t = tfloat80;
goto L2;
L2:
- e = new RealExp(e.loc, ldouble(0.0), t);
+ e = new RealExp(e.loc, real_t(0), t);
break;
default:
e = Type.getProperty(e.loc, ident, flag);
@@ -3974,7 +3944,7 @@ else
case Tfloat32:
case Tfloat64:
case Tfloat80:
- e = new RealExp(e.loc, ldouble(0.0), this);
+ e = new RealExp(e.loc, real_t(0), this);
break;
default:
e = Type.getProperty(e.loc, ident, flag);
@@ -4117,17 +4087,13 @@ else
case Tfloat32:
case Tfloat64:
case Tfloat80:
- return new RealExp(loc, Port.snan, this);
+ return new RealExp(loc, Target.RealProperties.snan, this);
case Tcomplex32:
case Tcomplex64:
case Tcomplex80:
- {
- // Can't use fvalue + I*fvalue (the im part becomes a quiet NaN).
- complex_t cvalue;
- (cast(real_t*)&cvalue)[0] = Port.snan;
- (cast(real_t*)&cvalue)[1] = Port.snan;
- return new ComplexExp(loc, cvalue, this);
- }
+ // Can't use fvalue + I*fvalue (the im part becomes a quiet NaN).
+ const cvalue = complex_t(Target.RealProperties.snan, Target.RealProperties.snan);
+ return new ComplexExp(loc, cvalue, this);
case Tvoid:
error(loc, "void does not have a default initializer");
return new ErrorExp();
diff --git a/ddmd/optimize.d b/ddmd/optimize.d
index e80b876..b8f4286 100644
--- a/ddmd/optimize.d
+++ b/ddmd/optimize.d
@@ -18,7 +18,7 @@ import ddmd.expression;
import ddmd.globals;
import ddmd.init;
import ddmd.mtype;
-import ddmd.root.longdouble;
+import ddmd.root.ctfloat;
import ddmd.sideeffect;
import ddmd.tokens;
import ddmd.visitor;
@@ -756,7 +756,7 @@ extern (C++) Expression Expression_optimize(Expression e, int result, bool keepL
if (binOptimize(e, result))
return;
// Replace 1 ^^ x or 1.0^^x by (x, 1)
- if ((e.e1.op == TOKint64 && e.e1.toInteger() == 1) || (e.e1.op == TOKfloat64 && e.e1.toReal() == 1.0))
+ if ((e.e1.op == TOKint64 && e.e1.toInteger() == 1) || (e.e1.op == TOKfloat64 && e.e1.toReal() == real_t(1)))
{
ret = new CommaExp(e.loc, e.e2, e.e1);
return;
@@ -770,25 +770,25 @@ extern (C++) Expression Expression_optimize(Expression e, int result, bool keepL
return;
}
// Replace x ^^ 0 or x^^0.0 by (x, 1)
- if ((e.e2.op == TOKint64 && e.e2.toInteger() == 0) || (e.e2.op == TOKfloat64 && e.e2.toReal() == 0.0))
+ if ((e.e2.op == TOKint64 && e.e2.toInteger() == 0) || (e.e2.op == TOKfloat64 && e.e2.toReal() == real_t(0)))
{
if (e.e1.type.isintegral())
ret = new IntegerExp(e.loc, 1, e.e1.type);
else
- ret = new RealExp(e.loc, ldouble(1.0), e.e1.type);
+ ret = new RealExp(e.loc, real_t(1), e.e1.type);
ret = new CommaExp(e.loc, e.e1, ret);
return;
}
// Replace x ^^ 1 or x^^1.0 by (x)
- if ((e.e2.op == TOKint64 && e.e2.toInteger() == 1) || (e.e2.op == TOKfloat64 && e.e2.toReal() == 1.0))
+ if ((e.e2.op == TOKint64 && e.e2.toInteger() == 1) || (e.e2.op == TOKfloat64 && e.e2.toReal() == real_t(1)))
{
ret = e.e1;
return;
}
// Replace x ^^ -1.0 by (1.0 / x)
- if ((e.e2.op == TOKfloat64 && e.e2.toReal() == -1.0))
+ if ((e.e2.op == TOKfloat64 && e.e2.toReal() == real_t(-1)))
{
- ret = new DivExp(e.loc, new RealExp(e.loc, ldouble(1.0), e.e2.type), e.e1);
+ ret = new DivExp(e.loc, new RealExp(e.loc, real_t(1), e.e2.type), e.e1);
return;
}
// All other negative integral powers are illegal
@@ -808,8 +808,8 @@ extern (C++) Expression Expression_optimize(Expression e, int result, bool keepL
// https://issues.dlang.org/show_bug.cgi?id=14952
// This can be removed once compiling with DMD 2.068 or
// older is no longer supported.
- d_float80 r = e.e2.toReal();
- if (r == cast(sinteger_t)r)
+ const r = e.e2.toReal();
+ if (r == real_t(cast(sinteger_t)r))
e.e2 = new IntegerExp(e.loc, e.e2.toInteger(), Type.tint64);
}
else
diff --git a/ddmd/parse.d b/ddmd/parse.d
index c67881b..09395e1 100644
--- a/ddmd/parse.d
+++ b/ddmd/parse.d
@@ -6598,27 +6598,27 @@ public:
nextToken();
break;
case TOKfloat32v:
- e = new RealExp(loc, token.float80value, Type.tfloat32);
+ e = new RealExp(loc, token.floatvalue, Type.tfloat32);
nextToken();
break;
case TOKfloat64v:
- e = new RealExp(loc, token.float80value, Type.tfloat64);
+ e = new RealExp(loc, token.floatvalue, Type.tfloat64);
nextToken();
break;
case TOKfloat80v:
- e = new RealExp(loc, token.float80value, Type.tfloat80);
+ e = new RealExp(loc, token.floatvalue, Type.tfloat80);
nextToken();
break;
case TOKimaginary32v:
- e = new RealExp(loc, token.float80value, Type.timaginary32);
+ e = new RealExp(loc, token.floatvalue, Type.timaginary32);
nextToken();
break;
case TOKimaginary64v:
- e = new RealExp(loc, token.float80value, Type.timaginary64);
+ e = new RealExp(loc, token.floatvalue, Type.timaginary64);
nextToken();
break;
case TOKimaginary80v:
- e = new RealExp(loc, token.float80value, Type.timaginary80);
+ e = new RealExp(loc, token.floatvalue, Type.timaginary80);
nextToken();
break;
case TOKnull:
diff --git a/ddmd/root/ctfloat.d b/ddmd/root/ctfloat.d
new file mode 100644
index 0000000..e19fd05
--- /dev/null
+++ b/ddmd/root/ctfloat.d
@@ -0,0 +1,80 @@
+//===-- ctfloat.d ---------------------------------------------------------===//
+//
+// LDC - the LLVM D compiler
+//
+// This file is distributed under the BSD-style LDC license. See the LICENSE
+// file for details.
+//
+//===----------------------------------------------------------------------===//
+
+module ddmd.root.ctfloat;
+
+// Publicly import LDC real_t type used by the front-end for compile-time reals
+public import ddmd.root.real_t : real_t;
+
+// Compile-time floating-point helper
+extern (C++) struct CTFloat
+{
+ static __gshared bool yl2x_supported = false;
+ static __gshared bool yl2xp1_supported = false;
+
+ static void yl2x(const real_t* x, const real_t* y, real_t* res)
+ {
+ assert(0);
+ }
+
+ static void yl2xp1(const real_t* x, const real_t* y, real_t* res)
+ {
+ assert(0);
+ }
+
+ static real_t parse(const(char)* literal, bool* isOutOfRange = null);
+
+ static real_t sinImpl(const ref real_t x);
+ static real_t cosImpl(const ref real_t x);
+ static real_t tanImpl(const ref real_t x);
+ static real_t sqrtImpl(const ref real_t x);
+ static real_t fabsImpl(const ref real_t x);
+
+ // additional LDC built-ins
+ static real_t logImpl(const ref real_t x);
+ static real_t fminImpl(const ref real_t l, const ref real_t r);
+ static real_t fmaxImpl(const ref real_t l, const ref real_t r);
+ static real_t floorImpl(const ref real_t x);
+ static real_t ceilImpl(const ref real_t x);
+ static real_t truncImpl(const ref real_t x);
+ static real_t roundImpl(const ref real_t x);
+
+ static bool isIdenticalImpl(const ref real_t a, const ref real_t b);
+ static bool isNaNImpl(const ref real_t r);
+ static bool isSNaNImpl(const ref real_t r);
+ static bool isInfinityImpl(const ref real_t r);
+
+ static int sprintImpl(char* str, char fmt, const ref real_t x);
+
+ extern(D):
+
+ static real_t sin(real_t x) { return sinImpl(x); }
+ static real_t cos(real_t x) { return cosImpl(x); }
+ static real_t tan(real_t x) { return tanImpl(x); }
+ static real_t sqrt(real_t x) { return sqrtImpl(x); }
+ static real_t fabs(real_t x) { return fabsImpl(x); }
+
+ static real_t log(real_t x) { return logImpl(x); }
+ static real_t fmin(real_t l, real_t r) { return fminImpl(l, r); }
+ static real_t fmax(real_t l, real_t r) { return fmaxImpl(l, r); }
+ static real_t floor(real_t x) { return floorImpl(x); }
+ static real_t ceil(real_t x) { return ceilImpl(x); }
+ static real_t trunc(real_t x) { return truncImpl(x); }
+ static real_t round(real_t x) { return roundImpl(x); }
+
+ static bool isIdentical(real_t a, real_t b) { return isIdenticalImpl(a, b); }
+ static bool isNaN(real_t r) { return isNaNImpl(r); }
+ static bool isSNaN(real_t r) { return isSNaNImpl(r); }
+ static bool isInfinity(real_t r) { return isInfinityImpl(r); }
+
+ static int sprint(char* str, char fmt, real_t x)
+ {
+ return sprintImpl(str, fmt, x);
+ }
+}
diff --git a/ddmd/root/ctfloat.h b/ddmd/root/ctfloat.h
new file mode 100644
index 0000000..addbc0a
--- /dev/null
+++ b/ddmd/root/ctfloat.h
@@ -0,0 +1,56 @@
+//===-- ddmd/root/ctfloat.h - CTFloat implementation for LDC ---*- C++ -*-===//
+//
+// LDC - the LLVM D compiler
+//
+// This file is distributed under the BSD-style LDC license. See the LICENSE
+// file for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Front-end compile-time floating-point implementation for LDC.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CTFLOAT_H
+#define CTFLOAT_H
+
+#include "gen/real_t.h"
+
+// Type used by the front-end for compile-time reals
+typedef ldc::real_t real_t;
+
+// Compile-time floating-point helper
+struct CTFloat
+{
+ static bool yl2x_supported;
+ static bool yl2xp1_supported;
+
+ static void yl2x(const real_t *x, const real_t *y, real_t *res);
+ static void yl2xp1(const real_t *x, const real_t *y, real_t *res);
+
+ static real_t parse(const char *literal, bool *isOutOfRange = NULL);
+
+ static real_t sinImpl(const real_t &x);
+ static real_t cosImpl(const real_t &x);
+ static real_t tanImpl(const real_t &x);
+ static real_t sqrtImpl(const real_t &x);
+ static real_t fabsImpl(const real_t &x);
+
+ // additional LDC built-ins
+ static real_t logImpl(const real_t &x);
+ static real_t fminImpl(const real_t &l, const real_t &r);
+ static real_t fmaxImpl(const real_t &l, const real_t &r);
+ static real_t floorImpl(const real_t &x);
+ static real_t ceilImpl(const real_t &x);
+ static real_t truncImpl(const real_t &x);
+ static real_t roundImpl(const real_t &x);
+
+ static bool isIdenticalImpl(const real_t &a, const real_t &b);
+ static bool isNaNImpl(const real_t &r);
+ static bool isSNaNImpl(const real_t &r);
+ static bool isInfinityImpl(const real_t &r);
+
+ static int sprintImpl(char *str, char fmt, const real_t &x);
+};
+
+#endif
diff --git a/ddmd/root/longdouble.d b/ddmd/root/longdouble.d
deleted file mode 100644
index 13ee673..0000000
--- a/ddmd/root/longdouble.d
+++ /dev/null
@@ -1,15 +0,0 @@
-// Compiler implementation of the D programming language
-// Copyright (c) 1999-2015 by Digital Mars
-// All Rights Reserved
-// written by Walter Bright
-// http://www.digitalmars.com
-// Distributed under the Boost Software License, Version 1.0.
-// http://www.boost.org/LICENSE_1_0.txt
-
-module ddmd.root.longdouble;
-
-real ldouble(T)(T x)
-{
- return cast(real)x;
-}
-
diff --git a/ddmd/root/port.d b/ddmd/root/port.d
index dff213d..c5b5d8f 100644
--- a/ddmd/root/port.d
+++ b/ddmd/root/port.d
@@ -1,5 +1,5 @@
// Compiler implementation of the D programming language
-// Copyright (c) 1999-2015 by Digital Mars
+// Copyright (c) 1999-2016 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
@@ -9,104 +9,26 @@
module ddmd.root.port;
import core.stdc.ctype;
-import core.stdc.string;
-import core.stdc.stdio;
import core.stdc.errno;
-import core.math;
-
-version(CRuntime_DigitalMars) __gshared extern (C) extern const(char)* __locale_decpoint;
-version(CRuntime_Microsoft) extern(C++) struct longdouble { real r; }
-version(CRuntime_Microsoft) extern(C++) size_t ld_sprint(char* str, int fmt, longdouble x);
-
-extern (C) float strtof(const(char)* p, char** endp);
-extern (C) double strtod(const(char)* p, char** endp);
-
-version(IN_LLVM_MSVC)
- extern (C) double strtold(const(char)* p, char** endp);
-else
-version(CRuntime_Microsoft)
- extern (C++) longdouble strtold_dm(const(char)* p, char** endp);
-else
- extern (C) real strtold(const(char)* p, char** endp);
-
-version(CRuntime_Microsoft)
-{
- enum _OVERFLOW = 3; /* overflow range error */
- enum _UNDERFLOW = 4; /* underflow range error */
-
- extern (C) int _atoflt(float* value, const char * str);
- extern (C) int _atodbl(double* value, const char * str);
-}
+import core.stdc.stdio;
+import core.stdc.stdlib;
-extern (C++) struct Port
+private extern (C)
{
- enum nan = double.nan;
- enum infinity = double.infinity;
- version(IN_LLVM_MSVC)
- private alias ldbl = double;
- else
- private alias ldbl = real;
-
- version(IN_LLVM)
- {
- enum ldbl_min_normal = ldbl.min_normal;
- enum ldbl_max = ldbl.max;
- enum ldbl_nan = ldbl.nan;
- enum ldbl_infinity = ldbl.infinity;
- enum ldbl_dig = ldbl.dig;
- enum ldbl_epsilon = ldbl.epsilon;
- enum ldbl_mant_dig = ldbl.mant_dig;
- enum ldbl_max_10_exp = ldbl.max_10_exp;
- enum ldbl_max_exp = ldbl.max_exp;
- enum ldbl_min_10_exp = ldbl.min_10_exp;
- enum ldbl_min_exp = ldbl.min_exp;
- }
- else
- {
- enum ldbl_max = real.max;
- enum ldbl_nan = real.nan;
- enum ldbl_infinity = real.infinity;
- }
- version(IN_LLVM)
- {
- static __gshared bool yl2x_supported = false;
- static __gshared bool yl2xp1_supported = false;
- }
- else
- version(DigitalMars)
- {
- static __gshared bool yl2x_supported = true;
- static __gshared bool yl2xp1_supported = true;
- }
- else
- {
- static __gshared bool yl2x_supported = false;
- static __gshared bool yl2xp1_supported = false;
- }
- static __gshared real snan;
-
- static bool isNan(double r)
- {
- return !(r == r);
- }
-
- static real sqrt(real x)
- {
- return .sqrt(x);
- }
+ version(CRuntime_DigitalMars) __gshared extern const(char)* __locale_decpoint;
- static real fmodl(real a, real b)
+ version(CRuntime_Microsoft)
{
- return a % b;
- }
+ enum _OVERFLOW = 3; /* overflow range error */
+ enum _UNDERFLOW = 4; /* underflow range error */
- static bool fequal(real a, real b)
- {
- // don't compare pad bytes in extended precision
- enum sz = (real.mant_dig == 64) ? 10 : real.sizeof;
- return memcmp(&a, &b, sz) == 0;
+ int _atoflt(float* value, const(char)* str);
+ int _atodbl(double* value, const(char)* str);
}
+}
+extern (C++) struct Port
+{
static int memicmp(const char* s1, const char* s2, size_t n)
{
int result = 0;
@@ -140,165 +62,54 @@ extern (C++) struct Port
return t;
}
- static int isSignallingNan(double r)
- {
- return isNan(r) && !(((cast(ubyte*)&r)[6]) & 8);
- }
-
- static int isSignallingNan(real r)
- {
- return isNan(r) && !(((cast(ubyte*)&r)[7]) & 0x40);
- }
-
- version(CRuntime_Microsoft)
- {
- static int isSignallingNan(longdouble ld)
- {
- return isSignallingNan(*cast(real*)&ld);
- }
- }
-
- static int isInfinity(double r)
+ static bool isFloat32LiteralOutOfRange(const(char)* s)
{
- return r is double.infinity || r is -double.infinity;
- }
-
- static float strtof(const(char)* p, char** endp)
- {
- version (CRuntime_DigitalMars)
+ errno = 0;
+ version(CRuntime_DigitalMars)
{
auto save = __locale_decpoint;
__locale_decpoint = ".";
}
- version (CRuntime_Microsoft)
+ version(CRuntime_Microsoft)
{
float r;
- if(endp)
- {
- r = .strtod(p, endp); // does not set errno for underflows, but unused
- }
- else
- {
- int res = _atoflt(&r, p);
- if (res == _UNDERFLOW || res == _OVERFLOW)
- errno = ERANGE;
- }
+ int res = _atoflt(&r, s);
+ if (res == _UNDERFLOW || res == _OVERFLOW)
+ errno = ERANGE;
}
else
{
- auto r = .strtof(p, endp);
+ strtof(s, null);
}
- version (CRuntime_DigitalMars) __locale_decpoint = save;
- return r;
+ version(CRuntime_DigitalMars) __locale_decpoint = save;
+ return errno == ERANGE;
}
- static double strtod(const(char)* p, char** endp)
+ static bool isFloat64LiteralOutOfRange(const(char)* s)
{
- version (CRuntime_DigitalMars)
+ errno = 0;
+ version(CRuntime_DigitalMars)
{
auto save = __locale_decpoint;
__locale_decpoint = ".";
}
- version (CRuntime_Microsoft)
- {
- double r;
- if(endp)
- {
- r = .strtod(p, endp); // does not set errno for underflows, but unused
- }
- else
- {
- int res = _atodbl(&r, p);
- if (res == _UNDERFLOW || res == _OVERFLOW)
- errno = ERANGE;
- }
- }
- else
- {
- auto r = .strtod(p, endp);
- }
- version (CRuntime_DigitalMars) __locale_decpoint = save;
- return r;
- }
-
- static real strtold(const(char)* p, char** endp)
- {
- version (CRuntime_DigitalMars)
- {
- auto save = __locale_decpoint;
- __locale_decpoint = ".";
- }
-
- version(IN_LLVM_MSVC)
- auto r = .strtold(p, endp); // C99 conformant since VS 2015
- else
- version (CRuntime_Microsoft)
- auto r = .strtold_dm(p, endp).r;
- else
- auto r = .strtold(p, endp);
- version (CRuntime_DigitalMars) __locale_decpoint = save;
- return r;
- }
-
- static size_t ld_sprint(char* str, int fmt, real x)
- {
- version(IN_LLVM_MSVC)
- {
- if ((cast(real)cast(ulong)x) == x)
- {
- // ((1.5 -> 1 -> 1.0) == 1.5) is false
- // ((1.0 -> 1 -> 1.0) == 1.0) is true
- // see http://en.cppreference.com/w/cpp/io/c/fprintf
- char[4] sfmt = "%#g\0";
- sfmt[2] = cast(char)fmt;
- return sprintf(str, sfmt.ptr, double(x));
- }
- else
- {
- char[3] sfmt = "%g\0";
- sfmt[1] = cast(char)fmt;
- return sprintf(str, sfmt.ptr, double(x));
- }
- }
- else
version(CRuntime_Microsoft)
{
- return .ld_sprint(str, fmt, longdouble(x));
+ double r;
+ int res = _atodbl(&r, s);
+ if (res == _UNDERFLOW || res == _OVERFLOW)
+ errno = ERANGE;
}
else
{
- if ((cast(real)cast(ulong)x) == x)
- {
- // ((1.5 -> 1 -> 1.0) == 1.5) is false
- // ((1.0 -> 1 -> 1.0) == 1.0) is true
- // see http://en.cppreference.com/w/cpp/io/c/fprintf
- char[5] sfmt = "%#Lg\0";
- sfmt[3] = cast(char)fmt;
- return sprintf(str, sfmt.ptr, x);
- }
- else
- {
- char[4] sfmt = "%Lg\0";
- sfmt[2] = cast(char)fmt;
- return sprintf(str, sfmt.ptr, x);
- }
+ /* Should do our own strtod(), since dmc and linux gcc
+ * accept 2.22507e-308, while apple gcc will only take
+ * 2.22508e-308. Not sure who is right.
+ */
+ strtod(s, null);
}
- }
-
- static void yl2x_impl(real* x, real* y, real* res)
- {
- version(DigitalMars)
- *res = yl2x(*x, *y);
- version(IN_LLVM)
- assert(0);
- }
-
- static void yl2xp1_impl(real* x, real* y, real* res)
- {
- version(DigitalMars)
- *res = yl2xp1(*x, *y);
- version(IN_LLVM)
- assert(0);
+ version(CRuntime_DigitalMars) __locale_decpoint = save;
+ return errno == ERANGE;
}
// Little endian
@@ -349,29 +160,28 @@ extern (C++) struct Port
return (p[0] << 8) | p[1];
}
- version(IN_LLVM)
- { // LDC_FIXME: look at the old port.c how to implement this with system calls for some OSses
- static int stricmp(const(char)* s1, const(char)* s2)
+version(IN_LLVM)
+{
+ static int stricmp(const(char)* s1, const(char)* s2)
+ {
+ int result = 0;
+ for (;;)
{
- int result = 0;
-
- for (;;)
- { char c1 = *s1;
- char c2 = *s2;
+ const c1 = *s1++;
+ const c2 = *s2++;
- result = c1 - c2;
+ result = c1 - c2;
+ if (result)
+ {
+ result = toupper(c1) - toupper(c2);
if (result)
- {
- result = toupper(c1) - toupper(c2);
- if (result)
- break;
- }
- if (!c1)
break;
- s1++;
- s2++;
}
- return result;
+ if (!c1)
+ break;
}
+ return result;
}
}
+
+}
diff --git a/ddmd/root/port.h b/ddmd/root/port.h
index e3b06ef..a94d720 100644
--- a/ddmd/root/port.h
+++ b/ddmd/root/port.h
@@ -1,5 +1,5 @@
-/* Copyright (c) 1999-2014 by Digital Mars
+/* Copyright (c) 1999-2016 by Digital Mars
* All Rights Reserved, written by Walter Bright
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
@@ -20,8 +20,6 @@
#endif
#include <stdint.h>
-#include "longdouble.h"
-
#if _MSC_VER
#include <alloca.h>
typedef __int64 longlong;
@@ -35,50 +33,22 @@ typedef unsigned char utf8_t;
struct Port
{
- static double nan;
- static longdouble ldbl_nan;
- static longdouble snan;
-
- static double infinity;
- static longdouble ldbl_infinity;
-
- static double dbl_max;
- static double dbl_min;
- static longdouble ldbl_max;
-
- static bool yl2x_supported;
- static bool yl2xp1_supported;
-
- static int isNan(double);
- static int isNan(longdouble);
-
- static int isSignallingNan(double);
- static int isSignallingNan(longdouble);
-
- static int isInfinity(double);
-
- static longdouble fmodl(longdouble x, longdouble y);
- static longdouble sqrt(longdouble x);
- static int fequal(longdouble x, longdouble y);
+ static int memicmp(const char *s1, const char *s2, int n);
+ static char *strupr(char *s);
- static void yl2x_impl(longdouble* x, longdouble* y, longdouble* res);
- static void yl2xp1_impl(longdouble* x, longdouble* y, longdouble* res);
+ static bool isFloat32LiteralOutOfRange(const char *s);
+ static bool isFloat64LiteralOutOfRange(const char *s);
- static char *strupr(char *);
+ static void writelongLE(unsigned value, void *buffer);
+ static unsigned readlongLE(void *buffer);
+ static void writelongBE(unsigned value, void *buffer);
+ static unsigned readlongBE(void *buffer);
+ static unsigned readwordLE(void *buffer);
+ static unsigned readwordBE(void *buffer);
- static int memicmp(const char *s1, const char *s2, int n);
+#ifdef IN_LLVM
static int stricmp(const char *s1, const char *s2);
-
- static float strtof(const char *p, char **endp);
- static double strtod(const char *p, char **endp);
- static longdouble strtold(const char *p, char **endp);
-
- static void writelongLE(unsigned value, void* buffer);
- static unsigned readlongLE(void* buffer);
- static void writelongBE(unsigned value, void* buffer);
- static unsigned readlongBE(void* buffer);
- static unsigned readwordLE(void* buffer);
- static unsigned readwordBE(void* buffer);
+#endif
};
#endif
diff --git a/ddmd/root/real_t.d b/ddmd/root/real_t.d
new file mode 100644
index 0000000..799036e
--- /dev/null
+++ b/ddmd/root/real_t.d
@@ -0,0 +1,109 @@
+//===-- real_t.d ----------------------------------------------------------===//
+//
+// LDC - the LLVM D compiler
+//
+// This file is distributed under the BSD-style LDC license. See the LICENSE
+// file for details.
+//
+//===----------------------------------------------------------------------===//
+
+module ddmd.root.real_t;
+
+private struct APFloatPrototype
+{
+ void* semantics;
+ union
+ {
+ long part;
+ long* parts;
+ }
+ short exponent;
+ int categoryAndSign;
+}
+
+extern (C++, ldc) struct real_t
+{
+ this(float f) { initFrom(f); }
+ this(double f) { initFrom(f); }
+ this(int i) { initFrom(i); }
+ this(long i) { initFrom(i); }
+ this(uint i) { initFrom(i); }
+ this(ulong i) { initFrom(i); }
+
+ bool toBool() const;
+ float toFloat32() const;
+ double toFloat64() const;
+ int toInt32() const;
+ long toInt64() const;
+ uint toUInt32() const;
+ ulong toUInt64() const;
+
+ extern(D) T opCast(T)() const
+ {
+ static if (is(T == bool)) return toBool();
+ else static if (is(T == float)) return toFloat();
+ else static if (is(T == double)) return toDouble();
+ else static if (is(T == int)) return toInt32();
+ else static if (is(T == long)) return toInt64();
+ else static if (is(T == uint)) return toUInt32();
+ else static if (is(T == ulong)) return toUInt64();
+ else static assert(0, "Trying to cast real_t to unsupported type");
+ }
+
+ // arithmetic operators
+ real_t opNeg() const;
+ real_t add(const ref real_t r) const;
+ real_t sub(const ref real_t r) const;
+ real_t mul(const ref real_t r) const;
+ real_t div(const ref real_t r) const;
+ real_t mod(const ref real_t r) const;
+
+ // D binary operators (for rvalues)
+ extern(D) real_t opBinary(string op)(real_t r) const
+ {
+ static if (op == "+") return add(r);
+ else static if (op == "-") return sub(r);
+ else static if (op == "*") return mul(r);
+ else static if (op == "/") return div(r);
+ else static if (op == "%") return mod(r);
+ else static assert(0, "Unsupported binary operator");
+ }
+
+ // comparison
+ int cmp(const ref real_t r) const;
+
+ extern(D) int opCmp(real_t r) const { return cmp(r); }
+ extern(D) bool opEquals(real_t r) const { return cmp(r) == 0; }
+
+ // D lifetime
+ extern(D) this(this) { postblit(); }
+ extern(D) void opAssign(real_t r) { moveAssign(r); }
+ extern(D) ~this() { destruct(); }
+
+private:
+ // non-trivial llvm::APFloat, the hard way:
+ union
+ {
+ byte[APFloatPrototype.sizeof] value = void;
+ long for_alignment_only = void;
+
+ // Designate default-constructed real_t instances in D (with invalid
+ // APFloat values) by initializing the pointer at the beginning with
+ // null.
+ // See comment in C++ header.
+ void* valueSemantics = null;
+ }
+
+ void initFrom(float f);
+ void initFrom(double f);
+ void initFrom(int i);
+ void initFrom(long i);
+ void initFrom(uint i);
+ void initFrom(ulong i);
+
+ bool isInitialized() const;
+ void safeInit();
+ void postblit();
+ void moveAssign(ref real_t r);
+ void destruct();
+}
diff --git a/ddmd/target.d b/ddmd/target.d
index fd307de..f6a806a 100644
--- a/ddmd/target.d
+++ b/ddmd/target.d
@@ -14,7 +14,7 @@ import ddmd.expression;
import ddmd.globals;
import ddmd.identifier;
import ddmd.mtype;
-import ddmd.root.longdouble;
+import ddmd.root.ctfloat;
import ddmd.root.outbuffer;
version(IN_LLVM)
@@ -31,6 +31,49 @@ extern(C++) struct Target
static __gshared int c_long_doublesize; // size of a C 'long double'
static __gshared int classinfosize; // size of 'ClassInfo'
+ extern(D) template FPTypeProperties(T)
+ {
+ static real_t max() { return real_t(T.max); }
+ static real_t min_normal() { return real_t(T.min_normal); }
+ static real_t nan() { return real_t(T.nan); }
+ static real_t snan() { return real_t(T.init); }
+ static real_t infinity() { return real_t(T.infinity); }
+ static real_t epsilon() { return real_t(T.epsilon); }
+
+ enum : long
+ {
+ dig = T.dig,
+ mant_dig = T.mant_dig,
+ max_exp = T.max_exp,
+ min_exp = T.min_exp,
+ max_10_exp = T.max_10_exp,
+ min_10_exp = T.min_10_exp
+ }
+ }
+
+ alias FloatProperties = FPTypeProperties!float;
+ alias DoubleProperties = FPTypeProperties!double;
+
+ static struct RealProperties
+ {
+ static __gshared
+ {
+ real_t max = void;
+ real_t min_normal = void;
+ real_t nan = void;
+ real_t snan = void;
+ real_t infinity = void;
+ real_t epsilon = void;
+
+ long dig;
+ long mant_dig;
+ long max_exp;
+ long min_exp;
+ long max_10_exp;
+ long min_10_exp;
+ }
+ }
+
static void _init();
// Type sizes and support.
static uint alignsize(Type type);
@@ -62,6 +105,33 @@ struct Target
extern (C++) static __gshared int c_long_doublesize; // size of a C 'long double'
extern (C++) static __gshared int classinfosize; // size of 'ClassInfo'
+ template FPTypeProperties(T)
+ {
+ enum : real_t
+ {
+ max = T.max,
+ min_normal = T.min_normal,
+ nan = T.nan,
+ snan = T.init,
+ infinity = T.infinity,
+ epsilon = T.epsilon
+ }
+
+ enum : long
+ {
+ dig = T.dig,
+ mant_dig = T.mant_dig,
+ max_exp = T.max_exp,
+ min_exp = T.min_exp,
+ max_10_exp = T.max_10_exp,
+ min_10_exp = T.min_10_exp
+ }
+ }
+
+ alias FloatProperties = FPTypeProperties!float;
+ alias DoubleProperties = FPTypeProperties!double;
+ alias RealProperties = FPTypeProperties!real;
+
extern (C++) static void _init()
{
// These have default values for 32 bit code, they get
@@ -355,7 +425,7 @@ extern (C++) static Expression decodeInteger(Loc loc, Type type, ubyte* buffer)
return new IntegerExp(loc, value, type);
}
-// Write the real value of 'e' into a unsigned byte buffer.
+// Write the real_t value of 'e' into a unsigned byte buffer.
extern (C++) static void encodeReal(Expression e, ubyte* buffer)
{
switch (e.type.ty)
@@ -377,23 +447,23 @@ extern (C++) static void encodeReal(Expression e, ubyte* buffer)
}
}
-// Write the bytes encoded in 'buffer' into a longdouble and returns
+// Write the bytes encoded in 'buffer' into a real_t and returns
// the value as a new RealExp.
extern (C++) static Expression decodeReal(Loc loc, Type type, ubyte* buffer)
{
- real value;
+ real_t value;
switch (type.ty)
{
case Tfloat32:
{
float* p = cast(float*)buffer;
- value = ldouble(*p);
+ value = real_t(*p);
break;
}
case Tfloat64:
{
double* p = cast(double*)buffer;
- value = ldouble(*p);
+ value = real_t(*p);
break;
}
default:
diff --git a/ddmd/target.h b/ddmd/target.h
index 9860439..ba162a1 100644
--- a/ddmd/target.h
+++ b/ddmd/target.h
@@ -33,6 +33,14 @@ struct Target
static int c_long_doublesize; // size of a C 'long double'
static int classinfosize; // size of 'ClassInfo'
+#ifdef IN_LLVM
+ struct RealProperties
+ {
+ static real_t max, min_normal, nan, snan, infinity, epsilon;
+ static int64_t dig, mant_dig, max_exp, min_exp, max_10_exp, min_10_exp;
+ };
+#endif
+
static void _init();
// Type sizes and support.
static unsigned alignsize(Type* type);
diff --git a/ddmd/tokens.d b/ddmd/tokens.d
index 5422855..c811234 100644
--- a/ddmd/tokens.d
+++ b/ddmd/tokens.d
@@ -14,7 +14,7 @@ import core.stdc.string;
import ddmd.globals;
import ddmd.id;
import ddmd.identifier;
-import ddmd.root.port;
+import ddmd.root.ctfloat;
import ddmd.root.outbuffer;
import ddmd.root.rmem;
import ddmd.utf;
@@ -565,7 +565,8 @@ extern (C++) struct Token
d_int64 int64value;
d_uns64 uns64value;
// Floats
- d_float80 float80value;
+ version(IN_LLVM) {} else
+ real_t floatvalue;
struct
{
@@ -577,6 +578,11 @@ extern (C++) struct Token
Identifier ident;
}
+ version(IN_LLVM)
+ {
+ real_t floatvalue;
+ }
+
static __gshared const(char)*[TOKMAX] tochars;
static this()
@@ -739,7 +745,7 @@ extern (C++) struct Token
extern (C++) const(char)* toChars()
{
- __gshared char[3 + 3 * float80value.sizeof + 1] buffer;
+ __gshared char[3 + 3 * floatvalue.sizeof + 1] buffer;
const(char)* p = &buffer[0];
switch (value)
{
@@ -759,26 +765,26 @@ extern (C++) struct Token
sprintf(&buffer[0], "%lluUL", cast(ulong)uns64value);
break;
case TOKfloat32v:
- Port.ld_sprint(&buffer[0], 'g', float80value);
+ CTFloat.sprint(&buffer[0], 'g', floatvalue);
strcat(&buffer[0], "f");
break;
case TOKfloat64v:
- Port.ld_sprint(&buffer[0], 'g', float80value);
+ CTFloat.sprint(&buffer[0], 'g', floatvalue);
break;
case TOKfloat80v:
- Port.ld_sprint(&buffer[0], 'g', float80value);
+ CTFloat.sprint(&buffer[0], 'g', floatvalue);
strcat(&buffer[0], "L");
break;
case TOKimaginary32v:
- Port.ld_sprint(&buffer[0], 'g', float80value);
+ CTFloat.sprint(&buffer[0], 'g', floatvalue);
strcat(&buffer[0], "fi");
break;
case TOKimaginary64v:
- Port.ld_sprint(&buffer[0], 'g', float80value);
+ CTFloat.sprint(&buffer[0], 'g', floatvalue);
strcat(&buffer[0], "i");
break;
case TOKimaginary80v:
- Port.ld_sprint(&buffer[0], 'g', float80value);
+ CTFloat.sprint(&buffer[0], 'g', floatvalue);
strcat(&buffer[0], "Li");
break;
case TOKstring:
diff --git a/ddmd/tokens.h b/ddmd/tokens.h
index f55e6b4..0581a8e 100644
--- a/ddmd/tokens.h
+++ b/ddmd/tokens.h
@@ -205,7 +205,9 @@ struct Token
d_uns64 uns64value;
// Floats
- d_float80 float80value;
+#if !defined(IN_LLVM)
+ real_t floatvalue;
+#endif
struct
{ utf8_t *ustring; // UTF8 string
@@ -216,6 +218,10 @@ struct Token
Identifier *ident;
};
+#ifdef IN_LLVM
+ real_t floatvalue = real_t(0);
+#endif
+
static const char *tochars[TOKMAX];
static void initTokens();
diff --git a/driver/main.cpp b/driver/main.cpp
index ca3a8d8..1015ebb 100644
--- a/driver/main.cpp
+++ b/driver/main.cpp
@@ -1013,6 +1013,7 @@ int cppmain(int argc, char **argv) {
// Initialization
Type::_init();
+ ldc::real_t::_init();
Id::initialize();
Module::_init();
Target::_init();
diff --git a/gen/abi-arm.cpp b/gen/abi-arm.cpp
index 957e3ef..2ec8915 100644
--- a/gen/abi-arm.cpp
+++ b/gen/abi-arm.cpp
@@ -17,6 +17,7 @@
#include "gen/abi.h"
#include "gen/abi-generic.h"
#include "gen/abi-arm.h"
+#include "llvm/Target/TargetMachine.h"
struct ArmTargetABI : TargetABI {
HFAToArray hfaToArray;
@@ -39,7 +40,9 @@ struct ArmTargetABI : TargetABI {
return rt->ty == Tsarray || rt->ty == Tstruct;
return rt->ty == Tsarray ||
- (rt->ty == Tstruct && rt->size() > 4 && !isHFA((TypeStruct *)rt));
+ (rt->ty == Tstruct && rt->size() > 4 &&
+ (gTargetMachine->Options.FloatABIType == llvm::FloatABI::Soft ||
+ !isHFA((TypeStruct *)rt)));
}
bool passByVal(Type *t) override {
diff --git a/gen/asm-x86.h b/gen/asm-x86.h
index fb96da5..9764ca8 100644
--- a/gen/asm-x86.h
+++ b/gen/asm-x86.h
@@ -2006,7 +2006,7 @@ typedef enum { Opr_Invalid, Opr_Immediate, Opr_Reg, Opr_Mem } OperandClass;
// mov eax, fs:4
// -- have to assume we know whether or not to use '$'
-static Token eof_tok;
+static Token *eof_tok;
static Expression *Handled;
static Identifier *ident_seg;
@@ -2074,8 +2074,11 @@ struct AsmProcessor {
ident_seg = Identifier::idPool("seg");
- eof_tok.value = TOKeof;
- eof_tok.next = nullptr;
+ if (!eof_tok) {
+ eof_tok = new Token();
+ eof_tok->value = TOKeof;
+ eof_tok->next = nullptr;
+ }
}
}
@@ -2085,7 +2088,7 @@ struct AsmProcessor {
if (token->next) {
token = token->next;
} else {
- token = &eof_tok;
+ token = eof_tok;
}
}
@@ -2093,7 +2096,7 @@ struct AsmProcessor {
if (token->next) {
return token->next;
}
- return &eof_tok;
+ return eof_tok;
}
void expectEnd() {
@@ -3716,7 +3719,7 @@ struct AsmProcessor {
case TOKfloat64v:
case TOKfloat80v:
// %% need different types?
- e = createRealExp(stmt->loc, token->float80value, Type::tfloat80);
+ e = createRealExp(stmt->loc, token->floatvalue, Type::tfloat80);
nextToken();
break;
case TOKidentifier: {
@@ -3937,7 +3940,7 @@ struct AsmProcessor {
if (token->value == TOKfloat32v || token->value == TOKfloat64v ||
token->value == TOKfloat80v) {
long words[3];
- real_to_target(words, & token->float80value.rv(), mode);
+ real_to_target(words, & token->floatvalue.rv(), mode);
// don't use directives..., just use .long like GCC
insnTemplate->printf(".long\t%u", words[0]);
if (mode != SFmode)
diff --git a/gen/complex.cpp b/gen/complex.cpp
index ec8a924..851e431 100644
--- a/gen/complex.cpp
+++ b/gen/complex.cpp
@@ -41,7 +41,8 @@ LLType *DtoComplexBaseType(Type *t) {
////////////////////////////////////////////////////////////////////////////////
-LLConstant *DtoConstComplex(Type *_ty, longdouble re, longdouble im) {
+LLConstant *DtoConstComplex(Type *_ty, const ldc::real_t &re,
+ const ldc::real_t &im) {
Type *base = nullptr;
switch (_ty->toBasetype()->ty) {
default:
diff --git a/gen/complex.h b/gen/complex.h
index b3c58b9..ecc404c 100644
--- a/gen/complex.h
+++ b/gen/complex.h
@@ -14,8 +14,8 @@
#ifndef LDC_GEN_COMPLEX_H
#define LDC_GEN_COMPLEX_H
+#include "ctfloat.h"
#include "tokens.h"
-#include "longdouble.h"
class DValue;
struct Loc;
@@ -30,7 +30,8 @@ class Value;
llvm::StructType *DtoComplexType(Type *t);
llvm::Type *DtoComplexBaseType(Type *t);
-llvm::Constant *DtoConstComplex(Type *t, longdouble re, longdouble im);
+llvm::Constant *DtoConstComplex(Type *t, const ldc::real_t &re,
+ const ldc::real_t &im);
llvm::Constant *DtoComplexShuffleMask(unsigned a, unsigned b);
diff --git a/gen/ctfloat.cpp b/gen/ctfloat.cpp
new file mode 100644
index 0000000..afd1d82
--- /dev/null
+++ b/gen/ctfloat.cpp
@@ -0,0 +1,178 @@
+//===-- gen/ctfloat.cpp - CTFloat implementation for LDC -------*- C++ -*-===//
+//
+// LDC - the LLVM D compiler
+//
+// This file is distributed under the BSD-style LDC license. See the LICENSE
+// file for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Front-end compile-time floating-point implementation for LDC.
+//
+//===----------------------------------------------------------------------===//
+
+#include "root/ctfloat.h"
+#include "llvm/ADT/SmallString.h"
+#include <cmath>
+
+using llvm::APFloat;
+
+namespace {
+
+real_t fromHostReal(long double x) {
+ char buffer[64];
+ sprintf(buffer, "%La", x);
+ return CTFloat::parse(buffer);
+}
+
+long double toHostReal(const real_t &x) {
+ char buffer[64];
+ CTFloat::sprintImpl(buffer, 'a', x);
+ return strtold(buffer, nullptr);
+}
+
+}
+
+real_t CTFloat::sinImpl(const real_t &x) {
+ if (&real_t::getSemantics() == &APFloat::IEEEdouble)
+ return std::sin(x.toDouble());
+ return fromHostReal(std::sin(toHostReal(x)));
+}
+
+real_t CTFloat::cosImpl(const real_t &x) {
+ if (&real_t::getSemantics() == &APFloat::IEEEdouble)
+ return std::cos(x.toDouble());
+ return fromHostReal(std::cos(toHostReal(x)));
+}
+
+real_t CTFloat::tanImpl(const real_t &x) {
+ if (&real_t::getSemantics() == &APFloat::IEEEdouble)
+ return std::tan(x.toDouble());
+ return fromHostReal(std::tan(toHostReal(x)));
+}
+
+real_t CTFloat::sqrtImpl(const real_t &x) {
+ if (&real_t::getSemantics() == &APFloat::IEEEdouble)
+ return std::sqrt(x.toDouble());
+ return fromHostReal(std::sqrt(toHostReal(x)));
+}
+
+real_t CTFloat::fabsImpl(const real_t &x) {
+ if (x.value.isNegative()) {
+ auto f = x.value;
+ f.changeSign();
+ return f;
+ }
+ return x;
+}
+
+// additional LDC built-ins:
+real_t CTFloat::logImpl(const real_t &x) {
+ if (&real_t::getSemantics() == &APFloat::IEEEdouble)
+ return std::log(x.toDouble());
+ return fromHostReal(std::log(toHostReal(x)));
+}
+
+real_t CTFloat::fminImpl(const real_t &l, const real_t &r) {
+ if (&real_t::getSemantics() == &APFloat::IEEEdouble)
+ return std::fmin(l.toDouble(), r.toDouble());
+ return fromHostReal(std::fmin(toHostReal(l), toHostReal(r)));
+}
+
+real_t CTFloat::fmaxImpl(const real_t &l, const real_t &r) {
+ if (&real_t::getSemantics() == &APFloat::IEEEdouble)
+ return std::fmax(l.toDouble(), r.toDouble());
+ return fromHostReal(std::fmax(toHostReal(l), toHostReal(r)));
+}
+
+real_t CTFloat::floorImpl(const real_t &x) {
+ if (&real_t::getSemantics() == &APFloat::IEEEdouble)
+ return std::floor(x.toDouble());
+ return fromHostReal(std::floor(toHostReal(x)));
+}
+
+real_t CTFloat::ceilImpl(const real_t &x) {
+ if (&real_t::getSemantics() == &APFloat::IEEEdouble)
+ return std::ceil(x.toDouble());
+ return fromHostReal(std::ceil(toHostReal(x)));
+}
+
+real_t CTFloat::truncImpl(const real_t &x) {
+ if (&real_t::getSemantics() == &APFloat::IEEEdouble)
+ return std::trunc(x.toDouble());
+ return fromHostReal(std::trunc(toHostReal(x)));
+}
+
+real_t CTFloat::roundImpl(const real_t &x) {
+ if (&real_t::getSemantics() == &APFloat::IEEEdouble)
+ return std::round(x.toDouble());
+ return fromHostReal(std::round(toHostReal(x)));
+}
+
+bool CTFloat::isIdenticalImpl(const real_t &a, const real_t &b) {
+ return a.value.bitwiseIsEqual(b.value);
+}
+bool CTFloat::isNaNImpl(const real_t &r) { return r.value.isNaN(); }
+bool CTFloat::isSNaNImpl(const real_t &r) { return r.value.isSignaling(); }
+bool CTFloat::isInfinityImpl(const real_t &r) { return r.value.isInfinity(); }
+
+real_t CTFloat::parse(const char *literal, bool *isOutOfRange) {
+ APFloat x(real_t::getSemantics(), APFloat::uninitialized);
+ auto status = x.convertFromString(literal, APFloat::rmNearestTiesToEven);
+ if (isOutOfRange) {
+ *isOutOfRange =
+ (status == APFloat::opOverflow || status == APFloat::opUnderflow);
+ }
+ return x;
+}
+
+int CTFloat::sprintImpl(char *str, char fmt, const real_t &x) {
+ // The signature of this method leads to buffer overflows.
+ if (fmt == 'a' || fmt == 'A') {
+ return x.value.convertToHexString(str, 0, fmt == 'A',
+ APFloat::rmNearestTiesToEven);
+ }
+
+ assert(fmt == 'g');
+ llvm::SmallString<64> buf;
+ // printf's default precision is 6 digits
+ constexpr int precision = 6;
+ x.value.toString(buf, precision);
+
+ // post-processing for printf compatibility
+ if (x.value.isFinite()) {
+ int exponentIndex = -1;
+ bool hasDecimalPoint = false;
+ for (size_t i = 0; i < buf.size(); ++i) {
+ auto &c = buf[i];
+ if (c == 'E') {
+ c = 'e'; // lower case
+ exponentIndex = int(i);
+ } else if (c == '.') {
+ hasDecimalPoint = true;
+ }
+ }
+
+ if (exponentIndex != -1) {
+ // printf prints at least 2 exponent digits
+ // "1.5e+3" => "1.5e+03"
+ int firstExponentDigitIndex = exponentIndex + 2; // past "e±"
+ int numExponentDigits = buf.size() - firstExponentDigitIndex;
+ if (numExponentDigits == 1) {
+ auto digit = buf.back();
+ buf.back() = '0';
+ buf.push_back(digit);
+ }
+ } else if (!hasDecimalPoint) {
+ // LLVM may print the number as integer without ".~E" suffix
+ // "1" => "1.00000", "10" => "10.0000"
+ int numDigits = buf.size() - (buf[0] == '-' ? 1 : 0);
+ buf.push_back('.');
+ if (numDigits < precision)
+ buf.append(precision - numDigits, '0');
+ }
+ }
+
+ strcpy(str, buf.str().str().c_str());
+ return buf.size();
+}
diff --git a/gen/real_t.cpp b/gen/real_t.cpp
new file mode 100644
index 0000000..abd5075
--- /dev/null
+++ b/gen/real_t.cpp
@@ -0,0 +1,257 @@
+//===-- gen/real_t.cpp - Interface of real_t for LDC ------------*- C++ -*-===//
+//
+// LDC - the LLVM D compiler
+//
+// This file is distributed under the BSD-style LDC license. See the LICENSE
+// file for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implements a real_t type for LDC.
+//
+//===----------------------------------------------------------------------===//
+
+#include "globals.h"
+#include "gen/real_t.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/CommandLine.h"
+#include <type_traits>
+
+using llvm::APFloat;
+
+static llvm::cl::opt<bool>
+ longdouble64("long-double-64",
+ llvm::cl::desc("Choose real to be 64bit double"),
+ llvm::cl::ZeroOrMore, llvm::cl::init(false));
+
+namespace ldc {
+
+/*** SEMANTICS ***/
+
+const llvm::fltSemantics *real_t::semantics = nullptr;
+
+void real_t::_init() {
+ const auto &targetTriple = *global.params.targetTriple;
+ if (longdouble64 || targetTriple.isWindowsMSVCEnvironment()) {
+ semantics = &APFloat::IEEEdouble;
+ } else {
+ switch (targetTriple.getArch()) {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ semantics = &APFloat::x87DoubleExtended;
+ break;
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64le:
+ semantics = &APFloat::PPCDoubleDouble;
+ break;
+ default:
+ semantics = &APFloat::IEEEdouble;
+ break;
+ }
+ }
+}
+
+
+
+/*** TYPE CONVERSIONS ***/
+
+template <typename T> void real_t::fromInteger(T i) {
+ const llvm::integerPart tmp(i);
+ value.convertFromSignExtendedInteger(&tmp, 1, std::is_signed<T>::value,
+ APFloat::rmNearestTiesToEven);
+}
+
+template <typename T> T real_t::toInteger() const {
+ llvm::APSInt trunc(8 * sizeof(T), !std::is_signed<T>::value);
+ bool ignored;
+ value.convertToInteger(trunc, APFloat::rmTowardZero, &ignored);
+ return static_cast<T>(std::is_signed<T>::value ? trunc.getSExtValue()
+ : trunc.getZExtValue());
+}
+
+real_t::real_t(float f) : value(f) {
+ bool ignored;
+ auto status = value.convert(getSemantics(), APFloat::rmNearestTiesToEven, &ignored);
+ assert(status == APFloat::opOK);
+}
+
+real_t::real_t(double f) : value(f) {
+ bool ignored;
+ auto status = value.convert(getSemantics(), APFloat::rmNearestTiesToEven, &ignored);
+ assert(status == APFloat::opOK);
+}
+
+real_t::real_t(int32_t i) : value(getSemantics(), APFloat::uninitialized) {
+ fromInteger(i);
+}
+real_t::real_t(int64_t i) : value(getSemantics(), APFloat::uninitialized) {
+ fromInteger(i);
+}
+real_t::real_t(uint32_t i) : value(getSemantics(), APFloat::uninitialized) {
+ fromInteger(i);
+}
+real_t::real_t(uint64_t i) : value(getSemantics(), APFloat::uninitialized) {
+ fromInteger(i);
+}
+
+void real_t::initFrom(float f) { new (this) real_t(f); }
+void real_t::initFrom(double f) { new (this) real_t(f); }
+void real_t::initFrom(int32_t i) { new (this) real_t(i); }
+void real_t::initFrom(int64_t i) { new (this) real_t(i); }
+void real_t::initFrom(uint32_t i) { new (this) real_t(i); }
+void real_t::initFrom(uint64_t i) { new (this) real_t(i); }
+
+bool real_t::toBool() const { return !value.isZero(); }
+
+float real_t::toFloat() const {
+ auto trunc = value;
+ bool ignored;
+ auto status = trunc.convert(APFloat::IEEEsingle, APFloat::rmNearestTiesToEven,
+ &ignored);
+ // assert(status == APFloat::opOK);
+ return trunc.convertToFloat();
+}
+
+double real_t::toDouble() const {
+ auto trunc = value;
+ bool ignored;
+ auto status = trunc.convert(APFloat::IEEEdouble, APFloat::rmNearestTiesToEven,
+ &ignored);
+ // assert(status == APFloat::opOK);
+ return trunc.convertToDouble();
+}
+
+int32_t real_t::toInt32() const { return toInteger<int32_t>(); }
+int64_t real_t::toInt64() const { return toInteger<int64_t>(); }
+uint32_t real_t::toUInt32() const { return toInteger<uint32_t>(); }
+uint64_t real_t::toUInt64() const { return toInteger<uint64_t>(); }
+
+
+
+/*** LIFETIME ***/
+
+bool real_t::isInitialized() const { return valueSemantics != nullptr; }
+
+void real_t::safeInit() { new (this) real_t; }
+
+// C++
+real_t::real_t(const real_t &r) : real_t() {
+ if (r.isInitialized())
+ value = r.value;
+}
+real_t::real_t(real_t &&r) : real_t() {
+ if (r.isInitialized())
+ value = std::move(r.value);
+}
+
+// D
+void real_t::postblit() {
+ if (!isInitialized()) // leave uninitialized if original was too
+ return;
+
+ // this instance is a bitcopy of the right-hand-side
+ // 1) save the bitcopy
+ alignas(alignof(APFloat)) char rhsBitcopy[sizeof(value)];
+ memcpy(rhsBitcopy, &value, sizeof(value));
+ // 2) safely initialize this APFloat
+ safeInit();
+ // 3) assign the bitcopy, i.e., copy the value
+ value = *reinterpret_cast<const APFloat *>(rhsBitcopy);
+ // 4) don't destruct the bitcopy!
+}
+
+// C++
+real_t &real_t::operator=(const real_t &r) {
+ if (!isInitialized())
+ safeInit();
+ if (r.isInitialized())
+ value = r.value;
+ return *this;
+}
+real_t &real_t::operator=(real_t &&r) {
+ moveAssign(r);
+ return *this;
+}
+
+// D
+void real_t::moveAssign(real_t &r) {
+ if (!isInitialized())
+ safeInit();
+ if (r.isInitialized())
+ value = std::move(r.value);
+}
+
+// C++
+real_t::~real_t() { destruct(); }
+
+// D
+void real_t::destruct() {
+ if (isInitialized())
+ value.APFloat::~APFloat();
+}
+
+
+
+/*** ARITHMETIC OPERATORS ***/
+
+#if LDC_LLVM_VER < 306 // no llvm::APFloat operators
+APFloat operator+(const APFloat &l, const APFloat &r) {
+ APFloat x = l;
+ x.add(r, APFloat::rmNearestTiesToEven);
+ return x;
+}
+APFloat operator-(const APFloat &l, const APFloat &r) {
+ APFloat x = l;
+ x.subtract(r, APFloat::rmNearestTiesToEven);
+ return x;
+}
+APFloat operator*(const APFloat &l, const APFloat &r) {
+ APFloat x = l;
+ x.multiply(r, APFloat::rmNearestTiesToEven);
+ return x;
+}
+APFloat operator/(const APFloat &l, const APFloat &r) {
+ APFloat x = l;
+ x.divide(r, APFloat::rmNearestTiesToEven);
+ return x;
+}
+#endif
+
+real_t real_t::opNeg() const {
+ auto tmp = value;
+ tmp.changeSign();
+ return tmp;
+}
+
+real_t real_t::add(const real_t &r) const { return value + r.value; }
+real_t real_t::sub(const real_t &r) const { return value - r.value; }
+real_t real_t::mul(const real_t &r) const { return value * r.value; }
+real_t real_t::div(const real_t &r) const { return value / r.value; }
+real_t real_t::mod(const real_t &r) const {
+ auto x = value;
+#if LDC_LLVM_VER >= 308
+ x.mod(r.value);
+#else
+ x.mod(r.value, APFloat::rmNearestTiesToEven);
+#endif
+ return x;
+}
+
+
+int real_t::cmp(const real_t &r) const {
+ auto res = value.compare(r.value);
+ switch (res) {
+ case APFloat::cmpLessThan:
+ return -1;
+ case APFloat::cmpEqual:
+ return 0;
+ case APFloat::cmpGreaterThan:
+ return 1;
+ default:
+ assert(0);
+ }
+ return 0;
+}
+
+} // namespace ldc
diff --git a/gen/real_t.h b/gen/real_t.h
new file mode 100644
index 0000000..698f0e8
--- /dev/null
+++ b/gen/real_t.h
@@ -0,0 +1,156 @@
+//===-- gen/real_t.h - Interface of real_t for LDC --------------*- C++ -*-===//
+//
+// LDC - the LLVM D compiler
+//
+// This file is distributed under the BSD-style LDC license. See the LICENSE
+// file for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implements a real_t type for LDC.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LDC_GEN_REAL_T_H
+#define LDC_GEN_REAL_T_H
+
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/StringRef.h"
+
+struct CTFloat;
+
+namespace ldc {
+
+struct real_t {
+ friend CTFloat;
+
+ static void _init();
+
+ static const llvm::fltSemantics &getSemantics() { return *semantics; }
+
+ static real_t nan() { return llvm::APFloat::getNaN(getSemantics()); }
+ static real_t snan() { return llvm::APFloat::getSNaN(getSemantics()); }
+ static real_t infinity() { return llvm::APFloat::getInf(getSemantics()); }
+
+
+ real_t(float f);
+ real_t(double f);
+ real_t(int32_t i);
+ real_t(int64_t i);
+ real_t(uint32_t i);
+ real_t(uint64_t i);
+
+ bool toBool() const;
+ float toFloat() const;
+ double toDouble() const;
+ int32_t toInt32() const;
+ int64_t toInt64() const;
+ uint32_t toUInt32() const;
+ uint64_t toUInt64() const;
+
+ operator bool() const { return toBool(); }
+ operator float() const { return toFloat(); }
+ operator double() const { return toDouble(); }
+ operator int32_t() const { return toInt32(); }
+ operator int64_t() const { return toInt64(); }
+ operator uint32_t() const { return toUInt32(); }
+ operator uint64_t() const { return toUInt64(); }
+ operator const llvm::APFloat &() const { return value; }
+
+ // arithmetic operators
+ real_t opNeg() const;
+ real_t add(const real_t &r) const;
+ real_t sub(const real_t &r) const;
+ real_t mul(const real_t &r) const;
+ real_t div(const real_t &r) const;
+ real_t mod(const real_t &r) const;
+
+ // comparison
+ int cmp(const real_t &r) const;
+
+ // C++ lifetime
+ real_t(const real_t &r);
+ real_t(real_t &&r);
+ real_t &operator=(const real_t &r);
+ real_t &operator=(real_t &&r);
+ ~real_t();
+
+private:
+ static const llvm::fltSemantics *semantics;
+
+ template <typename T> void fromInteger(T i);
+ template <typename T> T toInteger() const;
+
+ union {
+ llvm::APFloat value;
+
+ // Due to D not allowing default ctors for structs, default-constructed
+ // real_t instances in D cannot default-construct their llvm::APFloat value
+ // (and the default payload isn't known at compile-time).
+ // The D declaration of real_t makes sure the semantics pointer at the
+ // beginning of the APFloat defaults to null (via real_t.init; null is
+ // otherwise illegal for all valid APFloats). This way, we can detect
+ // default-constructed D real_t instances with invalid APFloat values.
+ void *valueSemantics;
+ };
+
+ // private default-construction in C++
+ real_t() : value(llvm::APFloat::Bogus, llvm::APFloat::uninitialized) {}
+
+ // enable private implicit conversion from APFloat
+ real_t(const llvm::APFloat &value) : value(value) {}
+ real_t(llvm::APFloat &&value) : value(std::move(value)) {}
+
+ // (silly) forwarders to the C++ ctors for the D ctors
+ void initFrom(float f);
+ void initFrom(double f);
+ void initFrom(int32_t i);
+ void initFrom(int64_t i);
+ void initFrom(uint32_t i);
+ void initFrom(uint64_t i);
+
+ // lifetime helpers
+ bool isInitialized() const;
+ void safeInit();
+ void postblit();
+ void moveAssign(real_t &r);
+ void destruct();
+};
+
+// C++ arithmetic and comparison operators:
+
+inline real_t operator-(const real_t &x) { return x.opNeg(); }
+inline real_t operator+(const real_t &l, const real_t &r) { return l.add(r); }
+inline real_t operator-(const real_t &l, const real_t &r) { return l.sub(r); }
+inline real_t operator*(const real_t &l, const real_t &r) { return l.mul(r); }
+inline real_t operator/(const real_t &l, const real_t &r) { return l.div(r); }
+inline real_t operator%(const real_t &l, const real_t &r) { return l.mod(r); }
+
+inline real_t &operator+=(real_t &l, const real_t &r) { return l = l + r; }
+inline real_t &operator-=(real_t &l, const real_t &r) { return l = l - r; }
+inline real_t &operator*=(real_t &l, const real_t &r) { return l = l * r; }
+inline real_t &operator/=(real_t &l, const real_t &r) { return l = l / r; }
+
+inline bool operator<(const real_t &l, const real_t &r) {
+ return l.cmp(r) == -1;
+}
+inline bool operator<=(const real_t &l, const real_t &r) {
+ return l.cmp(r) <= 0;
+}
+inline bool operator>(const real_t &l, const real_t &r) {
+ return l.cmp(r) == 1;
+}
+inline bool operator>=(const real_t &l, const real_t &r) {
+ return l.cmp(r) >= 0;
+}
+inline bool operator==(const real_t &l, const real_t &r) {
+ return l.cmp(r) == 0;
+}
+inline bool operator!=(const real_t &l, const real_t &r) {
+ return l.cmp(r) != 0;
+}
+
+} // namespace ldc
+
+#endif
diff --git a/gen/target.cpp b/gen/target.cpp
index c4bee62..758983e 100644
--- a/gen/target.cpp
+++ b/gen/target.cpp
@@ -20,6 +20,8 @@
#include <pthread.h>
#endif
+using llvm::APFloat;
+
/*
These guys are allocated by ddmd/target.d:
int Target::ptrsize;
@@ -43,6 +45,36 @@ void Target::_init() {
// according to DMD, only for MSVC++:
reverseCppOverloads = global.params.targetTriple->isWindowsMSVCEnvironment();
+
+ RealProperties::nan = real_t::nan();
+ RealProperties::snan = real_t::snan();
+ RealProperties::infinity = real_t::infinity();
+
+ auto pTargetRealSemantics = &real->getFltSemantics();
+ if (pTargetRealSemantics == &APFloat::x87DoubleExtended) {
+ RealProperties::max = CTFloat::parse("0x1.fffffffffffffffep+16383");
+ RealProperties::min_normal = CTFloat::parse("0x1p-16382");
+ RealProperties::epsilon = CTFloat::parse("0x1p-63");
+ RealProperties::dig = 18;
+ RealProperties::mant_dig = 64;
+ RealProperties::max_exp = 16384;
+ RealProperties::min_exp = -16381;
+ RealProperties::max_10_exp = 4932;
+ RealProperties::min_10_exp = -4932;
+ } else if (pTargetRealSemantics == &APFloat::IEEEdouble ||
+ pTargetRealSemantics == &APFloat::PPCDoubleDouble) {
+ RealProperties::max = CTFloat::parse("0x1.fffffffffffffp+1023");
+ RealProperties::min_normal = CTFloat::parse("0x1p-1022");
+ RealProperties::epsilon = CTFloat::parse("0x1p-52");
+ RealProperties::dig = 15;
+ RealProperties::mant_dig = 53;
+ RealProperties::max_exp = 1024;
+ RealProperties::min_exp = -1021;
+ RealProperties::max_10_exp = 308;
+ RealProperties::min_10_exp = -307;
+ } else {
+ assert(0 && "No type properties for target `real` type");
+ }
}
/******************************
@@ -138,10 +170,10 @@ Expression *Target::paintAsType(Expression *e, Type *type) {
return createIntegerExp(e->loc, u.int64value, type);
case Tfloat32:
- return createRealExp(e->loc, ldouble(u.float32value), type);
+ return createRealExp(e->loc, u.float32value, type);
case Tfloat64:
- return createRealExp(e->loc, ldouble(u.float64value), type);
+ return createRealExp(e->loc, u.float64value, type);
default:
assert(0);
diff --git a/gen/toconstelem.cpp b/gen/toconstelem.cpp
index 7cea0ec..fd1bf53 100644
--- a/gen/toconstelem.cpp
+++ b/gen/toconstelem.cpp
@@ -120,8 +120,12 @@ public:
//////////////////////////////////////////////////////////////////////////////
void visit(RealExp *e) override {
- IF_LOG Logger::print("RealExp::toConstElem: %s @ %s | %La\n", e->toChars(),
- e->type->toChars(), e->value);
+ IF_LOG {
+ char buffer[64];
+ CTFloat::sprintImpl(buffer, 'a', e->value);
+ Logger::print("RealExp::toConstElem: %s @ %s | %s\n", e->toChars(),
+ e->type->toChars(), buffer);
+ }
LOG_SCOPE;
Type *t = e->type->toBasetype();
result = DtoConstFP(t, e->value);
diff --git a/gen/toir.cpp b/gen/toir.cpp
index 7c79f7e..31d3e0c 100644
--- a/gen/toir.cpp
+++ b/gen/toir.cpp
@@ -400,13 +400,13 @@ public:
default:
llvm_unreachable("Unexpected complex floating point type");
case Tcomplex32:
- c = DtoConstFP(Type::tfloat32, ldouble(0));
+ c = DtoConstFP(Type::tfloat32, 0);
break;
case Tcomplex64:
- c = DtoConstFP(Type::tfloat64, ldouble(0));
+ c = DtoConstFP(Type::tfloat64, 0);
break;
case Tcomplex80:
- c = DtoConstFP(Type::tfloat80, ldouble(0));
+ c = DtoConstFP(Type::tfloat80, 0);
break;
}
res = DtoAggrPair(DtoType(e->type), c, c);
@@ -1628,7 +1628,7 @@ public:
post = DtoGEP1(val, offset, false, "", p->scopebb());
} else if (e1type->isfloating()) {
assert(e2type->isfloating());
- LLValue *one = DtoConstFP(e1type, ldouble(1.0));
+ LLValue *one = DtoConstFP(e1type, 1);
if (e->op == TOKplusplus) {
post = llvm::BinaryOperator::CreateFAdd(val, one, "", p->scopebb());
} else if (e->op == TOKminusminus) {
diff --git a/gen/tollvm.cpp b/gen/tollvm.cpp
index 14b70ea..53339f4 100644
--- a/gen/tollvm.cpp
+++ b/gen/tollvm.cpp
@@ -411,41 +411,10 @@ llvm::ConstantInt *DtoConstUbyte(unsigned char i) {
return LLConstantInt::get(LLType::getInt8Ty(gIR->context()), i, false);
}
-LLConstant *DtoConstFP(Type *t, longdouble value) {
+LLConstant *DtoConstFP(Type *t, const ldc::real_t &value) {
LLType *llty = DtoType(t);
assert(llty->isFloatingPointTy());
-
- if (llty == LLType::getFloatTy(gIR->context()) ||
- llty == LLType::getDoubleTy(gIR->context())) {
- return LLConstantFP::get(llty, value);
- }
- if (llty == LLType::getX86_FP80Ty(gIR->context())) {
- uint64_t bits[] = {0, 0};
- bits[0] = *reinterpret_cast<uint64_t *>(&value);
- bits[1] =
- *reinterpret_cast<uint16_t *>(reinterpret_cast<uint64_t *>(&value) + 1);
- return LLConstantFP::get(gIR->context(), APFloat(APFloat::x87DoubleExtended,
- APInt(80, 2, bits)));
- }
- if (llty == LLType::getFP128Ty(gIR->context())) {
- union {
- longdouble ld;
- uint64_t bits[2];
- } t;
- t.ld = value;
- return LLConstantFP::get(gIR->context(),
- APFloat(APFloat::IEEEquad, APInt(128, 2, t.bits)));
- }
- if (llty == LLType::getPPC_FP128Ty(gIR->context())) {
- uint64_t bits[] = {0, 0};
- bits[0] = *reinterpret_cast<uint64_t *>(&value);
- bits[1] =
- *reinterpret_cast<uint16_t *>(reinterpret_cast<uint64_t *>(&value) + 1);
- return LLConstantFP::get(
- gIR->context(), APFloat(APFloat::PPCDoubleDouble, APInt(128, 2, bits)));
- }
-
- llvm_unreachable("Unknown floating point type encountered");
+ return LLConstantFP::get(llty, value);
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/gen/tollvm.h b/gen/tollvm.h
index 25feba4..ff0bcbb 100644
--- a/gen/tollvm.h
+++ b/gen/tollvm.h
@@ -23,6 +23,7 @@
#include "gen/llvm.h"
#include "gen/structs.h"
#include "gen/attributes.h"
+#include "gen/real_t.h"
// D->LLVM type handling stuff
@@ -91,7 +92,7 @@ LLConstantInt *DtoConstSize_t(uint64_t);
LLConstantInt *DtoConstUint(unsigned i);
LLConstantInt *DtoConstInt(int i);
LLConstantInt *DtoConstUbyte(unsigned char i);
-LLConstant *DtoConstFP(Type *t, longdouble value);
+LLConstant *DtoConstFP(Type *t, const ldc::real_t &value);
LLConstant *DtoConstString(const char *);
LLConstant *DtoConstBool(bool);
diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt
index f5fd2d7..af389ab 100644
--- a/runtime/CMakeLists.txt
+++ b/runtime/CMakeLists.txt
@@ -12,7 +12,7 @@ set(MULTILIB OFF CACHE BOOL
set(BUILD_BC_LIBS OFF CACHE BOOL "Build the runtime as LLVM bitcode libraries")
set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/include/d CACHE PATH "Path to install D modules to")
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Whether to build the runtime as a shared library")
-set(D_FLAGS -w CACHE STRING "Runtime build flags, separated by ;")
+set(D_FLAGS -w;-mtriple=armv7-none-linux-androideabi CACHE STRING "Runtime build flags, separated by ;")
set(D_FLAGS_DEBUG -g;-link-debuglib CACHE STRING "Runtime build flags (debug libraries), separated by ;")
set(D_FLAGS_RELEASE -O3;-release CACHE STRING "Runtime build flags (release libraries), separated by ;")
if(MSVC)
@@ -59,6 +59,7 @@ file(GLOB CORE_D ${RUNTIME_DIR}/src/core/*.d)
file(GLOB_RECURSE CORE_D_INTERNAL ${RUNTIME_DIR}/src/core/internal/*.d)
file(GLOB CORE_D_SYNC ${RUNTIME_DIR}/src/core/sync/*.d)
file(GLOB CORE_D_STDC ${RUNTIME_DIR}/src/core/stdc/*.d)
+list(REMOVE_ITEM CORE_D_STDC ${RUNTIME_DIR}/src/core/stdc/tgmath.d)
file(GLOB_RECURSE GC_D ${RUNTIME_DIR}/src/gc/*.d)
file(GLOB_RECURSE DCRT_D ${RUNTIME_DIR}/src/rt/*.d)
file(GLOB_RECURSE LDC_D ${RUNTIME_DIR}/src/ldc/*.d)
@@ -504,8 +505,11 @@ endmacro()
#
# Set up build targets.
#
-
-set(RT_CFLAGS "")
+set(CMAKE_C_COMPILER $ENV{NDK}/toolchains/llvm/prebuilt/linux-$ENV{NDK_ARCH}/bin/clang)
+set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER})
+set(RT_CFLAGS "-gcc-toolchain $ENV{NDK}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-$ENV{NDK_ARCH} -fpic -ffunction-sections -funwind-tables -fstack-protector-strong -Wno-invalid-command-line-argument -Wno-unused-command-line-argument -no-canonical-prefixes -fno-integrated-as -target armv7-none-linux-androideabi -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -Os -g -DNDEBUG -fomit-frame-pointer -fno-strict-aliasing -DANDROID -Wa,--noexecstack -Wformat -Werror=format-security -isystem $ENV{NDK}/platforms/android-9/arch-arm/usr/include")
+set(RT_LDFLAGS "-Wl,-z,nocopyreloc;--sysroot=$ENV{NDK}/platforms/android-9/arch-arm;-lgcc;-gcc-toolchain;$ENV{NDK}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-$ENV{NDK_ARCH};-target;armv7-none-linux-androideabi;-no-canonical-prefixes;-fuse-ld=bfd;-Wl,--fix-cortex-a8;-Wl,--no-undefined;-Wl,-z,noexecstack;-Wl,-z,relro;-Wl,-z,now;-Wl,--warn-shared-textrel;-Wl,--fatal-warnings;-fPIE;-pie;-mthumb;-lc;-lm")
+set(TEST_SO_LDFLAGS "-Wl,-soname,libnative-activity${name_suffix}.so;-shared;--sysroot=$ENV{NDK}/platforms/android-9/arch-arm;-lgcc;-gcc-toolchain;$ENV{NDK}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-$ENV{NDK_ARCH};-no-canonical-prefixes;-fuse-ld=bfd;-target;armv7-none-linux-androideabi;-Wl,--fix-cortex-a8;-Wl,--no-undefined;-Wl,-z,noexecstack;-Wl,-z,relro;-Wl,-z,now;-Wl,--warn-shared-textrel;-Wl,--fatal-warnings;-mthumb;-llog;-landroid;-lEGL;-lGLESv1_CM;-lc;-lm")
# This is a bit of a mess as we need to join the two libraries together on
# OS X before installing them. After this has run, LIBS_TO_INSTALL contains
@@ -684,6 +688,10 @@ macro(build_test_runner name_suffix d_flags c_flags)
if(PHOBOS2_DIR)
set(phobos2_o "")
set(phobos2_bc "")
+ set(test_runner_o "")
+ set(test_runner ${PROJECT_BINARY_DIR}/test-runner${name_suffix}${CMAKE_EXECUTABLE_SUFFIX})
+ set(ANDROID_DIR "${PROJECT_PARENT_DIR}/../android")
+ set(test_runner_so ${ANDROID_DIR}/samples/native-activity/libs/armeabi-v7a/libnative-activity${name_suffix}.so)
compile_phobos2("${flags}" "-unittest${name_suffix}" "" phobos2_o phobos2_bc)
set(phobos2-casm phobos2-ldc-casm${name_suffix})
@@ -698,6 +707,65 @@ macro(build_test_runner name_suffix d_flags c_flags)
set_target_properties(${phobos2-casm} PROPERTIES EXCLUDE_FROM_ALL ON EXCLUDE_FROM_DEFAULT_BUILD ON)
add_custom_target(phobos2-ldc-unittest${name_suffix} DEPENDS ${phobos2_o} ${phobos2-casm})
+ set(runner_flags "${flags}")
+ if("${flags}" MATCHES "-debug")
+ list(APPEND runner_flags -d-debug)
+ endif()
+ dc("${RUNTIME_DIR}/src/test_runner.d" "${runner_flags}" "${RUNTIME_DIR}"
+ "${name_suffix}" test_runner_o druntime_bc)
+ add_custom_command(
+ OUTPUT ${test_runner}
+ COMMAND ${CMAKE_C_COMPILER} ${RT_LDFLAGS} ${test_runner_o}
+ ${druntime_o} ${phobos2_o}
+ "${output_path}/lib${druntime-casm}.a"
+ "${output_path}/lib${phobos2-casm}.a"
+ -o${test_runner}
+ WORKING_DIRECTORY ${PROJECT_PARENT_DIR}
+ DEPENDS ${CMAKE_C_COMPILER}
+ ${test_runner_o}
+ ${druntime_o}
+ ${druntime-casm}
+ ${phobos2_o}
+ ${phobos2-casm}
+ )
+ add_custom_target(test-runner${name_suffix} DEPENDS ${test_runner})
+ set(test_runner_apk_o "")
+ dc("${RUNTIME_DIR}/src/test_runner.d" "${runner_flags};-d-version=apk;-I${ANDROID_DIR}" "${RUNTIME_DIR}"
+ "-apk${name_suffix}" test_runner_apk_o druntime_bc)
+ set(file_apk_o "")
+ dc("${PHOBOS2_DIR}/std/file.d" "${flags};-d-version=apk" "${PHOBOS2_DIR}"
+ "-apk-unittest${name_suffix}" file_apk_o phobos2_bc)
+ set(main_o "")
+ dc("${ANDROID_DIR}/samples/native-activity/jni/main.d" "${D_FLAGS};${d_flags};-I${ANDROID_DIR}" "${RUNTIME_DIR}"
+ "${name_suffix}" main_o druntime_bc)
+ set(sensor_o "")
+ dc("${ANDROID_DIR}/android/sensor.d" "${D_FLAGS};${d_flags};-I${ANDROID_DIR}" "${RUNTIME_DIR}"
+ "${name_suffix}" sensor_o druntime_bc)
+ string(REPLACE " " ";" RT_CFLAGS${name_suffix} ${RT_CFLAGS})
+ set(android_native_app_glue_o "")
+ dc("${ANDROID_DIR}/android_native_app_glue.d" "${D_FLAGS};${d_flags};-I${ANDROID_DIR}" "${RUNTIME_DIR}"
+ "${name_suffix}" android_native_app_glue_o druntime_bc)
+ list(REMOVE_ITEM phobos2_o "${PROJECT_PARENT_DIR}/build/runtime/std/file-unittest${name_suffix}.o")
+ add_custom_command(
+ OUTPUT ${test_runner_so}
+ COMMAND ${CMAKE_C_COMPILER} ${TEST_SO_LDFLAGS}
+ ${main_o} ${sensor_o} ${test_runner_apk_o}
+ ${file_apk_o} ${android_native_app_glue_o}
+ ${druntime_o} ${phobos2_o}
+ "${output_path}/lib${druntime-casm}.a"
+ "${output_path}/lib${phobos2-casm}.a"
+ -o${test_runner_so}
+ WORKING_DIRECTORY ${PROJECT_PARENT_DIR}
+ DEPENDS ${CMAKE_C_COMPILER}
+ ${main_o} ${sensor_o}
+ ${test_runner_apk_o} ${android_native_app_glue_o}
+ ${druntime_o}
+ ${druntime-casm}
+ ${phobos2_o}
+ ${phobos2-casm}
+ ${file_apk_o}
+ )
+ add_custom_target(test-runner-apk${name_suffix} DEPENDS ${test_runner_so})
add_test(build-phobos2-ldc-unittest${name_suffix} "${CMAKE_COMMAND}"
--build ${CMAKE_BINARY_DIR} --target phobos2-ldc-unittest${name_suffix})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment