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 | |

12 | enum EXPECTED_RESULT { |

13 | LESS_0, LESS_EQUAL_0, EQUAL_0, GREATER_0, GREATER_EQUAL_0, NEQUAL_0 |

14 | }; |

15 | |

16 | static 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 | |

27 | static inline float fromRep32(uint32_t x) |

28 | { |

29 | float ret; |

30 | memcpy(&ret, &x, 4); |

31 | return ret; |

32 | } |

33 | |

34 | static 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 |

42 | static 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 | |

51 | static 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 | |

62 | static inline uint32_t toRep32(float x) |

63 | { |

64 | uint32_t ret; |

65 | memcpy(&ret, &x, 4); |

66 | return ret; |

67 | } |

68 | |

69 | static 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 |

77 | static inline __uint128_t toRep128(long double x) |

78 | { |

79 | __uint128_t ret; |

80 | memcpy(&ret, &x, 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(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(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(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 |

143 | static 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 | |

165 | static 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 | |

199 | static 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 | |

220 | static inline TYPE_FP16 makeQNaN16(void) |

221 | { |

222 | return fromRep16(0x7e00U); |

223 | } |

224 | |

225 | static inline float makeQNaN32(void) |

226 | { |

227 | return fromRep32(0x7fc00000U); |

228 | } |

229 | |

230 | static inline double makeQNaN64(void) |

231 | { |

232 | return fromRep64(0x7ff8000000000000UL); |

233 | } |

234 | |

235 | #if __LDBL_MANT_DIG__ == 113 |

236 | static inline long double makeQNaN128(void) |

237 | { |

238 | return fromRep128(0x7fff800000000000UL, 0x0UL); |

239 | } |

240 | #endif |

241 | |

242 | static inline TYPE_FP16 makeNaN16(uint16_t rand) |

243 | { |

244 | return fromRep16(0x7c00U | (rand & 0x7fffU)); |

245 | } |

246 | |

247 | static inline float makeNaN32(uint32_t rand) |

248 | { |

249 | return fromRep32(0x7f800000U | (rand & 0x7fffffU)); |

250 | } |

251 | |

252 | static inline double makeNaN64(uint64_t rand) |

253 | { |

254 | return fromRep64(0x7ff0000000000000UL | (rand & 0xfffffffffffffUL)); |

255 | } |

256 | |

257 | #if __LDBL_MANT_DIG__ == 113 |

258 | static inline long double makeNaN128(uint64_t rand) |

259 | { |

260 | return fromRep128(0x7fff000000000000UL | (rand & 0xffffffffffffUL), 0x0UL); |

261 | } |

262 | #endif |

263 | |

264 | static inline TYPE_FP16 makeInf16(void) |

265 | { |

266 | return fromRep16(0x7c00U); |

267 | } |

268 | |

269 | static inline float makeInf32(void) |

270 | { |

271 | return fromRep32(0x7f800000U); |

272 | } |

273 | |

274 | static inline float makeNegativeInf32(void) |

275 | { |

276 | return fromRep32(0xff800000U); |

277 | } |

278 | |

279 | static inline double makeInf64(void) |

280 | { |

281 | return fromRep64(0x7ff0000000000000UL); |

282 | } |

283 | |

284 | static inline double makeNegativeInf64(void) |

285 | { |

286 | return fromRep64(0xfff0000000000000UL); |

287 | } |

288 | |

289 | #if __LDBL_MANT_DIG__ == 113 |

290 | static inline long double makeInf128(void) |

291 | { |

292 | return fromRep128(0x7fff000000000000UL, 0x0UL); |

293 | } |

294 | |

295 | static inline long double makeNegativeInf128(void) |

296 | { |

297 | return fromRep128(0xffff000000000000UL, 0x0UL); |

298 | } |

299 | #endif |

300 |