Last active
April 21, 2016 04:55
-
-
Save joakim-noah/63693ead3aa62216e1d9 to your computer and use it in GitHub Desktop.
LDC for Android/ARM, applied to the ltsmaster branch 2.068
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/CMakeLists.txt b/CMakeLists.txt | |
index 2239280..825b37b 100644 | |
--- a/CMakeLists.txt | |
+++ b/CMakeLists.txt | |
@@ -8,6 +8,7 @@ if(MSVC) | |
endif() | |
include(CheckIncludeFile) | |
+include(CheckSymbolExists) | |
include(CheckLibraryExists) | |
include(CheckCXXCompilerFlag) | |
@@ -364,6 +365,27 @@ if(LLVM_ENABLE_ASSERTIONS) | |
endif() | |
# | |
+# check string functions | |
+# | |
+check_symbol_exists(memicmp "string.h" HAVE_MEMICMP) | |
+check_symbol_exists(stricmp "string.h" HAVE_STRICMP) | |
+check_symbol_exists(strupr "string.h" HAVE_STRUPR) | |
+check_symbol_exists(strtof "stdlib.h" HAVE_STRTOF) | |
+ | |
+if(HAVE_MEMICMP) | |
+ add_definitions(-DHAVE_MEMICMP) | |
+endif() | |
+ | |
+if(HAVE_STRICMP) | |
+ add_definitions(-DHAVE_STRICMP) | |
+endif() | |
+ | |
+if(HAVE_STRUPR) | |
+ add_definitions(-DHAVE_STRUPR) | |
+endif() | |
+ | |
+ | |
+# | |
# Check endianess. | |
# There is no realiable way to delegate the work to the compiler. | |
# E.g. gcc up to version 4.6 defines __LITTLE_ENDIAN, but not 4.7 | |
@@ -517,7 +539,6 @@ endif() | |
# | |
# LDMD | |
# | |
-include(CheckSymbolExists) | |
CHECK_SYMBOL_EXISTS(_SC_ARG_MAX "unistd.h" HAVE_SC_ARG_MAX) | |
if (HAVE_SC_ARG_MAX) | |
add_definitions(-DHAVE_SC_ARG_MAX) | |
diff --git a/dmd2/builtin.c b/dmd2/builtin.c | |
index 9375f8d..7ff5ae3 100644 | |
--- a/dmd2/builtin.c | |
+++ b/dmd2/builtin.c | |
@@ -50,41 +50,78 @@ Expression *eval_unimp(Loc loc, FuncDeclaration *fd, Expressions *arguments) | |
return NULL; | |
} | |
+#if IN_LLVM | |
Expression *eval_sin(Loc loc, FuncDeclaration *fd, Expressions *arguments) | |
{ | |
Expression *arg0 = (*arguments)[0]; | |
assert(arg0->op == TOKfloat64); | |
- return new RealExp(loc, sinl(arg0->toReal()), arg0->type); | |
+ return new RealExp(loc, ldouble(arg0->toReal()).sin(), arg0->type); | |
} | |
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, ldouble(arg0->toReal()).cos(), arg0->type); | |
} | |
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, ldouble(arg0->toReal()).tan(), arg0->type); | |
} | |
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, ldouble(arg0->toReal()).sqrt(), arg0->type); | |
} | |
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, ldouble(arg0->toReal()).abs(), arg0->type); | |
+} | |
+#else | |
+Expression *eval_sin(Loc loc, FuncDeclaration *fd, Expressions *arguments) | |
+{ | |
+ Expression *arg0 = (*arguments)[0]; | |
+ assert(arg0->op == TOKfloat64); | |
+ return new RealExp(loc, sinl(arg0->toReal()), arg0->type); | |
+} | |
+ | |
+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); | |
+} | |
+ | |
+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); | |
+} | |
+ | |
+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); | |
} | |
+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); | |
+} | |
+#endif | |
+ | |
#if IN_LLVM | |
static inline Type *getTypeOfOverloadedIntrinsic(FuncDeclaration *fd) | |
@@ -134,7 +171,7 @@ Expression *eval_llvmsin(Loc loc, FuncDeclaration *fd, Expressions *arguments) | |
Type* type = getTypeOfOverloadedIntrinsic(fd); | |
Expression *arg0 = (*arguments)[0]; | |
assert(arg0->op == TOKfloat64); | |
- return new RealExp(loc, sinl(arg0->toReal()), type); | |
+ return new RealExp(loc, ldouble(arg0->toReal()).sin(), type); | |
} | |
Expression *eval_llvmcos(Loc loc, FuncDeclaration *fd, Expressions *arguments) | |
@@ -142,7 +179,7 @@ Expression *eval_llvmcos(Loc loc, FuncDeclaration *fd, Expressions *arguments) | |
Type* type = getTypeOfOverloadedIntrinsic(fd); | |
Expression *arg0 = (*arguments)[0]; | |
assert(arg0->op == TOKfloat64); | |
- return new RealExp(loc, cosl(arg0->toReal()), type); | |
+ return new RealExp(loc, ldouble(arg0->toReal()).cos(), type); | |
} | |
Expression *eval_llvmsqrt(Loc loc, FuncDeclaration *fd, Expressions *arguments) | |
@@ -150,15 +187,7 @@ Expression *eval_llvmsqrt(Loc loc, FuncDeclaration *fd, Expressions *arguments) | |
Type* type = getTypeOfOverloadedIntrinsic(fd); | |
Expression *arg0 = (*arguments)[0]; | |
assert(arg0->op == TOKfloat64); | |
- return new RealExp(loc, sqrtl(arg0->toReal()), type); | |
-} | |
- | |
-Expression *eval_llvmlog(Loc loc, FuncDeclaration *fd, Expressions *arguments) | |
-{ | |
- Type* type = getTypeOfOverloadedIntrinsic(fd); | |
- Expression *arg0 = (*arguments)[0]; | |
- assert(arg0->op == TOKfloat64); | |
- return new RealExp(loc, logl(arg0->toReal()), type); | |
+ return new RealExp(loc, ldouble(arg0->toReal().sqrt()), type); | |
} | |
Expression *eval_llvmfabs(Loc loc, FuncDeclaration *fd, Expressions *arguments) | |
@@ -166,7 +195,7 @@ Expression *eval_llvmfabs(Loc loc, FuncDeclaration *fd, Expressions *arguments) | |
Type* type = getTypeOfOverloadedIntrinsic(fd); | |
Expression *arg0 = (*arguments)[0]; | |
assert(arg0->op == TOKfloat64); | |
- return new RealExp(loc, fabsl(arg0->toReal()), type); | |
+ return new RealExp(loc, ldouble(arg0->toReal().abs()), type); | |
} | |
Expression *eval_llvmminnum(Loc loc, FuncDeclaration *fd, Expressions *arguments) | |
@@ -176,7 +205,7 @@ Expression *eval_llvmminnum(Loc loc, FuncDeclaration *fd, Expressions *arguments | |
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, longdouble::fmin(ldouble(arg0->toReal()), ldouble(arg1->toReal())), type); | |
} | |
Expression *eval_llvmmaxnum(Loc loc, FuncDeclaration *fd, Expressions *arguments) | |
@@ -186,7 +215,7 @@ Expression *eval_llvmmaxnum(Loc loc, FuncDeclaration *fd, Expressions *arguments | |
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, longdouble::fmax(ldouble(arg0->toReal()), ldouble(arg1->toReal())), type); | |
} | |
Expression *eval_llvmfloor(Loc loc, FuncDeclaration *fd, Expressions *arguments) | |
@@ -194,7 +223,7 @@ Expression *eval_llvmfloor(Loc loc, FuncDeclaration *fd, Expressions *arguments) | |
Type* type = getTypeOfOverloadedIntrinsic(fd); | |
Expression *arg0 = (*arguments)[0]; | |
assert(arg0->op == TOKfloat64); | |
- return new RealExp(loc, floor(arg0->toReal()), type); | |
+ return new RealExp(loc, ldouble(arg0->toReal()).floor(), type); | |
} | |
Expression *eval_llvmceil(Loc loc, FuncDeclaration *fd, Expressions *arguments) | |
@@ -202,7 +231,7 @@ Expression *eval_llvmceil(Loc loc, FuncDeclaration *fd, Expressions *arguments) | |
Type* type = getTypeOfOverloadedIntrinsic(fd); | |
Expression *arg0 = (*arguments)[0]; | |
assert(arg0->op == TOKfloat64); | |
- return new RealExp(loc, ceil(arg0->toReal()), type); | |
+ return new RealExp(loc, ldouble(arg0->toReal()).ceil(), type); | |
} | |
Expression *eval_llvmtrunc(Loc loc, FuncDeclaration *fd, Expressions *arguments) | |
@@ -210,7 +239,7 @@ Expression *eval_llvmtrunc(Loc loc, FuncDeclaration *fd, Expressions *arguments) | |
Type* type = getTypeOfOverloadedIntrinsic(fd); | |
Expression *arg0 = (*arguments)[0]; | |
assert(arg0->op == TOKfloat64); | |
- return new RealExp(loc, trunc(arg0->toReal()), type); | |
+ return new RealExp(loc, ldouble(arg0->toReal()).trunc(), type); | |
} | |
Expression *eval_llvmround(Loc loc, FuncDeclaration *fd, Expressions *arguments) | |
@@ -218,7 +247,7 @@ Expression *eval_llvmround(Loc loc, FuncDeclaration *fd, Expressions *arguments) | |
Type* type = getTypeOfOverloadedIntrinsic(fd); | |
Expression *arg0 = (*arguments)[0]; | |
assert(arg0->op == TOKfloat64); | |
- return new RealExp(loc, round(arg0->toReal()), type); | |
+ return new RealExp(loc, ldouble(arg0->toReal()).round(), type); | |
} | |
Expression *eval_cttz(Loc loc, FuncDeclaration *fd, Expressions *arguments) | |
@@ -390,7 +419,7 @@ Expression *eval_popcnt(Loc loc, FuncDeclaration *fd, Expressions *arguments) | |
return new IntegerExp(loc, cnt, arg0->type); | |
} | |
-Expression *eval_yl2x(Loc loc, FuncDeclaration *fd, Expressions *arguments) | |
+/*Expression *eval_yl2x(Loc loc, FuncDeclaration *fd, Expressions *arguments) | |
{ | |
Expression *arg0 = (*arguments)[0]; | |
assert(arg0->op == TOKfloat64); | |
@@ -414,7 +443,7 @@ Expression *eval_yl2xp1(Loc loc, FuncDeclaration *fd, Expressions *arguments) | |
longdouble result; | |
Port::yl2xp1_impl(&x, &y, &result); | |
return new RealExp(loc, result, arg0->type); | |
-} | |
+}*/ | |
void builtin_init() | |
{ | |
@@ -450,20 +479,20 @@ void builtin_init() | |
// @safe @nogc pure nothrow real function(real, real) | |
add_builtin("_D4core4math5atan2FNaNbNiNfeeZe", &eval_unimp); | |
- if (Port::yl2x_supported) | |
+ /*if (Port::yl2x_supported) | |
{ | |
add_builtin("_D4core4math4yl2xFNaNbNiNfeeZe", &eval_yl2x); | |
} | |
- else | |
+ else*/ | |
{ | |
add_builtin("_D4core4math4yl2xFNaNbNiNfeeZe", &eval_unimp); | |
} | |
- if (Port::yl2xp1_supported) | |
+ /*if (Port::yl2xp1_supported) | |
{ | |
add_builtin("_D4core4math6yl2xp1FNaNbNiNfeeZe", &eval_yl2xp1); | |
} | |
- else | |
+ else*/ | |
{ | |
add_builtin("_D4core4math6yl2xp1FNaNbNiNfeeZe", &eval_unimp); | |
} | |
@@ -497,20 +526,20 @@ void builtin_init() | |
// @safe @nogc pure nothrow real function(real, real) | |
add_builtin("_D3std4math5atan2FNaNbNiNfeeZe", &eval_unimp); | |
- if (Port::yl2x_supported) | |
+ /*if (Port::yl2x_supported) | |
{ | |
add_builtin("_D3std4math4yl2xFNaNbNiNfeeZe", &eval_yl2x); | |
} | |
- else | |
+ else*/ | |
{ | |
add_builtin("_D3std4math4yl2xFNaNbNiNfeeZe", &eval_unimp); | |
} | |
- if (Port::yl2xp1_supported) | |
+ /*if (Port::yl2xp1_supported) | |
{ | |
add_builtin("_D3std4math6yl2xp1FNaNbNiNfeeZe", &eval_yl2xp1); | |
} | |
- else | |
+ else*/ | |
{ | |
add_builtin("_D3std4math6yl2xp1FNaNbNiNfeeZe", &eval_unimp); | |
} | |
@@ -540,13 +569,6 @@ void builtin_init() | |
add_builtin("llvm.sqrt.f128", &eval_llvmsqrt); | |
add_builtin("llvm.sqrt.ppcf128", &eval_llvmsqrt); | |
- // intrinsic llvm.log.f32/f64/f80/f128/ppcf128 | |
- add_builtin("llvm.log.f32", &eval_llvmlog); | |
- add_builtin("llvm.log.f64", &eval_llvmlog); | |
- add_builtin("llvm.log.f80", &eval_llvmlog); | |
- add_builtin("llvm.log.f128", &eval_llvmlog); | |
- add_builtin("llvm.log.ppcf128", &eval_llvmlog); | |
- | |
// intrinsic llvm.fabs.f32/f64/f80/f128/ppcf128 | |
add_builtin("llvm.fabs.f32", &eval_llvmfabs); | |
add_builtin("llvm.fabs.f64", &eval_llvmfabs); | |
diff --git a/dmd2/root/longdouble.h b/dmd2/root/longdouble.h | |
index b7f9f67..2f6e0a3 100644 | |
--- a/dmd2/root/longdouble.h | |
+++ b/dmd2/root/longdouble.h | |
@@ -11,6 +11,13 @@ | |
#ifndef __LONG_DOUBLE_H__ | |
#define __LONG_DOUBLE_H__ | |
+#if IN_LLVM | |
+ | |
+#include "gen/ldc-real.h" | |
+ | |
+#else | |
+ | |
+#if !_MSC_VER // has native 10 byte doubles | |
#include <stdio.h> | |
typedef long double longdouble; | |
typedef volatile long double volatile_longdouble; | |
@@ -47,4 +54,194 @@ inline size_t ld_sprint(char* str, int fmt, longdouble x) | |
#undef sprintf | |
#endif | |
+#else | |
+ | |
+#include <float.h> | |
+#include <limits> | |
+ | |
+struct longdouble; | |
+ | |
+extern "C" | |
+{ | |
+ // implemented in ldfpu.asm for _WIN64 | |
+ double ld_read(const longdouble* ld); | |
+ long long ld_readll(const longdouble* ld); | |
+ unsigned long long ld_readull(const longdouble* ld); | |
+ void ld_set(longdouble* ld, double d); | |
+ void ld_setll(longdouble* ld, long long d); | |
+ void ld_setull(longdouble* ld, unsigned long long d); | |
+} | |
+ | |
+struct longdouble | |
+{ | |
+ unsigned long long mantissa; | |
+ unsigned short exponent:15; // bias 0x3fff | |
+ unsigned short sign:1; | |
+ unsigned short fill:16; // for 12 byte alignment | |
+ | |
+ // no constructor to be able to use this class in a union | |
+ // use ldouble() to explicitely create a longdouble value | |
+ | |
+ template<typename T> longdouble& operator=(T x) { set(x); return *this; } | |
+ | |
+ void set(longdouble ld) { mantissa = ld.mantissa; exponent = ld.exponent; sign = ld.sign; } | |
+ | |
+ // we need to list all basic types to avoid ambiguities | |
+ void set(float d) { ld_set(this, d); } | |
+ void set(double d) { ld_set(this, d); } | |
+ void set(long double d) { ld_set(this, d); } | |
+ | |
+ void set(signed char d) { ld_set(this, d); } | |
+ void set(short d) { ld_set(this, d); } | |
+ void set(int d) { ld_set(this, d); } | |
+ void set(long d) { ld_set(this, d); } | |
+ void set(long long d) { ld_setll(this, d); } | |
+ | |
+ void set(unsigned char d) { ld_set(this, d); } | |
+ void set(unsigned short d) { ld_set(this, d); } | |
+ void set(unsigned int d) { ld_set(this, d); } | |
+ void set(unsigned long d) { ld_set(this, d); } | |
+ void set(unsigned long long d) { ld_setull(this, d); } | |
+ void set(bool d) { ld_set(this, d); } | |
+ | |
+ operator float () { return ld_read(this); } | |
+ operator double () { return ld_read(this); } | |
+ | |
+ operator signed char () { return ld_read(this); } | |
+ operator short () { return ld_read(this); } | |
+ operator int () { return ld_read(this); } | |
+ operator long () { return ld_read(this); } | |
+ operator long long () { return ld_readll(this); } | |
+ | |
+ operator unsigned char () { return ld_read(this); } | |
+ operator unsigned short () { return ld_read(this); } | |
+ operator unsigned int () { return ld_read(this); } | |
+ operator unsigned long () { return ld_read(this); } | |
+ operator unsigned long long() { return ld_readull(this); } | |
+ operator bool () { return mantissa != 0 || exponent != 0; } // correct? | |
+}; | |
+ | |
+// some optimizations are avoided by adding volatile to the longdouble | |
+// type, but this introduces bad ambiguities when using the class implementation above | |
+// as we are going through asm these optimizations won't kick in anyway, so "volatile" | |
+// is not required. | |
+typedef longdouble volatile_longdouble; | |
+ | |
+inline longdouble ldouble(unsigned long long mantissa, int exp, int sign = 0) | |
+{ | |
+ longdouble d; | |
+ d.mantissa = mantissa; | |
+ d.exponent = exp; | |
+ d.sign = sign; | |
+ return d; | |
+} | |
+ | |
+// codegen bug in VS2010/VS2012, if the set() function not inlined | |
+// (this passed on stack, but expected in ECX; RVO?) | |
+#if _MSC_VER >= 1600 | |
+#define LDOUBLE_INLINE __declspec(noinline) | |
+#else | |
+#define LDOUBLE_INLINE inline | |
+#endif | |
+ | |
+template<typename T> LDOUBLE_INLINE longdouble ldouble(T x) { longdouble d; d.set(x); return d; } | |
+ | |
+#undef LDOUBLE_INLINE | |
+ | |
+longdouble operator+(longdouble ld1, longdouble ld2); | |
+longdouble operator-(longdouble ld1, longdouble ld2); | |
+longdouble operator*(longdouble ld1, longdouble ld2); | |
+longdouble operator/(longdouble ld1, longdouble ld2); | |
+ | |
+bool operator< (longdouble ld1, longdouble ld2); | |
+bool operator<=(longdouble ld1, longdouble ld2); | |
+bool operator> (longdouble ld1, longdouble ld2); | |
+bool operator>=(longdouble ld1, longdouble ld2); | |
+bool operator==(longdouble ld1, longdouble ld2); | |
+bool operator!=(longdouble ld1, longdouble ld2); | |
+ | |
+inline longdouble operator-(longdouble ld1) { ld1.sign ^= 1; return ld1; } | |
+inline longdouble operator+(longdouble ld1) { return ld1; } | |
+ | |
+template<typename T> inline longdouble operator+(longdouble ld, T x) { return ld + ldouble(x); } | |
+template<typename T> inline longdouble operator-(longdouble ld, T x) { return ld - ldouble(x); } | |
+template<typename T> inline longdouble operator*(longdouble ld, T x) { return ld * ldouble(x); } | |
+template<typename T> inline longdouble operator/(longdouble ld, T x) { return ld / ldouble(x); } | |
+ | |
+template<typename T> inline longdouble operator+(T x, longdouble ld) { return ldouble(x) + ld; } | |
+template<typename T> inline longdouble operator-(T x, longdouble ld) { return ldouble(x) - ld; } | |
+template<typename T> inline longdouble operator*(T x, longdouble ld) { return ldouble(x) * ld; } | |
+template<typename T> inline longdouble operator/(T x, longdouble ld) { return ldouble(x) / ld; } | |
+ | |
+template<typename T> inline longdouble& operator+=(longdouble& ld, T x) { return ld = ld + x; } | |
+template<typename T> inline longdouble& operator-=(longdouble& ld, T x) { return ld = ld - x; } | |
+template<typename T> inline longdouble& operator*=(longdouble& ld, T x) { return ld = ld * x; } | |
+template<typename T> inline longdouble& operator/=(longdouble& ld, T x) { return ld = ld / x; } | |
+ | |
+template<typename T> inline bool operator< (longdouble ld, T x) { return ld < ldouble(x); } | |
+template<typename T> inline bool operator<=(longdouble ld, T x) { return ld <= ldouble(x); } | |
+template<typename T> inline bool operator> (longdouble ld, T x) { return ld > ldouble(x); } | |
+template<typename T> inline bool operator>=(longdouble ld, T x) { return ld >= ldouble(x); } | |
+template<typename T> inline bool operator==(longdouble ld, T x) { return ld == ldouble(x); } | |
+template<typename T> inline bool operator!=(longdouble ld, T x) { return ld != ldouble(x); } | |
+ | |
+template<typename T> inline bool operator< (T x, longdouble ld) { return ldouble(x) < ld; } | |
+template<typename T> inline bool operator<=(T x, longdouble ld) { return ldouble(x) <= ld; } | |
+template<typename T> inline bool operator> (T x, longdouble ld) { return ldouble(x) > ld; } | |
+template<typename T> inline bool operator>=(T x, longdouble ld) { return ldouble(x) >= ld; } | |
+template<typename T> inline bool operator==(T x, longdouble ld) { return ldouble(x) == ld; } | |
+template<typename T> inline bool operator!=(T x, longdouble ld) { return ldouble(x) != ld; } | |
+ | |
+int _isnan(longdouble ld); | |
+ | |
+longdouble fabsl(longdouble ld); | |
+longdouble sqrtl(longdouble ld); | |
+longdouble sinl (longdouble ld); | |
+longdouble cosl (longdouble ld); | |
+longdouble tanl (longdouble ld); | |
+ | |
+longdouble fmodl(longdouble x, longdouble y); | |
+longdouble ldexpl(longdouble ldval, int exp); // see strtold | |
+ | |
+inline longdouble fabs (longdouble ld) { return fabsl(ld); } | |
+inline longdouble sqrt (longdouble ld) { return sqrtl(ld); } | |
+ | |
+#undef LDBL_DIG | |
+#undef LDBL_MAX | |
+#undef LDBL_MIN | |
+#undef LDBL_EPSILON | |
+#undef LDBL_MANT_DIG | |
+#undef LDBL_MAX_EXP | |
+#undef LDBL_MIN_EXP | |
+#undef LDBL_MAX_10_EXP | |
+#undef LDBL_MIN_10_EXP | |
+ | |
+#define LDBL_DIG 18 | |
+#define LDBL_MAX ldouble(0xffffffffffffffffULL, 0x7ffe) | |
+#define LDBL_MIN ldouble(0x8000000000000000ULL, 1) | |
+#define LDBL_EPSILON ldouble(0x8000000000000000ULL, 0x3fff - 63) // allow denormal? | |
+#define LDBL_MANT_DIG 64 | |
+#define LDBL_MAX_EXP 16384 | |
+#define LDBL_MIN_EXP (-16381) | |
+#define LDBL_MAX_10_EXP 4932 | |
+#define LDBL_MIN_10_EXP (-4932) | |
+ | |
+extern longdouble ld_zero; | |
+extern longdouble ld_one; | |
+extern longdouble ld_pi; | |
+extern longdouble ld_log2t; | |
+extern longdouble ld_log2e; | |
+extern longdouble ld_log2; | |
+extern longdouble ld_ln2; | |
+ | |
+extern longdouble ld_inf; | |
+extern longdouble ld_qnan; | |
+extern longdouble ld_snan; | |
+ | |
+size_t ld_sprint(char* str, int fmt, longdouble x); | |
+ | |
+#endif // !_MSC_VER | |
+ | |
+#endif // IN_LLVM | |
+ | |
#endif // __LONG_DOUBLE_H__ | |
diff --git a/dmd2/root/port.c b/dmd2/root/port.c | |
deleted file mode 100644 | |
index ac23e8e..0000000 | |
--- a/dmd2/root/port.c | |
+++ /dev/null | |
@@ -1,1267 +0,0 @@ | |
- | |
-/* Copyright (c) 1999-2014 by Digital Mars | |
- * All Rights Reserved, written by Walter Bright | |
- * http://www.digitalmars.com | |
- * Distributed under the Boost Software License, Version 1.0. | |
- * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) | |
- * https://github.com/D-Programming-Language/dmd/blob/master/src/root/port.c | |
- */ | |
- | |
-#include "port.h" | |
- | |
-#if __DMC__ | |
-#include <math.h> | |
-#include <float.h> | |
-#include <fp.h> | |
-#include <time.h> | |
-#include <stdlib.h> | |
-#include <string.h> | |
-#include <wchar.h> | |
- | |
-double Port::nan = NAN; | |
-longdouble Port::ldbl_nan = NAN; | |
-longdouble Port::snan; | |
- | |
-double Port::infinity = INFINITY; | |
-longdouble Port::ldbl_infinity = INFINITY; | |
- | |
-double Port::dbl_max = DBL_MAX; | |
-double Port::dbl_min = DBL_MIN; | |
-longdouble Port::ldbl_max = LDBL_MAX; | |
- | |
-bool Port::yl2x_supported = true; | |
-bool Port::yl2xp1_supported = true; | |
- | |
-struct PortInitializer | |
-{ | |
- PortInitializer(); | |
-}; | |
- | |
-static PortInitializer portinitializer; | |
- | |
-PortInitializer::PortInitializer() | |
-{ | |
- union | |
- { unsigned int ui[4]; | |
- longdouble ld; | |
- } snan = {{ 0, 0xA0000000, 0x7FFF, 0 }}; | |
- | |
- Port::snan = snan.ld; | |
-} | |
- | |
-int Port::isNan(double r) | |
-{ | |
- return ::isnan(r); | |
-} | |
- | |
-int Port::isNan(longdouble r) | |
-{ | |
- return ::isnan(r); | |
-} | |
- | |
-int Port::isSignallingNan(double r) | |
-{ | |
- /* A signalling NaN is a NaN with 0 as the most significant bit of | |
- * its significand, which is bit 51 of 0..63 for 64 bit doubles. | |
- */ | |
- return isNan(r) && !((((unsigned char*)&r)[6]) & 8); | |
-} | |
- | |
-int Port::isSignallingNan(longdouble r) | |
-{ | |
- /* A signalling NaN is a NaN with 0 as the most significant bit of | |
- * its significand, which is bit 62 of 0..79 for 80 bit reals. | |
- */ | |
- return isNan(r) && !((((unsigned char*)&r)[7]) & 0x40); | |
-} | |
- | |
-int Port::isInfinity(double r) | |
-{ | |
- return (::fpclassify(r) == FP_INFINITE); | |
-} | |
- | |
-longdouble Port::sqrt(longdouble x) | |
-{ | |
- return ::sqrtl(x); | |
-} | |
- | |
-longdouble Port::fmodl(longdouble x, longdouble y) | |
-{ | |
- return ::fmodl(x, y); | |
-} | |
- | |
-int Port::fequal(longdouble x, longdouble y) | |
-{ | |
- /* In some cases, the REALPAD bytes get garbage in them, | |
- * so be sure and ignore them. | |
- */ | |
- return memcmp(&x, &y, 10) == 0; | |
-} | |
- | |
-void Port::yl2x_impl(longdouble* x, longdouble* y, longdouble* res) | |
-{ | |
- *res = _inline_yl2x(*x, *y); | |
-} | |
- | |
-void Port::yl2xp1_impl(longdouble* x, longdouble* y, longdouble* res) | |
-{ | |
- *res = _inline_yl2xp1(*x, *y); | |
-} | |
- | |
-char *Port::strupr(char *s) | |
-{ | |
- return ::strupr(s); | |
-} | |
- | |
-int Port::memicmp(const char *s1, const char *s2, int n) | |
-{ | |
- return ::memicmp(s1, s2, n); | |
-} | |
- | |
-int Port::stricmp(const char *s1, const char *s2) | |
-{ | |
- return ::stricmp(s1, s2); | |
-} | |
- | |
- | |
-extern "C" const char * __cdecl __locale_decpoint; | |
- | |
-float Port::strtof(const char *buffer, char **endp) | |
-{ | |
- const char *save = __locale_decpoint; | |
- __locale_decpoint = "."; | |
- float result = ::strtof(buffer, endp); | |
- __locale_decpoint = save; | |
- return result; | |
-} | |
- | |
-double Port::strtod(const char *buffer, char **endp) | |
-{ | |
- const char *save = __locale_decpoint; | |
- __locale_decpoint = "."; | |
- double result = ::strtod(buffer, endp); | |
- __locale_decpoint = save; | |
- return result; | |
-} | |
- | |
-longdouble Port::strtold(const char *buffer, char **endp) | |
-{ | |
- const char *save = __locale_decpoint; | |
- __locale_decpoint = "."; | |
- longdouble result = ::strtold(buffer, endp); | |
- __locale_decpoint = save; | |
- return result; | |
-} | |
- | |
-#endif | |
- | |
-#if _MSC_VER | |
- | |
-// Disable useless warnings about unreferenced functions | |
-#pragma warning (disable : 4514) | |
- | |
-#include <llvm/ADT/APFloat.h> | |
-#include <llvm/ADT/StringRef.h> | |
-#include <math.h> | |
-#include <float.h> // for _isnan | |
-#include <time.h> | |
-#include <errno.h> | |
-#include <string.h> | |
-#include <ctype.h> | |
-#include <wchar.h> | |
-#include <stdlib.h> | |
-#include <limits> // for std::numeric_limits | |
-#include "target.h" | |
- | |
-#if IN_LLVM | |
-#include "llvm/Support/ErrorHandling.h" | |
-#endif | |
- | |
-double Port::nan; | |
-longdouble Port::ldbl_nan; | |
-longdouble Port::snan; | |
- | |
-double Port::infinity; | |
-longdouble Port::ldbl_infinity; | |
- | |
-double Port::dbl_max = DBL_MAX; | |
-double Port::dbl_min = DBL_MIN; | |
-longdouble Port::ldbl_max = LDBL_MAX; | |
- | |
-#if IN_LLVM | |
-bool Port::yl2x_supported = false; | |
-bool Port::yl2xp1_supported = false; | |
-#else | |
-#if _M_IX86 || _M_X64 | |
-bool Port::yl2x_supported = true; | |
-bool Port::yl2xp1_supported = true; | |
-#else | |
-bool Port::yl2x_supported = false; | |
-bool Port::yl2xp1_supported = false; | |
-#endif | |
-#endif | |
- | |
-struct PortInitializer | |
-{ | |
- PortInitializer(); | |
-}; | |
- | |
-static PortInitializer portinitializer; | |
- | |
-PortInitializer::PortInitializer() | |
-{ | |
-#if IN_LLVM | |
- union { | |
- unsigned long ul[2]; | |
- double d; | |
- } | |
- nan = { { 0, 0x7FF80000 } }, | |
- snan = { { 0, 0x7FFC0000 } }, | |
- inf = { { 0, 0x7FF00000 } }; | |
- | |
- Port::nan = nan.d; | |
- Port::ldbl_nan = nan.d; | |
- Port::snan = snan.d; | |
- Port::infinity = inf.d; | |
- Port::ldbl_infinity = inf.d; | |
-#else | |
- union { | |
- unsigned long ul[2]; | |
- double d; | |
- } nan = { { 0, 0x7FF80000 } }; | |
- | |
- Port::nan = nan.d; | |
- Port::ldbl_nan = ld_qnan; | |
- Port::snan = ld_snan; | |
- Port::infinity = std::numeric_limits<double>::infinity(); | |
- Port::ldbl_infinity = ld_inf; | |
-#endif | |
- | |
- _set_abort_behavior(_WRITE_ABORT_MSG, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // disable crash report | |
-} | |
- | |
-int Port::isNan(double r) | |
-{ | |
-#if _MSC_VER >= 1900 | |
- return ::isnan(r); | |
-#else | |
- return ::_isnan(r); | |
-#endif | |
-} | |
- | |
-int Port::isNan(longdouble r) | |
-{ | |
-#if IN_LLVM | |
- return ::isnan(r); | |
-#else | |
- return ::_isnan(r); | |
-#endif | |
-} | |
- | |
-int Port::isSignallingNan(double r) | |
-{ | |
- /* A signalling NaN is a NaN with 0 as the most significant bit of | |
- * its significand, which is bit 51 of 0..63 for 64 bit doubles. | |
- */ | |
- return isNan(r) && !((((unsigned char*)&r)[6]) & 8); | |
-} | |
- | |
-int Port::isSignallingNan(longdouble r) | |
-{ | |
- /* MSVC doesn't have 80 bit long doubles | |
- */ | |
- return isSignallingNan((double) r); | |
-} | |
- | |
-int Port::isInfinity(double r) | |
-{ | |
-#if _MSC_VER >= 1900 | |
- return ::isinf(r); | |
-#else | |
- return (::_fpclass(r) & (_FPCLASS_NINF | _FPCLASS_PINF)); | |
-#endif | |
-} | |
- | |
-longdouble Port::sqrt(longdouble x) | |
-{ | |
- return ::sqrtl(x); | |
-} | |
- | |
-longdouble Port::fmodl(longdouble x, longdouble y) | |
-{ | |
- return ::fmodl(x, y); | |
-} | |
- | |
-int Port::fequal(longdouble x, longdouble y) | |
-{ | |
- /* In some cases, the REALPAD bytes get garbage in them, | |
- * so be sure and ignore them. | |
- */ | |
- return memcmp(&x, &y, Target::realsize - Target::realpad) == 0; | |
-} | |
- | |
-#if IN_LLVM | |
-void Port::yl2x_impl(longdouble* x, longdouble* y, longdouble* res) | |
-{ | |
- llvm_unreachable("Port::yl2x_impl"); | |
-} | |
- | |
-void Port::yl2xp1_impl(longdouble* x, longdouble* y, longdouble* res) | |
-{ | |
- llvm_unreachable("Port::yl2xp1_impl"); | |
-} | |
-#else | |
-#if _M_IX86 | |
-void Port::yl2x_impl(longdouble* x, longdouble* y, longdouble* res) | |
-{ | |
- __asm | |
- { | |
- mov eax, y | |
- mov ebx, x | |
- mov ecx, res | |
- fld tbyte ptr [eax] | |
- fld tbyte ptr [ebx] | |
- fyl2x | |
- fstp tbyte ptr [ecx] | |
- } | |
-} | |
- | |
-void Port::yl2xp1_impl(longdouble* x, longdouble* y, longdouble* res) | |
-{ | |
- __asm | |
- { | |
- mov eax, y | |
- mov ebx, x | |
- mov ecx, res | |
- fld tbyte ptr [eax] | |
- fld tbyte ptr [ebx] | |
- fyl2xp1 | |
- fstp tbyte ptr [ecx] | |
- } | |
-} | |
-#elif _M_X64 | |
- | |
-//defined in ldfpu.asm | |
-extern "C" | |
-{ | |
- void ld_yl2x(longdouble *x, longdouble *y, longdouble *r); | |
- void ld_yl2xp1(longdouble *x, longdouble *y, longdouble *r); | |
-} | |
- | |
-void Port::yl2x_impl(longdouble* x, longdouble* y, longdouble* res) | |
-{ | |
- ld_yl2x(x, y, res); | |
-} | |
- | |
-void Port::yl2xp1_impl(longdouble* x, longdouble* y, longdouble* res) | |
-{ | |
- ld_yl2xp1(x, y, res); | |
-} | |
-#else | |
- | |
-void Port::yl2x_impl(longdouble* x, longdouble* y, longdouble* res) | |
-{ | |
- assert(0); | |
-} | |
- | |
-void Port::yl2xp1_impl(longdouble* x, longdouble* y, longdouble* res) | |
-{ | |
- assert(0); | |
-} | |
- | |
-#endif | |
-#endif | |
- | |
-char *Port::strupr(char *s) | |
-{ | |
- return ::strupr(s); | |
-} | |
- | |
-int Port::memicmp(const char *s1, const char *s2, int n) | |
-{ | |
- return ::memicmp(s1, s2, n); | |
-} | |
- | |
-int Port::stricmp(const char *s1, const char *s2) | |
-{ | |
- return ::stricmp(s1, s2); | |
-} | |
- | |
-float Port::strtof(const char *p, char **endp) | |
-{ | |
-#if _MSC_VER >= 1900 | |
- return ::strtof(p, endp); // C99 conformant since VS 2015 | |
-#else | |
- if(endp) | |
- return static_cast<float>(::strtod(p, endp)); // does not set errno for underflows, but unused | |
- | |
- _CRT_FLOAT flt; | |
- int res = _atoflt(&flt, (char*)p); | |
- if (res == _UNDERFLOW) | |
- errno = ERANGE; | |
- return flt.f; | |
-#endif | |
-} | |
- | |
-double Port::strtod(const char *p, char **endp) | |
-{ | |
-#if _MSC_VER >= 1900 | |
- return ::strtod(p, endp); // C99 conformant since VS 2015 | |
-#else | |
- if(endp) | |
- return ::strtod(p, endp); // does not set errno for underflows, but unused | |
- | |
- _CRT_DOUBLE dbl; | |
- int res = _atodbl(&dbl, const_cast<char*> (p)); | |
- if (res == _UNDERFLOW) | |
- errno = ERANGE; | |
- return dbl.x; | |
-#endif | |
-} | |
- | |
-// from backend/strtold.c, renamed to avoid clash with decl in stdlib.h | |
-longdouble strtold_dm(const char *p,char **endp); | |
- | |
-longdouble Port::strtold(const char *p, char **endp) | |
-{ | |
-#if IN_LLVM | |
-#if _MSC_VER >= 1900 | |
- return ::strtold(p, endp); // C99 conformant since VS 2015 | |
-#else | |
- // MSVC strtold() before VS 2015 does not support hex float strings. Just | |
- // use the function provided by LLVM because we going to use it anyway. | |
- llvm::APFloat val(llvm::APFloat::IEEEdouble, llvm::APFloat::uninitialized); | |
- val.convertFromString(llvm::StringRef(p), llvm::APFloat::rmNearestTiesToEven); | |
- return val.convertToDouble(); | |
-#endif | |
-#else | |
- return ::strtold_dm(p, endp); | |
-#endif | |
-} | |
- | |
-#endif | |
- | |
-#if __MINGW32__ | |
- | |
-#include <math.h> | |
-#include <time.h> | |
-#include <sys/time.h> | |
-#include <unistd.h> | |
-#include <stdio.h> | |
-#include <stdlib.h> | |
-#include <string.h> | |
-#include <ctype.h> | |
-#include <wchar.h> | |
-#include <float.h> | |
-#include <assert.h> | |
- | |
-double Port::nan; | |
-longdouble Port::ldbl_nan; | |
-longdouble Port::snan; | |
- | |
-static double zero = 0; | |
-double Port::infinity = 1 / zero; | |
-longdouble Port::ldbl_infinity = 1 / zero; | |
- | |
-double Port::dbl_max = 1.7976931348623157e308; | |
-double Port::dbl_min = 5e-324; | |
-longdouble Port::ldbl_max = LDBL_MAX; | |
- | |
-#if _X86_ || __x86_64__ | |
-bool Port::yl2x_supported = true; | |
-bool Port::yl2xp1_supported = true; | |
-#else | |
-bool Port::yl2x_supported = false; | |
-bool Port::yl2xp1_supported = false; | |
-#endif | |
- | |
-struct PortInitializer | |
-{ | |
- PortInitializer(); | |
-}; | |
- | |
-static PortInitializer portinitializer; | |
- | |
-PortInitializer::PortInitializer() | |
-{ | |
- union | |
- { unsigned int ui[2]; | |
- double d; | |
- } nan = {{ 0, 0x7FF80000 }}; | |
- | |
- Port::nan = nan.d; | |
- assert(!signbit(Port::nan)); | |
- | |
- union | |
- { unsigned int ui[4]; | |
- longdouble ld; | |
- } ldbl_nan = {{ 0, 0xC0000000, 0x7FFF, 0}}; | |
- | |
- Port::ldbl_nan = ldbl_nan.ld; | |
- assert(!signbit(Port::ldbl_nan)); | |
- | |
- union | |
- { unsigned int ui[4]; | |
- longdouble ld; | |
- } snan = {{ 0, 0xA0000000, 0x7FFF, 0 }}; | |
- | |
- Port::snan = snan.ld; | |
-} | |
- | |
-int Port::isNan(double r) | |
-{ | |
- return isnan(r); | |
-} | |
- | |
-int Port::isNan(longdouble r) | |
-{ | |
- return isnan(r); | |
-} | |
- | |
-int Port::isSignallingNan(double r) | |
-{ | |
- /* A signalling NaN is a NaN with 0 as the most significant bit of | |
- * its significand, which is bit 51 of 0..63 for 64 bit doubles. | |
- */ | |
- return isNan(r) && !((((unsigned char*)&r)[6]) & 8); | |
-} | |
- | |
-int Port::isSignallingNan(longdouble r) | |
-{ | |
- /* A signalling NaN is a NaN with 0 as the most significant bit of | |
- * its significand, which is bit 62 of 0..79 for 80 bit reals. | |
- */ | |
- return isNan(r) && !((((unsigned char*)&r)[7]) & 0x40); | |
-} | |
- | |
-int Port::isInfinity(double r) | |
-{ | |
- return isinf(r); | |
-} | |
- | |
-longdouble Port::sqrt(longdouble x) | |
-{ | |
- return ::sqrtl(x); | |
-} | |
- | |
-longdouble Port::fmodl(longdouble x, longdouble y) | |
-{ | |
- return ::fmodl(x, y); | |
-} | |
- | |
-int Port::fequal(longdouble x, longdouble y) | |
-{ | |
- /* In some cases, the REALPAD bytes get garbage in them, | |
- * so be sure and ignore them. | |
- */ | |
- return memcmp(&x, &y, 10) == 0; | |
-} | |
- | |
-#if _X86_ || __x86_64__ | |
-void Port::yl2x_impl(longdouble* x, longdouble* y, longdouble* res) | |
-{ | |
- __asm__ volatile("fyl2x": "=t" (*res): "u" (*y), "0" (*x) : "st(1)" ); | |
-} | |
- | |
-void Port::yl2xp1_impl(longdouble* x, longdouble* y, longdouble* res) | |
-{ | |
- __asm__ volatile("fyl2xp1": "=t" (*res): "u" (*y), "0" (*x) : "st(1)" ); | |
-} | |
-#else | |
-void Port::yl2x_impl(longdouble* x, longdouble* y, longdouble* res) | |
-{ | |
- assert(0); | |
-} | |
- | |
-void Port::yl2xp1_impl(longdouble* x, longdouble* y, longdouble* res) | |
-{ | |
- assert(0); | |
-} | |
-#endif | |
- | |
-char *Port::strupr(char *s) | |
-{ | |
- char *t = s; | |
- | |
- while (*s) | |
- { | |
- *s = toupper(*s); | |
- s++; | |
- } | |
- | |
- return t; | |
-} | |
- | |
-int Port::memicmp(const char *s1, const char *s2, int n) | |
-{ | |
- int result = 0; | |
- | |
- for (int i = 0; i < n; i++) | |
- { char c1 = s1[i]; | |
- char c2 = s2[i]; | |
- | |
- result = c1 - c2; | |
- if (result) | |
- { | |
- result = toupper(c1) - toupper(c2); | |
- if (result) | |
- break; | |
- } | |
- } | |
- return result; | |
-} | |
- | |
-int Port::stricmp(const char *s1, const char *s2) | |
-{ | |
- int result = 0; | |
- | |
- for (;;) | |
- { char c1 = *s1; | |
- char c2 = *s2; | |
- | |
- result = c1 - c2; | |
- if (result) | |
- { | |
- result = toupper(c1) - toupper(c2); | |
- if (result) | |
- break; | |
- } | |
- if (!c1) | |
- break; | |
- s1++; | |
- s2++; | |
- } | |
- return result; | |
-} | |
- | |
-float Port::strtof(const char *p, char **endp) | |
-{ | |
- return ::strtof(p, endp); | |
-} | |
- | |
-double Port::strtod(const char *p, char **endp) | |
-{ | |
- return ::strtod(p, endp); | |
-} | |
- | |
-longdouble Port::strtold(const char *p, char **endp) | |
-{ | |
- return ::__mingw_strtold(p, endp); | |
-} | |
- | |
-#endif | |
- | |
-#if __linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __NetBSD__ || __DragonFly__ || __HAIKU__ | |
- | |
-#include <math.h> | |
-#if __FreeBSD__ && __i386__ | |
-#include <ieeefp.h> | |
-#endif | |
-#include <time.h> | |
-#include <sys/time.h> | |
-#include <unistd.h> | |
-#include <stdio.h> | |
-#include <stdlib.h> | |
-#include <string.h> | |
-#include <ctype.h> | |
-#include <wchar.h> | |
-#include <float.h> | |
-#include <assert.h> | |
-#include "target.h" | |
- | |
-#if IN_LLVM | |
-#include "llvm/ADT/APFloat.h" | |
-#endif | |
- | |
-double Port::nan; | |
-longdouble Port::ldbl_nan; | |
-longdouble Port::snan; | |
- | |
-static double zero = 0; | |
-double Port::infinity = 1 / zero; | |
-longdouble Port::ldbl_infinity = 1 / zero; | |
- | |
-double Port::dbl_max = 1.7976931348623157e308; | |
-double Port::dbl_min = 5e-324; | |
-longdouble Port::ldbl_max = LDBL_MAX; | |
- | |
-#if __i386 || __x86_64__ | |
-bool Port::yl2x_supported = true; | |
-bool Port::yl2xp1_supported = true; | |
-#else | |
-bool Port::yl2x_supported = false; | |
-bool Port::yl2xp1_supported = false; | |
-#endif | |
- | |
-struct PortInitializer | |
-{ | |
- PortInitializer(); | |
-}; | |
- | |
-static PortInitializer portinitializer; | |
- | |
-PortInitializer::PortInitializer() | |
-{ | |
-#if IN_LLVM | |
- | |
-// Derive LLVM APFloat::fltSemantics from native format | |
-#if LDBL_MANT_DIG == 53 | |
-#define FLT_SEMANTIC llvm::APFloat::IEEEdouble | |
-#elif LDBL_MANT_DIG == 64 | |
-#define FLT_SEMANTIC llvm::APFloat::x87DoubleExtended | |
-#elif LDBL_MANT_DIG == 106 | |
-#define FLT_SEMANTIC llvm::APFloat::PPCDoubleDouble | |
-#elif LDBL_MANT_DIG == 113 | |
-#define FLT_SEMANTIC llvm::APFloat::IEEEquad | |
-#else | |
-#error "Unsupported native floating point format" | |
-#endif | |
- | |
- Port::nan = *reinterpret_cast<const double*>(llvm::APFloat::getNaN(llvm::APFloat::IEEEdouble).bitcastToAPInt().getRawData()); | |
- Port::ldbl_nan = *reinterpret_cast<const long double*>(llvm::APFloat::getNaN(FLT_SEMANTIC).bitcastToAPInt().getRawData()); | |
- Port::snan = *reinterpret_cast<const long double*>(llvm::APFloat::getSNaN(FLT_SEMANTIC).bitcastToAPInt().getRawData()); | |
- | |
-#else | |
- union | |
- { unsigned int ui[2]; | |
- double d; | |
- } nan = {{ 0, 0x7FF80000 }}; | |
- Port::nan = nan.d; | |
- assert(!signbit(Port::nan)); | |
- | |
- union | |
- { unsigned int ui[4]; | |
- longdouble ld; | |
- } ldbl_nan = {{ 0, 0xC0000000, 0x7FFF, 0}}; | |
- Port::ldbl_nan = ldbl_nan.ld; | |
- | |
- assert(!signbit(Port::ldbl_nan)); | |
- | |
- union | |
- { unsigned int ui[4]; | |
- longdouble ld; | |
- } snan = {{ 0, 0xA0000000, 0x7FFF, 0 }}; | |
- Port::snan = snan.ld; | |
-#endif | |
- | |
-#if __FreeBSD__ && __i386__ | |
- // LDBL_MAX comes out as infinity. Fix. | |
- static unsigned char x[sizeof(longdouble)] = | |
- { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x7F }; | |
- Port::ldbl_max = *(longdouble *)&x[0]; | |
- // FreeBSD defaults to double precision. Switch to extended precision. | |
- fpsetprec(FP_PE); | |
-#endif | |
-} | |
- | |
-int Port::isNan(double r) | |
-{ | |
-#if __APPLE__ | |
-#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 | |
- return __inline_isnand(r); | |
-#else | |
- return __inline_isnan(r); | |
-#endif | |
-#elif __HAIKU__ || __FreeBSD__ || __OpenBSD__ || __NetBSD__ || __DragonFly__ | |
- return isnan(r); | |
-#else | |
- #undef isnan | |
- return std::isnan(r); | |
-#endif | |
-} | |
- | |
-int Port::isNan(longdouble r) | |
-{ | |
-#if __APPLE__ | |
-#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 | |
- return __inline_isnanl(r); | |
-#else | |
- return __inline_isnan(r); | |
-#endif | |
-#elif __HAIKU__ || __FreeBSD__ || __OpenBSD__ || __NetBSD__ || __DragonFly__ | |
- return isnan(r); | |
-#else | |
- #undef isnan | |
- return std::isnan(r); | |
-#endif | |
-} | |
- | |
-int Port::isSignallingNan(double r) | |
-{ | |
- /* A signalling NaN is a NaN with 0 as the most significant bit of | |
- * its significand, which is bit 51 of 0..63 for 64 bit doubles. | |
- */ | |
- return isNan(r) && !((((unsigned char*)&r)[6]) & 8); | |
-} | |
- | |
-int Port::isSignallingNan(longdouble r) | |
-{ | |
- /* A signalling NaN is a NaN with 0 as the most significant bit of | |
- * its significand, which is bit 62 of 0..79 for 80 bit reals. | |
- */ | |
- return isNan(r) && !((((unsigned char*)&r)[7]) & 0x40); | |
-} | |
- | |
-int Port::isInfinity(double r) | |
-{ | |
-#if __APPLE__ | |
- return fpclassify(r) == FP_INFINITE; | |
-#elif __HAIKU__ || __FreeBSD__ || __OpenBSD__ || __NetBSD__ || __DragonFly__ | |
- return isinf(r); | |
-#else | |
- #undef isinf | |
- return std::isinf(r); | |
-#endif | |
-} | |
- | |
-longdouble Port::sqrt(longdouble x) | |
-{ | |
- return std::sqrt(x); | |
-} | |
- | |
-longdouble Port::fmodl(longdouble x, longdouble y) | |
-{ | |
-#if __FreeBSD__ && __FreeBSD_version < 800000 || __OpenBSD__ || __NetBSD__ || __DragonFly__ | |
- return ::fmod(x, y); // hack for now, fix later | |
-#else | |
- return std::fmod(x, y); | |
-#endif | |
-} | |
- | |
-int Port::fequal(longdouble x, longdouble y) | |
-{ | |
- /* In some cases, the REALPAD bytes get garbage in them, | |
- * so be sure and ignore them. | |
- */ | |
- return memcmp(&x, &y, Target::realsize - Target::realpad) == 0; | |
-} | |
- | |
-#if __i386 || __x86_64__ | |
-void Port::yl2x_impl(longdouble* x, longdouble* y, longdouble* res) | |
-{ | |
- __asm__ volatile("fyl2x": "=t" (*res): "u" (*y), "0" (*x) : "st(1)" ); | |
-} | |
- | |
-void Port::yl2xp1_impl(longdouble* x, longdouble* y, longdouble* res) | |
-{ | |
- __asm__ volatile("fyl2xp1": "=t" (*res): "u" (*y), "0" (*x) : "st(1)" ); | |
-} | |
-#else | |
-void Port::yl2x_impl(longdouble* x, longdouble* y, longdouble* res) | |
-{ | |
- assert(0); | |
-} | |
- | |
-void Port::yl2xp1_impl(longdouble* x, longdouble* y, longdouble* res) | |
-{ | |
- assert(0); | |
-} | |
-#endif | |
- | |
-char *Port::strupr(char *s) | |
-{ | |
- char *t = s; | |
- | |
- while (*s) | |
- { | |
- *s = std::toupper(*s); | |
- s++; | |
- } | |
- | |
- return t; | |
-} | |
- | |
-int Port::memicmp(const char *s1, const char *s2, int n) | |
-{ | |
- int result = 0; | |
- | |
- for (int i = 0; i < n; i++) | |
- { char c1 = s1[i]; | |
- char c2 = s2[i]; | |
- | |
- result = c1 - c2; | |
- if (result) | |
- { | |
- result = std::toupper(c1) - std::toupper(c2); | |
- if (result) | |
- break; | |
- } | |
- } | |
- return result; | |
-} | |
- | |
-int Port::stricmp(const char *s1, const char *s2) | |
-{ | |
- int result = 0; | |
- | |
- for (;;) | |
- { char c1 = *s1; | |
- char c2 = *s2; | |
- | |
- result = c1 - c2; | |
- if (result) | |
- { | |
- result = std::toupper(c1) - std::toupper(c2); | |
- if (result) | |
- break; | |
- } | |
- if (!c1) | |
- break; | |
- s1++; | |
- s2++; | |
- } | |
- return result; | |
-} | |
- | |
-float Port::strtof(const char *p, char **endp) | |
-{ | |
- return std::strtof(p, endp); | |
-} | |
- | |
-double Port::strtod(const char *p, char **endp) | |
-{ | |
- return std::strtod(p, endp); | |
-} | |
- | |
-longdouble Port::strtold(const char *p, char **endp) | |
-{ | |
- return std::strtold(p, endp); | |
-} | |
- | |
-#endif | |
- | |
-#if __sun | |
- | |
-#define __C99FEATURES__ 1 // Needed on Solaris for NaN and more | |
-#include <math.h> | |
-#include <time.h> | |
-#include <sys/time.h> | |
-#include <unistd.h> | |
-#include <stdio.h> | |
-#include <stdlib.h> | |
-#include <string.h> | |
-#include <ctype.h> | |
-#include <wchar.h> | |
-#include <float.h> | |
-#include <ieeefp.h> | |
-#include <assert.h> | |
- | |
-double Port::nan; | |
-longdouble Port::ldbl_nan; | |
-longdouble Port::snan; | |
- | |
-static double zero = 0; | |
-double Port::infinity = 1 / zero; | |
-longdouble Port::ldbl_infinity = 1 / zero; | |
- | |
-double Port::dbl_max = 1.7976931348623157e308; | |
-double Port::dbl_min = 5e-324; | |
-longdouble Port::ldbl_max = LDBL_MAX; | |
- | |
-#if __i386 || __x86_64__ | |
-bool Port::yl2x_supported = true; | |
-bool Port::yl2xp1_supported = true; | |
-#else | |
-bool Port::yl2x_supported = false; | |
-bool Port::yl2xp1_supported = false; | |
-#endif | |
- | |
-struct PortInitializer | |
-{ | |
- PortInitializer(); | |
-}; | |
- | |
-static PortInitializer portinitializer; | |
- | |
-PortInitializer::PortInitializer() | |
-{ | |
- union | |
- { unsigned int ui[2]; | |
- double d; | |
- } nan = {{ 0, 0x7FF80000 }}; | |
- | |
- Port::nan = nan.d; | |
- assert(!signbit(Port::nan)); | |
- | |
- union | |
- { unsigned int ui[4]; | |
- longdouble ld; | |
- } ldbl_nan = {{ 0, 0xC0000000, 0x7FFF, 0}}; | |
- | |
- Port::ldbl_nan = ldbl_nan.ld; | |
- assert(!signbit(Port::ldbl_nan)); | |
- | |
- union | |
- { unsigned int ui[4]; | |
- longdouble ld; | |
- } snan = {{ 0, 0xA0000000, 0x7FFF, 0 }}; | |
- | |
- Port::snan = snan.ld; | |
-} | |
- | |
-int Port::isNan(double r) | |
-{ | |
- return isnan(r); | |
-} | |
- | |
-int Port::isNan(longdouble r) | |
-{ | |
- return isnan(r); | |
-} | |
- | |
-int Port::isSignallingNan(double r) | |
-{ | |
- /* A signalling NaN is a NaN with 0 as the most significant bit of | |
- * its significand, which is bit 51 of 0..63 for 64 bit doubles. | |
- */ | |
- return isNan(r) && !((((unsigned char*)&r)[6]) & 8); | |
-} | |
- | |
-int Port::isSignallingNan(longdouble r) | |
-{ | |
- /* A signalling NaN is a NaN with 0 as the most significant bit of | |
- * its significand, which is bit 62 of 0..79 for 80 bit reals. | |
- */ | |
- return isNan(r) && !((((unsigned char*)&r)[7]) & 0x40); | |
-} | |
- | |
-int Port::isInfinity(double r) | |
-{ | |
- return isinf(r); | |
-} | |
- | |
-longdouble Port::sqrt(longdouble x) | |
-{ | |
- return ::sqrtl(x); | |
-} | |
- | |
-longdouble Port::fmodl(longdouble x, longdouble y) | |
-{ | |
- return ::fmodl(x, y); | |
-} | |
- | |
-int Port::fequal(longdouble x, longdouble y) | |
-{ | |
- /* In some cases, the REALPAD bytes get garbage in them, | |
- * so be sure and ignore them. | |
- */ | |
- return memcmp(&x, &y, 10) == 0; | |
-} | |
-#if __i386 | |
-#if IN_LLVM | |
-// There seems to be an issue with register usage if compiled as PIC. | |
-void Port::yl2x_impl(long double* x, long double* y, long double* res) | |
-{ | |
- __asm__ volatile("movl %0, %%eax;" // move x, y, res to registers | |
- "movl %1, %%ecx;" | |
- "fldt (%%edx);" // push *y and *x to the FPU stack | |
- "fldt (%%eax);" // "t" suffix means tbyte | |
- "movl %2, %%eax;" | |
- "fyl2x;" // do operation and wait | |
- "fstpt (%%eax)" // pop result to a *res | |
- : // output: empty | |
- :"r"(x), "r"(y), "r"(res) // input: x => %0, y => %1, res => %2 | |
- :"%eax", "%ecx", "%eax"); // clobbered register: eax, ecx, eax | |
-} | |
- | |
-void Port::yl2xp1_impl(long double* x, long double* y, long double* res) | |
-{ | |
- __asm__ volatile("movl %0, %%eax;" // move x, y, res to registers | |
- "movl %1, %%ecx;" | |
- "fldt (%%ecx);" // push *y and *x to the FPU stack | |
- "fldt (%%eax);" // "t" suffix means tbyte | |
- "movl %2, %%eax;" | |
- "fyl2xp1;" // do operation and wait | |
- "fstpt (%%eax)" // pop result to a *res | |
- : // output: empty | |
- :"r"(x), "r"(y), "r"(res) // input: x => %0, y => %1, res => %2 | |
- :"%eax", "%ecx", "%eax"); // clobbered register: eax, ecx, eax | |
-} | |
-#else | |
-void Port::yl2x_impl(long double* x, long double* y, long double* res) | |
-{ | |
- __asm__ volatile("movl %0, %%eax;" // move x, y, res to registers | |
- "movl %1, %%ebx;" | |
- "movl %2, %%ecx;" | |
- "fldt (%%ebx);" // push *y and *x to the FPU stack | |
- "fldt (%%eax);" // "t" suffix means tbyte | |
- "fyl2x;" // do operation and wait | |
- "fstpt (%%ecx)" // pop result to a *res | |
- : // output: empty | |
- :"r"(x), "r"(y), "r"(res) // input: x => %0, y => %1, res => %2 | |
- :"%eax", "%ebx", "%ecx"); // clobbered register: eax, ebc, ecx | |
-} | |
- | |
-void Port::yl2xp1_impl(long double* x, long double* y, long double* res) | |
-{ | |
- __asm__ volatile("movl %0, %%eax;" // move x, y, res to registers | |
- "movl %1, %%ebx;" | |
- "movl %2, %%ecx;" | |
- "fldt (%%ebx);" // push *y and *x to the FPU stack | |
- "fldt (%%eax);" // "t" suffix means tbyte | |
- "fyl2xp1;" // do operation and wait | |
- "fstpt (%%ecx)" // pop result to a *res | |
- : // output: empty | |
- :"r"(x), "r"(y), "r"(res) // input: x => %0, y => %1, res => %2 | |
- :"%eax", "%ebx", "%ecx"); // clobbered register: eax, ebc, ecx | |
-} | |
-#endif | |
-#elif __x86_64__ | |
-void Port::yl2x_impl(long double* x, long double* y, long double* res) | |
-{ | |
- __asm__ volatile("movq %0, %%rcx;" // move x, y, res to registers | |
- "movq %1, %%rdx;" | |
- "movq %2, %%r8;" | |
- "fldt (%%rdx);" // push *y and *x to the FPU stack | |
- "fldt (%%rcx);" // "t" suffix means tbyte | |
- "fyl2x;" // do operation and wait | |
- "fstpt (%%r8)" // pop result to a *res | |
- : // output: empty | |
- :"r"(x), "r"(y), "r"(res) // input: x => %0, y => %1, res => %2 | |
- :"%rcx", "%rdx", "%r8"); // clobbered register: rcx, rdx, r8 | |
-} | |
- | |
-void Port::yl2xp1_impl(long double* x, long double* y, long double* res) | |
-{ | |
- __asm__ volatile("movq %0, %%rcx;" // move x, y, res to registers | |
- "movq %1, %%rdx;" | |
- "movq %2, %%r8;" | |
- "fldt (%%rdx);" // push *y and *x to the FPU stack | |
- "fldt (%%rcx);" // "t" suffix means tbyte | |
- "fyl2xp1;" // do operation and wait | |
- "fstpt (%%r8)" // pop result to a *res | |
- : // output: empty | |
- :"r"(x), "r"(y), "r"(res) // input: x => %0, y => %1, res => %2 | |
- :"%rcx", "%rdx", "%r8"); // clobbered register: rcx, rdx, r8 | |
-} | |
-#else | |
-void Port::yl2x_impl(longdouble* x, longdouble* y, longdouble* res) | |
-{ | |
- assert(0); | |
-} | |
- | |
-void Port::yl2xp1_impl(longdouble* x, longdouble* y, longdouble* res) | |
-{ | |
- assert(0); | |
-} | |
-#endif | |
- | |
-char *Port::strupr(char *s) | |
-{ | |
- char *t = s; | |
- | |
- while (*s) | |
- { | |
- *s = toupper(*s); | |
- s++; | |
- } | |
- | |
- return t; | |
-} | |
- | |
-int Port::memicmp(const char *s1, const char *s2, int n) | |
-{ | |
- int result = 0; | |
- | |
- for (int i = 0; i < n; i++) | |
- { char c1 = s1[i]; | |
- char c2 = s2[i]; | |
- | |
- result = c1 - c2; | |
- if (result) | |
- { | |
- result = toupper(c1) - toupper(c2); | |
- if (result) | |
- break; | |
- } | |
- } | |
- return result; | |
-} | |
- | |
-int Port::stricmp(const char *s1, const char *s2) | |
-{ | |
- int result = 0; | |
- | |
- for (;;) | |
- { char c1 = *s1; | |
- char c2 = *s2; | |
- | |
- result = c1 - c2; | |
- if (result) | |
- { | |
- result = toupper(c1) - toupper(c2); | |
- if (result) | |
- break; | |
- } | |
- if (!c1) | |
- break; | |
- s1++; | |
- s2++; | |
- } | |
- return result; | |
-} | |
- | |
-float Port::strtof(const char *p, char **endp) | |
-{ | |
- return ::strtof(p, endp); | |
-} | |
- | |
-double Port::strtod(const char *p, char **endp) | |
-{ | |
- return ::strtod(p, endp); | |
-} | |
- | |
-longdouble Port::strtold(const char *p, char **endp) | |
-{ | |
- return ::strtold(p, endp); | |
-} | |
- | |
-#endif | |
- | |
-// Little endian | |
-void Port::writelongLE(unsigned value, void* buffer) | |
-{ | |
- unsigned char *p = (unsigned char*)buffer; | |
- p[3] = (unsigned char)(value >> 24); | |
- p[2] = (unsigned char)(value >> 16); | |
- p[1] = (unsigned char)(value >> 8); | |
- p[0] = (unsigned char)(value); | |
-} | |
- | |
-// Little endian | |
-unsigned Port::readlongLE(void* buffer) | |
-{ | |
- unsigned char *p = (unsigned char*)buffer; | |
- return (((((p[3] << 8) | p[2]) << 8) | p[1]) << 8) | p[0]; | |
-} | |
- | |
-// Big endian | |
-void Port::writelongBE(unsigned value, void* buffer) | |
-{ | |
- unsigned char *p = (unsigned char*)buffer; | |
- p[0] = (unsigned char)(value >> 24); | |
- p[1] = (unsigned char)(value >> 16); | |
- p[2] = (unsigned char)(value >> 8); | |
- p[3] = (unsigned char)(value); | |
-} | |
- | |
-// Big endian | |
-unsigned Port::readlongBE(void* buffer) | |
-{ | |
- unsigned char *p = (unsigned char*)buffer; | |
- return (((((p[0] << 8) | p[1]) << 8) | p[2]) << 8) | p[3]; | |
-} | |
- | |
-// Little endian | |
-unsigned Port::readwordLE(void *buffer) | |
-{ | |
- unsigned char *p = (unsigned char*)buffer; | |
- return (p[1] << 8) | p[0]; | |
-} | |
- | |
-// Big endian | |
-unsigned Port::readwordBE(void *buffer) | |
-{ | |
- unsigned char *p = (unsigned char*)buffer; | |
- return (p[0] << 8) | p[1]; | |
-} | |
diff --git a/dmd2/root/port.h b/dmd2/root/port.h | |
index e3b06ef..583291c 100644 | |
--- a/dmd2/root/port.h | |
+++ b/dmd2/root/port.h | |
@@ -33,6 +33,13 @@ typedef unsigned long long ulonglong; | |
typedef unsigned char utf8_t; | |
+#if IN_LLVM | |
+namespace ldc | |
+{ | |
+ void port_init(); | |
+} | |
+#endif | |
+ | |
struct Port | |
{ | |
static double nan; | |
diff --git a/driver/main.cpp b/driver/main.cpp | |
index ee10ab5..8309380 100644 | |
--- a/driver/main.cpp | |
+++ b/driver/main.cpp | |
@@ -1005,6 +1009,8 @@ int main(int argc, char **argv) { | |
initPrecedence(); | |
builtin_init(); | |
initTraitsStringTable(); | |
+ ldc::real_init(); | |
+ ldc::port_init(); | |
// Build import search path | |
if (global.params.imppath) { | |
diff --git a/gen/ldc-real.cpp b/gen/ldc-real.cpp | |
new file mode 100644 | |
index 0000000..33101b9 | |
--- /dev/null | |
+++ b/gen/ldc-real.cpp | |
@@ -0,0 +1,357 @@ | |
+//===-- gen/ldc-real.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 "gen/ldc-real.h" | |
+#include "gen/llvmcompat.h" | |
+#include "llvm/ADT/SmallString.h" | |
+#include "llvm/ADT/Triple.h" | |
+#include "llvm/Support/CommandLine.h" | |
+#include "llvm/Target/TargetMachine.h" | |
+#include "mars.h" // Only for warning() | |
+#include <cmath> // Only for sin(), cos(), tan() | |
+ | |
+static llvm::cl::opt<bool> longdouble64("long-double-64", | |
+ llvm::cl::desc("Choose real to be 64bit double"), | |
+ llvm::cl::ZeroOrMore, | |
+ llvm::cl::init(false)); | |
+ | |
+extern llvm::TargetMachine *gTargetMachine; | |
+ | |
+const llvm::fltSemantics &ldc::longdouble::getFltSemantics() | |
+{ | |
+ static llvm::Triple::ArchType arch = llvm::Triple::UnknownArch; | |
+ switch (arch) | |
+ { | |
+ case llvm::Triple::UnknownArch: | |
+ arch = llvm::Triple(gTargetMachine->getTargetTriple()).getArch(); | |
+ if (arch != llvm::Triple::UnknownArch) | |
+ return getFltSemantics(); | |
+ else | |
+ return llvm::APFloat::IEEEdouble; | |
+ case llvm::Triple::x86: | |
+ case llvm::Triple::x86_64: | |
+ return longdouble64 ? llvm::APFloat::IEEEdouble : llvm::APFloat::x87DoubleExtended; | |
+ case llvm::Triple::ppc: | |
+ case llvm::Triple::ppc64: | |
+#if LDC_LLVM_VER >= 304 | |
+ case llvm::Triple::ppc64le: | |
+#endif | |
+ return longdouble64 ? llvm::APFloat::IEEEdouble : llvm::APFloat::PPCDoubleDouble; | |
+ default: | |
+ return llvm::APFloat::IEEEdouble; | |
+ } | |
+} | |
+ | |
+ldc::longdouble ldc::longdouble::abs() const | |
+{ | |
+ if (value()->isNegative()) | |
+ { | |
+ llvm::APFloat f(*value()); | |
+ f.changeSign(); | |
+ ldc::longdouble tmp; | |
+ return tmp.init(f); | |
+ } | |
+ return *this; | |
+} | |
+ | |
+static llvm::APFloat::opStatus sqrt(llvm::APFloat &the) | |
+{ | |
+ if (!the.isNaN() && !the.isInfinity() && !the.isZero()) | |
+ { | |
+ if (the.isNegative()) { | |
+ the = llvm::APFloat::getNaN(the.getSemantics()); | |
+ return llvm::APFloat::opInvalidOp; | |
+ } | |
+ | |
+ static const llvm::APFloat onehalf(the.getSemantics(), "0.5"); | |
+ llvm::APFloat x0(the); | |
+ | |
+ int loop = 0; | |
+ do { | |
+ llvm::APFloat x1(the); | |
+ x1.divide(x0, llvm::APFloat::rmNearestTiesToEven); | |
+ x1.add(x0, llvm::APFloat::rmNearestTiesToEven); | |
+ x1.multiply(onehalf, llvm::APFloat::rmNearestTiesToEven); | |
+ if (x1.bitwiseIsEqual(x0)) break; | |
+ x0 = x1; | |
+ } while (loop++ < 10); | |
+ | |
+ the = x0; | |
+ } | |
+ return llvm::APFloat::opOK; | |
+} | |
+ | |
+ldc::longdouble ldc::longdouble::sqrt() const | |
+{ | |
+ llvm::APFloat f(*value()); | |
+ ::sqrt(f); | |
+ ldc::longdouble tmp; | |
+ return tmp.init(f); | |
+} | |
+ | |
+static llvm::APFloat::opStatus sin(llvm::APFloat &the) | |
+{ | |
+// Using a Maclaurin series: | |
+// sin(x) = x - x^3/3! + x^5/5! - x^7/7! + x^9/9! - x^11/11! + x^13/13! ... | |
+// Also note: | |
+// sin(-x) = - sin(x) | |
+ static const llvm::APFloat zero(the.getSemantics()); | |
+ static const llvm::APFloat pi(the.getSemantics(), "3.1415"); | |
+ static const llvm::APFloat plusone(the.getSemantics(), "1"); | |
+ static const llvm::APFloat minusone(the.getSemantics(), "-1"); | |
+ static const llvm::APFloat S6(the.getSemantics(), "156"); // 13*12 | |
+ static const llvm::APFloat S5(the.getSemantics(), "110"); // 11*10 | |
+ static const llvm::APFloat S4(the.getSemantics(), "72"); // 9* 8 | |
+ static const llvm::APFloat S3(the.getSemantics(), "42"); // 7* 6 | |
+ static const llvm::APFloat S2(the.getSemantics(), "20"); // 4* 5 | |
+ static const llvm::APFloat S1(the.getSemantics(), "6"); // 2* 3 | |
+ | |
+ bool negate = the.compare(zero) == llvm::APFloat::cmpLessThan; | |
+ if (negate) | |
+ the.changeSign(); | |
+ llvm::APFloat the2(the); the2.multiply(the2, llvm::APFloat::rmNearestTiesToEven); | |
+ | |
+ llvm::APFloat v(the2); | |
+ v.divide(S6, llvm::APFloat::rmNearestTiesToEven); | |
+ v.add(minusone, llvm::APFloat::rmNearestTiesToEven); | |
+ v.multiply(the2, llvm::APFloat::rmNearestTiesToEven); | |
+ v.divide(S5, llvm::APFloat::rmNearestTiesToEven); | |
+ v.add(plusone, llvm::APFloat::rmNearestTiesToEven); | |
+ v.multiply(the2, llvm::APFloat::rmNearestTiesToEven); | |
+ v.divide(S4, llvm::APFloat::rmNearestTiesToEven); | |
+ v.add(minusone, llvm::APFloat::rmNearestTiesToEven); | |
+ v.multiply(the2, llvm::APFloat::rmNearestTiesToEven); | |
+ v.divide(S3, llvm::APFloat::rmNearestTiesToEven); | |
+ v.add(plusone, llvm::APFloat::rmNearestTiesToEven); | |
+ v.multiply(the2, llvm::APFloat::rmNearestTiesToEven); | |
+ v.divide(S2, llvm::APFloat::rmNearestTiesToEven); | |
+ v.add(minusone, llvm::APFloat::rmNearestTiesToEven); | |
+ v.multiply(the2, llvm::APFloat::rmNearestTiesToEven); | |
+ v.divide(S1, llvm::APFloat::rmNearestTiesToEven); | |
+ | |
+ v.multiply(the, llvm::APFloat::rmNearestTiesToEven); | |
+ if (negate) | |
+ v.changeSign(); | |
+ the = v; | |
+ | |
+ return llvm::APFloat::opOK; | |
+} | |
+ | |
+ldc::longdouble ldc::longdouble::sin() const | |
+{ | |
+ warning(Loc(), "sin() uses only double precision"); | |
+ double d = std::sin(value()->convertToDouble()); | |
+ return ldouble(d); | |
+#if 0 | |
+// Not good enough yet. | |
+ llvm::APFloat f(*value()); | |
+ ::sin(f); | |
+ ldc::longdouble tmp; | |
+ return tmp.init(f); | |
+#endif | |
+} | |
+ | |
+ldc::longdouble ldc::longdouble::cos() const | |
+{ | |
+ warning(Loc(), "cos() uses only double precision"); | |
+ double d = std::cos(value()->convertToDouble()); | |
+ return ldouble(d); | |
+} | |
+ | |
+ldc::longdouble ldc::longdouble::tan() const | |
+{ | |
+ warning(Loc(), "tan() uses only double precision"); | |
+ double d = std::tan(value()->convertToDouble()); | |
+ return ldouble(d); | |
+} | |
+ | |
+ldc::longdouble ldc::longdouble::floor() const | |
+{ | |
+ // matches man floor(3) description | |
+ // floor(+-0) returns +-0. | |
+ // floor(+-infinity) returns +-infinity. | |
+ longdouble tmp; | |
+ tmp.init(*this).value()->roundToIntegral(llvm::APFloat::rmTowardNegative); | |
+ return tmp; | |
+} | |
+ | |
+ldc::longdouble ldc::longdouble::ceil() const | |
+{ | |
+ // matches man ceil(3) special values | |
+ // ceil(+-0) returns +-0. | |
+ // ceil(+-infinity) returns +-infinity. | |
+ longdouble tmp; | |
+ tmp.init(*this).value()->roundToIntegral(llvm::APFloat::rmTowardPositive); | |
+ return tmp; | |
+} | |
+ | |
+ldc::longdouble ldc::longdouble::trunc() const | |
+{ | |
+ // matches man trunc(3) special values | |
+ // trunc(+-0) returns +-0. | |
+ // trunc(+-infinity) returns +-infinity. | |
+ longdouble tmp; | |
+ tmp.init(*this).value()->roundToIntegral(llvm::APFloat::rmTowardZero); | |
+ return tmp; | |
+} | |
+ | |
+ldc::longdouble ldc::longdouble::round() const | |
+{ | |
+ // matches man round(3) special values | |
+ // round(+-0) returns +-0. | |
+ // round(+-infinity) returns +-infinity. | |
+ longdouble tmp; | |
+ tmp.init(*this).value()->roundToIntegral(llvm::APFloat::rmNearestTiesToAway); | |
+ return tmp; | |
+} | |
+ | |
+ldc::longdouble ldc::longdouble::fmin(longdouble x, longdouble y) | |
+{ | |
+ // matches man fmin(3) special values and -0,+0 ordering | |
+ // If exactly one argument is a NaN, fmin() returns the other | |
+ // argument. If both arguments are NaNs, fmin() returns a NaN. | |
+ return (x.isNaN() ? y : | |
+ y.isNaN() ? x : | |
+ x <= y ? x : y); | |
+} | |
+ | |
+ldc::longdouble ldc::longdouble::fmax(longdouble x, longdouble y) | |
+{ | |
+ // matches man fmax(3) special values and -0,+0 ordering | |
+ // If exactly one argument is a NaN, fmax() returns the other | |
+ // argument. If both arguments are NaNs, fmax() returns a NaN. | |
+ return (x.isNaN() ? y : | |
+ y.isNaN() ? x : | |
+ x >= y ? x : y); | |
+} | |
+ | |
+ldc::longdouble ldc::longdouble::fmod(ldc::longdouble x, ldc::longdouble y) | |
+{ | |
+ llvm::APFloat f(*x.value()); | |
+ f.mod(*y.value());//, llvm::APFloat::rmNearestTiesToEven); | |
+ ldc::longdouble tmp; | |
+ return tmp.init(f); | |
+} | |
+ | |
+ldc::longdouble ldc::longdouble::ldexp(ldc::longdouble ldval, int exp) | |
+{ | |
+ llvm_unreachable("ldc::longdouble::ldexp() not implemented"); | |
+} | |
+ | |
+int ldc::longdouble::format (char *buf) const | |
+{ | |
+ llvm::SmallString<64> str; | |
+ value()->toString(str, 0, 0); | |
+ strcpy(buf, str.str().str().c_str()); | |
+ return strlen(buf); | |
+} | |
+ | |
+int ldc::longdouble::formatHex (char *buf, bool upper) const | |
+{ | |
+ return value()->convertToHexString(buf, 0, upper, llvm::APFloat::rmNearestTiesToEven); | |
+} | |
+ | |
+static llvm::APFloat toLD(const llvm::APFloat &f) | |
+{ | |
+ llvm::APFloat cvt(f); | |
+ bool ignored; | |
+ llvm::APFloat::opStatus status = cvt.convert(ldc::longdouble::getFltSemantics(), llvm::APFloat::rmNearestTiesToEven, &ignored); | |
+ assert(status == llvm::APFloat::opOK); | |
+ (void)status; | |
+ return cvt; | |
+} | |
+ | |
+ldc::real_properties ldc::real_limits[ldc::longdouble::NumModes]; | |
+ | |
+void ldc::real_init() | |
+{ | |
+ using ldc::longdouble; | |
+ using llvm::APFloat; | |
+ | |
+ const llvm::fltSemantics &ldSem = longdouble::getFltSemantics(); | |
+ enum { x87, ppc, other }; | |
+ int real; | |
+ switch (APFloat::semanticsPrecision(ldSem)) | |
+ { | |
+ case 64: real = x87; break; | |
+ case 106: real = ppc; break; | |
+ case 53: real = other; break; | |
+ default: llvm_unreachable("Floating point type not supported"); | |
+ } | |
+ | |
+ real_limits[longdouble::Float].maxval = toLD(APFloat::getLargest(APFloat::IEEEsingle)); | |
+ real_limits[longdouble::Double].maxval = toLD(APFloat::getLargest(APFloat::IEEEdouble)); | |
+ real_limits[longdouble::LongDouble].maxval = APFloat::getLargest(ldSem); | |
+ | |
+ real_limits[longdouble::Float].minval = toLD(APFloat::getSmallestNormalized(APFloat::IEEEsingle)); | |
+ real_limits[longdouble::Double].minval = toLD(APFloat::getSmallestNormalized(APFloat::IEEEdouble)); | |
+ real_limits[longdouble::LongDouble].minval = APFloat::getSmallestNormalized(ldSem); | |
+ | |
+ real_limits[longdouble::Float].epsilonval = APFloat(ldSem, "1.19209290e-07"); | |
+ real_limits[longdouble::Double].epsilonval = APFloat(ldSem, "2.2204460492503131e-016"); | |
+ switch (real) | |
+ { | |
+ case x87: real_limits[longdouble::LongDouble].epsilonval = APFloat(ldSem, "1.0842021724855044340e-019"); break; | |
+ case ppc: real_limits[longdouble::LongDouble].epsilonval = APFloat(ldSem, "2.2204460492503131e-016"); break; // like double | |
+ case other: real_limits[longdouble::LongDouble].epsilonval = APFloat(ldSem, "2.2204460492503131e-016"); break; // aka double | |
+ } | |
+ | |
+ real_limits[longdouble::Float].dig = 6; | |
+ real_limits[longdouble::Double].dig = 15; | |
+ switch (real) | |
+ { | |
+ case x87: real_limits[longdouble::LongDouble].dig = 80; break; | |
+ case ppc: real_limits[longdouble::LongDouble].dig = 15; break; // like double | |
+ case other: real_limits[longdouble::LongDouble].dig = 15; break; // aka double | |
+ } | |
+ | |
+ real_limits[longdouble::Float].mant_dig = APFloat::semanticsPrecision(APFloat::IEEEsingle); | |
+ real_limits[longdouble::Double].mant_dig = APFloat::semanticsPrecision(APFloat::IEEEdouble); | |
+ real_limits[longdouble::LongDouble].mant_dig = APFloat::semanticsPrecision(ldSem); | |
+ | |
+ real_limits[longdouble::Float].max_10_exp = 38; | |
+ real_limits[longdouble::Double].max_10_exp = 308; | |
+ switch (real) | |
+ { | |
+ case x87: real_limits[longdouble::LongDouble].max_10_exp = 4932; break; | |
+ case ppc: real_limits[longdouble::LongDouble].max_10_exp = 308; break; // like double | |
+ case other: real_limits[longdouble::LongDouble].max_10_exp = 308; break; // aka double | |
+ } | |
+ | |
+ real_limits[longdouble::Float].min_10_exp = -37; | |
+ real_limits[longdouble::Double].min_10_exp = -307; | |
+ switch (real) | |
+ { | |
+ case x87: real_limits[longdouble::LongDouble].min_10_exp = -4932; break; | |
+ case ppc: real_limits[longdouble::LongDouble].min_10_exp = -307; break; // like double | |
+ case other: real_limits[longdouble::LongDouble].min_10_exp = -307; break; // aka double | |
+ } | |
+ | |
+ real_limits[longdouble::Float].max_exp = 128; | |
+ real_limits[longdouble::Double].max_exp = 1024; | |
+ switch (real) | |
+ { | |
+ case x87: real_limits[longdouble::LongDouble].max_exp = 16384; break; | |
+ case ppc: real_limits[longdouble::LongDouble].max_exp = 1024; break; // like double | |
+ case other: real_limits[longdouble::LongDouble].max_exp = 1024; break; // aka double | |
+ } | |
+ | |
+ real_limits[longdouble::Float].min_exp = -125; | |
+ real_limits[longdouble::Double].min_exp = -1021; | |
+ switch (real) | |
+ { | |
+ case x87: real_limits[longdouble::LongDouble].min_exp = -16381; break; | |
+ case ppc: real_limits[longdouble::LongDouble].min_exp = -1021; break; // like double | |
+ case other: real_limits[longdouble::LongDouble].min_exp = -1021; break; // aka double | |
+ } | |
+} | |
diff --git a/gen/ldc-real.h b/gen/ldc-real.h | |
new file mode 100644 | |
index 0000000..0e715fb | |
--- /dev/null | |
+++ b/gen/ldc-real.h | |
@@ -0,0 +1,557 @@ | |
+//===-- gen/ldc-real.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 longdouble type for LDC. | |
+// | |
+//===----------------------------------------------------------------------===// | |
+ | |
+#ifndef LDC_GEN_LDC_REAL_H | |
+#define LDC_GEN_LDC_REAL_H | |
+ | |
+#undef min | |
+#undef max | |
+ | |
+#include "llvm/ADT/APFloat.h" | |
+#include "llvm/ADT/APSInt.h" | |
+#include "llvm/ADT/StringRef.h" | |
+ | |
+namespace ldc | |
+{ | |
+ | |
+class longdouble | |
+{ | |
+public: | |
+ // List of supported floating point semantics in D. | |
+ enum FloatSemanticsInD | |
+ { | |
+ Float, | |
+ Double, | |
+ LongDouble, | |
+ NumModes | |
+ }; | |
+ | |
+private: | |
+ // Space for a llvm:APFloat object. | |
+ // This class must not have a default constructor. Therefore we have to | |
+ // manage the payload on our own. | |
+ unsigned char mem[sizeof(llvm::APFloat)]; | |
+ | |
+ llvm::APFloat *value() | |
+ { | |
+ return reinterpret_cast<llvm::APFloat *>(&this->mem); | |
+ } | |
+ | |
+ const llvm::APFloat *value() const | |
+ { | |
+ return reinterpret_cast<const llvm::APFloat *>(&this->mem); | |
+ } | |
+ | |
+ longdouble &init(const llvm::APFloat &other) | |
+ { | |
+ new (&this->mem) llvm::APFloat(other); | |
+ return *this; | |
+ } | |
+ | |
+ longdouble &init(const longdouble &other) | |
+ { | |
+ return init(*other.value()); | |
+ } | |
+ | |
+public: | |
+ static const llvm::fltSemantics &getFltSemantics(); | |
+ | |
+ template<typename T> | |
+ longdouble& operator=(T x) | |
+ { | |
+ set(x); | |
+ return *this; | |
+ } | |
+ | |
+ longdouble operator+(const longdouble &r) | |
+ { | |
+ longdouble tmp; | |
+ tmp.init(*this).value()->add(*r.value(), llvm::APFloat::rmNearestTiesToEven); | |
+ return tmp; | |
+ } | |
+ | |
+ longdouble operator-(const longdouble &r) | |
+ { | |
+ longdouble tmp; | |
+ tmp.init(*this).value()->subtract(*r.value(), llvm::APFloat::rmNearestTiesToEven); | |
+ return tmp; | |
+ } | |
+ | |
+ longdouble operator-() | |
+ { | |
+ longdouble tmp; | |
+ tmp.init(*this).value()->changeSign(); | |
+ return tmp; | |
+ } | |
+ | |
+ longdouble operator*(const longdouble &r) | |
+ { | |
+ longdouble tmp; | |
+ tmp.init(*this).value()->multiply(*r.value(), llvm::APFloat::rmNearestTiesToEven); | |
+ return tmp; | |
+ } | |
+ | |
+ longdouble operator/(const longdouble &r) | |
+ { | |
+ longdouble tmp; | |
+ tmp.init(*this).value()->divide(*r.value(), llvm::APFloat::rmNearestTiesToEven); | |
+ return tmp; | |
+ } | |
+ | |
+ longdouble operator%(const longdouble &r) | |
+ { | |
+ longdouble tmp; | |
+ tmp.init(*this).value()->mod(*r.value());//, llvm::APFloat::rmNearestTiesToEven); | |
+ return tmp; | |
+ } | |
+ | |
+ bool operator<(const longdouble &r) | |
+ { | |
+ return value()->compare(*r.value()) == llvm::APFloat::cmpLessThan; | |
+ } | |
+ | |
+ bool operator>(const longdouble &r) | |
+ { | |
+ return value()->compare(*r.value()) == llvm::APFloat::cmpGreaterThan; | |
+ } | |
+ | |
+ bool operator<=(const longdouble &r) | |
+ { | |
+ llvm::APFloat::cmpResult res = value()->compare(*r.value()); | |
+ return res == llvm::APFloat::cmpLessThan | |
+ || res == llvm::APFloat::cmpEqual; | |
+ } | |
+ | |
+ bool operator>=(const longdouble &r) | |
+ { | |
+ llvm::APFloat::cmpResult res = value()->compare(*r.value()); | |
+ return res == llvm::APFloat::cmpGreaterThan | |
+ || res == llvm::APFloat::cmpEqual; | |
+ } | |
+ | |
+ bool operator==(const longdouble &r) | |
+ { | |
+ return value()->compare(*r.value()) == llvm::APFloat::cmpEqual; | |
+ } | |
+ | |
+ bool operator!=(const longdouble &r) | |
+ { | |
+ llvm::APFloat::cmpResult res = value()->compare(*r.value()); | |
+ return res != llvm::APFloat::cmpEqual; | |
+ } | |
+ | |
+ operator float () const | |
+ { | |
+ return convertToFloat(); | |
+ } | |
+ operator double () const | |
+ { | |
+ return convertToDouble(); | |
+ } | |
+ | |
+ operator signed char () const { return convertToInteger<signed char, false>(); } | |
+ operator short () const { return convertToInteger<short, false>(); } | |
+ operator int () const { return convertToInteger<int, false>(); } | |
+ operator long () const { return convertToInteger<long, false>(); } | |
+ operator long long () const { return convertToInteger<long long, false>(); } | |
+ | |
+ operator unsigned char () const { return convertToInteger<unsigned char, true>(); } | |
+ operator unsigned short () const { return convertToInteger<unsigned short, true>(); } | |
+ operator unsigned int () const { return convertToInteger<unsigned int, true>(); } | |
+ operator unsigned long () const { return convertToInteger<unsigned long, true>(); } | |
+ operator unsigned long long() const { return convertToInteger<unsigned long long, true>(); } | |
+ | |
+ operator llvm::APFloat& () | |
+ { | |
+ return *value(); | |
+ } | |
+ | |
+ operator const llvm::APFloat& () const | |
+ { | |
+ return *value(); | |
+ } | |
+ | |
+ operator bool () const | |
+ { | |
+ return value()->isZero() ? false : true; | |
+ } | |
+ | |
+ double convertToDouble() const | |
+ { | |
+ llvm::APFloat trunc(*value()); | |
+ bool ignored; | |
+ llvm::APFloat::opStatus status = trunc.convert(llvm::APFloat::IEEEdouble, llvm::APFloat::rmNearestTiesToEven, &ignored); | |
+ //assert(status == llvm::APFloat::opOK); | |
+ (void)status; | |
+ return trunc.convertToDouble(); | |
+ } | |
+ | |
+ float convertToFloat() const | |
+ { | |
+ llvm::APFloat trunc(*value()); | |
+ bool ignored; | |
+ llvm::APFloat::opStatus status = trunc.convert(llvm::APFloat::IEEEsingle, llvm::APFloat::rmNearestTiesToEven, &ignored); | |
+ //assert(status == llvm::APFloat::opOK); | |
+ (void)status; | |
+ return trunc.convertToFloat(); | |
+ } | |
+ | |
+ template<typename T, bool IsUnsigned> | |
+ T convertToInteger() const | |
+ { | |
+ llvm::APSInt val(8*sizeof(T), IsUnsigned); | |
+ bool ignored; | |
+ value()->convertToInteger(val, llvm::APFloat::rmNearestTiesToEven, &ignored); | |
+ return static_cast<T>(IsUnsigned ? val.getZExtValue() : val.getSExtValue()); | |
+ } | |
+ | |
+ longdouble &set(int8_t i) | |
+ { | |
+ const llvm::integerPart tmp = static_cast<llvm::integerPart>(i); | |
+ llvm::APFloat v(getFltSemantics(), llvm::APFloat::uninitialized); | |
+ v.convertFromSignExtendedInteger(&tmp, 1, true, llvm::APFloat::rmNearestTiesToEven); | |
+ return init(v); | |
+ } | |
+ | |
+ longdouble &set(int16_t i) | |
+ { | |
+ const llvm::integerPart tmp = static_cast<llvm::integerPart>(i); | |
+ llvm::APFloat v(getFltSemantics(), llvm::APFloat::uninitialized); | |
+ v.convertFromSignExtendedInteger(&tmp, 1, true, llvm::APFloat::rmNearestTiesToEven); | |
+ return init(v); | |
+ } | |
+ | |
+ longdouble &set(int32_t i) | |
+ { | |
+ const llvm::integerPart tmp = static_cast<llvm::integerPart>(i); | |
+ llvm::APFloat v(getFltSemantics(), llvm::APFloat::uninitialized); | |
+ v.convertFromSignExtendedInteger(&tmp, 1, true, llvm::APFloat::rmNearestTiesToEven); | |
+ return init(v); | |
+ } | |
+ | |
+ longdouble &set(int64_t i) | |
+ { | |
+ const llvm::integerPart tmp = static_cast<llvm::integerPart>(i); | |
+ llvm::APFloat v(getFltSemantics(), llvm::APFloat::uninitialized); | |
+ v.convertFromSignExtendedInteger(&tmp, 1, true, llvm::APFloat::rmNearestTiesToEven); | |
+ return init(v); | |
+ } | |
+ | |
+ longdouble &set(uint8_t i) | |
+ { | |
+ const llvm::integerPart tmp = static_cast<llvm::integerPart>(i); | |
+ llvm::APFloat v(getFltSemantics(), llvm::APFloat::uninitialized); | |
+ v.convertFromSignExtendedInteger(&tmp, 1, false, llvm::APFloat::rmNearestTiesToEven); | |
+ return init(v); | |
+ } | |
+ | |
+ longdouble &set(uint16_t i) | |
+ { | |
+ const llvm::integerPart tmp = static_cast<llvm::integerPart>(i); | |
+ llvm::APFloat v(getFltSemantics(), llvm::APFloat::uninitialized); | |
+ v.convertFromSignExtendedInteger(&tmp, 1, false, llvm::APFloat::rmNearestTiesToEven); | |
+ return init(v); | |
+ } | |
+ | |
+ longdouble &set(uint32_t i) | |
+ { | |
+ const llvm::integerPart tmp = static_cast<llvm::integerPart>(i); | |
+ llvm::APFloat v(getFltSemantics(), llvm::APFloat::uninitialized); | |
+ v.convertFromSignExtendedInteger(&tmp, 1, false, llvm::APFloat::rmNearestTiesToEven); | |
+ return init(v); | |
+ } | |
+ | |
+ longdouble &set(uint64_t i) | |
+ { | |
+ const llvm::integerPart tmp = static_cast<llvm::integerPart>(i); | |
+ llvm::APFloat v(getFltSemantics(), llvm::APFloat::uninitialized); | |
+ v.convertFromSignExtendedInteger(&tmp, 1, false, llvm::APFloat::rmNearestTiesToEven); | |
+ return init(v); | |
+ } | |
+ | |
+ // Apple sdk on osx defines uint64_t as unsigned long long, so long types | |
+ // are also needed to play with mars.h typedefs (dinteger_t and sinteger_t). | |
+#if defined(__APPLE__) && defined(__LP64__) | |
+ longdouble &set(long i) { return set((int64_t)i); } | |
+ longdouble &set(unsigned long i) { return set((uint64_t)i); } | |
+#endif | |
+ | |
+#if defined(_MSC_VER) | |
+ longdouble &set(unsigned long i) | |
+ { | |
+ const llvm::integerPart tmp = static_cast<llvm::integerPart>(i); | |
+ llvm::APFloat v(getFltSemantics(), llvm::APFloat::uninitialized); | |
+ v.convertFromSignExtendedInteger(&tmp, 1, false, llvm::APFloat::rmNearestTiesToEven); | |
+ return init(v); | |
+ } | |
+#endif | |
+ | |
+ longdouble &set(float r) | |
+ { | |
+ llvm::APFloat extended(r); | |
+ bool ignored; | |
+ llvm::APFloat::opStatus status = extended.convert(getFltSemantics(), llvm::APFloat::rmNearestTiesToEven, &ignored); | |
+ assert(status == llvm::APFloat::opOK); | |
+ (void)status; | |
+ return init(extended); | |
+ } | |
+ | |
+ longdouble &set(double r) | |
+ { | |
+ llvm::APFloat extended(r); | |
+ bool ignored; | |
+ llvm::APFloat::opStatus status = extended.convert(getFltSemantics(), llvm::APFloat::rmNearestTiesToEven, &ignored); | |
+ assert(status == llvm::APFloat::opOK); | |
+ (void)status; | |
+ return init(extended); | |
+ } | |
+ | |
+ longdouble &set(const llvm::APFloat &r) | |
+ { | |
+ return init(r); | |
+ } | |
+ | |
+ longdouble &set(const longdouble &r) | |
+ { | |
+ return init(r); | |
+ } | |
+ | |
+ bool isNaN() const | |
+ { | |
+ return value()->isNaN(); | |
+ } | |
+ | |
+ bool isSignaling() const | |
+ { | |
+#if LDC_LLVM_VER >= 304 | |
+ return value()->isSignaling(); | |
+#else | |
+ if (!value()->isNaN()) | |
+ return false; | |
+ double d = convertToDouble(); | |
+ /* A signalling NaN is a NaN with 0 as the most significant bit of | |
+ * its significand, which is bit 51 of 0..63 for 64 bit doubles. | |
+ * FIXME: Check: meaning of the bit is reversed for MIPS?!?! | |
+ */ | |
+ return !((((unsigned char*)&d)[6]) & 8); | |
+#endif | |
+ } | |
+ | |
+ static longdouble getNaN() | |
+ { | |
+ longdouble tmp; | |
+ return tmp.init(llvm::APFloat::getNaN(getFltSemantics())); | |
+ } | |
+ | |
+ static longdouble getSNaN() | |
+ { | |
+ longdouble tmp; | |
+ return tmp.init(llvm::APFloat::getSNaN(getFltSemantics())); | |
+ } | |
+ | |
+ static longdouble getInf() | |
+ { | |
+ longdouble tmp; | |
+ return tmp.init(llvm::APFloat::getInf(getFltSemantics())); | |
+ } | |
+ | |
+ static longdouble getLargest() | |
+ { | |
+ longdouble tmp; | |
+ return tmp.init(llvm::APFloat::getLargest(getFltSemantics())); | |
+ } | |
+ | |
+ longdouble abs() const; | |
+ longdouble sqrt() const; | |
+ longdouble sin() const; | |
+ longdouble cos() const; | |
+ longdouble tan() const; | |
+ | |
+ longdouble floor() const; | |
+ longdouble ceil() const; | |
+ longdouble trunc() const; | |
+ longdouble round() const; | |
+ | |
+ static longdouble fmin(longdouble x, longdouble y); | |
+ static longdouble fmax(longdouble x, longdouble y); | |
+ | |
+ static longdouble fmod(longdouble x, longdouble y); | |
+ static longdouble ldexp(longdouble ldval, int exp); | |
+ | |
+ static longdouble convertFromString(const char *str) | |
+ { | |
+ llvm::APFloat v(getFltSemantics(), llvm::APFloat::uninitialized); | |
+ v.convertFromString(llvm::StringRef(str), llvm::APFloat::rmNearestTiesToEven); | |
+ longdouble tmp; | |
+ return tmp.init(v); | |
+ } | |
+ | |
+ int format(char *buf) const; | |
+ int formatHex(char *buf, bool upper) const; | |
+}; | |
+ | |
+} // namespace ldc | |
+ | |
+typedef ldc::longdouble longdouble; | |
+typedef ldc::longdouble volatile_longdouble; | |
+ | |
+// Use ldouble() to explicitely create a longdouble value. | |
+template<typename T> | |
+inline longdouble | |
+ldouble (T x) | |
+{ | |
+ longdouble d; | |
+ d.set(x); | |
+ return d; | |
+} | |
+ | |
+template<typename T> inline longdouble operator+(longdouble ld, T x) { return ld + ldouble(x); } | |
+template<typename T> inline longdouble operator-(longdouble ld, T x) { return ld - ldouble(x); } | |
+template<typename T> inline longdouble operator*(longdouble ld, T x) { return ld * ldouble(x); } | |
+template<typename T> inline longdouble operator/(longdouble ld, T x) { return ld / ldouble(x); } | |
+ | |
+template<typename T> inline longdouble operator+(T x, longdouble ld) { return ldouble(x) + ld; } | |
+template<typename T> inline longdouble operator-(T x, longdouble ld) { return ldouble(x) - ld; } | |
+template<typename T> inline longdouble operator*(T x, longdouble ld) { return ldouble(x) * ld; } | |
+template<typename T> inline longdouble operator/(T x, longdouble ld) { return ldouble(x) / ld; } | |
+ | |
+template<typename T> inline longdouble& operator+=(longdouble& ld, T x) { return ld = ld + x; } | |
+template<typename T> inline longdouble& operator-=(longdouble& ld, T x) { return ld = ld - x; } | |
+template<typename T> inline longdouble& operator*=(longdouble& ld, T x) { return ld = ld * x; } | |
+template<typename T> inline longdouble& operator/=(longdouble& ld, T x) { return ld = ld / x; } | |
+ | |
+template<typename T> inline bool operator< (longdouble ld, T x) { return ld < ldouble(x); } | |
+template<typename T> inline bool operator<=(longdouble ld, T x) { return ld <= ldouble(x); } | |
+template<typename T> inline bool operator> (longdouble ld, T x) { return ld > ldouble(x); } | |
+template<typename T> inline bool operator>=(longdouble ld, T x) { return ld >= ldouble(x); } | |
+template<typename T> inline bool operator==(longdouble ld, T x) { return ld == ldouble(x); } | |
+template<typename T> inline bool operator!=(longdouble ld, T x) { return ld != ldouble(x); } | |
+ | |
+template<typename T> inline bool operator< (T x, longdouble ld) { return ldouble(x) < ld; } | |
+template<typename T> inline bool operator<=(T x, longdouble ld) { return ldouble(x) <= ld; } | |
+template<typename T> inline bool operator> (T x, longdouble ld) { return ldouble(x) > ld; } | |
+template<typename T> inline bool operator>=(T x, longdouble ld) { return ldouble(x) >= ld; } | |
+template<typename T> inline bool operator==(T x, longdouble ld) { return ldouble(x) == ld; } | |
+template<typename T> inline bool operator!=(T x, longdouble ld) { return ldouble(x) != ld; } | |
+ | |
+inline longdouble fabsl(longdouble ld) { return ld.abs(); } | |
+inline longdouble sqrtl(longdouble ld) { return ld.sqrt(); } | |
+inline longdouble sinl (longdouble ld) { return ld.sin(); } | |
+inline longdouble cosl (longdouble ld) { return ld.cos(); } | |
+inline longdouble tanl (longdouble ld) { return ld.tan(); } | |
+inline longdouble floorl (longdouble ld) { return ld.floor(); } | |
+inline longdouble ceill (longdouble ld) { return ld.ceil(); } | |
+inline longdouble truncl (longdouble ld) { return ld.trunc(); } | |
+inline longdouble roundl (longdouble ld) { return ld.round(); } | |
+ | |
+inline longdouble fminl(longdouble x, longdouble y) { return ldc::longdouble::fmin(x, y); } | |
+inline longdouble fmaxl(longdouble x, longdouble y) { return ldc::longdouble::fmax(x, y); } | |
+inline longdouble fmodl(longdouble x, longdouble y) { return ldc::longdouble::fmod(x, y); } | |
+inline longdouble ldexpl(longdouble ldval, int exp) { return ldc::longdouble::ldexp(ldval, exp); } | |
+ | |
+inline longdouble fabs (longdouble ld) { return fabsl(ld); } | |
+inline longdouble sqrt (longdouble ld) { return sqrtl(ld); } | |
+inline longdouble floor (longdouble ld) { return floorl(ld); } | |
+inline longdouble ceil (longdouble ld) { return ceill(ld); } | |
+inline longdouble trunc (longdouble ld) { return truncl(ld); } | |
+inline longdouble round (longdouble ld) { return roundl(ld); } | |
+inline longdouble fmin(longdouble x, longdouble y) { return fminl(x,y); } | |
+inline longdouble fmax(longdouble x, longdouble y) { return fmaxl(x,y); } | |
+ | |
+inline size_t | |
+ld_sprint(char* str, int fmt, longdouble x) | |
+{ | |
+ // The signature of this method leads to buffer overflows. | |
+ if (fmt == 'a' || fmt == 'A') | |
+ return x.formatHex(str, fmt == 'A'); | |
+ assert(fmt == 'g'); | |
+ return x.format(str); | |
+} | |
+ | |
+namespace ldc | |
+{ | |
+ | |
+// List of values for .max, .min, etc, for floats in D. | |
+struct real_properties | |
+{ | |
+ longdouble maxval, minval, epsilonval; | |
+ int64_t dig, mant_dig; | |
+ int64_t max_10_exp, min_10_exp; | |
+ int64_t max_exp, min_exp; | |
+}; | |
+ | |
+extern real_properties real_limits[longdouble::NumModes]; | |
+ | |
+// Initialize real_properties. | |
+void real_init(); | |
+ | |
+} // namespace ldc | |
+ | |
+// Macros are used by the D frontend, so map to longdouble property values instead of host long double. | |
+#undef FLT_MAX | |
+#undef DBL_MAX | |
+#undef LDBL_MAX | |
+#undef FLT_MIN | |
+#undef DBL_MIN | |
+#undef LDBL_MIN | |
+#undef FLT_DIG | |
+#undef DBL_DIG | |
+#undef LDBL_DIG | |
+#undef FLT_MANT_DIG | |
+#undef DBL_MANT_DIG | |
+#undef LDBL_MANT_DIG | |
+#undef FLT_MAX_10_EXP | |
+#undef DBL_MAX_10_EXP | |
+#undef LDBL_MAX_10_EXP | |
+#undef FLT_MIN_10_EXP | |
+#undef DBL_MIN_10_EXP | |
+#undef LDBL_MIN_10_EXP | |
+#undef FLT_MAX_EXP | |
+#undef DBL_MAX_EXP | |
+#undef LDBL_MAX_EXP | |
+#undef FLT_MIN_EXP | |
+#undef DBL_MIN_EXP | |
+#undef LDBL_MIN_EXP | |
+#undef FLT_EPSILON | |
+#undef DBL_EPSILON | |
+#undef LDBL_EPSILON | |
+ | |
+#define FLT_MAX ldc::real_limits[ldc::longdouble::Float].maxval; | |
+#define DBL_MAX ldc::real_limits[ldc::longdouble::Double].maxval; | |
+#define LDBL_MAX ldc::real_limits[ldc::longdouble::LongDouble].maxval; | |
+#define FLT_MIN ldc::real_limits[ldc::longdouble::Float].minval; | |
+#define DBL_MIN ldc::real_limits[ldc::longdouble::Double].minval; | |
+#define LDBL_MIN ldc::real_limits[ldc::longdouble::LongDouble].minval; | |
+#define FLT_DIG ldc::real_limits[ldc::longdouble::Float].dig; | |
+#define DBL_DIG ldc::real_limits[ldc::longdouble::Double].dig; | |
+#define LDBL_DIG ldc::real_limits[ldc::longdouble::LongDouble].dig; | |
+#define FLT_MANT_DIG ldc::real_limits[ldc::longdouble::Float].mant_dig; | |
+#define DBL_MANT_DIG ldc::real_limits[ldc::longdouble::Double].mant_dig; | |
+#define LDBL_MANT_DIG ldc::real_limits[ldc::longdouble::LongDouble].mant_dig; | |
+#define FLT_MAX_10_EXP ldc::real_limits[ldc::longdouble::Float].max_10_exp; | |
+#define DBL_MAX_10_EXP ldc::real_limits[ldc::longdouble::Double].max_10_exp; | |
+#define LDBL_MAX_10_EXP ldc::real_limits[ldc::longdouble::LongDouble].max_10_exp; | |
+#define FLT_MIN_10_EXP ldc::real_limits[ldc::longdouble::Float].min_10_exp; | |
+#define DBL_MIN_10_EXP ldc::real_limits[ldc::longdouble::Double].min_10_exp; | |
+#define LDBL_MIN_10_EXP ldc::real_limits[ldc::longdouble::LongDouble].min_10_exp; | |
+#define FLT_MAX_EXP ldc::real_limits[ldc::longdouble::Float].max_exp; | |
+#define DBL_MAX_EXP ldc::real_limits[ldc::longdouble::Double].max_exp; | |
+#define LDBL_MAX_EXP ldc::real_limits[ldc::longdouble::LongDouble].max_exp; | |
+#define FLT_MIN_EXP ldc::real_limits[ldc::longdouble::Float].min_exp; | |
+#define DBL_MIN_EXP ldc::real_limits[ldc::longdouble::Double].min_exp; | |
+#define LDBL_MIN_EXP ldc::real_limits[ldc::longdouble::LongDouble].min_exp; | |
+#define FLT_EPSILON ldc::real_limits[ldc::longdouble::Float].epsilonval; | |
+#define DBL_EPSILON ldc::real_limits[ldc::longdouble::Double].epsilonval; | |
+#define LDBL_EPSILON ldc::real_limits[ldc::longdouble::LongDouble].epsilonval; | |
+ | |
+#endif | |
diff --git a/gen/port.cpp b/gen/port.cpp | |
new file mode 100644 | |
index 0000000..78703d1 | |
--- /dev/null | |
+++ b/gen/port.cpp | |
@@ -0,0 +1,193 @@ | |
+ | |
+// Copyright (c) 1999-2012 by Digital Mars | |
+// All Rights Reserved | |
+// written by Walter Bright | |
+// http://www.digitalmars.com | |
+ | |
+#include "port.h" | |
+ | |
+#include <cstdlib> | |
+#include <cstring> | |
+#include <cctype> | |
+ | |
+/* Implements all floating point operation using llvm::APFloat. | |
+ */ | |
+ | |
+double Port::nan; | |
+longdouble Port::ldbl_nan; | |
+longdouble Port::snan; | |
+ | |
+double Port::infinity; | |
+longdouble Port::ldbl_infinity; | |
+ | |
+double Port::dbl_max; | |
+double Port::dbl_min; | |
+longdouble Port::ldbl_max; | |
+ | |
+void ldc::port_init() | |
+{ | |
+ Port::nan = llvm::APFloat::getNaN(llvm::APFloat::IEEEdouble).convertToDouble(); | |
+ Port::infinity = llvm::APFloat::getInf(llvm::APFloat::IEEEdouble).convertToDouble(); | |
+ Port::dbl_max = llvm::APFloat::getLargest(llvm::APFloat::IEEEdouble).convertToDouble(); | |
+ Port::dbl_min = llvm::APFloat::getSmallest(llvm::APFloat::IEEEdouble).convertToDouble(); | |
+ | |
+ Port::ldbl_nan = longdouble::getNaN(); | |
+ Port::snan = longdouble::getSNaN(); | |
+ Port::ldbl_infinity = longdouble::getInf(); | |
+ Port::ldbl_max = longdouble::getLargest(); | |
+} | |
+ | |
+int Port::isNan(double r) | |
+{ | |
+ return llvm::APFloat(r).isNaN(); | |
+} | |
+ | |
+int Port::isNan(longdouble r) | |
+{ | |
+ return r.isNaN(); | |
+} | |
+ | |
+int Port::isSignallingNan(double r) | |
+{ | |
+ return ldouble(r).isSignaling(); | |
+} | |
+ | |
+int Port::isSignallingNan(longdouble r) | |
+{ | |
+ return r.isSignaling(); | |
+} | |
+ | |
+int Port::isInfinity(double r) | |
+{ | |
+ return llvm::APFloat(r).isInfinity(); | |
+} | |
+ | |
+longdouble Port::fmodl(longdouble x, longdouble y) | |
+{ | |
+ return longdouble::fmod(x, y); | |
+} | |
+ | |
+longdouble Port::sqrt(longdouble x) | |
+{ | |
+ return ldouble(x).sqrt(); | |
+} | |
+ | |
+int Port::fequal(longdouble x, longdouble y) | |
+{ | |
+ return x == y; | |
+} | |
+ | |
+int Port::memicmp(const char *s1, const char *s2, int n) | |
+{ | |
+#if HAVE_MEMICMP | |
+ return ::memicmp(s1, s2, n); | |
+#else | |
+ int result = 0; | |
+ | |
+ for (int i = 0; i < n; i++) | |
+ { char c1 = s1[i]; | |
+ char c2 = s2[i]; | |
+ | |
+ result = c1 - c2; | |
+ if (result) | |
+ { | |
+ result = toupper(c1) - toupper(c2); | |
+ if (result) | |
+ break; | |
+ } | |
+ } | |
+ return result; | |
+#endif | |
+} | |
+ | |
+int Port::stricmp(const char *s1, const char *s2) | |
+{ | |
+#if HAVE_STRICMP | |
+ return ::stricmp(s1, s2); | |
+#else | |
+ int result = 0; | |
+ | |
+ for (;;) | |
+ { char c1 = *s1; | |
+ char c2 = *s2; | |
+ | |
+ result = c1 - c2; | |
+ if (result) | |
+ { | |
+ result = toupper(c1) - toupper(c2); | |
+ if (result) | |
+ break; | |
+ } | |
+ if (!c1) | |
+ break; | |
+ s1++; | |
+ s2++; | |
+ } | |
+ return result; | |
+#endif | |
+} | |
+ | |
+char *Port::strupr(char *s) | |
+{ | |
+#if HAVE_STRUPR | |
+ return ::strupr(s); | |
+#else | |
+ char *t = s; | |
+ | |
+ while (*s) | |
+ { | |
+ *s = toupper(*s); | |
+ s++; | |
+ } | |
+ | |
+ return t; | |
+#endif | |
+} | |
+ | |
+float Port::strtof(const char *p, char **endp) | |
+{ | |
+#if HAVE_STRTOF | |
+ return ::strtof(p, endp); | |
+#else | |
+ return static_cast<float>(::strtod(p, endp)); | |
+#endif | |
+} | |
+ | |
+double Port::strtod(const char *p, char **endp) | |
+{ | |
+ return ::strtod(p, endp); | |
+} | |
+ | |
+longdouble Port::strtold(const char *p, char **endp) | |
+{ | |
+ assert(!endp); | |
+ longdouble res = longdouble::convertFromString(p); | |
+ return res; | |
+} | |
+// Little endian | |
+unsigned Port::readlongLE(void* buffer) | |
+{ | |
+ unsigned char *p = (unsigned char*)buffer; | |
+ return (((((p[3] << 8) | p[2]) << 8) | p[1]) << 8) | p[0]; | |
+} | |
+ | |
+// Big endian | |
+unsigned Port::readlongBE(void* buffer) | |
+{ | |
+ unsigned char *p = (unsigned char*)buffer; | |
+ return (((((p[0] << 8) | p[1]) << 8) | p[2]) << 8) | p[3]; | |
+} | |
+ | |
+// Little endian | |
+unsigned Port::readwordLE(void *buffer) | |
+{ | |
+ unsigned char *p = (unsigned char*)buffer; | |
+ return (p[1] << 8) | p[0]; | |
+} | |
+ | |
+// Big endian | |
+unsigned Port::readwordBE(void *buffer) | |
+{ | |
+ unsigned char *p = (unsigned char*)buffer; | |
+ return (p[0] << 8) | p[1]; | |
+} | |
diff --git a/gen/tollvm.cpp b/gen/tollvm.cpp | |
index 36fc085..e84937d 100644 | |
--- a/gen/tollvm.cpp | |
+++ b/gen/tollvm.cpp | |
@@ -418,37 +418,12 @@ LLConstant *DtoConstFP(Type *t, longdouble value) { | |
LLType *llty = DtoType(t); | |
assert(llty->isFloatingPointTy()); | |
- if (llty == LLType::getFloatTy(gIR->context()) || | |
- llty == LLType::getDoubleTy(gIR->context())) { | |
- return LLConstantFP::get(llty, value); | |
- } | |
- if (llty == LLType::getX86_FP80Ty(gIR->context())) { | |
- uint64_t bits[] = {0, 0}; | |
- bits[0] = *reinterpret_cast<uint64_t *>(&value); | |
- bits[1] = | |
- *reinterpret_cast<uint16_t *>(reinterpret_cast<uint64_t *>(&value) + 1); | |
- return LLConstantFP::get(gIR->context(), APFloat(APFloat::x87DoubleExtended, | |
- APInt(80, 2, bits))); | |
- } | |
- if (llty == LLType::getFP128Ty(gIR->context())) { | |
- union { | |
- longdouble ld; | |
- uint64_t bits[2]; | |
- } t; | |
- t.ld = value; | |
- return LLConstantFP::get(gIR->context(), | |
- APFloat(APFloat::IEEEquad, APInt(128, 2, t.bits))); | |
- } | |
- if (llty == LLType::getPPC_FP128Ty(gIR->context())) { | |
- uint64_t bits[] = {0, 0}; | |
- bits[0] = *reinterpret_cast<uint64_t *>(&value); | |
- bits[1] = | |
- *reinterpret_cast<uint16_t *>(reinterpret_cast<uint64_t *>(&value) + 1); | |
- return LLConstantFP::get( | |
- gIR->context(), APFloat(APFloat::PPCDoubleDouble, APInt(128, 2, bits))); | |
- } | |
- | |
- llvm_unreachable("Unknown floating point type encountered"); | |
+ if (llty == LLType::getFloatTy(gIR->context())) | |
+ return LLConstantFP::get(llty, value.convertToFloat()); | |
+ else if (llty == LLType::getDoubleTy(gIR->context())) | |
+ return LLConstantFP::get(llty, value.convertToDouble()); | |
+ else | |
+ return LLConstantFP::get(gIR->context(), value); | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt | |
index e01bc90..7d25650 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;-d CACHE STRING "Runtime build flags, separated by ;") | |
+set(D_FLAGS -w;-d;-mtriple=armv7-none-linux-androideabi CACHE STRING "Runtime build flags, separated by ;") | |
set(D_FLAGS_DEBUG -g;-link-debuglib CACHE STRING "Runtime build flags (debug libraries), separated by ;") | |
set(D_FLAGS_RELEASE -O3;-release CACHE STRING "Runtime build flags (release libraries), separated by ;") | |
if(MSVC) | |
@@ -59,6 +59,7 @@ file(GLOB CORE_D ${RUNTIME_DIR}/src/core/*.d) | |
file(GLOB_RECURSE CORE_D_INTERNAL ${RUNTIME_DIR}/src/core/internal/*.d) | |
file(GLOB CORE_D_SYNC ${RUNTIME_DIR}/src/core/sync/*.d) | |
file(GLOB CORE_D_STDC ${RUNTIME_DIR}/src/core/stdc/*.d) | |
+list(REMOVE_ITEM CORE_D_STDC ${RUNTIME_DIR}/src/core/stdc/tgmath.d) | |
file(GLOB_RECURSE GC_D ${RUNTIME_DIR}/src/gc/*.d) | |
file(GLOB_RECURSE DCRT_D ${RUNTIME_DIR}/src/rt/*.d) | |
file(GLOB_RECURSE LDC_D ${RUNTIME_DIR}/src/ldc/*.d) | |
@@ -496,8 +497,11 @@ endmacro() | |
# | |
# Set up build targets. | |
# | |
- | |
-set(RT_CFLAGS "") | |
+set(CMAKE_C_COMPILER $ENV{NDK}/toolchains/llvm/prebuilt/linux-$ENV{NDK_ARCH}/bin/clang) | |
+set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER}) | |
+set(RT_CFLAGS "-gcc-toolchain $ENV{NDK}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-$ENV{NDK_ARCH} -fpic -ffunction-sections -funwind-tables -fstack-protector-strong -Wno-invalid-command-line-argument -Wno-unused-command-line-argument -no-canonical-prefixes -fno-integrated-as -target armv7-none-linux-androideabi -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -Os -g -DNDEBUG -fomit-frame-pointer -fno-strict-aliasing -DANDROID -Wa,--noexecstack -Wformat -Werror=format-security -isystem $ENV{NDK}/platforms/android-9/arch-arm/usr/include") | |
+set(RT_LDFLAGS "-Wl,-z,nocopyreloc;--sysroot=$ENV{NDK}/platforms/android-9/arch-arm;-lgcc;-gcc-toolchain;$ENV{NDK}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-$ENV{NDK_ARCH};-target;armv7-none-linux-androideabi;-no-canonical-prefixes;-fuse-ld=bfd;-Wl,--fix-cortex-a8;-Wl,--no-undefined;-Wl,-z,noexecstack;-Wl,-z,relro;-Wl,-z,now;-Wl,--warn-shared-textrel;-Wl,--fatal-warnings;-fPIE;-pie;-mthumb;-lc;-lm") | |
+set(TEST_SO_LDFLAGS "-Wl,-soname,libnative-activity${name_suffix}.so;-shared;--sysroot=$ENV{NDK}/platforms/android-9/arch-arm;-lgcc;-gcc-toolchain;$ENV{NDK}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-$ENV{NDK_ARCH};-no-canonical-prefixes;-fuse-ld=bfd;-target;armv7-none-linux-androideabi;-Wl,--fix-cortex-a8;-Wl,--no-undefined;-Wl,-z,noexecstack;-Wl,-z,relro;-Wl,-z,now;-Wl,--warn-shared-textrel;-Wl,--fatal-warnings;-mthumb;-llog;-landroid;-lEGL;-lGLESv1_CM;-lc;-lm") | |
# This is a bit of a mess as we need to join the two libraries together on | |
# OS X before installing them. After this has run, LIBS_TO_INSTALL contains | |
@@ -676,6 +680,11 @@ macro(build_test_runner name_suffix d_flags c_flags) | |
if(PHOBOS2_DIR) | |
set(phobos2_o "") | |
set(phobos2_bc "") | |
+ set(test_runner_o "") | |
+ set(test_runner ${PROJECT_BINARY_DIR}/test-runner${name_suffix}${CMAKE_EXECUTABLE_SUFFIX}) | |
+ set(ANDROID_DIR "${PROJECT_PARENT_DIR}/../android") | |
+ set(android_native_app_glue_o "${ANDROID_DIR}/samples/native-activity/android_native_app_glue.o") | |
+ set(test_runner_so ${ANDROID_DIR}/samples/native-activity/libs/armeabi-v7a/libnative-activity${name_suffix}.so) | |
compile_phobos2("${flags}" "-unittest${name_suffix}" "" phobos2_o phobos2_bc) | |
set(phobos2-casm phobos2-ldc-casm${name_suffix}) | |
@@ -690,6 +699,68 @@ macro(build_test_runner name_suffix d_flags c_flags) | |
set_target_properties(${phobos2-casm} PROPERTIES EXCLUDE_FROM_ALL ON EXCLUDE_FROM_DEFAULT_BUILD ON) | |
add_custom_target(phobos2-ldc-unittest${name_suffix} DEPENDS ${phobos2_o} ${phobos2-casm}) | |
+ set(runner_flags "${flags}") | |
+ if("${flags}" MATCHES "-debug") | |
+ list(APPEND runner_flags -d-debug) | |
+ endif() | |
+ dc("${RUNTIME_DIR}/src/test_runner.d" "${runner_flags}" "${RUNTIME_DIR}" | |
+ "${name_suffix}" test_runner_o druntime_bc) | |
+ add_custom_command( | |
+ OUTPUT ${test_runner} | |
+ COMMAND ${CMAKE_C_COMPILER} ${RT_LDFLAGS} ${test_runner_o} | |
+ ${druntime_o} ${phobos2_o} | |
+ "${output_path}/lib${druntime-casm}.a" | |
+ "${output_path}/lib${phobos2-casm}.a" | |
+ -o${test_runner} | |
+ WORKING_DIRECTORY ${PROJECT_PARENT_DIR} | |
+ DEPENDS ${CMAKE_C_COMPILER} | |
+ ${test_runner_o} | |
+ ${druntime_o} | |
+ ${druntime-casm} | |
+ ${phobos2_o} | |
+ ${phobos2-casm} | |
+ ) | |
+ add_custom_target(test-runner${name_suffix} DEPENDS ${test_runner}) | |
+ set(test_runner_apk_o "") | |
+ dc("${RUNTIME_DIR}/src/test_runner.d" "${runner_flags};-d-version=apk;-I${ANDROID_DIR}" "${RUNTIME_DIR}" | |
+ "-apk${name_suffix}" test_runner_apk_o druntime_bc) | |
+ set(file_apk_o "") | |
+ dc("${PHOBOS2_DIR}/std/file.d" "${flags};-d-version=apk" "${PHOBOS2_DIR}" | |
+ "-apk-unittest${name_suffix}" file_apk_o phobos2_bc) | |
+ set(main_o "") | |
+ dc("${ANDROID_DIR}/samples/native-activity/jni/main.d" "${D_FLAGS};${d_flags};-I${ANDROID_DIR}" "${RUNTIME_DIR}" | |
+ "${name_suffix}" main_o druntime_bc) | |
+ set(sensor_o "") | |
+ dc("${ANDROID_DIR}/android/sensor.d" "${D_FLAGS};${d_flags};-I${ANDROID_DIR}" "${RUNTIME_DIR}" | |
+ "${name_suffix}" sensor_o druntime_bc) | |
+ string(REPLACE " " ";" RT_CFLAGS${name_suffix} ${RT_CFLAGS}) | |
+ add_custom_command( | |
+ OUTPUT ${android_native_app_glue_o} | |
+ COMMAND ${CMAKE_C_COMPILER} ${RT_CFLAGS} -c "${ANDROID_DIR}/samples/native-activity/android_native_app_glue.c" -o ${android_native_app_glue_o} | |
+ WORKING_DIRECTORY ${PROJECT_PARENT_DIR} | |
+ DEPENDS ${CMAKE_C_COMPILER} | |
+ ) | |
+ list(REMOVE_ITEM phobos2_o "${PROJECT_PARENT_DIR}/build/runtime/std/file-unittest${name_suffix}.o") | |
+ add_custom_command( | |
+ OUTPUT ${test_runner_so} | |
+ COMMAND ${CMAKE_C_COMPILER} ${TEST_SO_LDFLAGS} | |
+ ${main_o} ${sensor_o} ${test_runner_apk_o} | |
+ ${file_apk_o} ${android_native_app_glue_o} | |
+ ${druntime_o} ${phobos2_o} | |
+ "${output_path}/lib${druntime-casm}.a" | |
+ "${output_path}/lib${phobos2-casm}.a" | |
+ -o${test_runner_so} | |
+ WORKING_DIRECTORY ${PROJECT_PARENT_DIR} | |
+ DEPENDS ${CMAKE_C_COMPILER} | |
+ ${main_o} ${sensor_o} | |
+ ${test_runner_apk_o} ${android_native_app_glue_o} | |
+ ${druntime_o} | |
+ ${druntime-casm} | |
+ ${phobos2_o} | |
+ ${phobos2-casm} | |
+ ${file_apk_o} | |
+ ) | |
+ add_custom_target(test-runner-apk${name_suffix} DEPENDS ${test_runner_so}) | |
add_test(build-phobos2-ldc-unittest${name_suffix} "${CMAKE_COMMAND}" | |
--build ${CMAKE_BINARY_DIR} --target phobos2-ldc-unittest${name_suffix}) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment