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;