1 #include <gtest/gtest.h>
2
3 #include <cstdint>
4
5 #include <fp16.h>
6 #include <fp16/psimd.h>
7
8
TEST(FP16_IEEE_TO_FP32_PSIMD,infinity)9 TEST(FP16_IEEE_TO_FP32_PSIMD, infinity) {
10 const uint16_t positive_infinity_f16 = UINT16_C(0x7C00);
11 const uint16_t negative_infinity_f16 = UINT16_C(0xFC00);
12
13 const uint32_t positive_infinity_f32 = UINT32_C(0x7F800000);
14 const uint32_t negative_infinity_f32 = UINT32_C(0xFF800000);
15
16 const psimd_u16 fp16 = {
17 positive_infinity_f16, negative_infinity_f16,
18 negative_infinity_f16, positive_infinity_f16
19 };
20 const psimd_u32 fp32 = (psimd_u32) fp16_ieee_to_fp32_psimd(fp16);
21
22 EXPECT_EQ(positive_infinity_f32, fp32[0]) <<
23 std::hex << std::uppercase << std::setfill('0') <<
24 "F16 = 0x" << std::setw(4) << fp16[0] << ", " <<
25 "F32(F16) = 0x" << std::setw(8) << fp32[0] << ", " <<
26 "F32 = 0x" << std::setw(8) << positive_infinity_f32;
27 EXPECT_EQ(negative_infinity_f32, fp32[1]) <<
28 std::hex << std::uppercase << std::setfill('0') <<
29 "F16 = 0x" << std::setw(4) << fp16[1] << ", " <<
30 "F32(F16) = 0x" << std::setw(8) << fp32[1] << ", " <<
31 "F32 = 0x" << std::setw(8) << negative_infinity_f32;
32 EXPECT_EQ(negative_infinity_f32, fp32[2]) <<
33 std::hex << std::uppercase << std::setfill('0') <<
34 "F16 = 0x" << std::setw(4) << fp16[2] << ", " <<
35 "F32(F16) = 0x" << std::setw(8) << fp32[2] << ", " <<
36 "F32 = 0x" << std::setw(8) << negative_infinity_f32;
37 EXPECT_EQ(positive_infinity_f32, fp32[3]) <<
38 std::hex << std::uppercase << std::setfill('0') <<
39 "F16 = 0x" << std::setw(4) << fp16[3] << ", " <<
40 "F32(F16) = 0x" << std::setw(8) << fp32[3] << ", " <<
41 "F32 = 0x" << std::setw(8) << positive_infinity_f32;
42 }
43
TEST(FP16_IEEE_TO_FP32_PSIMD,positive_nan)44 TEST(FP16_IEEE_TO_FP32_PSIMD, positive_nan) {
45 for (uint16_t h = 0; h < 0x0400; h += 4) {
46 const psimd_u16 fp16 = {
47 (uint16_t) (h + 0x7C00 + (h == 0)) /* Avoid infinity */,
48 (uint16_t) (h + 0x7C01),
49 (uint16_t) (h + 0x7C02),
50 (uint16_t) (h + 0x7C03),
51 };
52 const psimd_u32 fp32 = (psimd_u32) fp16_ieee_to_fp32_psimd(fp16);
53
54 /* Check sign */
55 EXPECT_EQ(fp32[0] & UINT32_C(0x80000000), 0) <<
56 std::hex << std::uppercase << std::setfill('0') <<
57 "F16 = 0x" << std::setw(4) << fp16[0] << ", " <<
58 "F32(F16) = 0x" << std::setw(8) << fp32[0];
59 EXPECT_EQ(fp32[1] & UINT32_C(0x80000000), 0) <<
60 std::hex << std::uppercase << std::setfill('0') <<
61 "F16 = 0x" << std::setw(4) << fp16[1] << ", " <<
62 "F32(F16) = 0x" << std::setw(8) << fp32[1];
63 EXPECT_EQ(fp32[2] & UINT32_C(0x80000000), 0) <<
64 std::hex << std::uppercase << std::setfill('0') <<
65 "F16 = 0x" << std::setw(4) << fp16[2] << ", " <<
66 "F32(F16) = 0x" << std::setw(8) << fp32[2];
67 EXPECT_EQ(fp32[3] & UINT32_C(0x80000000), 0) <<
68 std::hex << std::uppercase << std::setfill('0') <<
69 "F16 = 0x" << std::setw(4) << fp16[3] << ", " <<
70 "F32(F16) = 0x" << std::setw(8) << fp32[3];
71
72 /* Check exponent */
73 EXPECT_EQ(fp32[0] & UINT32_C(0x7F800000), UINT32_C(0x7F800000)) <<
74 std::hex << std::uppercase << std::setfill('0') <<
75 "F16 = 0x" << std::setw(4) << fp16[0] << ", " <<
76 "F32(F16) = 0x" << std::setw(8) << fp32[0];
77 EXPECT_EQ(fp32[1] & UINT32_C(0x7F800000), UINT32_C(0x7F800000)) <<
78 std::hex << std::uppercase << std::setfill('0') <<
79 "F16 = 0x" << std::setw(4) << fp16[1] << ", " <<
80 "F32(F16) = 0x" << std::setw(8) << fp32[1];
81 EXPECT_EQ(fp32[2] & UINT32_C(0x7F800000), UINT32_C(0x7F800000)) <<
82 std::hex << std::uppercase << std::setfill('0') <<
83 "F16 = 0x" << std::setw(4) << fp16[2] << ", " <<
84 "F32(F16) = 0x" << std::setw(8) << fp32[2];
85 EXPECT_EQ(fp32[3] & UINT32_C(0x7F800000), UINT32_C(0x7F800000)) <<
86 std::hex << std::uppercase << std::setfill('0') <<
87 "F16 = 0x" << std::setw(4) << fp16[3] << ", " <<
88 "F32(F16) = 0x" << std::setw(8) << fp32[3];
89
90 /* Check mantissa */
91 EXPECT_NE(fp32[0] & UINT32_C(0x007FFFFF), UINT32_C(0)) <<
92 std::hex << std::uppercase << std::setfill('0') <<
93 "F16 = 0x" << std::setw(4) << fp16[0] << ", " <<
94 "F32(F16) = 0x" << std::setw(8) << fp32[0];
95 EXPECT_NE(fp32[1] & UINT32_C(0x007FFFFF), UINT32_C(0)) <<
96 std::hex << std::uppercase << std::setfill('0') <<
97 "F16 = 0x" << std::setw(4) << fp16[1] << ", " <<
98 "F32(F16) = 0x" << std::setw(8) << fp32[1];
99 EXPECT_NE(fp32[2] & UINT32_C(0x007FFFFF), UINT32_C(0)) <<
100 std::hex << std::uppercase << std::setfill('0') <<
101 "F16 = 0x" << std::setw(4) << fp16[2] << ", " <<
102 "F32(F16) = 0x" << std::setw(8) << fp32[2];
103 EXPECT_NE(fp32[3] & UINT32_C(0x007FFFFF), UINT32_C(0)) <<
104 std::hex << std::uppercase << std::setfill('0') <<
105 "F16 = 0x" << std::setw(4) << fp16[3] << ", " <<
106 "F32(F16) = 0x" << std::setw(8) << fp32[3];
107 }
108 }
109
TEST(FP16_IEEE_TO_FP32_PSIMD,negative_nan)110 TEST(FP16_IEEE_TO_FP32_PSIMD, negative_nan) {
111 for (uint16_t h = 0; h < 0x0400; h += 4) {
112 const psimd_u16 fp16 = {
113 (uint16_t) (h + 0xFC00 + (h == 0)) /* Avoid infinity */,
114 (uint16_t) (h + 0xFC01),
115 (uint16_t) (h + 0xFC02),
116 (uint16_t) (h + 0xFC03),
117 };
118 const psimd_u32 fp32 = (psimd_u32) fp16_ieee_to_fp32_psimd(fp16);
119
120 /* Check sign */
121 EXPECT_EQ(fp32[0] & UINT32_C(0x80000000), UINT32_C(0x80000000)) <<
122 std::hex << std::uppercase << std::setfill('0') <<
123 "F16 = 0x" << std::setw(4) << fp16[0] << ", " <<
124 "F32(F16) = 0x" << std::setw(8) << fp32[0];
125 EXPECT_EQ(fp32[1] & UINT32_C(0x80000000), UINT32_C(0x80000000)) <<
126 std::hex << std::uppercase << std::setfill('0') <<
127 "F16 = 0x" << std::setw(4) << fp16[1] << ", " <<
128 "F32(F16) = 0x" << std::setw(8) << fp32[1];
129 EXPECT_EQ(fp32[2] & UINT32_C(0x80000000), UINT32_C(0x80000000)) <<
130 std::hex << std::uppercase << std::setfill('0') <<
131 "F16 = 0x" << std::setw(4) << fp16[2] << ", " <<
132 "F32(F16) = 0x" << std::setw(8) << fp32[2];
133 EXPECT_EQ(fp32[3] & UINT32_C(0x80000000), UINT32_C(0x80000000)) <<
134 std::hex << std::uppercase << std::setfill('0') <<
135 "F16 = 0x" << std::setw(4) << fp16[3] << ", " <<
136 "F32(F16) = 0x" << std::setw(8) << fp32[3];
137
138 /* Check exponent */
139 EXPECT_EQ(fp32[0] & UINT32_C(0x7F800000), UINT32_C(0x7F800000)) <<
140 std::hex << std::uppercase << std::setfill('0') <<
141 "F16 = 0x" << std::setw(4) << fp16[0] << ", " <<
142 "F32(F16) = 0x" << std::setw(8) << fp32[0];
143 EXPECT_EQ(fp32[1] & UINT32_C(0x7F800000), UINT32_C(0x7F800000)) <<
144 std::hex << std::uppercase << std::setfill('0') <<
145 "F16 = 0x" << std::setw(4) << fp16[1] << ", " <<
146 "F32(F16) = 0x" << std::setw(8) << fp32[1];
147 EXPECT_EQ(fp32[2] & UINT32_C(0x7F800000), UINT32_C(0x7F800000)) <<
148 std::hex << std::uppercase << std::setfill('0') <<
149 "F16 = 0x" << std::setw(4) << fp16[2] << ", " <<
150 "F32(F16) = 0x" << std::setw(8) << fp32[2];
151 EXPECT_EQ(fp32[3] & UINT32_C(0x7F800000), UINT32_C(0x7F800000)) <<
152 std::hex << std::uppercase << std::setfill('0') <<
153 "F16 = 0x" << std::setw(4) << fp16[3] << ", " <<
154 "F32(F16) = 0x" << std::setw(8) << fp32[3];
155
156 /* Check mantissa */
157 EXPECT_NE(fp32[0] & UINT32_C(0x007FFFFF), UINT32_C(0)) <<
158 std::hex << std::uppercase << std::setfill('0') <<
159 "F16 = 0x" << std::setw(4) << fp16[0] << ", " <<
160 "F32(F16) = 0x" << std::setw(8) << fp32[0];
161 EXPECT_NE(fp32[1] & UINT32_C(0x007FFFFF), UINT32_C(0)) <<
162 std::hex << std::uppercase << std::setfill('0') <<
163 "F16 = 0x" << std::setw(4) << fp16[1] << ", " <<
164 "F32(F16) = 0x" << std::setw(8) << fp32[1];
165 EXPECT_NE(fp32[2] & UINT32_C(0x007FFFFF), UINT32_C(0)) <<
166 std::hex << std::uppercase << std::setfill('0') <<
167 "F16 = 0x" << std::setw(4) << fp16[2] << ", " <<
168 "F32(F16) = 0x" << std::setw(8) << fp32[2];
169 EXPECT_NE(fp32[3] & UINT32_C(0x007FFFFF), UINT32_C(0)) <<
170 std::hex << std::uppercase << std::setfill('0') <<
171 "F16 = 0x" << std::setw(4) << fp16[3] << ", " <<
172 "F32(F16) = 0x" << std::setw(8) << fp32[3];
173 }
174 }
175
TEST(FP16_IEEE_TO_FP32_PSIMD,positive_normalized_values)176 TEST(FP16_IEEE_TO_FP32_PSIMD, positive_normalized_values) {
177 const uint32_t exponentBias = 15;
178 for (int32_t e = -14; e <= 15; e++) {
179 for (uint16_t h = 0; h < 0x0400; h += 4) {
180 const psimd_u16 fp16 = {
181 (uint16_t) (h + ((e + exponentBias) << 10) + 0),
182 (uint16_t) (h + ((e + exponentBias) << 10) + 1),
183 (uint16_t) (h + ((e + exponentBias) << 10) + 2),
184 (uint16_t) (h + ((e + exponentBias) << 10) + 3),
185 };
186 const psimd_u32 fp32 = (psimd_u32) fp16_ieee_to_fp32_psimd(fp16);
187
188 EXPECT_EQ(fp16_ieee_to_fp32_bits(fp16[0]), fp32[0]) <<
189 std::hex << std::uppercase << std::setfill('0') <<
190 "F16 = 0x" << std::setw(4) << fp16[0] << ", " <<
191 "F32(F16) = 0x" << std::setw(8) << fp32[0] << ", " <<
192 "F32 = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(fp16[0]);
193 EXPECT_EQ(fp16_ieee_to_fp32_bits(fp16[1]), fp32[1]) <<
194 std::hex << std::uppercase << std::setfill('0') <<
195 "F16 = 0x" << std::setw(4) << fp16[1] << ", " <<
196 "F32(F16) = 0x" << std::setw(8) << fp32[1] << ", " <<
197 "F32 = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(fp16[1]);
198 EXPECT_EQ(fp16_ieee_to_fp32_bits(fp16[2]), fp32[2]) <<
199 std::hex << std::uppercase << std::setfill('0') <<
200 "F16 = 0x" << std::setw(4) << fp16[2] << ", " <<
201 "F32(F16) = 0x" << std::setw(8) << fp32[2] << ", " <<
202 "F32 = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(fp16[2]);
203 EXPECT_EQ(fp16_ieee_to_fp32_bits(fp16[3]), fp32[3]) <<
204 std::hex << std::uppercase << std::setfill('0') <<
205 "F16 = 0x" << std::setw(4) << fp16[3] << ", " <<
206 "F32(F16) = 0x" << std::setw(8) << fp32[3] << ", " <<
207 "F32 = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(fp16[3]);
208 }
209 }
210 }
211
TEST(FP16_IEEE_TO_FP32_PSIMD,negative_normalized_values)212 TEST(FP16_IEEE_TO_FP32_PSIMD, negative_normalized_values) {
213 const uint32_t exponentBias = 15;
214 for (int32_t e = -14; e <= 15; e++) {
215 for (uint16_t h = 0; h < 0x0400; h += 4) {
216 const psimd_u16 fp16 = {
217 (uint16_t) (h + ((e + exponentBias) << 10) + 0x8000),
218 (uint16_t) (h + ((e + exponentBias) << 10) + 0x8001),
219 (uint16_t) (h + ((e + exponentBias) << 10) + 0x8002),
220 (uint16_t) (h + ((e + exponentBias) << 10) + 0x8003),
221 };
222 const psimd_u32 fp32 = (psimd_u32) fp16_ieee_to_fp32_psimd(fp16);
223
224 EXPECT_EQ(fp16_ieee_to_fp32_bits(fp16[0]), fp32[0]) <<
225 std::hex << std::uppercase << std::setfill('0') <<
226 "F16 = 0x" << std::setw(4) << fp16[0] << ", " <<
227 "F32(F16) = 0x" << std::setw(8) << fp32[0] << ", " <<
228 "F32 = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(fp16[0]);
229 EXPECT_EQ(fp16_ieee_to_fp32_bits(fp16[1]), fp32[1]) <<
230 std::hex << std::uppercase << std::setfill('0') <<
231 "F16 = 0x" << std::setw(4) << fp16[1] << ", " <<
232 "F32(F16) = 0x" << std::setw(8) << fp32[1] << ", " <<
233 "F32 = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(fp16[1]);
234 EXPECT_EQ(fp16_ieee_to_fp32_bits(fp16[2]), fp32[2]) <<
235 std::hex << std::uppercase << std::setfill('0') <<
236 "F16 = 0x" << std::setw(4) << fp16[2] << ", " <<
237 "F32(F16) = 0x" << std::setw(8) << fp32[2] << ", " <<
238 "F32 = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(fp16[2]);
239 EXPECT_EQ(fp16_ieee_to_fp32_bits(fp16[3]), fp32[3]) <<
240 std::hex << std::uppercase << std::setfill('0') <<
241 "F16 = 0x" << std::setw(4) << fp16[3] << ", " <<
242 "F32(F16) = 0x" << std::setw(8) << fp32[3] << ", " <<
243 "F32 = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(fp16[3]);
244 }
245 }
246 }
247
TEST(FP16_IEEE_TO_FP32_PSIMD,positive_denormalized_values)248 TEST(FP16_IEEE_TO_FP32_PSIMD, positive_denormalized_values) {
249 for (uint16_t h = 0; h < 0x0400; h += 4) {
250 const psimd_u16 fp16 = {
251 (uint16_t) (h + 0),
252 (uint16_t) (h + 1),
253 (uint16_t) (h + 2),
254 (uint16_t) (h + 3),
255 };
256 const psimd_u32 fp32 = (psimd_u32) fp16_ieee_to_fp32_psimd(fp16);
257
258 EXPECT_EQ(fp16_ieee_to_fp32_bits(fp16[0]), fp32[0]) <<
259 std::hex << std::uppercase << std::setfill('0') <<
260 "F16 = 0x" << std::setw(4) << fp16[0] << ", " <<
261 "F32(F16) = 0x" << std::setw(8) << fp32[0] << ", " <<
262 "F32 = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(fp16[0]);
263 EXPECT_EQ(fp16_ieee_to_fp32_bits(fp16[1]), fp32[1]) <<
264 std::hex << std::uppercase << std::setfill('0') <<
265 "F16 = 0x" << std::setw(4) << fp16[1] << ", " <<
266 "F32(F16) = 0x" << std::setw(8) << fp32[1] << ", " <<
267 "F32 = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(fp16[1]);
268 EXPECT_EQ(fp16_ieee_to_fp32_bits(fp16[2]), fp32[2]) <<
269 std::hex << std::uppercase << std::setfill('0') <<
270 "F16 = 0x" << std::setw(4) << fp16[2] << ", " <<
271 "F32(F16) = 0x" << std::setw(8) << fp32[2] << ", " <<
272 "F32 = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(fp16[2]);
273 EXPECT_EQ(fp16_ieee_to_fp32_bits(fp16[3]), fp32[3]) <<
274 std::hex << std::uppercase << std::setfill('0') <<
275 "F16 = 0x" << std::setw(4) << fp16[3] << ", " <<
276 "F32(F16) = 0x" << std::setw(8) << fp32[3] << ", " <<
277 "F32 = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(fp16[3]);
278 }
279 }
280
TEST(FP16_IEEE_TO_FP32_PSIMD,negative_denormalized_values)281 TEST(FP16_IEEE_TO_FP32_PSIMD, negative_denormalized_values) {
282 for (uint16_t h = 0; h < 0x0400; h += 4) {
283 const psimd_u16 fp16 = {
284 (uint16_t) (h + 0x8000),
285 (uint16_t) (h + 0x8001),
286 (uint16_t) (h + 0x8002),
287 (uint16_t) (h + 0x8003),
288 };
289 const psimd_u32 fp32 = (psimd_u32) fp16_ieee_to_fp32_psimd(fp16);
290
291 EXPECT_EQ(fp16_ieee_to_fp32_bits(fp16[0]), fp32[0]) <<
292 std::hex << std::uppercase << std::setfill('0') <<
293 "F16 = 0x" << std::setw(4) << fp16[0] << ", " <<
294 "F32(F16) = 0x" << std::setw(8) << fp32[0] << ", " <<
295 "F32 = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(fp16[0]);
296 EXPECT_EQ(fp16_ieee_to_fp32_bits(fp16[1]), fp32[1]) <<
297 std::hex << std::uppercase << std::setfill('0') <<
298 "F16 = 0x" << std::setw(4) << fp16[1] << ", " <<
299 "F32(F16) = 0x" << std::setw(8) << fp32[1] << ", " <<
300 "F32 = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(fp16[1]);
301 EXPECT_EQ(fp16_ieee_to_fp32_bits(fp16[2]), fp32[2]) <<
302 std::hex << std::uppercase << std::setfill('0') <<
303 "F16 = 0x" << std::setw(4) << fp16[2] << ", " <<
304 "F32(F16) = 0x" << std::setw(8) << fp32[2] << ", " <<
305 "F32 = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(fp16[2]);
306 EXPECT_EQ(fp16_ieee_to_fp32_bits(fp16[3]), fp32[3]) <<
307 std::hex << std::uppercase << std::setfill('0') <<
308 "F16 = 0x" << std::setw(4) << fp16[3] << ", " <<
309 "F32(F16) = 0x" << std::setw(8) << fp32[3] << ", " <<
310 "F32 = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(fp16[3]);
311 }
312 }
313