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