|
11 | 11 | #ifndef __LONG_DOUBLE_H__
|
12 | 12 | #define __LONG_DOUBLE_H__
|
13 | 13 |
|
| 14 | +#if IN_LLVM |
| 15 | + |
| 16 | +#include "gen/ldc-real.h" |
| 17 | + |
| 18 | +#else |
| 19 | + |
| 20 | +#if !_MSC_VER // has native 10 byte doubles |
14 | 21 | #include <stdio.h>
|
15 | 22 | typedef long double longdouble;
|
16 | 23 | typedef volatile long double volatile_longdouble;
|
@@ -47,4 +54,194 @@ inline size_t ld_sprint(char* str, int fmt, longdouble x)
|
47 | 54 | #undef sprintf
|
48 | 55 | #endif
|
49 | 56 |
|
| 57 | +#else |
| 58 | + |
| 59 | +#include <float.h> |
| 60 | +#include <limits> |
| 61 | + |
| 62 | +struct longdouble; |
| 63 | + |
| 64 | +extern "C" |
| 65 | +{ |
| 66 | + // implemented in ldfpu.asm for _WIN64 |
| 67 | + double ld_read(const longdouble* ld); |
| 68 | + long long ld_readll(const longdouble* ld); |
| 69 | + unsigned long long ld_readull(const longdouble* ld); |
| 70 | + void ld_set(longdouble* ld, double d); |
| 71 | + void ld_setll(longdouble* ld, long long d); |
| 72 | + void ld_setull(longdouble* ld, unsigned long long d); |
| 73 | +} |
| 74 | + |
| 75 | +struct longdouble |
| 76 | +{ |
| 77 | + unsigned long long mantissa; |
| 78 | + unsigned short exponent:15; // bias 0x3fff |
| 79 | + unsigned short sign:1; |
| 80 | + unsigned short fill:16; // for 12 byte alignment |
| 81 | + |
| 82 | + // no constructor to be able to use this class in a union |
| 83 | + // use ldouble() to explicitely create a longdouble value |
| 84 | + |
| 85 | + template<typename T> longdouble& operator=(T x) { set(x); return *this; } |
| 86 | + |
| 87 | + void set(longdouble ld) { mantissa = ld.mantissa; exponent = ld.exponent; sign = ld.sign; } |
| 88 | + |
| 89 | + // we need to list all basic types to avoid ambiguities |
| 90 | + void set(float d) { ld_set(this, d); } |
| 91 | + void set(double d) { ld_set(this, d); } |
| 92 | + void set(long double d) { ld_set(this, d); } |
| 93 | + |
| 94 | + void set(signed char d) { ld_set(this, d); } |
| 95 | + void set(short d) { ld_set(this, d); } |
| 96 | + void set(int d) { ld_set(this, d); } |
| 97 | + void set(long d) { ld_set(this, d); } |
| 98 | + void set(long long d) { ld_setll(this, d); } |
| 99 | + |
| 100 | + void set(unsigned char d) { ld_set(this, d); } |
| 101 | + void set(unsigned short d) { ld_set(this, d); } |
| 102 | + void set(unsigned int d) { ld_set(this, d); } |
| 103 | + void set(unsigned long d) { ld_set(this, d); } |
| 104 | + void set(unsigned long long d) { ld_setull(this, d); } |
| 105 | + void set(bool d) { ld_set(this, d); } |
| 106 | + |
| 107 | + operator float () { return ld_read(this); } |
| 108 | + operator double () { return ld_read(this); } |
| 109 | + |
| 110 | + operator signed char () { return ld_read(this); } |
| 111 | + operator short () { return ld_read(this); } |
| 112 | + operator int () { return ld_read(this); } |
| 113 | + operator long () { return ld_read(this); } |
| 114 | + operator long long () { return ld_readll(this); } |
| 115 | + |
| 116 | + operator unsigned char () { return ld_read(this); } |
| 117 | + operator unsigned short () { return ld_read(this); } |
| 118 | + operator unsigned int () { return ld_read(this); } |
| 119 | + operator unsigned long () { return ld_read(this); } |
| 120 | + operator unsigned long long() { return ld_readull(this); } |
| 121 | + operator bool () { return mantissa != 0 || exponent != 0; } // correct? |
| 122 | +}; |
| 123 | + |
| 124 | +// some optimizations are avoided by adding volatile to the longdouble |
| 125 | +// type, but this introduces bad ambiguities when using the class implementation above |
| 126 | +// as we are going through asm these optimizations won't kick in anyway, so "volatile" |
| 127 | +// is not required. |
| 128 | +typedef longdouble volatile_longdouble; |
| 129 | + |
| 130 | +inline longdouble ldouble(unsigned long long mantissa, int exp, int sign = 0) |
| 131 | +{ |
| 132 | + longdouble d; |
| 133 | + d.mantissa = mantissa; |
| 134 | + d.exponent = exp; |
| 135 | + d.sign = sign; |
| 136 | + return d; |
| 137 | +} |
| 138 | + |
| 139 | +// codegen bug in VS2010/VS2012, if the set() function not inlined |
| 140 | +// (this passed on stack, but expected in ECX; RVO?) |
| 141 | +#if _MSC_VER >= 1600 |
| 142 | +#define LDOUBLE_INLINE __declspec(noinline) |
| 143 | +#else |
| 144 | +#define LDOUBLE_INLINE inline |
| 145 | +#endif |
| 146 | + |
| 147 | +template<typename T> LDOUBLE_INLINE longdouble ldouble(T x) { longdouble d; d.set(x); return d; } |
| 148 | + |
| 149 | +#undef LDOUBLE_INLINE |
| 150 | + |
| 151 | +longdouble operator+(longdouble ld1, longdouble ld2); |
| 152 | +longdouble operator-(longdouble ld1, longdouble ld2); |
| 153 | +longdouble operator*(longdouble ld1, longdouble ld2); |
| 154 | +longdouble operator/(longdouble ld1, longdouble ld2); |
| 155 | + |
| 156 | +bool operator< (longdouble ld1, longdouble ld2); |
| 157 | +bool operator<=(longdouble ld1, longdouble ld2); |
| 158 | +bool operator> (longdouble ld1, longdouble ld2); |
| 159 | +bool operator>=(longdouble ld1, longdouble ld2); |
| 160 | +bool operator==(longdouble ld1, longdouble ld2); |
| 161 | +bool operator!=(longdouble ld1, longdouble ld2); |
| 162 | + |
| 163 | +inline longdouble operator-(longdouble ld1) { ld1.sign ^= 1; return ld1; } |
| 164 | +inline longdouble operator+(longdouble ld1) { return ld1; } |
| 165 | + |
| 166 | +template<typename T> inline longdouble operator+(longdouble ld, T x) { return ld + ldouble(x); } |
| 167 | +template<typename T> inline longdouble operator-(longdouble ld, T x) { return ld - ldouble(x); } |
| 168 | +template<typename T> inline longdouble operator*(longdouble ld, T x) { return ld * ldouble(x); } |
| 169 | +template<typename T> inline longdouble operator/(longdouble ld, T x) { return ld / ldouble(x); } |
| 170 | + |
| 171 | +template<typename T> inline longdouble operator+(T x, longdouble ld) { return ldouble(x) + ld; } |
| 172 | +template<typename T> inline longdouble operator-(T x, longdouble ld) { return ldouble(x) - ld; } |
| 173 | +template<typename T> inline longdouble operator*(T x, longdouble ld) { return ldouble(x) * ld; } |
| 174 | +template<typename T> inline longdouble operator/(T x, longdouble ld) { return ldouble(x) / ld; } |
| 175 | + |
| 176 | +template<typename T> inline longdouble& operator+=(longdouble& ld, T x) { return ld = ld + x; } |
| 177 | +template<typename T> inline longdouble& operator-=(longdouble& ld, T x) { return ld = ld - x; } |
| 178 | +template<typename T> inline longdouble& operator*=(longdouble& ld, T x) { return ld = ld * x; } |
| 179 | +template<typename T> inline longdouble& operator/=(longdouble& ld, T x) { return ld = ld / x; } |
| 180 | + |
| 181 | +template<typename T> inline bool operator< (longdouble ld, T x) { return ld < ldouble(x); } |
| 182 | +template<typename T> inline bool operator<=(longdouble ld, T x) { return ld <= ldouble(x); } |
| 183 | +template<typename T> inline bool operator> (longdouble ld, T x) { return ld > ldouble(x); } |
| 184 | +template<typename T> inline bool operator>=(longdouble ld, T x) { return ld >= ldouble(x); } |
| 185 | +template<typename T> inline bool operator==(longdouble ld, T x) { return ld == ldouble(x); } |
| 186 | +template<typename T> inline bool operator!=(longdouble ld, T x) { return ld != ldouble(x); } |
| 187 | + |
| 188 | +template<typename T> inline bool operator< (T x, longdouble ld) { return ldouble(x) < ld; } |
| 189 | +template<typename T> inline bool operator<=(T x, longdouble ld) { return ldouble(x) <= ld; } |
| 190 | +template<typename T> inline bool operator> (T x, longdouble ld) { return ldouble(x) > ld; } |
| 191 | +template<typename T> inline bool operator>=(T x, longdouble ld) { return ldouble(x) >= ld; } |
| 192 | +template<typename T> inline bool operator==(T x, longdouble ld) { return ldouble(x) == ld; } |
| 193 | +template<typename T> inline bool operator!=(T x, longdouble ld) { return ldouble(x) != ld; } |
| 194 | + |
| 195 | +int _isnan(longdouble ld); |
| 196 | + |
| 197 | +longdouble fabsl(longdouble ld); |
| 198 | +longdouble sqrtl(longdouble ld); |
| 199 | +longdouble sinl (longdouble ld); |
| 200 | +longdouble cosl (longdouble ld); |
| 201 | +longdouble tanl (longdouble ld); |
| 202 | + |
| 203 | +longdouble fmodl(longdouble x, longdouble y); |
| 204 | +longdouble ldexpl(longdouble ldval, int exp); // see strtold |
| 205 | + |
| 206 | +inline longdouble fabs (longdouble ld) { return fabsl(ld); } |
| 207 | +inline longdouble sqrt (longdouble ld) { return sqrtl(ld); } |
| 208 | + |
| 209 | +#undef LDBL_DIG |
| 210 | +#undef LDBL_MAX |
| 211 | +#undef LDBL_MIN |
| 212 | +#undef LDBL_EPSILON |
| 213 | +#undef LDBL_MANT_DIG |
| 214 | +#undef LDBL_MAX_EXP |
| 215 | +#undef LDBL_MIN_EXP |
| 216 | +#undef LDBL_MAX_10_EXP |
| 217 | +#undef LDBL_MIN_10_EXP |
| 218 | + |
| 219 | +#define LDBL_DIG 18 |
| 220 | +#define LDBL_MAX ldouble(0xffffffffffffffffULL, 0x7ffe) |
| 221 | +#define LDBL_MIN ldouble(0x8000000000000000ULL, 1) |
| 222 | +#define LDBL_EPSILON ldouble(0x8000000000000000ULL, 0x3fff - 63) // allow denormal? |
| 223 | +#define LDBL_MANT_DIG 64 |
| 224 | +#define LDBL_MAX_EXP 16384 |
| 225 | +#define LDBL_MIN_EXP (-16381) |
| 226 | +#define LDBL_MAX_10_EXP 4932 |
| 227 | +#define LDBL_MIN_10_EXP (-4932) |
| 228 | + |
| 229 | +extern longdouble ld_zero; |
| 230 | +extern longdouble ld_one; |
| 231 | +extern longdouble ld_pi; |
| 232 | +extern longdouble ld_log2t; |
| 233 | +extern longdouble ld_log2e; |
| 234 | +extern longdouble ld_log2; |
| 235 | +extern longdouble ld_ln2; |
| 236 | + |
| 237 | +extern longdouble ld_inf; |
| 238 | +extern longdouble ld_qnan; |
| 239 | +extern longdouble ld_snan; |
| 240 | + |
| 241 | +size_t ld_sprint(char* str, int fmt, longdouble x); |
| 242 | + |
| 243 | +#endif // !_MSC_VER |
| 244 | + |
| 245 | +#endif // IN_LLVM |
| 246 | + |
50 | 247 | #endif // __LONG_DOUBLE_H__
|
0 commit comments