@samitouri / QOSamiQemu / commits / 2e555f5b44

tests/hexagon: add tests for HVX bfloat

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com> Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com> Reviewed-by: Brian Cain <brian.cain@oss.qualcomm.com> Link: https://lore.kernel.org/qemu-devel/392114c4c16e6f7f2835a6513987aafea82b565c.1776339451.git.matheus.bernardino@oss.qualcomm.com Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>

Matheus Tavares Bernardino committed Apr 16, 2026 at 04:39 UTC 2e555f5b44d1586517e44d47f73afa6062f48b93
5 files changed +166
tests/tcg/hexagon/fp_hvx.c
+41
@@ -29,6 +29,7 @@ int err;
29 #define CHECK_NAN(A, DEF_NAN) (isnan(A) ? DEF_NAN : (A))
30 #define NAN_SF float_sf(0x7FFFFFFF)
31 #define NAN_HF float_hf(0x7FFF)
32 +#define NAN_BF float_hf(0x7FFF)
33
34 /******************************************************************************
35 * Binary operations
@@ -91,11 +92,43 @@ DEF_TEST_OP_2(vmpy, MULT_HF, hf, hf);
92 #define MAX_HF(X, Y) MAX(X, Y, NAN_HF)
93 #define MIN_SF(X, Y) MIN(X, Y, NAN_SF)
94 #define MAX_SF(X, Y) MAX(X, Y, NAN_SF)
95 +#define MIN_BF(X, Y) MIN(X, Y, NAN_BF)
96 +#define MAX_BF(X, Y) MAX(X, Y, NAN_BF)
97
98 DEF_TEST_OP_2(vfmin, MIN_SF, sf, sf);
99 DEF_TEST_OP_2(vfmax, MAX_SF, sf, sf);
100 DEF_TEST_OP_2(vfmin, MIN_HF, hf, hf);
101 DEF_TEST_OP_2(vfmax, MAX_HF, hf, hf);
102 +DEF_TEST_OP_2(vmin, MIN_BF, bf, bf);
103 +DEF_TEST_OP_2(vmax, MAX_BF, bf, bf);
104 +
105 +#define DEF_TEST_OP_2_INTERLEAVED(vop, op, type_res, type_arg) \
106 + static void test_##vop##_##type_res##_##type_arg(void) \
107 + { \
108 + memset(expect, 0xff, sizeof(expect)); \
109 + memset(output, 0xff, sizeof(output)); \
110 + for (int i = 0; i < BUFSIZE / 2; i++) { \
111 + HVX_VectorPair *hvx_output = (HVX_VectorPair *)&output[2 * i]; \
112 + HVX_Vector hvx_buffer0 = *(HVX_Vector *)&buffer0[i]; \
113 + HVX_Vector hvx_buffer1 = *(HVX_Vector *)&buffer1[i]; \
114 + *hvx_output = \
115 + Q6_W##type_res##_##vop##_V##type_arg##V##type_arg(hvx_buffer0, \
116 + hvx_buffer1); \
117 + for (int j = 0; j < MAX_VEC_SIZE_BYTES / bytes_##type_res; j++) { \
118 + expect[2 * i].type_res[j] = \
119 + raw_##type_res(op(float_##type_arg(buffer0[i].type_arg[2 * j]), \
120 + float_##type_arg(buffer1[i].type_arg[2 * j]))); \
121 + expect[2 * i + 1].type_res[j] = \
122 + raw_##type_res(op(float_##type_arg(buffer0[i].type_arg[2 * j + 1]), \
123 + float_##type_arg(buffer1[i].type_arg[2 * j + 1]))); \
124 + } \
125 + } \
126 + check_output_##type_res(__LINE__, BUFSIZE); \
127 + }
128 +
129 +DEF_TEST_OP_2_INTERLEAVED(vadd, SUM_SF, sf, bf);
130 +DEF_TEST_OP_2_INTERLEAVED(vsub, SUB_SF, sf, bf);
131 +DEF_TEST_OP_2_INTERLEAVED(vmpy, MULT_SF, sf, bf);
132
133 /******************************************************************************
134 * Other tests
@@ -180,6 +213,14 @@ int main(void)
213 test_vfmax_sf_sf();
214 test_vfmax_hf_hf();
215
216 + /* bfloat */
217 + init_buffers_bf();
218 + test_vmin_bf_bf();
219 + test_vmax_bf_bf();
220 + test_vadd_sf_bf();
221 + test_vsub_sf_bf();
222 + test_vmpy_sf_bf();
223 +
224 puts(err ? "FAIL" : "PASS");
225 return err ? 1 : 0;
226 }
tests/tcg/hexagon/fp_hvx_cmp.c
+51
@@ -22,9 +22,11 @@ int err;
22
23 #define MAX_TESTS_hf (MAX_VEC_SIZE_BYTES / 2)
24 #define MAX_TESTS_sf (MAX_VEC_SIZE_BYTES / 4)
25 +#define MAX_TESTS_bf (MAX_VEC_SIZE_BYTES / 2)
26
27 #define TRUE_MASK_sf 0xffffffff
28 #define TRUE_MASK_hf 0xffff
29 +#define TRUE_MASK_bf 0xffff
30
31 static const char *comparisons[MAX_TESTS_sf][2];
32 static HVX_Vector *hvx_output = (HVX_Vector *)&output[0];
@@ -160,6 +162,54 @@ static void test_cmp_hf(void)
162 CHECK(hf, 2);
163 }
164
165 +static void test_cmp_bf(void)
166 +{
167 + /*
168 + * General ordering for bf:
169 + * QNaN > SNaN > +Inf > numbers > -Inf > SNaN_neg > QNaN_neg
170 + */
171 +
172 + /* Test equality */
173 + PREP_TEST();
174 + ADD_TEST_CMP(bf, 0, 0, false);
175 + ADD_TEST_CMP(bf, BF_SNaN, BF_SNaN, false);
176 + CHECK(bf, 2);
177 +
178 + /* Common numbers */
179 + PREP_TEST();
180 + TEST_CMP_GT(bf, BF_two, BF_one);
181 + TEST_CMP_GT(bf, BF_one, BF_zero);
182 + CHECK(bf, 2);
183 +
184 + /* Infinity vs Infinity/NaN */
185 + PREP_TEST();
186 + TEST_CMP_GT(bf, BF_QNaN, BF_INF);
187 + TEST_CMP_GT(bf, BF_SNaN, BF_INF);
188 + TEST_CMP_GT(bf, BF_INF, BF_INF_neg);
189 + TEST_CMP_GT(bf, BF_INF, BF_SNaN_neg);
190 + TEST_CMP_GT(bf, BF_INF, BF_QNaN_neg);
191 + TEST_CMP_GT(bf, BF_INF_neg, BF_SNaN_neg);
192 + TEST_CMP_GT(bf, BF_INF_neg, BF_QNaN_neg);
193 + TEST_CMP_GT(bf, BF_SNaN, BF_INF_neg);
194 + TEST_CMP_GT(bf, BF_QNaN, BF_INF_neg);
195 + CHECK(bf, 2);
196 +
197 + /* NaN vs NaN */
198 + PREP_TEST();
199 + TEST_CMP_GT(bf, BF_QNaN, BF_SNaN);
200 + TEST_CMP_GT(bf, BF_SNaN, BF_SNaN_neg);
201 + TEST_CMP_GT(bf, BF_SNaN_neg, BF_QNaN_neg);
202 + CHECK(bf, 2);
203 +
204 + /* NaN vs non-NaN */
205 + PREP_TEST();
206 + TEST_CMP_GT(bf, BF_QNaN, BF_one);
207 + TEST_CMP_GT(bf, BF_SNaN, BF_one);
208 + TEST_CMP_GT(bf, BF_one, BF_QNaN_neg);
209 + TEST_CMP_GT(bf, BF_one, BF_SNaN_neg);
210 + CHECK(bf, 2);
211 +}
212 +
213 static void check_byte_pred(HVX_VectorPred pred, int byte_idx, uint8_t exp_mask,
214 int line)
215 {
@@ -217,6 +267,7 @@ int main(void)
267
268 test_cmp_sf();
269 test_cmp_hf();
270 + test_cmp_bf();
271 test_cmp_variants();
272
273 puts(err ? "FAIL" : "PASS");
tests/tcg/hexagon/fp_hvx_cvt.c
+31
@@ -19,6 +19,8 @@ int err;
19 #include "hvx_misc.h"
20 #include "hex_test.h"
21
22 +#define NAN_BF 0x7FFF
23 +
24 #define TEST_EXP(TO, FROM, VAL, EXP) do { \
25 ((MMVector *)&buffer)->FROM[index] = VAL; \
26 expect[0].TO[index] = EXP; \
@@ -172,6 +174,34 @@ DEF_TEST_VCONV(sf, w, { \
174 TEST_EXP(sf, w, 16777219, raw_sf((float)16777220)); /* rounds UP */ \
175 })
176
177 +#define TEST_EXP_BF(VAL, EXP) do { \
178 + ((MMVector *)&buffers[1])->sf[index] = VAL; \
179 + ((MMVector *)&buffers[0])->sf[index] = VAL; \
180 + expect[0].bf[2 * index] = EXP; \
181 + expect[0].bf[2 * index + 1] = EXP; \
182 + index++; \
183 +} while (0)
184 +
185 +static void test_vconv_bf_sf(void)
186 +{
187 + HVX_Vector *hvx_output = (HVX_Vector *)&output[0];
188 + HVX_Vector buffers[2];
189 + int index = 0;
190 + memset(&buffers, 0, sizeof(buffers));
191 + memset(expect, 0, sizeof(expect));
192 +
193 + TEST_EXP_BF(SF_QNaN, NAN_BF);
194 + TEST_EXP_BF(SF_SNaN, NAN_BF);
195 + TEST_EXP_BF(SF_QNaN_neg, NAN_BF);
196 + TEST_EXP_BF(SF_INF, BF_INF);
197 + TEST_EXP_BF(SF_INF_neg, BF_INF_neg);
198 + TEST_EXP_BF(SF_one, BF_one);
199 + TEST_EXP_BF(SF_zero_neg, BF_zero_neg);
200 +
201 + *hvx_output = Q6_Vbf_vcvt_VsfVsf(buffers[0], buffers[1]);
202 + check_output_hf(__LINE__, 1);
203 +}
204 +
205 int main(void)
206 {
207 test_vcvt_uh_hf();
@@ -182,6 +212,7 @@ int main(void)
212 test_vconv_sf_w();
213 test_vconv_h_hf();
214 test_vconv_hf_h();
215 + test_vconv_bf_sf();
216
217 puts(err ? "FAIL" : "PASS");
218 return err ? 1 : 0;
tests/tcg/hexagon/hex_test.h
+13
@@ -126,6 +126,19 @@ const uint16_t HF_small_neg = 0x8010;
126 const uint16_t HF_any = 0x3c00;
127 const uint16_t HF_neg_two = 0xc000;
128
129 +const uint16_t BF_INF = 0x7f80;
130 +const uint16_t BF_INF_neg = 0xff80;
131 +const uint16_t BF_QNaN = 0x7fc0;
132 +const uint16_t BF_SNaN = 0x7f81;
133 +const uint16_t BF_QNaN_neg = 0xffc0;
134 +const uint16_t BF_SNaN_neg = 0xff81;
135 +const uint16_t BF_HEX_NaN = 0x7fff;
136 +const uint16_t BF_zero = 0x0000;
137 +const uint16_t BF_zero_neg = 0x8000;
138 +const uint16_t BF_one = 0x3f80;
139 +const uint16_t BF_two = 0x4000;
140 +const uint16_t BF_four = 0x4080;
141 +
142 const uint32_t SF_INF = 0x7f800000;
143 const uint32_t SF_INF_neg = 0xff800000;
144 const uint32_t SF_QNaN = 0x7fc00000;
tests/tcg/hexagon/hvx_misc.h
+30
@@ -41,6 +41,7 @@ typedef union {
41 uint16_t uh[MAX_VEC_SIZE_BYTES / 2];
42 uint16_t hf[MAX_VEC_SIZE_BYTES / 2]; /* convenience alias */
43 int16_t h[MAX_VEC_SIZE_BYTES / 2];
44 + uint16_t bf[MAX_VEC_SIZE_BYTES / 2];
45 uint8_t ub[MAX_VEC_SIZE_BYTES / 1];
46 int8_t b[MAX_VEC_SIZE_BYTES / 1];
47 } MMVector;
@@ -73,6 +74,7 @@ CHECK_OUTPUT_FUNC(uh, 2)
74 CHECK_OUTPUT_FUNC(hf, 2)
75 CHECK_OUTPUT_FUNC(ub, 1)
76 CHECK_OUTPUT_FUNC(b, 1)
77 +CHECK_OUTPUT_FUNC(bf, 2)
78
79 static inline void init_buffers(void)
80 {
@@ -97,6 +99,12 @@ static const uint32_t FP_VALUES[] = {
99 };
100 #define FP_VALUES_MAX ARRAY_SIZE(FP_VALUES)
101
102 +static const uint16_t BF_VALUES[] = {
103 + BF_INF, BF_INF_neg, BF_QNaN, BF_SNaN, BF_QNaN_neg, BF_SNaN_neg,
104 + BF_HEX_NaN, BF_zero, BF_zero_neg, BF_one, BF_two, BF_four,
105 +};
106 +#define BF_VALUES_MAX ARRAY_SIZE(BF_VALUES)
107 +
108 static inline void init_buffers_fp(void)
109 {
110 _Static_assert(BUFSIZE * (MAX_VEC_SIZE_BYTES / 4) >
@@ -116,6 +124,25 @@ static inline void init_buffers_fp(void)
124 }
125 }
126
127 +static inline void init_buffers_bf(void)
128 +{
129 + _Static_assert(BUFSIZE * (MAX_VEC_SIZE_BYTES / 2) >
130 + BF_VALUES_MAX * BF_VALUES_MAX,
131 + "test arrays can't fit all BF_VALUES combinations");
132 + int counter1 = 0, counter2 = 0;
133 + for (int i = 0; i < BUFSIZE; i++) {
134 + for (int j = 0; j < MAX_VEC_SIZE_BYTES / 2; j++) {
135 + buffer0[i].bf[j] = BF_VALUES[counter1];
136 + buffer1[i].bf[j] = BF_VALUES[counter2];
137 + counter2++;
138 + if (counter2 == BF_VALUES_MAX) {
139 + counter2 = 0;
140 + counter1 = (counter1 + 1) % BF_VALUES_MAX;
141 + }
142 + }
143 + }
144 +}
145 +
146 #define VEC_OP1(ASM, EL, IN, OUT) \
147 asm("v2 = vmem(%0 + #0)\n\t" \
148 "v2" #EL " = " #ASM "(v2" #EL ")\n\t" \
@@ -212,10 +239,13 @@ static inline void test_##NAME(bool invert) \
239
240 #define float_sf(x) ({ typeof(x) _x = (x); *((float *)&(_x)); })
241 #define float_hf(x) ({ typeof(x) _x = (x); *((_Float16 *) &(_x)); })
242 +#define float_bf(x) ({ uint32_t _u = ((uint32_t)(x)) << 16; *((float *)&(_u)); })
243 #define raw_sf(x) ({ typeof(x) _x = (x); *((uint32_t *)&(_x)); })
244 #define raw_hf(x) ({ typeof(x) _x = (x); *((uint16_t *)&(_x)); })
245 +#define raw_bf(x) ({ typeof(x) _x = (x); (uint16_t)(*((uint32_t *)&(_x)) >> 16); })
246 #define float_hf_to_sf(x) ((float)x)
247 #define bytes_hf 2
248 #define bytes_sf 4
249 +#define bytes_bf 2
250
251 #endif