master
c 275 lines 7.97 KB
Raw
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 #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];
33 static HVX_Vector buffers[2], true_vec, false_vec;
34 static int exp_index;
35
36 #define ADD_TEST_CMP(TYPE, VAL1, VAL2, EXP) do { \
37 ((MMVector *)&buffers[0])->TYPE[exp_index] = VAL1; \
38 ((MMVector *)&buffers[1])->TYPE[exp_index] = VAL2; \
39 expect[0].TYPE[exp_index] = EXP ? TRUE_MASK_##TYPE : 0; \
40 comparisons[exp_index][0] = #VAL1; \
41 comparisons[exp_index][1] = #VAL2; \
42 assert(exp_index < MAX_TESTS_##TYPE); \
43 exp_index++; \
44 } while (0)
45
46 #define TEST_CMP_GT(TYPE, VAL1, VAL2) do { \
47 ADD_TEST_CMP(TYPE, VAL1, VAL2, true); \
48 ADD_TEST_CMP(TYPE, VAL2, VAL1, false); \
49 } while (0)
50
51 #define PREP_TEST() do { \
52 memset(&buffers, 0, sizeof(buffers)); \
53 memset(expect, 0, sizeof(expect)); \
54 exp_index = 0; \
55 } while (0)
56
57 #define CHECK(TYPE, TYPESZ) do { \
58 HVX_VectorPred pred = Q6_Q_vcmp_gt_V##TYPE##V##TYPE(buffers[0], buffers[1]); \
59 *hvx_output = Q6_V_vmux_QVV(pred, true_vec, false_vec); \
60 for (int j = 0; j < MAX_VEC_SIZE_BYTES / TYPESZ; j++) { \
61 if (output[0].TYPE[j] != expect[0].TYPE[j]) { \
62 printf("ERROR: expected %s %s %s\n", comparisons[j][0], \
63 (expect[0].TYPE[j] != 0 ? ">" : "<="), comparisons[j][1]); \
64 err++; \
65 } \
66 } \
67 } while (0)
68
69 static void test_cmp_sf(void)
70 {
71 /*
72 * General ordering for sf:
73 * QNaN > SNaN > +Inf > numbers > -Inf > SNaN_neg > QNaN_neg
74 */
75
76 /* Test equality */
77 PREP_TEST();
78 ADD_TEST_CMP(sf, raw_sf(2.2), raw_sf(2.2), false);
79 ADD_TEST_CMP(sf, SF_SNaN, SF_SNaN, false);
80 CHECK(sf, 4);
81
82 /* Common numbers */
83 PREP_TEST();
84 TEST_CMP_GT(sf, raw_sf(2.2), raw_sf(2.1));
85 TEST_CMP_GT(sf, raw_sf(0), raw_sf(-2.2));
86 CHECK(sf, 4);
87
88 /* Infinity vs Infinity/NaN */
89 PREP_TEST();
90 TEST_CMP_GT(sf, SF_QNaN, SF_INF);
91 TEST_CMP_GT(sf, SF_SNaN, SF_INF);
92 TEST_CMP_GT(sf, SF_INF, SF_INF_neg);
93 TEST_CMP_GT(sf, SF_INF, SF_SNaN_neg);
94 TEST_CMP_GT(sf, SF_INF, SF_QNaN_neg);
95 TEST_CMP_GT(sf, SF_INF_neg, SF_SNaN_neg);
96 TEST_CMP_GT(sf, SF_INF_neg, SF_QNaN_neg);
97 TEST_CMP_GT(sf, SF_SNaN, SF_INF_neg);
98 TEST_CMP_GT(sf, SF_QNaN, SF_INF_neg);
99 CHECK(sf, 4);
100
101 /* NaN vs NaN */
102 PREP_TEST();
103 TEST_CMP_GT(sf, SF_QNaN, SF_SNaN);
104 TEST_CMP_GT(sf, SF_SNaN, SF_SNaN_neg);
105 TEST_CMP_GT(sf, SF_SNaN_neg, SF_QNaN_neg);
106 CHECK(sf, 4);
107
108 /* NaN vs non-NaN */
109 PREP_TEST();
110 TEST_CMP_GT(sf, SF_QNaN, SF_one);
111 TEST_CMP_GT(sf, SF_SNaN, SF_one);
112 TEST_CMP_GT(sf, SF_one, SF_QNaN_neg);
113 TEST_CMP_GT(sf, SF_one, SF_SNaN_neg);
114 CHECK(sf, 4);
115 }
116
117 static void test_cmp_hf(void)
118 {
119 /*
120 * General ordering for hf:
121 * QNaN > SNaN > +Inf > numbers > -Inf > QSNaN_neg > QNaN_neg
122 */
123
124 /* Test equality */
125 PREP_TEST();
126 ADD_TEST_CMP(hf, raw_hf((_Float16)2.2), raw_hf((_Float16)2.2), false);
127 ADD_TEST_CMP(hf, HF_SNaN, HF_SNaN, false);
128 CHECK(hf, 2);
129
130 /* Common numbers */
131 PREP_TEST();
132 TEST_CMP_GT(hf, raw_hf((_Float16)2.2), raw_hf((_Float16)2.1));
133 TEST_CMP_GT(hf, raw_hf((_Float16)0), raw_hf((_Float16) - 2.2));
134 CHECK(hf, 2);
135
136 /* Infinity vs Infinity/NaN */
137 PREP_TEST();
138 TEST_CMP_GT(hf, HF_QNaN, HF_INF);
139 TEST_CMP_GT(hf, HF_SNaN, HF_INF);
140 TEST_CMP_GT(hf, HF_INF, HF_INF_neg);
141 TEST_CMP_GT(hf, HF_INF, HF_SNaN_neg);
142 TEST_CMP_GT(hf, HF_INF, HF_QNaN_neg);
143 TEST_CMP_GT(hf, HF_INF_neg, HF_SNaN_neg);
144 TEST_CMP_GT(hf, HF_INF_neg, HF_QNaN_neg);
145 TEST_CMP_GT(hf, HF_SNaN, HF_INF_neg);
146 TEST_CMP_GT(hf, HF_QNaN, HF_INF_neg);
147 CHECK(hf, 2);
148
149 /* NaN vs NaN */
150 PREP_TEST();
151 TEST_CMP_GT(hf, HF_QNaN, HF_SNaN);
152 TEST_CMP_GT(hf, HF_SNaN, HF_SNaN_neg);
153 TEST_CMP_GT(hf, HF_SNaN_neg, HF_QNaN_neg);
154 CHECK(hf, 2);
155
156 /* NaN vs non-NaN */
157 PREP_TEST();
158 TEST_CMP_GT(hf, HF_QNaN, HF_one);
159 TEST_CMP_GT(hf, HF_SNaN, HF_one);
160 TEST_CMP_GT(hf, HF_one, HF_QNaN_neg);
161 TEST_CMP_GT(hf, HF_one, HF_SNaN_neg);
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 {
216 /*
217 * Note: ((uint8_t *)&pred)[N] returns the expanded value of bit N:
218 * 0xFF if bit is set, 0x00 if clear.
219 */
220 for (int i = 0; i < 8; i++) {
221 int idx = byte_idx * 8 + i;
222 int val = ((uint8_t *)&pred)[idx];
223 int exp = (exp_mask >> i) & 1 ? 0xff : 0x00;
224 if (exp != val) {
225 printf("ERROR line %d: pred bit %d is 0x%x, should be 0x%x\n",
226 line, idx, val, exp);
227 err++;
228 }
229 }
230 }
231
232 #define CHECK_BYTE_PRED(PRED, BYTE, EXP) check_byte_pred(PRED, BYTE, EXP, __LINE__)
233
234 static void test_cmp_variants(void)
235 {
236 HVX_VectorPred pred;
237
238 /*
239 * Setup: comparison result will have bits 4-7 set (0xF0 in pred byte 0)
240 * - sf[0]: SF_zero > SF_one = false -> bits 0-3 = 0
241 * - sf[1]: SF_one > SF_zero = true -> bits 4-7 = 1
242 */
243 PREP_TEST();
244 ADD_TEST_CMP(sf, SF_zero, SF_one, false);
245 ADD_TEST_CMP(sf, SF_one, SF_zero, true);
246
247 /* greater and: 0xF0 & 0xF0 = 0xF0 */
248 memset(&pred, 0xF0, sizeof(pred));
249 pred = Q6_Q_vcmp_gtand_QVsfVsf(pred, buffers[0], buffers[1]);
250 CHECK_BYTE_PRED(pred, 0, 0xF0);
251
252 /* greater or: 0x0F | 0xF0 = 0xFF */
253 memset(&pred, 0x0F, sizeof(pred));
254 pred = Q6_Q_vcmp_gtor_QVsfVsf(pred, buffers[0], buffers[1]);
255 CHECK_BYTE_PRED(pred, 0, 0xFF);
256
257 /* greater xor: 0xFF ^ 0xF0 = 0x0F */
258 memset(&pred, 0xFF, sizeof(pred));
259 pred = Q6_Q_vcmp_gtxacc_QVsfVsf(pred, buffers[0], buffers[1]);
260 CHECK_BYTE_PRED(pred, 0, 0x0F);
261 }
262
263 int main(void)
264 {
265 memset(&true_vec, 0xff, sizeof(true_vec));
266 memset(&false_vec, 0, sizeof(false_vec));
267
268 test_cmp_sf();
269 test_cmp_hf();
270 test_cmp_bf();
271 test_cmp_variants();
272
273 puts(err ? "FAIL" : "PASS");
274 return err ? 1 : 0;
275 }