tests/hexagon: add tests for v68 HVX IEEE float conversions
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/ec6af07a285c47e5f6df343860bfedce5bed9421.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
57da1eb994e4fe7073e9079864ba6d94a7a55ee7
4 files changed
+207
tests/tcg/hexagon/Makefile.target
+3
@@ -51,6 +51,7 @@ HEX_TESTS += scatter_gather
51
HEX_TESTS += hvx_misc
52
HEX_TESTS += hvx_histogram
53
HEX_TESTS += fp_hvx
54
+HEX_TESTS += fp_hvx_cvt
55
HEX_TESTS += fp_hvx_disabled
56
HEX_TESTS += invalid-slots
57
HEX_TESTS += valid-slots
@@ -142,6 +143,8 @@ fp_hvx: fp_hvx.c hvx_misc.h hex_test.h
143
fp_hvx: CFLAGS += -mhvx -mhvx-ieee-fp
144
fp_hvx_disabled: fp_hvx_disabled.c hvx_misc.h hex_test.h
145
fp_hvx_disabled: CFLAGS += -mhvx -mhvx-ieee-fp
146
+fp_hvx_cvt: fp_hvx_cvt.c hvx_misc.h hex_test.h
147
+fp_hvx_cvt: CFLAGS += -mhvx -mhvx-ieee-fp
148
149
run-fp_hvx_disabled: QEMU_OPTS += -cpu v73,ieee-fp=false
150
tests/tcg/hexagon/fp_hvx_cvt.c
new
+188
@@ -0,0 +1,188 @@
1
+/*
2
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
3
+ *
4
+ * SPDX-License-Identifier: GPL-2.0-or-later
5
+ */
6
+
7
+#include <stdio.h>
8
+#include <stdint.h>
9
+#include <stdbool.h>
10
+#include <string.h>
11
+#include <hexagon_types.h>
12
+#include <hvx_hexagon_protos.h>
13
+
14
+#if __HEXAGON_ARCH__ > 75
15
+#error "After v75, compiler will replace some FP HVX instructions."
16
+#endif
17
+
18
+int err;
19
+#include "hvx_misc.h"
20
+#include "hex_test.h"
21
+
22
+#define TEST_EXP(TO, FROM, VAL, EXP) do { \
23
+ ((MMVector *)&buffer)->FROM[index] = VAL; \
24
+ expect[0].TO[index] = EXP; \
25
+ index++; \
26
+} while (0)
27
+
28
+#define DEF_TEST_CVT(TO, FROM, TESTS) \
29
+ static void test_vcvt_##TO##_##FROM(void) \
30
+ { \
31
+ HVX_Vector *hvx_output = (HVX_Vector *)&output[0]; \
32
+ HVX_Vector buffer; \
33
+ int index = 0; \
34
+ memset(&buffer, 0, sizeof(buffer)); \
35
+ memset(expect, 0, sizeof(expect)); \
36
+ TESTS \
37
+ * hvx_output = Q6_V##TO##_vcvt_V##FROM(buffer); \
38
+ check_output_##TO(__LINE__, 1); \
39
+ }
40
+
41
+DEF_TEST_CVT(uh, hf, { \
42
+ TEST_EXP(uh, hf, HF_QNaN, UINT16_MAX); \
43
+ TEST_EXP(uh, hf, HF_SNaN, UINT16_MAX); \
44
+ TEST_EXP(uh, hf, HF_QNaN_neg, UINT16_MAX); \
45
+ TEST_EXP(uh, hf, HF_INF, UINT16_MAX); \
46
+ TEST_EXP(uh, hf, HF_INF_neg, 0); \
47
+ TEST_EXP(uh, hf, HF_neg_two, 0); \
48
+ TEST_EXP(uh, hf, HF_zero_neg, 0); \
49
+ TEST_EXP(uh, hf, raw_hf((_Float16)2.1), 2); \
50
+ TEST_EXP(uh, hf, HF_one_recip, 1); \
51
+})
52
+
53
+DEF_TEST_CVT(h, hf, { \
54
+ TEST_EXP(h, hf, HF_QNaN, INT16_MAX); \
55
+ TEST_EXP(h, hf, HF_SNaN, INT16_MAX); \
56
+ TEST_EXP(h, hf, HF_QNaN_neg, INT16_MAX); \
57
+ TEST_EXP(h, hf, HF_INF, INT16_MAX); \
58
+ TEST_EXP(h, hf, HF_INF_neg, INT16_MIN); \
59
+ TEST_EXP(h, hf, HF_neg_two, -2); \
60
+ TEST_EXP(h, hf, HF_zero_neg, 0); \
61
+ TEST_EXP(h, hf, raw_hf((_Float16)2.1), 2); \
62
+ TEST_EXP(h, hf, HF_one_recip, 1); \
63
+})
64
+
65
+/*
66
+ * Some cvt operations take two vectors as input and perform the following:
67
+ * VdV.TO[4*i] = OP(VuV.FROM[2*i]);
68
+ * VdV.TO[4*i+1] = OP(VuV.FROM[2*i+1]);
69
+ * VdV.TO[4*i+2] = OP(VvV.FROM[2*i]);
70
+ * VdV.TO[4*i+3] = OP(VvV.FROM[2*i+1]))
71
+ * We use bf_index and index in a way that the tests are always done either
72
+ * using the first or third line of the above snippet.
73
+ */
74
+#define TEST_EXP_2(TO, FROM, VAL, EXP) do { \
75
+ ((MMVector *)&buffers[bf_index])->FROM[2 * index] = VAL; \
76
+ expect[0].TO[(4 * index) + (2 * bf_index)] = EXP; \
77
+ index++; \
78
+ bf_index = (bf_index + 1) % 2; \
79
+} while (0)
80
+
81
+#define DEF_TEST_CVT_2(TO, FROM, TESTS) \
82
+ static void test_vcvt_##TO##_##FROM(void) \
83
+ { \
84
+ HVX_Vector *hvx_output = (HVX_Vector *)&output[0]; \
85
+ HVX_Vector buffers[2]; \
86
+ int index = 0, bf_index = 0; \
87
+ memset(&buffers, 0, sizeof(buffers)); \
88
+ memset(expect, 0, sizeof(expect)); \
89
+ TESTS \
90
+ * hvx_output = Q6_V##TO##_vcvt_V##FROM##V##FROM(buffers[0], buffers[1]); \
91
+ check_output_##TO(__LINE__, 1); \
92
+ }
93
+
94
+DEF_TEST_CVT_2(ub, hf, { \
95
+ TEST_EXP_2(ub, hf, HF_QNaN, UINT8_MAX); \
96
+ TEST_EXP_2(ub, hf, HF_SNaN, UINT8_MAX); \
97
+ TEST_EXP_2(ub, hf, HF_QNaN_neg, UINT8_MAX); \
98
+ TEST_EXP_2(ub, hf, HF_INF, UINT8_MAX); \
99
+ TEST_EXP_2(ub, hf, HF_INF_neg, 0); \
100
+ TEST_EXP_2(ub, hf, HF_small_neg, 0); \
101
+ TEST_EXP_2(ub, hf, HF_neg_two, 0); \
102
+ TEST_EXP_2(ub, hf, HF_zero_neg, 0); \
103
+ TEST_EXP_2(ub, hf, raw_hf((_Float16)2.1), 2); \
104
+ TEST_EXP_2(ub, hf, HF_one_recip, 1); \
105
+})
106
+
107
+DEF_TEST_CVT_2(b, hf, { \
108
+ TEST_EXP_2(b, hf, HF_QNaN, INT8_MAX); \
109
+ TEST_EXP_2(b, hf, HF_SNaN, INT8_MAX); \
110
+ TEST_EXP_2(b, hf, HF_QNaN_neg, INT8_MAX); \
111
+ TEST_EXP_2(b, hf, HF_INF, INT8_MAX); \
112
+ TEST_EXP_2(b, hf, HF_INF_neg, INT8_MIN); \
113
+ TEST_EXP_2(b, hf, HF_small_neg, 0); \
114
+ TEST_EXP_2(b, hf, HF_neg_two, -2); \
115
+ TEST_EXP_2(b, hf, HF_zero_neg, 0); \
116
+ TEST_EXP_2(b, hf, raw_hf((_Float16)2.1), 2); \
117
+ TEST_EXP_2(b, hf, HF_one_recip, 1); \
118
+})
119
+
120
+#define DEF_TEST_VCONV(TO, FROM, TESTS) \
121
+ static void test_vconv_##TO##_##FROM(void) \
122
+ { \
123
+ HVX_Vector *hvx_output = (HVX_Vector *)&output[0]; \
124
+ HVX_Vector buffer; \
125
+ int index = 0; \
126
+ memset(&buffer, 0, sizeof(buffer)); \
127
+ memset(expect, 0, sizeof(expect)); \
128
+ TESTS \
129
+ * hvx_output = Q6_V##TO##_equals_V##FROM(buffer); \
130
+ check_output_##TO(__LINE__, 1); \
131
+ }
132
+
133
+DEF_TEST_VCONV(w, sf, { \
134
+ TEST_EXP(w, sf, SF_QNaN, INT32_MAX); \
135
+ TEST_EXP(w, sf, SF_SNaN, INT32_MAX); \
136
+ TEST_EXP(w, sf, SF_QNaN_neg, INT32_MIN); \
137
+ TEST_EXP(w, sf, SF_INF, INT32_MAX); \
138
+ TEST_EXP(w, sf, SF_INF_neg, INT32_MIN); \
139
+ TEST_EXP(w, sf, SF_small_neg, 0); \
140
+ TEST_EXP(w, sf, SF_neg_two, -2); \
141
+ TEST_EXP(w, sf, SF_zero_neg, 0); \
142
+ TEST_EXP(w, sf, raw_sf(2.1f), 2); \
143
+ TEST_EXP(w, sf, raw_sf(2.8f), 2); \
144
+})
145
+
146
+DEF_TEST_VCONV(h, hf, { \
147
+ TEST_EXP(h, hf, HF_QNaN, INT16_MAX); \
148
+ TEST_EXP(h, hf, HF_SNaN, INT16_MAX); \
149
+ TEST_EXP(h, hf, HF_QNaN_neg, INT16_MIN); \
150
+ TEST_EXP(h, hf, HF_INF, INT16_MAX); \
151
+ TEST_EXP(h, hf, HF_INF_neg, INT16_MIN); \
152
+ TEST_EXP(h, hf, HF_small_neg, 0); \
153
+ TEST_EXP(h, hf, HF_neg_two, -2); \
154
+ TEST_EXP(h, hf, HF_zero_neg, 0); \
155
+ TEST_EXP(h, hf, raw_hf((_Float16)2.1), 2); \
156
+ TEST_EXP(h, hf, raw_hf((_Float16)2.8), 2); \
157
+})
158
+
159
+DEF_TEST_VCONV(hf, h, { \
160
+ TEST_EXP(hf, h, 0, HF_zero); \
161
+ TEST_EXP(hf, h, 2, HF_two); \
162
+ TEST_EXP(hf, h, -2, HF_neg_two); \
163
+ TEST_EXP(hf, h, 2049, raw_hf((_Float16)2048)); /* rounds DOWN */ \
164
+ TEST_EXP(hf, h, 2051, raw_hf((_Float16)2052)); /* rounds UP */ \
165
+})
166
+
167
+DEF_TEST_VCONV(sf, w, { \
168
+ TEST_EXP(sf, w, 0, SF_zero); \
169
+ TEST_EXP(sf, w, 2, SF_two); \
170
+ TEST_EXP(sf, w, -2, SF_neg_two); \
171
+ TEST_EXP(sf, w, 16777217, raw_sf((float)16777216)); /* rounds DOWN */ \
172
+ TEST_EXP(sf, w, 16777219, raw_sf((float)16777220)); /* rounds UP */ \
173
+})
174
+
175
+int main(void)
176
+{
177
+ test_vcvt_uh_hf();
178
+ test_vcvt_h_hf();
179
+ test_vcvt_ub_hf();
180
+ test_vcvt_b_hf();
181
+ test_vconv_w_sf();
182
+ test_vconv_sf_w();
183
+ test_vconv_h_hf();
184
+ test_vconv_hf_h();
185
+
186
+ puts(err ? "FAIL" : "PASS");
187
+ return err ? 1 : 0;
188
+}
tests/tcg/hexagon/hex_test.h
+14
@@ -111,6 +111,20 @@ static inline void __check64_ne(int line, uint64_t val, uint64_t expect)
111
"usr = r2\n\t"
112
113
/* Some useful floating point values */
114
+const uint16_t HF_INF = 0x7c00;
115
+const uint16_t HF_INF_neg = 0xfc00;
116
+const uint16_t HF_QNaN = 0x7e00;
117
+const uint16_t HF_SNaN = 0x7d00;
118
+const uint16_t HF_QNaN_neg = 0xfe00;
119
+const uint16_t HF_zero = 0x0000;
120
+const uint16_t HF_zero_neg = 0x8000;
121
+const uint16_t HF_one = 0x3c00;
122
+const uint16_t HF_one_recip = 0x3bf9;
123
+const uint16_t HF_two = 0x4000;
124
+const uint16_t HF_small_neg = 0x8010;
125
+const uint16_t HF_any = 0x3c00;
126
+const uint16_t HF_neg_two = 0xc000;
127
+
128
const uint32_t SF_INF = 0x7f800000;
129
const uint32_t SF_INF_neg = 0xff800000;
130
const uint32_t SF_QNaN = 0x7fc00000;
tests/tcg/hexagon/hvx_misc.h
+2
@@ -69,7 +69,9 @@ CHECK_OUTPUT_FUNC(d, 8)
69
CHECK_OUTPUT_FUNC(w, 4)
70
CHECK_OUTPUT_FUNC(sf, 4)
71
CHECK_OUTPUT_FUNC(h, 2)
72
+CHECK_OUTPUT_FUNC(uh, 2)
73
CHECK_OUTPUT_FUNC(hf, 2)
74
+CHECK_OUTPUT_FUNC(ub, 1)
75
CHECK_OUTPUT_FUNC(b, 1)
76
77
static inline void init_buffers(void)