Skip to content

Instantly share code, notes, and snippets.

@joakim-noah
Last active April 21, 2016 04:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joakim-noah/63693ead3aa62216e1d9 to your computer and use it in GitHub Desktop.
Save joakim-noah/63693ead3aa62216e1d9 to your computer and use it in GitHub Desktop.
LDC for Android/ARM, applied to the ltsmaster branch 2.068
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