Last active
August 12, 2016 11:37
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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