Skip to content

Commit fd7b32b

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 9088152 commit fd7b32b

File tree

10 files changed

+1269
-984
lines changed

10 files changed

+1269
-984
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

@@ -339,6 +340,27 @@ if(LLVM_ENABLE_ASSERTIONS)
339340
string(REGEX REPLACE "(^| )[/-]D *NDEBUG( |$)" " " CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
340341
endif()
341342

343+
#
344+
# check string functions
345+
#
346+
check_symbol_exists(memicmp "string.h" HAVE_MEMICMP)
347+
check_symbol_exists(stricmp "string.h" HAVE_STRICMP)
348+
check_symbol_exists(strupr "string.h" HAVE_STRUPR)
349+
check_symbol_exists(strtof "stdlib.h" HAVE_STRTOF)
350+
351+
if(HAVE_MEMICMP)
352+
add_definitions(-DHAVE_MEMICMP)
353+
endif()
354+
355+
if(HAVE_STRICMP)
356+
add_definitions(-DHAVE_STRICMP)
357+
endif()
358+
359+
if(HAVE_STRUPR)
360+
add_definitions(-DHAVE_STRUPR)
361+
endif()
362+
363+
342364
#
343365
# Check endianess.
344366
# There is no realiable way to delegate the work to the compiler.
@@ -467,7 +489,6 @@ endif()
467489
#
468490
# LDMD
469491
#
470-
include(CheckSymbolExists)
471492
CHECK_SYMBOL_EXISTS(_SC_ARG_MAX "unistd.h" HAVE_SC_ARG_MAX)
472493
if (HAVE_SC_ARG_MAX)
473494
add_definitions(-DHAVE_SC_ARG_MAX)

dmd2/builtin.c

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

51+
#if IN_LLVM
5152
Expression *eval_sin(Loc loc, FuncDeclaration *fd, Expressions *arguments)
5253
{
5354
Expression *arg0 = (*arguments)[0];
5455
assert(arg0->op == TOKfloat64);
55-
return new RealExp(loc, sinl(arg0->toReal()), arg0->type);
56+
return new RealExp(loc, ldouble(arg0->toReal()).sin(), arg0->type);
5657
}
5758

5859
Expression *eval_cos(Loc loc, FuncDeclaration *fd, Expressions *arguments)
5960
{
6061
Expression *arg0 = (*arguments)[0];
6162
assert(arg0->op == TOKfloat64);
62-
return new RealExp(loc, cosl(arg0->toReal()), arg0->type);
63+
return new RealExp(loc, ldouble(arg0->toReal()).cos(), arg0->type);
6364
}
6465

6566
Expression *eval_tan(Loc loc, FuncDeclaration *fd, Expressions *arguments)
6667
{
6768
Expression *arg0 = (*arguments)[0];
6869
assert(arg0->op == TOKfloat64);
69-
return new RealExp(loc, tanl(arg0->toReal()), arg0->type);
70+
return new RealExp(loc, ldouble(arg0->toReal()).tan(), arg0->type);
7071
}
7172

7273
Expression *eval_sqrt(Loc loc, FuncDeclaration *fd, Expressions *arguments)
7374
{
7475
Expression *arg0 = (*arguments)[0];
7576
assert(arg0->op == TOKfloat64);
76-
return new RealExp(loc, Port::sqrt(arg0->toReal()), arg0->type);
77+
return new RealExp(loc, ldouble(arg0->toReal()).sqrt(), arg0->type);
7778
}
7879

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

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

88125
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)