@samitouri / QOSamiQemu / commits / 6bebed5a47

tests/hexagon: add tests for v68 HVX IEEE float comparisons

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/53e73707092d31bcde6ed8189c5496b00345f8fa.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 6bebed5a4771eb8149a9560c762e7dd326f35429
3 files changed +228
tests/tcg/hexagon/Makefile.target
+3
@@ -52,6 +52,7 @@ 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_cmp
56 HEX_TESTS += fp_hvx_disabled
57 HEX_TESTS += invalid-slots
58 HEX_TESTS += valid-slots
@@ -145,6 +146,8 @@ fp_hvx_disabled: fp_hvx_disabled.c hvx_misc.h hex_test.h
146 fp_hvx_disabled: CFLAGS += -mhvx -mhvx-ieee-fp
147 fp_hvx_cvt: fp_hvx_cvt.c hvx_misc.h hex_test.h
148 fp_hvx_cvt: CFLAGS += -mhvx -mhvx-ieee-fp
149 +fp_hvx_cmp: fp_hvx_cmp.c hvx_misc.h hex_test.h
150 +fp_hvx_cmp: CFLAGS += -mhvx -mhvx-ieee-fp
151
152 run-fp_hvx_disabled: QEMU_OPTS += -cpu v73,ieee-fp=false
153
tests/tcg/hexagon/fp_hvx_cmp.c new
+224
@@ -0,0 +1,224 @@
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 <assert.h>
12 +#include <hexagon_types.h>
13 +#include <hvx_hexagon_protos.h>
14 +
15 +#if __HEXAGON_ARCH__ > 75
16 +#error "After v75, compiler will replace some FP HVX instructions."
17 +#endif
18 +
19 +int err;
20 +#include "hvx_misc.h"
21 +#include "hex_test.h"
22 +
23 +#define MAX_TESTS_hf (MAX_VEC_SIZE_BYTES / 2)
24 +#define MAX_TESTS_sf (MAX_VEC_SIZE_BYTES / 4)
25 +
26 +#define TRUE_MASK_sf 0xffffffff
27 +#define TRUE_MASK_hf 0xffff
28 +
29 +static const char *comparisons[MAX_TESTS_sf][2];
30 +static HVX_Vector *hvx_output = (HVX_Vector *)&output[0];
31 +static HVX_Vector buffers[2], true_vec, false_vec;
32 +static int exp_index;
33 +
34 +#define ADD_TEST_CMP(TYPE, VAL1, VAL2, EXP) do { \
35 + ((MMVector *)&buffers[0])->TYPE[exp_index] = VAL1; \
36 + ((MMVector *)&buffers[1])->TYPE[exp_index] = VAL2; \
37 + expect[0].TYPE[exp_index] = EXP ? TRUE_MASK_##TYPE : 0; \
38 + comparisons[exp_index][0] = #VAL1; \
39 + comparisons[exp_index][1] = #VAL2; \
40 + assert(exp_index < MAX_TESTS_##TYPE); \
41 + exp_index++; \
42 +} while (0)
43 +
44 +#define TEST_CMP_GT(TYPE, VAL1, VAL2) do { \
45 + ADD_TEST_CMP(TYPE, VAL1, VAL2, true); \
46 + ADD_TEST_CMP(TYPE, VAL2, VAL1, false); \
47 +} while (0)
48 +
49 +#define PREP_TEST() do { \
50 + memset(&buffers, 0, sizeof(buffers)); \
51 + memset(expect, 0, sizeof(expect)); \
52 + exp_index = 0; \
53 +} while (0)
54 +
55 +#define CHECK(TYPE, TYPESZ) do { \
56 + HVX_VectorPred pred = Q6_Q_vcmp_gt_V##TYPE##V##TYPE(buffers[0], buffers[1]); \
57 + *hvx_output = Q6_V_vmux_QVV(pred, true_vec, false_vec); \
58 + for (int j = 0; j < MAX_VEC_SIZE_BYTES / TYPESZ; j++) { \
59 + if (output[0].TYPE[j] != expect[0].TYPE[j]) { \
60 + printf("ERROR: expected %s %s %s\n", comparisons[j][0], \
61 + (expect[0].TYPE[j] != 0 ? ">" : "<="), comparisons[j][1]); \
62 + err++; \
63 + } \
64 + } \
65 +} while (0)
66 +
67 +static void test_cmp_sf(void)
68 +{
69 + /*
70 + * General ordering for sf:
71 + * QNaN > SNaN > +Inf > numbers > -Inf > SNaN_neg > QNaN_neg
72 + */
73 +
74 + /* Test equality */
75 + PREP_TEST();
76 + ADD_TEST_CMP(sf, raw_sf(2.2), raw_sf(2.2), false);
77 + ADD_TEST_CMP(sf, SF_SNaN, SF_SNaN, false);
78 + CHECK(sf, 4);
79 +
80 + /* Common numbers */
81 + PREP_TEST();
82 + TEST_CMP_GT(sf, raw_sf(2.2), raw_sf(2.1));
83 + TEST_CMP_GT(sf, raw_sf(0), raw_sf(-2.2));
84 + CHECK(sf, 4);
85 +
86 + /* Infinity vs Infinity/NaN */
87 + PREP_TEST();
88 + TEST_CMP_GT(sf, SF_QNaN, SF_INF);
89 + TEST_CMP_GT(sf, SF_SNaN, SF_INF);
90 + TEST_CMP_GT(sf, SF_INF, SF_INF_neg);
91 + TEST_CMP_GT(sf, SF_INF, SF_SNaN_neg);
92 + TEST_CMP_GT(sf, SF_INF, SF_QNaN_neg);
93 + TEST_CMP_GT(sf, SF_INF_neg, SF_SNaN_neg);
94 + TEST_CMP_GT(sf, SF_INF_neg, SF_QNaN_neg);
95 + TEST_CMP_GT(sf, SF_SNaN, SF_INF_neg);
96 + TEST_CMP_GT(sf, SF_QNaN, SF_INF_neg);
97 + CHECK(sf, 4);
98 +
99 + /* NaN vs NaN */
100 + PREP_TEST();
101 + TEST_CMP_GT(sf, SF_QNaN, SF_SNaN);
102 + TEST_CMP_GT(sf, SF_SNaN, SF_SNaN_neg);
103 + TEST_CMP_GT(sf, SF_SNaN_neg, SF_QNaN_neg);
104 + CHECK(sf, 4);
105 +
106 + /* NaN vs non-NaN */
107 + PREP_TEST();
108 + TEST_CMP_GT(sf, SF_QNaN, SF_one);
109 + TEST_CMP_GT(sf, SF_SNaN, SF_one);
110 + TEST_CMP_GT(sf, SF_one, SF_QNaN_neg);
111 + TEST_CMP_GT(sf, SF_one, SF_SNaN_neg);
112 + CHECK(sf, 4);
113 +}
114 +
115 +static void test_cmp_hf(void)
116 +{
117 + /*
118 + * General ordering for hf:
119 + * QNaN > SNaN > +Inf > numbers > -Inf > QSNaN_neg > QNaN_neg
120 + */
121 +
122 + /* Test equality */
123 + PREP_TEST();
124 + ADD_TEST_CMP(hf, raw_hf((_Float16)2.2), raw_hf((_Float16)2.2), false);
125 + ADD_TEST_CMP(hf, HF_SNaN, HF_SNaN, false);
126 + CHECK(hf, 2);
127 +
128 + /* Common numbers */
129 + PREP_TEST();
130 + TEST_CMP_GT(hf, raw_hf((_Float16)2.2), raw_hf((_Float16)2.1));
131 + TEST_CMP_GT(hf, raw_hf((_Float16)0), raw_hf((_Float16) - 2.2));
132 + CHECK(hf, 2);
133 +
134 + /* Infinity vs Infinity/NaN */
135 + PREP_TEST();
136 + TEST_CMP_GT(hf, HF_QNaN, HF_INF);
137 + TEST_CMP_GT(hf, HF_SNaN, HF_INF);
138 + TEST_CMP_GT(hf, HF_INF, HF_INF_neg);
139 + TEST_CMP_GT(hf, HF_INF, HF_SNaN_neg);
140 + TEST_CMP_GT(hf, HF_INF, HF_QNaN_neg);
141 + TEST_CMP_GT(hf, HF_INF_neg, HF_SNaN_neg);
142 + TEST_CMP_GT(hf, HF_INF_neg, HF_QNaN_neg);
143 + TEST_CMP_GT(hf, HF_SNaN, HF_INF_neg);
144 + TEST_CMP_GT(hf, HF_QNaN, HF_INF_neg);
145 + CHECK(hf, 2);
146 +
147 + /* NaN vs NaN */
148 + PREP_TEST();
149 + TEST_CMP_GT(hf, HF_QNaN, HF_SNaN);
150 + TEST_CMP_GT(hf, HF_SNaN, HF_SNaN_neg);
151 + TEST_CMP_GT(hf, HF_SNaN_neg, HF_QNaN_neg);
152 + CHECK(hf, 2);
153 +
154 + /* NaN vs non-NaN */
155 + PREP_TEST();
156 + TEST_CMP_GT(hf, HF_QNaN, HF_one);
157 + TEST_CMP_GT(hf, HF_SNaN, HF_one);
158 + TEST_CMP_GT(hf, HF_one, HF_QNaN_neg);
159 + TEST_CMP_GT(hf, HF_one, HF_SNaN_neg);
160 + CHECK(hf, 2);
161 +}
162 +
163 +static void check_byte_pred(HVX_VectorPred pred, int byte_idx, uint8_t exp_mask,
164 + int line)
165 +{
166 + /*
167 + * Note: ((uint8_t *)&pred)[N] returns the expanded value of bit N:
168 + * 0xFF if bit is set, 0x00 if clear.
169 + */
170 + for (int i = 0; i < 8; i++) {
171 + int idx = byte_idx * 8 + i;
172 + int val = ((uint8_t *)&pred)[idx];
173 + int exp = (exp_mask >> i) & 1 ? 0xff : 0x00;
174 + if (exp != val) {
175 + printf("ERROR line %d: pred bit %d is 0x%x, should be 0x%x\n",
176 + line, idx, val, exp);
177 + err++;
178 + }
179 + }
180 +}
181 +
182 +#define CHECK_BYTE_PRED(PRED, BYTE, EXP) check_byte_pred(PRED, BYTE, EXP, __LINE__)
183 +
184 +static void test_cmp_variants(void)
185 +{
186 + HVX_VectorPred pred;
187 +
188 + /*
189 + * Setup: comparison result will have bits 4-7 set (0xF0 in pred byte 0)
190 + * - sf[0]: SF_zero > SF_one = false -> bits 0-3 = 0
191 + * - sf[1]: SF_one > SF_zero = true -> bits 4-7 = 1
192 + */
193 + PREP_TEST();
194 + ADD_TEST_CMP(sf, SF_zero, SF_one, false);
195 + ADD_TEST_CMP(sf, SF_one, SF_zero, true);
196 +
197 + /* greater and: 0xF0 & 0xF0 = 0xF0 */
198 + memset(&pred, 0xF0, sizeof(pred));
199 + pred = Q6_Q_vcmp_gtand_QVsfVsf(pred, buffers[0], buffers[1]);
200 + CHECK_BYTE_PRED(pred, 0, 0xF0);
201 +
202 + /* greater or: 0x0F | 0xF0 = 0xFF */
203 + memset(&pred, 0x0F, sizeof(pred));
204 + pred = Q6_Q_vcmp_gtor_QVsfVsf(pred, buffers[0], buffers[1]);
205 + CHECK_BYTE_PRED(pred, 0, 0xFF);
206 +
207 + /* greater xor: 0xFF ^ 0xF0 = 0x0F */
208 + memset(&pred, 0xFF, sizeof(pred));
209 + pred = Q6_Q_vcmp_gtxacc_QVsfVsf(pred, buffers[0], buffers[1]);
210 + CHECK_BYTE_PRED(pred, 0, 0x0F);
211 +}
212 +
213 +int main(void)
214 +{
215 + memset(&true_vec, 0xff, sizeof(true_vec));
216 + memset(&false_vec, 0, sizeof(false_vec));
217 +
218 + test_cmp_sf();
219 + test_cmp_hf();
220 + test_cmp_variants();
221 +
222 + puts(err ? "FAIL" : "PASS");
223 + return err ? 1 : 0;
224 +}
tests/tcg/hexagon/hex_test.h
+1
@@ -115,6 +115,7 @@ 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_SNaN_neg = 0xfd00;
119 const uint16_t HF_QNaN_neg = 0xfe00;
120 const uint16_t HF_zero = 0x0000;
121 const uint16_t HF_zero_neg = 0x8000;