1 /*
2 streflop: STandalone REproducible FLOating-Point
3 Copyright 2006 Nicolas Brodu
4 2012 Mark Vejvoda
5
6 You can redistribute this code and/or modify it under
7 the terms of the GNU General Public License as published
8 by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version
10
11 Heavily relies on GNU Libm, itself depending on netlib fplibm, GNU MP, and IBM MP lib.
12 Uses SoftFloat too.
13
14 Please read the history and copyright information in the documentation provided with the source code
15 */
16
17 #ifdef STREFLOP_SOFT
18
19 // Include generic version
20 #include "streflop.h"
21
22 // Macro to select the correct version of a softfloat function according to user flags
23 #if N_SPECIALIZED == 96
24
25 #define SF_PREPEND(func) floatx80 ## func
26 #define SF_APPEND(func) func ## floatx80
27 #define SF_TYPE floatx80
28
29 #elif N_SPECIALIZED == 64
30 #define SF_PREPEND(func) float64 ## func
31 #define SF_APPEND(func) func ## float64
32 #define SF_TYPE float64
33
34 #elif N_SPECIALIZED == 32
35 #define SF_PREPEND(func) float32 ## func
36 #define SF_APPEND(func) func ## float32
37 #define SF_TYPE float32
38
39 #else
40 #error Unknown specialization size (N_SPECIALIZED)
41 #endif
42
43 // This file may include System.h and SoftFloat
44 #include "System.h"
45
46 #include "softfloat/softfloat.h"
47
48 namespace streflop {
49
50 using namespace streflop::SoftFloat;
51
52
53 // The template instanciations for N = 4, 8, 10 are done here
54
operator +=(const SoftFloatWrapper<N_SPECIALIZED> & f)55 template<> SoftFloatWrapper<N_SPECIALIZED>& SoftFloatWrapper<N_SPECIALIZED>::operator+=(const SoftFloatWrapper<N_SPECIALIZED>& f) {
56 value<SF_TYPE>() = SF_PREPEND(_add)(value<SF_TYPE>(), f.value<SF_TYPE>());
57 return *this;
58 }
operator -=(const SoftFloatWrapper<N_SPECIALIZED> & f)59 template<> SoftFloatWrapper<N_SPECIALIZED>& SoftFloatWrapper<N_SPECIALIZED>::operator-=(const SoftFloatWrapper<N_SPECIALIZED>& f) {
60 value<SF_TYPE>() = SF_PREPEND(_sub)(value<SF_TYPE>(), f.value<SF_TYPE>());
61 return *this;
62 }
operator *=(const SoftFloatWrapper<N_SPECIALIZED> & f)63 template<> SoftFloatWrapper<N_SPECIALIZED>& SoftFloatWrapper<N_SPECIALIZED>::operator*=(const SoftFloatWrapper<N_SPECIALIZED>& f) {
64 value<SF_TYPE>() = SF_PREPEND(_mul)(value<SF_TYPE>(), f.value<SF_TYPE>());
65 return *this;
66 }
operator /=(const SoftFloatWrapper<N_SPECIALIZED> & f)67 template<> SoftFloatWrapper<N_SPECIALIZED>& SoftFloatWrapper<N_SPECIALIZED>::operator/=(const SoftFloatWrapper<N_SPECIALIZED>& f) {
68 value<SF_TYPE>() = SF_PREPEND(_div)(value<SF_TYPE>(), f.value<SF_TYPE>());
69 return *this;
70 }
operator ==(const SoftFloatWrapper<N_SPECIALIZED> & f) const71 template<> bool SoftFloatWrapper<N_SPECIALIZED>::operator==(const SoftFloatWrapper<N_SPECIALIZED>& f) const {
72 return SF_PREPEND(_eq)(value<SF_TYPE>(), f.value<SF_TYPE>());
73 }
operator !=(const SoftFloatWrapper<N_SPECIALIZED> & f) const74 template<> bool SoftFloatWrapper<N_SPECIALIZED>::operator!=(const SoftFloatWrapper<N_SPECIALIZED>& f) const {
75 // Boolean negation is OK for equality comparison
76 return !SF_PREPEND(_eq)(value<SF_TYPE>(), f.value<SF_TYPE>());
77 }
operator <(const SoftFloatWrapper<N_SPECIALIZED> & f) const78 template<> bool SoftFloatWrapper<N_SPECIALIZED>::operator<(const SoftFloatWrapper<N_SPECIALIZED>& f) const {
79 return SF_PREPEND(_lt)(value<SF_TYPE>(), f.value<SF_TYPE>());
80 }
operator <=(const SoftFloatWrapper<N_SPECIALIZED> & f) const81 template<> bool SoftFloatWrapper<N_SPECIALIZED>::operator<=(const SoftFloatWrapper<N_SPECIALIZED>& f) const {
82 return SF_PREPEND(_le)(value<SF_TYPE>(), f.value<SF_TYPE>());
83 }
operator >(const SoftFloatWrapper<N_SPECIALIZED> & f) const84 template<> bool SoftFloatWrapper<N_SPECIALIZED>::operator>(const SoftFloatWrapper<N_SPECIALIZED>& f) const {
85 // Take care of NaN, reverse arguments and do NOT take the boolean negation of <=
86 return SF_PREPEND(_lt)(f.value<SF_TYPE>(), value<SF_TYPE>());
87 }
operator >=(const SoftFloatWrapper<N_SPECIALIZED> & f) const88 template<> bool SoftFloatWrapper<N_SPECIALIZED>::operator>=(const SoftFloatWrapper<N_SPECIALIZED>& f) const {
89 // Take care of NaN, reverse arguments and do NOT take the boolean negation of <
90 return SF_PREPEND(_le)(f.value<SF_TYPE>(), value<SF_TYPE>());
91 }
92
93
94 // Use compile-time specialization with template meta-programming
95 // instead of macros to decide on the correct softfloat function
96 // => sizeof is useable
97 // Note: To avoid duplicate symbols, insert a third template argument corresponding to N_SPECIALIZED
98 // This is consistent with the use of SF_XXPEND macros
99 template<int N, typename T, bool is_large> struct IntConverter {
100 };
101
102 // Specialization for large ints > 32 bits
103 template<typename T> struct IntConverter<N_SPECIALIZED, T, true> {
104 static inline SF_TYPE
convert_from_intstreflop::IntConverter105 convert_from_int(T an_int) {
106 return SF_APPEND(int64_to_)((int64_t)an_int);
107 }
convert_to_intstreflop::IntConverter108 static inline T convert_to_int(SF_TYPE value) {
109 return (T)SF_PREPEND(_to_int64_round_to_zero)(value);
110 }
111 };
112
113 // Specialization for ints <= 32 bits
114 template<typename T> struct IntConverter<N_SPECIALIZED, T, false> {
115 static inline SF_TYPE
convert_from_intstreflop::IntConverter116 convert_from_int(T an_int) {
117 return SF_APPEND(int32_to_)((int32_t)an_int);
118 }
convert_to_intstreflop::IntConverter119 static inline T convert_to_int(SF_TYPE value) {
120 return (T)SF_PREPEND(_to_int32_round_to_zero)(value);
121 }
122 };
123
124 #define STREFLOP_X87DENORMAL_NATIVE_OPS_INT(native_type) \
125 template<> SoftFloatWrapper<N_SPECIALIZED>::SoftFloatWrapper(const native_type f) { \
126 value<SF_TYPE>() = IntConverter< N_SPECIALIZED, native_type, (sizeof(native_type)>4) >::convert_from_int(f); \
127 } \
128 template<> SoftFloatWrapper<N_SPECIALIZED>& SoftFloatWrapper<N_SPECIALIZED>::operator=(const native_type f) { \
129 value<SF_TYPE>() = IntConverter< N_SPECIALIZED, native_type, (sizeof(native_type)>4) >::convert_from_int(f); \
130 return *this; \
131 } \
132 template<> SoftFloatWrapper<N_SPECIALIZED>::operator native_type() const { \
133 return IntConverter< N_SPECIALIZED, native_type, (sizeof(native_type)>4) >::convert_to_int(value<SF_TYPE>()); \
134 } \
135 template<> SoftFloatWrapper<N_SPECIALIZED>& SoftFloatWrapper<N_SPECIALIZED>::operator+=(const native_type f) { \
136 value<SF_TYPE>() = SF_PREPEND(_add)(value<SF_TYPE>(), IntConverter< N_SPECIALIZED, native_type, (sizeof(native_type)>4) >::convert_from_int(f)); \
137 return *this; \
138 } \
139 template<> SoftFloatWrapper<N_SPECIALIZED>& SoftFloatWrapper<N_SPECIALIZED>::operator-=(const native_type f) { \
140 value<SF_TYPE>() = SF_PREPEND(_sub)(value<SF_TYPE>(), IntConverter< N_SPECIALIZED, native_type, (sizeof(native_type)>4) >::convert_from_int(f)); \
141 return *this; \
142 } \
143 template<> SoftFloatWrapper<N_SPECIALIZED>& SoftFloatWrapper<N_SPECIALIZED>::operator*=(const native_type f) { \
144 value<SF_TYPE>() = SF_PREPEND(_mul)(value<SF_TYPE>(), IntConverter< N_SPECIALIZED, native_type, (sizeof(native_type)>4) >::convert_from_int(f)); \
145 return *this; \
146 } \
147 template<> SoftFloatWrapper<N_SPECIALIZED>& SoftFloatWrapper<N_SPECIALIZED>::operator/=(const native_type f) { \
148 value<SF_TYPE>() = SF_PREPEND(_div)(value<SF_TYPE>(), IntConverter< N_SPECIALIZED, native_type, (sizeof(native_type)>4) >::convert_from_int(f)); \
149 return *this; \
150 } \
151 template<> bool SoftFloatWrapper<N_SPECIALIZED>::operator==(const native_type f) const { \
152 return SF_PREPEND(_eq)(value<SF_TYPE>(), IntConverter< N_SPECIALIZED, native_type, (sizeof(native_type)>4) >::convert_from_int(f)); \
153 } \
154 template<> bool SoftFloatWrapper<N_SPECIALIZED>::operator!=(const native_type f) const { \
155 return !SF_PREPEND(_eq)(value<SF_TYPE>(), IntConverter< N_SPECIALIZED, native_type, (sizeof(native_type)>4) >::convert_from_int(f)); \
156 } \
157 template<> bool SoftFloatWrapper<N_SPECIALIZED>::operator<(const native_type f) const { \
158 return SF_PREPEND(_lt)(value<SF_TYPE>(), IntConverter< N_SPECIALIZED, native_type, (sizeof(native_type)>4) >::convert_from_int(f)); \
159 } \
160 template<> bool SoftFloatWrapper<N_SPECIALIZED>::operator<=(const native_type f) const { \
161 return SF_PREPEND(_le)(value<SF_TYPE>(), IntConverter< N_SPECIALIZED, native_type, (sizeof(native_type)>4) >::convert_from_int(f)); \
162 } \
163 template<> bool SoftFloatWrapper<N_SPECIALIZED>::operator>(const native_type f) const { \
164 return SF_PREPEND(_lt)(IntConverter< N_SPECIALIZED, native_type, (sizeof(native_type)>4) >::convert_from_int(f), value<SF_TYPE>()); \
165 } \
166 template<> bool SoftFloatWrapper<N_SPECIALIZED>::operator>=(const native_type f) const { \
167 return SF_PREPEND(_le)(IntConverter< N_SPECIALIZED, native_type, (sizeof(native_type)>4) >::convert_from_int(f), value<SF_TYPE>()); \
168 }
169
170 // Now handle the same operations with native float types
171 // Use the softfloat property of memory pattern equivalence.
172 // => consider the float as a memory zone, then pass that to the softfloat conversion routines
173 // => this way, conversion is done by softfloat, not by the FPU
174 // Use a sizeof trick:
175 // - Specialize for BOTH C type and the expected type size of C type for correct memory pattern
176 // - Call the template with sizeof(C type) to rule out mismatching combinations
177 // - this way, it would be possible to extend the scheme to other architectures
178 // Ex: could specialize for <long double, 10>, <long double, 12> and <long double, 16>
179 // Note: read above note for specialization on N_SPECIALIZED
180 template<int N, typename ctype, int ctype_size> struct FloatConverter {
181 };
182
183 // dummy wrapers to cover all cases
float32_to_float32(float32 a_float)184 inline float32 float32_to_float32(float32 a_float) {return a_float;}
float64_to_float64(float64 a_float)185 inline float64 float64_to_float64(float64 a_float) {return a_float;}
floatx80_to_floatx80(floatx80 a_float)186 inline floatx80 floatx80_to_floatx80(floatx80 a_float) {return a_float;}
187
188 // Specialization for float32 when C float type size is 4
189 template<> struct FloatConverter<N_SPECIALIZED, float, 4> {
190 static inline SF_TYPE
convert_from_floatstreflop::FloatConverter191 convert_from_float(const float a_float) {
192 return SF_APPEND(float32_to_)(*reinterpret_cast<const float32*>(&a_float));
193 }
convert_to_floatstreflop::FloatConverter194 static inline float convert_to_float(SF_TYPE value) {
195 float32 res = SF_PREPEND(_to_float32)(value);
196 return *reinterpret_cast<float*>(&res);
197 }
198 };
199
200 // Specialization for double64 when C double type size is 8
201 template<> struct FloatConverter<N_SPECIALIZED, double, 8> {
202 static inline SF_TYPE
convert_from_floatstreflop::FloatConverter203 convert_from_float(const double a_float) {
204 return SF_APPEND(float64_to_)(*reinterpret_cast<const float64*>(&a_float));
205 }
convert_to_floatstreflop::FloatConverter206 static inline double convert_to_float(SF_TYPE value) {
207 float64 res = SF_PREPEND(_to_float64)(value);
208 return *reinterpret_cast<double*>(&res);
209 }
210 };
211
212 // Specialization for floatx80 when C long double type size is 8 (there is 16 bit padding, endian dependent)
213 template<> struct FloatConverter<N_SPECIALIZED, long double, 8> {
214 // Little endian OK: both address are the same
215 #if __FLOAT_WORD_ORDER == 1234
216 static inline SF_TYPE
convert_from_floatstreflop::FloatConverter217 convert_from_float(const long double a_float) {
218 return SF_APPEND(floatx80_to_)(*reinterpret_cast<const floatx80*>(&a_float));
219 }
convert_to_floatstreflop::FloatConverter220 static inline long double convert_to_float(SF_TYPE value) {
221 // avoid invalid memory access: must return a 8-bytes value from a 10-byte type
222 // do it this way, by declaring the 8-byte on the stack
223 long double holder;
224 // And use that space for the result using the softfloat memory bit pattern equivalence property
225 *reinterpret_cast<floatx80*>(&holder) = SF_PREPEND(_to_floatx80)(value);
226 return holder;
227 }
228 // big endian needs address modification, but for what architecture?
229 #elif __FLOAT_WORD_ORDER == 4321
230 #warning You are using a completely UNTESTED new architecture. Please check that the 8-byte long double containing a 10-byte float is properly aligned in memory so that softfloat may correctly read the bit pattern. If this works for you, remove this warning and please consider sending a patch!
231 static inline SF_TYPE
232 convert_from_float(const long double a_float) {
233 return SF_APPEND(floatx80_to_)(*reinterpret_cast<const floatx80*>(reinterpret_cast<const char*>(&a_float)-2));
234 }
235 static inline long double convert_to_float(SF_TYPE value) {
236 // avoid invalid memory access: must return a 8-bytes value from a 10-byte type
237 // do it this way, by declaring the 8-byte on the stack
238 long double holder;
239 // And use that space for the result using the softfloat memory bit pattern equivalence property
240 *reinterpret_cast<floatx80*>(reinterpret_cast<const char*>(&holder)-2) = SF_PREPEND(_to_floatx80)(value);
241 return holder;
242 }
243 #else
244 #error Unknown byte order
245 #endif
246 };
247
248 // Specialization for floatx80 when C long double type size is 12 (there is 16 bit padding, endian dependent)
249 template<> struct FloatConverter<N_SPECIALIZED, long double, 12> {
250 // Little endian OK: both address are the same
251 #if __FLOAT_WORD_ORDER == 1234
252 static inline SF_TYPE
convert_from_floatstreflop::FloatConverter253 convert_from_float(const long double a_float) {
254 return SF_APPEND(floatx80_to_)(*reinterpret_cast<const floatx80*>(&a_float));
255 }
convert_to_floatstreflop::FloatConverter256 static inline long double convert_to_float(SF_TYPE value) {
257 // avoid invalid memory access: must return a 12-bytes value from a 10-byte type
258 // do it this way, by declaring the 12-byte on the stack
259 long double holder;
260 // And use that space for the result using the softfloat memory bit pattern equivalence property
261 *reinterpret_cast<floatx80*>(&holder) = SF_PREPEND(_to_floatx80)(value);
262 return holder;
263 }
264 // big endian needs address modification, but for what architecture?
265 #elif __FLOAT_WORD_ORDER == 4321
266 #warning You are using a completely UNTESTED new architecture. Please check that the 12-byte long double containing a 10-byte float is properly aligned in memory so that softfloat may correctly read the bit pattern. If this works for you, remove this warning and please consider sending a patch!
267 static inline SF_TYPE
268 convert_from_float(const long double a_float) {
269 return SF_APPEND(floatx80_to_)(*reinterpret_cast<const floatx80*>(reinterpret_cast<const char*>(&a_float)+2));
270 }
271 static inline long double convert_to_float(SF_TYPE value) {
272 // avoid invalid memory access: must return a 12-bytes value from a 10-byte type
273 // do it this way, by declaring the 12-byte on the stack
274 long double holder;
275 // And use that space for the result using the softfloat memory bit pattern equivalence property
276 *reinterpret_cast<floatx80*>(reinterpret_cast<const char*>(&holder)+2) = SF_PREPEND(_to_floatx80)(value);
277 return holder;
278 }
279 #else
280 #error Unknown byte order
281 #endif
282 };
283
284 // Specialization for floatx80 when C long double type size is 16. This is the case for g++ using -m128bit-long-double, which is itself the default on x86_64
285 template<> struct FloatConverter<N_SPECIALIZED, long double, 16> {
286 // Little endian OK: both address are the same
287 #if __FLOAT_WORD_ORDER == 1234
288 static inline SF_TYPE
convert_from_floatstreflop::FloatConverter289 convert_from_float(const long double a_float) {
290 return SF_APPEND(floatx80_to_)(*reinterpret_cast<const floatx80*>(&a_float));
291 }
convert_to_floatstreflop::FloatConverter292 static inline long double convert_to_float(SF_TYPE value) {
293 // avoid invalid memory access: must return a 16-bytes value from a 10-byte type
294 // do it this way, by declaring the 16-byte on the stack
295 long double holder;
296 // And use that space for the result using the softfloat memory bit pattern equivalence property
297 *reinterpret_cast<floatx80*>(&holder) = SF_PREPEND(_to_floatx80)(value);
298 return holder;
299 }
300 // big endian needs address modification, but for what architecture?
301 #elif __FLOAT_WORD_ORDER == 4321
302 #warning You are using a completely UNTESTED new architecture. Please check that the 16-byte long double containing a 10-byte float is properly aligned in memory so that softfloat may correctly read the bit pattern. If this works for you, remove this warning and please consider sending a patch!
303 static inline SF_TYPE
304 convert_from_float(const long double a_float) {
305 return SF_APPEND(floatx80_to_)(*reinterpret_cast<const floatx80*>(reinterpret_cast<const char*>(&a_float)+6));
306 }
307 static inline long double convert_to_float(SF_TYPE value) {
308 // avoid invalid memory access: must return a 12-bytes value from a 10-byte type
309 // do it this way, by declaring the 12-byte on the stack
310 long double holder;
311 // And use that space for the result using the softfloat memory bit pattern equivalence property
312 *reinterpret_cast<floatx80*>(reinterpret_cast<const char*>(&holder)+6) = SF_PREPEND(_to_floatx80)(value);
313 return holder;
314 }
315 #else
316 #error Unknown byte order
317 #endif
318 };
319
320
321 #define STREFLOP_X87DENORMAL_NATIVE_OPS_FLOAT(native_type) \
322 template<> SoftFloatWrapper<N_SPECIALIZED>::SoftFloatWrapper(const native_type f) { \
323 value<SF_TYPE>() = FloatConverter< N_SPECIALIZED, native_type, sizeof(native_type)>::convert_from_float(f); \
324 } \
325 template<> SoftFloatWrapper<N_SPECIALIZED>& SoftFloatWrapper<N_SPECIALIZED>::operator=(const native_type f) { \
326 value<SF_TYPE>() = FloatConverter< N_SPECIALIZED, native_type, sizeof(native_type)>::convert_from_float(f); \
327 return *this; \
328 } \
329 template<> SoftFloatWrapper<N_SPECIALIZED>::operator native_type() const { \
330 return FloatConverter< N_SPECIALIZED, native_type, sizeof(native_type)>::convert_to_float(value<SF_TYPE>()); \
331 } \
332 template<> SoftFloatWrapper<N_SPECIALIZED>& SoftFloatWrapper<N_SPECIALIZED>::operator+=(const native_type f) { \
333 value<SF_TYPE>() = SF_PREPEND(_add)(value<SF_TYPE>(), FloatConverter< N_SPECIALIZED, native_type, sizeof(native_type)>::convert_from_float(f)); \
334 return *this; \
335 } \
336 template<> SoftFloatWrapper<N_SPECIALIZED>& SoftFloatWrapper<N_SPECIALIZED>::operator-=(const native_type f) { \
337 value<SF_TYPE>() = SF_PREPEND(_sub)(value<SF_TYPE>(), FloatConverter< N_SPECIALIZED, native_type, sizeof(native_type)>::convert_from_float(f)); \
338 return *this; \
339 } \
340 template<> SoftFloatWrapper<N_SPECIALIZED>& SoftFloatWrapper<N_SPECIALIZED>::operator*=(const native_type f) { \
341 value<SF_TYPE>() = SF_PREPEND(_mul)(value<SF_TYPE>(), FloatConverter< N_SPECIALIZED, native_type, sizeof(native_type)>::convert_from_float(f)); \
342 return *this; \
343 } \
344 template<> SoftFloatWrapper<N_SPECIALIZED>& SoftFloatWrapper<N_SPECIALIZED>::operator/=(const native_type f) { \
345 value<SF_TYPE>() = SF_PREPEND(_div)(value<SF_TYPE>(), FloatConverter< N_SPECIALIZED, native_type, sizeof(native_type)>::convert_from_float(f)); \
346 return *this; \
347 } \
348 template<> bool SoftFloatWrapper<N_SPECIALIZED>::operator==(const native_type f) const { \
349 return SF_PREPEND(_eq)(value<SF_TYPE>(), FloatConverter< N_SPECIALIZED, native_type, sizeof(native_type)>::convert_from_float(f)); \
350 } \
351 template<> bool SoftFloatWrapper<N_SPECIALIZED>::operator!=(const native_type f) const { \
352 return !SF_PREPEND(_eq)(value<SF_TYPE>(), FloatConverter< N_SPECIALIZED, native_type, sizeof(native_type)>::convert_from_float(f)); \
353 } \
354 template<> bool SoftFloatWrapper<N_SPECIALIZED>::operator<(const native_type f) const { \
355 return SF_PREPEND(_lt)(value<SF_TYPE>(), FloatConverter< N_SPECIALIZED, native_type, sizeof(native_type)>::convert_from_float(f)); \
356 } \
357 template<> bool SoftFloatWrapper<N_SPECIALIZED>::operator<=(const native_type f) const { \
358 return SF_PREPEND(_le)(value<SF_TYPE>(), FloatConverter< N_SPECIALIZED, native_type, sizeof(native_type)>::convert_from_float(f)); \
359 } \
360 template<> bool SoftFloatWrapper<N_SPECIALIZED>::operator>(const native_type f) const { \
361 return SF_PREPEND(_lt)(FloatConverter< N_SPECIALIZED, native_type, sizeof(native_type)>::convert_from_float(f), value<SF_TYPE>()); \
362 } \
363 template<> bool SoftFloatWrapper<N_SPECIALIZED>::operator>=(const native_type f) const { \
364 return SF_PREPEND(_le)(FloatConverter< N_SPECIALIZED, native_type, sizeof(native_type)>::convert_from_float(f), value<SF_TYPE>()); \
365 }
366
367 STREFLOP_X87DENORMAL_NATIVE_OPS_INT(char)
368 STREFLOP_X87DENORMAL_NATIVE_OPS_INT(unsigned char)
369 STREFLOP_X87DENORMAL_NATIVE_OPS_INT(short)
370 STREFLOP_X87DENORMAL_NATIVE_OPS_INT(unsigned short)
371 STREFLOP_X87DENORMAL_NATIVE_OPS_INT(int)
372 STREFLOP_X87DENORMAL_NATIVE_OPS_INT(unsigned int)
373 STREFLOP_X87DENORMAL_NATIVE_OPS_INT(long)
374 STREFLOP_X87DENORMAL_NATIVE_OPS_INT(unsigned long)
375 STREFLOP_X87DENORMAL_NATIVE_OPS_INT(long long)
376 STREFLOP_X87DENORMAL_NATIVE_OPS_INT(unsigned long long)
377
378 STREFLOP_X87DENORMAL_NATIVE_OPS_FLOAT(float)
379 STREFLOP_X87DENORMAL_NATIVE_OPS_FLOAT(double)
380 STREFLOP_X87DENORMAL_NATIVE_OPS_FLOAT(long double)
381
382 /// binary operators
383 /// use dummy argument factories to distinguish from integer conversion and avoid creating temporary object
384 template<> SoftFloatWrapper<N_SPECIALIZED> operator+(const SoftFloatWrapper<N_SPECIALIZED>& f1, const SoftFloatWrapper<N_SPECIALIZED>& f2) {
385 return SoftFloatWrapper<N_SPECIALIZED>(SF_PREPEND(_add)(f1.value<SF_TYPE>(), f2.value<SF_TYPE>()), true);
386 }
operator -(const SoftFloatWrapper<N_SPECIALIZED> & f1,const SoftFloatWrapper<N_SPECIALIZED> & f2)387 template<> SoftFloatWrapper<N_SPECIALIZED> operator-(const SoftFloatWrapper<N_SPECIALIZED>& f1, const SoftFloatWrapper<N_SPECIALIZED>& f2) {
388 return SoftFloatWrapper<N_SPECIALIZED>(SF_PREPEND(_sub)(f1.value<SF_TYPE>(), f2.value<SF_TYPE>()), true);
389 }
operator *(const SoftFloatWrapper<N_SPECIALIZED> & f1,const SoftFloatWrapper<N_SPECIALIZED> & f2)390 template<> SoftFloatWrapper<N_SPECIALIZED> operator*(const SoftFloatWrapper<N_SPECIALIZED>& f1, const SoftFloatWrapper<N_SPECIALIZED>& f2) {
391 return SoftFloatWrapper<N_SPECIALIZED>(SF_PREPEND(_mul)(f1.value<SF_TYPE>(), f2.value<SF_TYPE>()), true);
392 }
operator /(const SoftFloatWrapper<N_SPECIALIZED> & f1,const SoftFloatWrapper<N_SPECIALIZED> & f2)393 template<> SoftFloatWrapper<N_SPECIALIZED> operator/(const SoftFloatWrapper<N_SPECIALIZED>& f1, const SoftFloatWrapper<N_SPECIALIZED>& f2) {
394 return SoftFloatWrapper<N_SPECIALIZED>(SF_PREPEND(_div)(f1.value<SF_TYPE>(), f2.value<SF_TYPE>()), true);
395 }
396
397 #define STREFLOP_X87DENORMAL_BINARY_OPS_INT(native_type) \
398 template<> SoftFloatWrapper<N_SPECIALIZED> operator+(const SoftFloatWrapper<N_SPECIALIZED>& f1, const native_type f2) { \
399 return SoftFloatWrapper<N_SPECIALIZED>(SF_PREPEND(_add)(f1.value<SF_TYPE>(), IntConverter< N_SPECIALIZED, native_type, (sizeof(native_type)>4) >::convert_from_int(f2)), true); \
400 } \
401 template<> SoftFloatWrapper<N_SPECIALIZED> operator-(const SoftFloatWrapper<N_SPECIALIZED>& f1, const native_type f2) { \
402 return SoftFloatWrapper<N_SPECIALIZED>(SF_PREPEND(_sub)(f1.value<SF_TYPE>(), IntConverter< N_SPECIALIZED, native_type, (sizeof(native_type)>4) >::convert_from_int(f2)), true); \
403 } \
404 template<> SoftFloatWrapper<N_SPECIALIZED> operator*(const SoftFloatWrapper<N_SPECIALIZED>& f1, const native_type f2) { \
405 return SoftFloatWrapper<N_SPECIALIZED>(SF_PREPEND(_mul)(f1.value<SF_TYPE>(), IntConverter< N_SPECIALIZED, native_type, (sizeof(native_type)>4) >::convert_from_int(f2)), true); \
406 } \
407 template<> SoftFloatWrapper<N_SPECIALIZED> operator/(const SoftFloatWrapper<N_SPECIALIZED>& f1, const native_type f2) { \
408 return SoftFloatWrapper<N_SPECIALIZED>(SF_PREPEND(_div)(f1.value<SF_TYPE>(), IntConverter< N_SPECIALIZED, native_type, (sizeof(native_type)>4) >::convert_from_int(f2)), true); \
409 } \
410 template<> SoftFloatWrapper<N_SPECIALIZED> operator+(const native_type f1, const SoftFloatWrapper<N_SPECIALIZED>& f2) { \
411 return SoftFloatWrapper<N_SPECIALIZED>(SF_PREPEND(_add)(IntConverter< N_SPECIALIZED, native_type, (sizeof(native_type)>4) >::convert_from_int(f1), f2.value<SF_TYPE>()), true); \
412 } \
413 template<> SoftFloatWrapper<N_SPECIALIZED> operator-(const native_type f1, const SoftFloatWrapper<N_SPECIALIZED>& f2) { \
414 return SoftFloatWrapper<N_SPECIALIZED>(SF_PREPEND(_sub)(IntConverter< N_SPECIALIZED, native_type, (sizeof(native_type)>4) >::convert_from_int(f1), f2.value<SF_TYPE>()), true); \
415 } \
416 template<> SoftFloatWrapper<N_SPECIALIZED> operator*(const native_type f1, const SoftFloatWrapper<N_SPECIALIZED>& f2) { \
417 return SoftFloatWrapper<N_SPECIALIZED>(SF_PREPEND(_mul)(IntConverter< N_SPECIALIZED, native_type, (sizeof(native_type)>4) >::convert_from_int(f1), f2.value<SF_TYPE>()), true); \
418 } \
419 template<> SoftFloatWrapper<N_SPECIALIZED> operator/(const native_type f1, const SoftFloatWrapper<N_SPECIALIZED>& f2) { \
420 return SoftFloatWrapper<N_SPECIALIZED>(SF_PREPEND(_div)(IntConverter< N_SPECIALIZED, native_type, (sizeof(native_type)>4) >::convert_from_int(f1), f2.value<SF_TYPE>()), true); \
421 } \
422 template<> bool operator==(const native_type value, const SoftFloatWrapper<N_SPECIALIZED>& f) { \
423 return SF_PREPEND(_eq)(IntConverter< N_SPECIALIZED, native_type, (sizeof(native_type)>4) >::convert_from_int(value), f.value<SF_TYPE>()); \
424 } \
425 template<> bool operator!=(const native_type value, const SoftFloatWrapper<N_SPECIALIZED>& f) { \
426 return !SF_PREPEND(_eq)(IntConverter< N_SPECIALIZED, native_type, (sizeof(native_type)>4) >::convert_from_int(value), f.value<SF_TYPE>()); \
427 } \
428 template<> bool operator<(const native_type value, const SoftFloatWrapper<N_SPECIALIZED>& f) { \
429 return SF_PREPEND(_lt)(IntConverter< N_SPECIALIZED, native_type, (sizeof(native_type)>4) >::convert_from_int(value), f.value<SF_TYPE>()); \
430 } \
431 template<> bool operator<=(const native_type value, const SoftFloatWrapper<N_SPECIALIZED>& f) { \
432 return SF_PREPEND(_le)(IntConverter< N_SPECIALIZED, native_type, (sizeof(native_type)>4) >::convert_from_int(value), f.value<SF_TYPE>()); \
433 } \
434 template<> bool operator>(const native_type value, const SoftFloatWrapper<N_SPECIALIZED>& f) { \
435 return SF_PREPEND(_lt)(f.value<SF_TYPE>(), IntConverter< N_SPECIALIZED, native_type, (sizeof(native_type)>4) >::convert_from_int(value)); \
436 } \
437 template<> bool operator>=(const native_type value, const SoftFloatWrapper<N_SPECIALIZED>& f) { \
438 return SF_PREPEND(_le)(f.value<SF_TYPE>(), IntConverter< N_SPECIALIZED, native_type, (sizeof(native_type)>4) >::convert_from_int(value)); \
439 }
440
441
442 #define STREFLOP_X87DENORMAL_BINARY_OPS_FLOAT(native_type) \
443 template<> SoftFloatWrapper<N_SPECIALIZED> operator+(const SoftFloatWrapper<N_SPECIALIZED>& f1, const native_type f2) { \
444 return SoftFloatWrapper<N_SPECIALIZED>(SF_PREPEND(_add)(f1.value<SF_TYPE>(), FloatConverter< N_SPECIALIZED, native_type, sizeof(native_type)>::convert_from_float(f2)), true); \
445 } \
446 template<> SoftFloatWrapper<N_SPECIALIZED> operator-(const SoftFloatWrapper<N_SPECIALIZED>& f1, const native_type f2) { \
447 return SoftFloatWrapper<N_SPECIALIZED>(SF_PREPEND(_sub)(f1.value<SF_TYPE>(), FloatConverter< N_SPECIALIZED, native_type, sizeof(native_type)>::convert_from_float(f2)), true); \
448 } \
449 template<> SoftFloatWrapper<N_SPECIALIZED> operator*(const SoftFloatWrapper<N_SPECIALIZED>& f1, const native_type f2) { \
450 return SoftFloatWrapper<N_SPECIALIZED>(SF_PREPEND(_mul)(f1.value<SF_TYPE>(), FloatConverter< N_SPECIALIZED, native_type, sizeof(native_type)>::convert_from_float(f2)), true); \
451 } \
452 template<> SoftFloatWrapper<N_SPECIALIZED> operator/(const SoftFloatWrapper<N_SPECIALIZED>& f1, const native_type f2) { \
453 return SoftFloatWrapper<N_SPECIALIZED>(SF_PREPEND(_div)(f1.value<SF_TYPE>(), FloatConverter< N_SPECIALIZED, native_type, sizeof(native_type)>::convert_from_float(f2)), true); \
454 } \
455 template<> SoftFloatWrapper<N_SPECIALIZED> operator+(const native_type f1, const SoftFloatWrapper<N_SPECIALIZED>& f2) { \
456 return SoftFloatWrapper<N_SPECIALIZED>(SF_PREPEND(_add)(FloatConverter< N_SPECIALIZED, native_type, sizeof(native_type)>::convert_from_float(f1), f2.value<SF_TYPE>()), true); \
457 } \
458 template<> SoftFloatWrapper<N_SPECIALIZED> operator-(const native_type f1, const SoftFloatWrapper<N_SPECIALIZED>& f2) { \
459 return SoftFloatWrapper<N_SPECIALIZED>(SF_PREPEND(_sub)(FloatConverter< N_SPECIALIZED, native_type, sizeof(native_type)>::convert_from_float(f1), f2.value<SF_TYPE>()), true); \
460 } \
461 template<> SoftFloatWrapper<N_SPECIALIZED> operator*(const native_type f1, const SoftFloatWrapper<N_SPECIALIZED>& f2) { \
462 return SoftFloatWrapper<N_SPECIALIZED>(SF_PREPEND(_mul)(FloatConverter< N_SPECIALIZED, native_type, sizeof(native_type)>::convert_from_float(f1), f2.value<SF_TYPE>()), true); \
463 } \
464 template<> SoftFloatWrapper<N_SPECIALIZED> operator/(const native_type f1, const SoftFloatWrapper<N_SPECIALIZED>& f2) { \
465 return SoftFloatWrapper<N_SPECIALIZED>(SF_PREPEND(_div)(FloatConverter< N_SPECIALIZED, native_type, sizeof(native_type)>::convert_from_float(f1), f2.value<SF_TYPE>()), true); \
466 } \
467 template<> bool operator==(const native_type value, const SoftFloatWrapper<N_SPECIALIZED>& f) { \
468 return SF_PREPEND(_eq)(FloatConverter< N_SPECIALIZED, native_type, sizeof(native_type)>::convert_from_float(value), f.value<SF_TYPE>()); \
469 } \
470 template<> bool operator!=(const native_type value, const SoftFloatWrapper<N_SPECIALIZED>& f) { \
471 return !SF_PREPEND(_eq)(FloatConverter< N_SPECIALIZED, native_type, sizeof(native_type)>::convert_from_float(value), f.value<SF_TYPE>()); \
472 } \
473 template<> bool operator<(const native_type value, const SoftFloatWrapper<N_SPECIALIZED>& f) { \
474 return SF_PREPEND(_lt)(FloatConverter< N_SPECIALIZED, native_type, sizeof(native_type)>::convert_from_float(value), f.value<SF_TYPE>()); \
475 } \
476 template<> bool operator<=(const native_type value, const SoftFloatWrapper<N_SPECIALIZED>& f) { \
477 return SF_PREPEND(_le)(FloatConverter< N_SPECIALIZED, native_type, sizeof(native_type)>::convert_from_float(value), f.value<SF_TYPE>()); \
478 } \
479 template<> bool operator>(const native_type value, const SoftFloatWrapper<N_SPECIALIZED>& f) { \
480 return SF_PREPEND(_lt)(f.value<SF_TYPE>(), FloatConverter< N_SPECIALIZED, native_type, sizeof(native_type)>::convert_from_float(value)); \
481 } \
482 template<> bool operator>=(const native_type value, const SoftFloatWrapper<N_SPECIALIZED>& f) { \
483 return SF_PREPEND(_le)(f.value<SF_TYPE>(), FloatConverter< N_SPECIALIZED, native_type, sizeof(native_type)>::convert_from_float(value)); \
484 }
485
486 STREFLOP_X87DENORMAL_BINARY_OPS_INT(char)
487 STREFLOP_X87DENORMAL_BINARY_OPS_INT(unsigned char)
488 STREFLOP_X87DENORMAL_BINARY_OPS_INT(short)
489 STREFLOP_X87DENORMAL_BINARY_OPS_INT(unsigned short)
490 STREFLOP_X87DENORMAL_BINARY_OPS_INT(int)
491 STREFLOP_X87DENORMAL_BINARY_OPS_INT(unsigned int)
492 STREFLOP_X87DENORMAL_BINARY_OPS_INT(long)
493 STREFLOP_X87DENORMAL_BINARY_OPS_INT(unsigned long)
494 STREFLOP_X87DENORMAL_BINARY_OPS_INT(long long)
495 STREFLOP_X87DENORMAL_BINARY_OPS_INT(unsigned long long)
496
497 STREFLOP_X87DENORMAL_BINARY_OPS_FLOAT(float)
498 STREFLOP_X87DENORMAL_BINARY_OPS_FLOAT(double)
499 STREFLOP_X87DENORMAL_BINARY_OPS_FLOAT(long double)
500
501 /// Unary operators
502 template<> SoftFloatWrapper<N_SPECIALIZED> operator-(const SoftFloatWrapper<N_SPECIALIZED>& f) {
503 // We could do it right here by flipping the bit sign
504 // However, there is the exceptions handling and such, so...
505 return SoftFloatWrapper<N_SPECIALIZED>(SF_PREPEND(_sub)(SF_APPEND(int32_to_)(0), f.value<SF_TYPE>()), true);
506 }
operator +(const SoftFloatWrapper<N_SPECIALIZED> & f)507 template<> SoftFloatWrapper<N_SPECIALIZED> operator+(const SoftFloatWrapper<N_SPECIALIZED>& f) {
508 return f; // makes a copy
509 }
510
511
SoftFloatWrapper(const SoftFloatWrapper<32> & f)512 template<> SoftFloatWrapper<N_SPECIALIZED>::SoftFloatWrapper(const SoftFloatWrapper<32>& f) {
513 value<SF_TYPE>() = SF_APPEND(float32_to_)(f.value<float32>());
514 }
515
operator =(const SoftFloatWrapper<32> & f)516 template<> SoftFloatWrapper<N_SPECIALIZED>& SoftFloatWrapper<N_SPECIALIZED>::operator=(const SoftFloatWrapper<32>& f) {
517 value<SF_TYPE>() = SF_APPEND(float32_to_)(f.value<float32>());
518 return *this;
519 }
520
SoftFloatWrapper(const SoftFloatWrapper<64> & f)521 template<> SoftFloatWrapper<N_SPECIALIZED>::SoftFloatWrapper(const SoftFloatWrapper<64>& f) {
522 value<SF_TYPE>() = SF_APPEND(float64_to_)(f.value<float64>());
523 }
524
operator =(const SoftFloatWrapper<64> & f)525 template<> SoftFloatWrapper<N_SPECIALIZED>& SoftFloatWrapper<N_SPECIALIZED>::operator=(const SoftFloatWrapper<64>& f) {
526 value<SF_TYPE>() = SF_APPEND(float64_to_)(f.value<float64>());
527 return *this;
528 }
529
SoftFloatWrapper(const SoftFloatWrapper<96> & f)530 template<> SoftFloatWrapper<N_SPECIALIZED>::SoftFloatWrapper(const SoftFloatWrapper<96>& f) {
531 value<SF_TYPE>() = SF_APPEND(floatx80_to_)(f.value<floatx80>());
532 }
533
operator =(const SoftFloatWrapper<96> & f)534 template<> SoftFloatWrapper<N_SPECIALIZED>& SoftFloatWrapper<N_SPECIALIZED>::operator=(const SoftFloatWrapper<96>& f) {
535 value<SF_TYPE>() = SF_APPEND(floatx80_to_)(f.value<floatx80>());
536 return *this;
537 }
538
539 } // end of namespace
540
541 #endif
542