From e9cf6fc0f238e1cab91f7d414075daf25e34c815 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 21 Jul 2016 14:56:33 +0200 Subject: [PATCH] [DEV] ARM --- ddmd/builtin.d | 58 +++++----- ddmd/complex.d | 62 ++++------ ddmd/complex_t.h | 50 ++++----- ddmd/constfold.d | 94 ++++++++-------- ddmd/ctfeexpr.d | 11 +- ddmd/dcast.d | 11 +- ddmd/dmangle.d | 15 ++- ddmd/expression.d | 36 +++--- ddmd/expression.h | 6 +- ddmd/globals.d | 11 -- ddmd/globals.h | 12 +- ddmd/hdrgen.d | 11 +- ddmd/lexer.d | 20 ++-- ddmd/mars.h | 2 +- ddmd/mtype.d | 112 +++++++------------ ddmd/optimize.d | 18 +-- ddmd/parse.d | 12 +- ddmd/root/ctfloat.d | 80 +++++++++++++ ddmd/root/ctfloat.h | 56 ++++++++++ ddmd/root/longdouble.d | 15 --- ddmd/root/port.d | 298 +++++++++---------------------------------------- ddmd/root/port.h | 56 +++------- ddmd/root/real_t.d | 109 ++++++++++++++++++ ddmd/target.d | 82 +++++++++++++- ddmd/target.h | 8 ++ ddmd/tokens.d | 24 ++-- ddmd/tokens.h | 8 +- driver/main.cpp | 1 + gen/abi-arm.cpp | 5 +- gen/asm-x86.h | 17 +-- gen/complex.cpp | 3 +- gen/complex.h | 5 +- gen/ctfloat.cpp | 178 +++++++++++++++++++++++++++++ gen/real_t.cpp | 257 ++++++++++++++++++++++++++++++++++++++++++ gen/real_t.h | 156 ++++++++++++++++++++++++++ gen/target.cpp | 36 +++++- gen/toconstelem.cpp | 8 +- gen/toir.cpp | 8 +- gen/tollvm.cpp | 35 +----- gen/tollvm.h | 3 +- runtime/CMakeLists.txt | 10 +- 41 files changed, 1315 insertions(+), 684 deletions(-) create mode 100644 ddmd/root/ctfloat.d create mode 100644 ddmd/root/ctfloat.h delete mode 100644 ddmd/root/longdouble.d create mode 100644 ddmd/root/real_t.d create mode 100644 gen/ctfloat.cpp create mode 100644 gen/real_t.cpp create mode 100644 gen/real_t.h 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..42e85cc --- /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..eda0dee --- /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 -#include "longdouble.h" - #if _MSC_VER #include 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..e000072 --- /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..9420bb3 --- /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 + +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..759139b --- /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 + +using llvm::APFloat; + +static llvm::cl::opt + 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 void real_t::fromInteger(T i) { + const llvm::integerPart tmp(i); + value.convertFromSignExtendedInteger(&tmp, 1, std::is_signed::value, + APFloat::rmNearestTiesToEven); +} + +template T real_t::toInteger() const { + llvm::APSInt trunc(8 * sizeof(T), !std::is_signed::value); + bool ignored; + value.convertToInteger(trunc, APFloat::rmTowardZero, &ignored); + return static_cast(std::is_signed::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(); } +int64_t real_t::toInt64() const { return toInteger(); } +uint32_t real_t::toUInt32() const { return toInteger(); } +uint64_t real_t::toUInt64() const { return toInteger(); } + + + +/*** 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(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..4c9d8ba --- /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 void fromInteger(T i); + template 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 #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(&value); - bits[1] = - *reinterpret_cast(reinterpret_cast(&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(&value); - bits[1] = - *reinterpret_cast(reinterpret_cast(&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..3656097 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=arm-none-linux-gnueabi 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_SYSTEM_NAME Linux) +set(CMAKE_C_COMPILER /opt/arm-2009q1/bin/arm-none-linux-gnueabi-gcc) +set(CMAKE_CXX_COMPILER /opt/arm-2009q1/bin/arm-none-linux-gnueabi-c++) +set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER}) +set(RT_CFLAGS "-pthread -fpic -ffunction-sections -funwind-tables -mthumb -Os -g -DNDEBUG -fomit-frame-pointer -fno-strict-aliasing -Wa,--noexecstack -Wformat -Werror=format-security -isystem /opt/arm-2009q1/arm-none-linux-gnueabi/libc/usr/include") # 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 -- 1.9.1