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