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(dest: &ret, src: &x, n: 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(dest: &ret, src: &x, n: 4); |
34 | return ret; |
35 | } |
36 | |
37 | static inline double fromRep64(uint64_t x) |
38 | { |
39 | double ret; |
40 | memcpy(dest: &ret, src: &x, n: 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(dest: &ret, src: &x, n: 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(dest: &ret, src: &x, n: 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(dest: &ret, src: &x, n: 4); |
68 | return ret; |
69 | } |
70 | |
71 | static inline uint64_t toRep64(double x) |
72 | { |
73 | uint64_t ret; |
74 | memcpy(dest: &ret, src: &x, n: 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(dest: &ret, src: &x, n: 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(x: 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(x: 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(x: 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(x: 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(x: 0x7e00U); |
222 | } |
223 | |
224 | static inline float makeQNaN32(void) |
225 | { |
226 | return fromRep32(x: 0x7fc00000U); |
227 | } |
228 | |
229 | static inline double makeQNaN64(void) |
230 | { |
231 | return fromRep64(x: 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(dest: &ret, src: &bits, n: sizeof(ret)); |
242 | return ret; |
243 | } |
244 | |
245 | static inline uqwords F80ToRep80(xf_float x) { |
246 | uqwords ret; |
247 | memset(s: &ret, c: 0, n: sizeof(ret)); |
248 | memcpy(dest: &ret, src: &x, n: 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(x: 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(hi: 0x7fffu, lo: 0xc000000000000000UL); |
264 | } |
265 | |
266 | static inline xf_float makeNaN80(uint64_t rand) { |
267 | return F80FromRep80(hi: 0x7fffu, |
268 | lo: 0x8000000000000000 | (rand & 0x3fffffffffffffff)); |
269 | } |
270 | |
271 | static inline xf_float makeInf80(void) { |
272 | return F80FromRep80(hi: 0x7fffu, lo: 0x8000000000000000UL); |
273 | } |
274 | |
275 | static inline xf_float makeNegativeInf80(void) { |
276 | return F80FromRep80(hi: 0xffffu, lo: 0x8000000000000000UL); |
277 | } |
278 | #endif |
279 | |
280 | #if defined(CRT_HAS_TF_MODE) |
281 | static inline tf_float makeQNaN128(void) { |
282 | return fromRep128(hi: 0x7fff800000000000UL, lo: 0x0UL); |
283 | } |
284 | #endif |
285 | |
286 | static inline TYPE_FP16 makeNaN16(uint16_t rand) |
287 | { |
288 | return fromRep16(x: 0x7c00U | (rand & 0x7fffU)); |
289 | } |
290 | |
291 | static inline float makeNaN32(uint32_t rand) |
292 | { |
293 | return fromRep32(x: 0x7f800000U | (rand & 0x7fffffU)); |
294 | } |
295 | |
296 | static inline double makeNaN64(uint64_t rand) |
297 | { |
298 | return fromRep64(x: 0x7ff0000000000000UL | (rand & 0xfffffffffffffUL)); |
299 | } |
300 | |
301 | #if defined(CRT_HAS_TF_MODE) |
302 | static inline tf_float makeNaN128(uint64_t rand) { |
303 | return fromRep128(hi: 0x7fff000000000000UL | (rand & 0xffffffffffffUL), lo: 0x0UL); |
304 | } |
305 | #endif |
306 | |
307 | static inline TYPE_FP16 makeInf16(void) |
308 | { |
309 | return fromRep16(x: 0x7c00U); |
310 | } |
311 | |
312 | static inline TYPE_FP16 makeNegativeInf16(void) { return fromRep16(x: 0xfc00U); } |
313 | |
314 | static inline float makeInf32(void) |
315 | { |
316 | return fromRep32(x: 0x7f800000U); |
317 | } |
318 | |
319 | static inline float makeNegativeInf32(void) |
320 | { |
321 | return fromRep32(x: 0xff800000U); |
322 | } |
323 | |
324 | static inline double makeInf64(void) |
325 | { |
326 | return fromRep64(x: 0x7ff0000000000000UL); |
327 | } |
328 | |
329 | static inline double makeNegativeInf64(void) |
330 | { |
331 | return fromRep64(x: 0xfff0000000000000UL); |
332 | } |
333 | |
334 | #if defined(CRT_HAS_TF_MODE) |
335 | static inline tf_float makeInf128(void) { |
336 | return fromRep128(hi: 0x7fff000000000000UL, lo: 0x0UL); |
337 | } |
338 | |
339 | static inline tf_float makeNegativeInf128(void) { |
340 | return fromRep128(hi: 0xffff000000000000UL, lo: 0x0UL); |
341 | } |
342 | #endif |
343 |
Definitions
- EXPECTED_RESULT
- fromRep16
- fromRep32
- fromRep64
- fromRep128
- toRep16
- toRep32
- toRep64
- toRep128
- compareResultH
- compareResultF
- compareResultD
- compareResultF128
- compareResultCMP
- expectedStr
- makeQNaN16
- makeQNaN32
- makeQNaN64
- F80FromRep80
- F80ToRep80
- compareResultF80
- makeQNaN80
- makeNaN80
- makeInf80
- makeNegativeInf80
- makeQNaN128
- makeNaN16
- makeNaN32
- makeNaN64
- makeNaN128
- makeInf16
- makeNegativeInf16
- makeInf32
- makeNegativeInf32
- makeInf64
- makeNegativeInf64
- makeInf128
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more