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