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