@samitouri / QOSamiQemu / commits / 57da1eb994

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)