Skip to content

Commit a5445d5

Browse files
committed
Implement longdouble as a wrapper around llvm::APFloat.
This commit introduces a new class ldc::longdouble which provides real_t semantics based on the target. It uses llvm::APFloat as base implementation. This fixes issue ldc-developers#259.
1 parent 41eaa5b commit a5445d5

File tree

10 files changed

+1269
-1292
lines changed

10 files changed

+1269
-1292
lines changed

CMakeLists.txt

+22-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ if(MSVC)
88
endif()
99

1010
include(CheckIncludeFile)
11+
include(CheckSymbolExists)
1112
include(CheckLibraryExists)
1213
include(CheckCXXCompilerFlag)
1314

@@ -348,6 +349,27 @@ if(LLVM_ENABLE_ASSERTIONS)
348349
string(REGEX REPLACE "(^| )[/-]D *NDEBUG( |$)" "\\1-UNDEBUG\\2" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
349350
endif()
350351

352+
#
353+
# check string functions
354+
#
355+
check_symbol_exists(memicmp "string.h" HAVE_MEMICMP)
356+
check_symbol_exists(stricmp "string.h" HAVE_STRICMP)
357+
check_symbol_exists(strupr "string.h" HAVE_STRUPR)
358+
check_symbol_exists(strtof "stdlib.h" HAVE_STRTOF)
359+
360+
if(HAVE_MEMICMP)
361+
add_definitions(-DHAVE_MEMICMP)
362+
endif()
363+
364+
if(HAVE_STRICMP)
365+
add_definitions(-DHAVE_STRICMP)
366+
endif()
367+
368+
if(HAVE_STRUPR)
369+
add_definitions(-DHAVE_STRUPR)
370+
endif()
371+
372+
351373
#
352374
# Check endianess.
353375
# There is no realiable way to delegate the work to the compiler.
@@ -489,7 +511,6 @@ endif()
489511
#
490512
# LDMD
491513
#
492-
include(CheckSymbolExists)
493514
CHECK_SYMBOL_EXISTS(_SC_ARG_MAX "unistd.h" HAVE_SC_ARG_MAX)
494515
if (HAVE_SC_ARG_MAX)
495516
add_definitions(-DHAVE_SC_ARG_MAX)

dmd2/builtin.c

+42-5
Original file line numberDiff line numberDiff line change
@@ -50,41 +50,78 @@ Expression *eval_unimp(Loc loc, FuncDeclaration *fd, Expressions *arguments)
5050
return NULL;
5151
}
5252

53+
#if IN_LLVM
5354
Expression *eval_sin(Loc loc, FuncDeclaration *fd, Expressions *arguments)
5455
{
5556
Expression *arg0 = (*arguments)[0];
5657
assert(arg0->op == TOKfloat64);
57-
return new RealExp(loc, sinl(arg0->toReal()), arg0->type);
58+
return new RealExp(loc, ldouble(arg0->toReal()).sin(), arg0->type);
5859
}
5960

6061
Expression *eval_cos(Loc loc, FuncDeclaration *fd, Expressions *arguments)
6162
{
6263
Expression *arg0 = (*arguments)[0];
6364
assert(arg0->op == TOKfloat64);
64-
return new RealExp(loc, cosl(arg0->toReal()), arg0->type);
65+
return new RealExp(loc, ldouble(arg0->toReal()).cos(), arg0->type);
6566
}
6667

6768
Expression *eval_tan(Loc loc, FuncDeclaration *fd, Expressions *arguments)
6869
{
6970
Expression *arg0 = (*arguments)[0];
7071
assert(arg0->op == TOKfloat64);
71-
return new RealExp(loc, tanl(arg0->toReal()), arg0->type);
72+
return new RealExp(loc, ldouble(arg0->toReal()).tan(), arg0->type);
7273
}
7374

7475
Expression *eval_sqrt(Loc loc, FuncDeclaration *fd, Expressions *arguments)
7576
{
7677
Expression *arg0 = (*arguments)[0];
7778
assert(arg0->op == TOKfloat64);
78-
return new RealExp(loc, Port::sqrt(arg0->toReal()), arg0->type);
79+
return new RealExp(loc, ldouble(arg0->toReal()).sqrt(), arg0->type);
7980
}
8081

8182
Expression *eval_fabs(Loc loc, FuncDeclaration *fd, Expressions *arguments)
8283
{
8384
Expression *arg0 = (*arguments)[0];
8485
assert(arg0->op == TOKfloat64);
85-
return new RealExp(loc, fabsl(arg0->toReal()), arg0->type);
86+
return new RealExp(loc, ldouble(arg0->toReal()).abs(), arg0->type);
87+
}
88+
#else
89+
Expression *eval_sin(Loc loc, FuncDeclaration *fd, Expressions *arguments)
90+
{
91+
Expression *arg0 = (*arguments)[0];
92+
assert(arg0->op == TOKfloat64);
93+
return new RealExp(loc, sinl(arg0->toReal()), arg0->type);
94+
}
95+
96+
Expression *eval_cos(Loc loc, FuncDeclaration *fd, Expressions *arguments)
97+
{
98+
Expression *arg0 = (*arguments)[0];
99+
assert(arg0->op == TOKfloat64);
100+
return new RealExp(loc, cosl(arg0->toReal()), arg0->type);
101+
}
102+
103+
Expression *eval_tan(Loc loc, FuncDeclaration *fd, Expressions *arguments)
104+
{
105+
Expression *arg0 = (*arguments)[0];
106+
assert(arg0->op == TOKfloat64);
107+
return new RealExp(loc, tanl(arg0->toReal()), arg0->type);
108+
}
109+
110+
Expression *eval_sqrt(Loc loc, FuncDeclaration *fd, Expressions *arguments)
111+
{
112+
Expression *arg0 = (*arguments)[0];
113+
assert(arg0->op == TOKfloat64);
114+
return new RealExp(loc, Port::sqrt(arg0->toReal()), arg0->type);
86115
}
87116

117+
Expression *eval_fabs(Loc loc, FuncDeclaration *fd, Expressions *arguments)
118+
{
119+
Expression *arg0 = (*arguments)[0];
120+
assert(arg0->op == TOKfloat64);
121+
return new RealExp(loc, fabsl(arg0->toReal()), arg0->type);
122+
}
123+
#endif
124+
88125
#if IN_LLVM
89126

90127
static inline Type *getTypeOfOverloadedIntrinsic(FuncDeclaration *fd)

dmd2/root/longdouble.h

+197
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@
1111
#ifndef __LONG_DOUBLE_H__
1212
#define __LONG_DOUBLE_H__
1313

14+
#if IN_LLVM
15+
16+
#include "gen/ldc-real.h"
17+
18+
#else
19+
20+
#if !_MSC_VER // has native 10 byte doubles
1421
#include <stdio.h>
1522
typedef long double longdouble;
1623
typedef volatile long double volatile_longdouble;
@@ -47,4 +54,194 @@ inline size_t ld_sprint(char* str, int fmt, longdouble x)
4754
#undef sprintf
4855
#endif
4956

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+
50247
#endif // __LONG_DOUBLE_H__

0 commit comments

Comments
 (0)