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