343 lines · c
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_FLOAT1610#define TYPE_FP16 _Float1611#else12#define TYPE_FP16 uint16_t13#endif14 15enum EXPECTED_RESULT {16 LESS_0, LESS_EQUAL_0, EQUAL_0, GREATER_0, GREATER_EQUAL_0, NEQUAL_017};18 19static inline TYPE_FP16 fromRep16(uint16_t x)20{21#ifdef COMPILER_RT_HAS_FLOAT1622 TYPE_FP16 ret;23 memcpy(&ret, &x, sizeof(ret));24 return ret;25#else26 return x;27#endif28}29 30static inline float fromRep32(uint32_t x)31{32 float ret;33 memcpy(&ret, &x, 4);34 return ret;35}36 37static 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)45static 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#endif52 53static inline uint16_t toRep16(TYPE_FP16 x)54{55#ifdef COMPILER_RT_HAS_FLOAT1656 uint16_t ret;57 memcpy(&ret, &x, sizeof(ret));58 return ret;59#else60 return x;61#endif62}63 64static inline uint32_t toRep32(float x)65{66 uint32_t ret;67 memcpy(&ret, &x, 4);68 return ret;69}70 71static 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)79static inline __uint128_t toRep128(tf_float x) {80 __uint128_t ret;81 memcpy(&ret, &x, 16);82 return ret;83}84#endif85 86static 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 104static 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 122static 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 equal142// use two 64-bit integers instead of one 128-bit integer143// because 128-bit integer constant can't be assigned directly144static 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#endif163 164static 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 198static 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 219static inline TYPE_FP16 makeQNaN16(void)220{221 return fromRep16(0x7e00U);222}223 224static inline float makeQNaN32(void)225{226 return fromRep32(0x7fc00000U);227}228 229static inline double makeQNaN64(void)230{231 return fromRep64(0x7ff8000000000000UL);232}233 234#if HAS_80_BIT_LONG_DOUBLE235static 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 245static 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 254static 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 262static inline xf_float makeQNaN80(void) {263 return F80FromRep80(0x7fffu, 0xc000000000000000UL);264}265 266static inline xf_float makeNaN80(uint64_t rand) {267 return F80FromRep80(0x7fffu,268 0x8000000000000000 | (rand & 0x3fffffffffffffff));269}270 271static inline xf_float makeInf80(void) {272 return F80FromRep80(0x7fffu, 0x8000000000000000UL);273}274 275static inline xf_float makeNegativeInf80(void) {276 return F80FromRep80(0xffffu, 0x8000000000000000UL);277}278#endif279 280#if defined(CRT_HAS_TF_MODE)281static inline tf_float makeQNaN128(void) {282 return fromRep128(0x7fff800000000000UL, 0x0UL);283}284#endif285 286static inline TYPE_FP16 makeNaN16(uint16_t rand)287{288 return fromRep16(0x7c00U | (rand & 0x7fffU));289}290 291static inline float makeNaN32(uint32_t rand)292{293 return fromRep32(0x7f800000U | (rand & 0x7fffffU));294}295 296static inline double makeNaN64(uint64_t rand)297{298 return fromRep64(0x7ff0000000000000UL | (rand & 0xfffffffffffffUL));299}300 301#if defined(CRT_HAS_TF_MODE)302static inline tf_float makeNaN128(uint64_t rand) {303 return fromRep128(0x7fff000000000000UL | (rand & 0xffffffffffffUL), 0x0UL);304}305#endif306 307static inline TYPE_FP16 makeInf16(void)308{309 return fromRep16(0x7c00U);310}311 312static inline TYPE_FP16 makeNegativeInf16(void) { return fromRep16(0xfc00U); }313 314static inline float makeInf32(void)315{316 return fromRep32(0x7f800000U);317}318 319static inline float makeNegativeInf32(void)320{321 return fromRep32(0xff800000U);322}323 324static inline double makeInf64(void)325{326 return fromRep64(0x7ff0000000000000UL);327}328 329static inline double makeNegativeInf64(void)330{331 return fromRep64(0xfff0000000000000UL);332}333 334#if defined(CRT_HAS_TF_MODE)335static inline tf_float makeInf128(void) {336 return fromRep128(0x7fff000000000000UL, 0x0UL);337}338 339static inline tf_float makeNegativeInf128(void) {340 return fromRep128(0xffff000000000000UL, 0x0UL);341}342#endif343