xref: /llvm-project/compiler-rt/test/builtins/Unit/fp_test.h (revision d33dc14833b581d276a712a8425ab8f62a59c589)
1 #include <assert.h>
2 #include <limits.h>
3 #include <stdint.h>
4 #include <stdlib.h>
5 #include <string.h>
6 
7 #include "int_types.h"
8 
9 #ifdef COMPILER_RT_HAS_FLOAT16
10 #define TYPE_FP16 _Float16
11 #else
12 #define TYPE_FP16 uint16_t
13 #endif
14 
15 enum EXPECTED_RESULT {
16     LESS_0, LESS_EQUAL_0, EQUAL_0, GREATER_0, GREATER_EQUAL_0, NEQUAL_0
17 };
18 
19 static inline TYPE_FP16 fromRep16(uint16_t x)
20 {
21 #ifdef COMPILER_RT_HAS_FLOAT16
22     TYPE_FP16 ret;
23     memcpy(&ret, &x, sizeof(ret));
24     return ret;
25 #else
26     return x;
27 #endif
28 }
29 
30 static inline float fromRep32(uint32_t x)
31 {
32     float ret;
33     memcpy(&ret, &x, 4);
34     return ret;
35 }
36 
37 static inline double fromRep64(uint64_t x)
38 {
39     double ret;
40     memcpy(&ret, &x, 8);
41     return ret;
42 }
43 
44 #if defined(CRT_HAS_TF_MODE)
45 static inline tf_float fromRep128(uint64_t hi, uint64_t lo) {
46     __uint128_t x = ((__uint128_t)hi << 64) + lo;
47     tf_float ret;
48     memcpy(&ret, &x, 16);
49     return ret;
50 }
51 #endif
52 
53 static inline uint16_t toRep16(TYPE_FP16 x)
54 {
55 #ifdef COMPILER_RT_HAS_FLOAT16
56     uint16_t ret;
57     memcpy(&ret, &x, sizeof(ret));
58     return ret;
59 #else
60     return x;
61 #endif
62 }
63 
64 static inline uint32_t toRep32(float x)
65 {
66     uint32_t ret;
67     memcpy(&ret, &x, 4);
68     return ret;
69 }
70 
71 static inline uint64_t toRep64(double x)
72 {
73     uint64_t ret;
74     memcpy(&ret, &x, 8);
75     return ret;
76 }
77 
78 #if defined(CRT_HAS_TF_MODE)
79 static inline __uint128_t toRep128(tf_float x) {
80     __uint128_t ret;
81     memcpy(&ret, &x, 16);
82     return ret;
83 }
84 #endif
85 
86 static inline int compareResultH(TYPE_FP16 result,
87                                  uint16_t expected)
88 {
89     uint16_t rep = toRep16(result);
90 
91     if (rep == expected){
92         return 0;
93     }
94     // test other possible NaN representation(signal NaN)
95     else if (expected == 0x7e00U){
96         if ((rep & 0x7c00U) == 0x7c00U &&
97             (rep & 0x3ffU) > 0){
98             return 0;
99         }
100     }
101     return 1;
102 }
103 
104 static inline int compareResultF(float result,
105                                  uint32_t expected)
106 {
107     uint32_t rep = toRep32(result);
108 
109     if (rep == expected){
110         return 0;
111     }
112     // test other possible NaN representation(signal NaN)
113     else if (expected == 0x7fc00000U){
114         if ((rep & 0x7f800000U) == 0x7f800000U &&
115             (rep & 0x7fffffU) > 0){
116             return 0;
117         }
118     }
119     return 1;
120 }
121 
122 static inline int compareResultD(double result,
123                                  uint64_t expected)
124 {
125     uint64_t rep = toRep64(result);
126 
127     if (rep == expected){
128         return 0;
129     }
130     // test other possible NaN representation(signal NaN)
131     else if (expected == 0x7ff8000000000000UL){
132         if ((rep & 0x7ff0000000000000UL) == 0x7ff0000000000000UL &&
133             (rep & 0xfffffffffffffUL) > 0){
134             return 0;
135         }
136     }
137     return 1;
138 }
139 
140 #if defined(CRT_HAS_TF_MODE)
141 // return 0 if equal
142 // use two 64-bit integers instead of one 128-bit integer
143 // because 128-bit integer constant can't be assigned directly
144 static inline int compareResultF128(tf_float result, uint64_t expectedHi,
145                                     uint64_t expectedLo) {
146     __uint128_t rep = toRep128(result);
147     uint64_t hi = rep >> 64;
148     uint64_t lo = rep;
149 
150     if (hi == expectedHi && lo == expectedLo) {
151         return 0;
152     }
153     // test other possible NaN representation(signal NaN)
154     else if (expectedHi == 0x7fff800000000000UL && expectedLo == 0x0UL) {
155         if ((hi & 0x7fff000000000000UL) == 0x7fff000000000000UL &&
156             ((hi & 0xffffffffffffUL) > 0 || lo > 0)) {
157             return 0;
158         }
159     }
160     return 1;
161 }
162 #endif
163 
164 static inline int compareResultCMP(int result,
165                                    enum EXPECTED_RESULT expected)
166 {
167     switch(expected){
168         case LESS_0:
169             if (result < 0)
170                 return 0;
171             break;
172         case LESS_EQUAL_0:
173             if (result <= 0)
174                 return 0;
175             break;
176         case EQUAL_0:
177             if (result == 0)
178                 return 0;
179             break;
180         case NEQUAL_0:
181             if (result != 0)
182                 return 0;
183             break;
184         case GREATER_EQUAL_0:
185             if (result >= 0)
186                 return 0;
187             break;
188         case GREATER_0:
189             if (result > 0)
190                 return 0;
191             break;
192         default:
193             return 1;
194     }
195     return 1;
196 }
197 
198 static inline char *expectedStr(enum EXPECTED_RESULT expected)
199 {
200     switch(expected){
201         case LESS_0:
202             return "<0";
203         case LESS_EQUAL_0:
204             return "<=0";
205         case EQUAL_0:
206             return "=0";
207         case NEQUAL_0:
208             return "!=0";
209         case GREATER_EQUAL_0:
210             return ">=0";
211         case GREATER_0:
212             return ">0";
213         default:
214             return "";
215     }
216     return "";
217 }
218 
219 static inline TYPE_FP16 makeQNaN16(void)
220 {
221     return fromRep16(0x7e00U);
222 }
223 
224 static inline float makeQNaN32(void)
225 {
226     return fromRep32(0x7fc00000U);
227 }
228 
229 static inline double makeQNaN64(void)
230 {
231     return fromRep64(0x7ff8000000000000UL);
232 }
233 
234 #if HAS_80_BIT_LONG_DOUBLE
235 static inline xf_float F80FromRep80(uint16_t hi, uint64_t lo) {
236   uqwords bits;
237   bits.high.all = hi;
238   bits.low.all = lo;
239   xf_float ret;
240   static_assert(sizeof(xf_float) <= sizeof(uqwords), "wrong representation");
241   memcpy(&ret, &bits, sizeof(ret));
242   return ret;
243 }
244 
245 static inline uqwords F80ToRep80(xf_float x) {
246   uqwords ret;
247   memset(&ret, 0, sizeof(ret));
248   memcpy(&ret, &x, sizeof(x));
249   // Any bits beyond the first 16 in high are undefined.
250   ret.high.all = (uint16_t)ret.high.all;
251   return ret;
252 }
253 
254 static inline int compareResultF80(xf_float result, uint16_t expectedHi,
255                                    uint64_t expectedLo) {
256   uqwords rep = F80ToRep80(result);
257   // F80 high occupies the lower 16 bits of high.
258   assert((uint64_t)(uint16_t)rep.high.all == rep.high.all);
259   return !(rep.high.all == expectedHi && rep.low.all == expectedLo);
260 }
261 
262 static inline xf_float makeQNaN80(void) {
263   return F80FromRep80(0x7fffu, 0xc000000000000000UL);
264 }
265 
266 static inline xf_float makeNaN80(uint64_t rand) {
267   return F80FromRep80(0x7fffu,
268                       0x8000000000000000 | (rand & 0x3fffffffffffffff));
269 }
270 
271 static inline xf_float makeInf80(void) {
272   return F80FromRep80(0x7fffu, 0x8000000000000000UL);
273 }
274 
275 static inline xf_float makeNegativeInf80(void) {
276   return F80FromRep80(0xffffu, 0x8000000000000000UL);
277 }
278 #endif
279 
280 #if defined(CRT_HAS_TF_MODE)
281 static inline tf_float makeQNaN128(void) {
282     return fromRep128(0x7fff800000000000UL, 0x0UL);
283 }
284 #endif
285 
286 static inline TYPE_FP16 makeNaN16(uint16_t rand)
287 {
288     return fromRep16(0x7c00U | (rand & 0x7fffU));
289 }
290 
291 static inline float makeNaN32(uint32_t rand)
292 {
293     return fromRep32(0x7f800000U | (rand & 0x7fffffU));
294 }
295 
296 static inline double makeNaN64(uint64_t rand)
297 {
298     return fromRep64(0x7ff0000000000000UL | (rand & 0xfffffffffffffUL));
299 }
300 
301 #if defined(CRT_HAS_TF_MODE)
302 static inline tf_float makeNaN128(uint64_t rand) {
303     return fromRep128(0x7fff000000000000UL | (rand & 0xffffffffffffUL), 0x0UL);
304 }
305 #endif
306 
307 static inline TYPE_FP16 makeInf16(void)
308 {
309     return fromRep16(0x7c00U);
310 }
311 
312 static inline TYPE_FP16 makeNegativeInf16(void) { return fromRep16(0xfc00U); }
313 
314 static inline float makeInf32(void)
315 {
316     return fromRep32(0x7f800000U);
317 }
318 
319 static inline float makeNegativeInf32(void)
320 {
321     return fromRep32(0xff800000U);
322 }
323 
324 static inline double makeInf64(void)
325 {
326     return fromRep64(0x7ff0000000000000UL);
327 }
328 
329 static inline double makeNegativeInf64(void)
330 {
331     return fromRep64(0xfff0000000000000UL);
332 }
333 
334 #if defined(CRT_HAS_TF_MODE)
335 static inline tf_float makeInf128(void) {
336     return fromRep128(0x7fff000000000000UL, 0x0UL);
337 }
338 
339 static inline tf_float makeNegativeInf128(void) {
340     return fromRep128(0xffff000000000000UL, 0x0UL);
341 }
342 #endif
343