master
c 341 lines 8.51 KB
Raw
1 /*
2 * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
3 * SPDX-License-Identifier: GPL-2.0-or-later
4 *
5 * Exhaustive test for predicated .new branches with non-standard predicate
6 * values (non-all-0, non-all-1).
7 *
8 * Hexagon predicates are 8 bits wide but conditional branches evaluate only
9 * bit 0 (the LSB). A predicate value like 0xFE is non-zero yet has bit 0
10 * clear, so it must evaluate as "false".
11 *
12 * This test covers the distinct TCG code paths for predicated .new ops:
13 *
14 * 1. gen_cond_jump - J2_jumptnewpt / J2_jumpfnewpt (p0..p3)
15 * 2. gen_cond_jumpr - J2_jumprtnewpt / J2_jumprfnewpt
16 * 3. gen_cond_jumpr31 - SL2_jumpr31_tnew / SL2_jumpr31_fnew (duplex)
17 * 4. gen_testbit0_jumpnv - J4_tstbit0_t/f_jumpnv_t
18 * 5. Conditional .new loads and stores
19 */
20
21 #include <stdio.h>
22 #include <stdint.h>
23
24 int err;
25
26 #include "hex_test.h"
27
28 /*
29 * Non-standard predicate: non-zero (0xFE) but bit 0 clear => false.
30 * This distinguishes correct LSB evaluation from incorrect non-zero checks.
31 */
32 #define PRED_VAL 0xFEu
33 #define SENTINEL 0xDEADBEEFu
34 #define LOAD_VAL 0xAAAABBBBu
35
36 /* gen_cond_jump (J2_jumptnewpt) */
37
38 /*
39 * Macro to test jumptnew across predicate registers p0..p3.
40 * { Pn = and(Pn, Pn); if (Pn.new) jump:t TARGET }
41 *
42 * Pn.new = PRED_VAL & PRED_VAL = 0xFE => bit0=0 => not taken.
43 * Different predicate registers produce different instruction encodings.
44 */
45 #define TEST_JUMPTNEW(PREG) \
46 static void test_jumptnew_##PREG(void) \
47 { \
48 uint32_t jumped; \
49 asm( \
50 #PREG " = %[pred]\n" \
51 "{ " #PREG " = and(" #PREG ", " #PREG ")\n" \
52 " if (" #PREG ".new) jump:t 1f }\n" \
53 "%[jumped] = #0\n" \
54 "jump 2f\n" \
55 "1:\n" \
56 "%[jumped] = #1\n" \
57 "2:\n" \
58 : [jumped] "=r"(jumped) \
59 : [pred] "r"(PRED_VAL) \
60 : #PREG \
61 ); \
62 check32(jumped, 0); \
63 }
64
65 TEST_JUMPTNEW(p0)
66 TEST_JUMPTNEW(p1)
67 TEST_JUMPTNEW(p2)
68 TEST_JUMPTNEW(p3)
69
70 /* jumpfnew: bit0=0 => condition "false" => negated => jump IS taken */
71 static void test_jumpfnew_p0(void)
72 {
73 uint32_t jumped;
74
75 asm(
76 "p0 = %[pred]\n"
77 "{ p0 = and(p0, p0)\n"
78 " if (!p0.new) jump:t 1f }\n"
79 "%[jumped] = #0\n"
80 "jump 2f\n"
81 "1:\n"
82 "%[jumped] = #1\n"
83 "2:\n"
84 : [jumped] "=r"(jumped)
85 : [pred] "r"(PRED_VAL)
86 : "p0"
87 );
88 check32(jumped, 1);
89 }
90
91 /* gen_cond_jumpr (J2_jumprtnewpt) */
92
93 static void test_jumprtnew_p0(void)
94 {
95 uint32_t jumped;
96
97 asm(
98 "p0 = %[pred]\n"
99 "r0 = ##1f\n"
100 "{ p0 = and(p0, p0)\n"
101 " if (p0.new) jumpr:t r0 }\n"
102 "%[jumped] = #0\n"
103 "jump 2f\n"
104 "1:\n"
105 "%[jumped] = #1\n"
106 "2:\n"
107 : [jumped] "=r"(jumped)
108 : [pred] "r"(PRED_VAL)
109 : "p0", "r0"
110 );
111 check32(jumped, 0);
112 }
113
114 static void test_jumprfnew_p0(void)
115 {
116 uint32_t jumped;
117
118 asm(
119 "p0 = %[pred]\n"
120 "r0 = ##1f\n"
121 "{ p0 = and(p0, p0)\n"
122 " if (!p0.new) jumpr:t r0 }\n"
123 "%[jumped] = #0\n"
124 "jump 2f\n"
125 "1:\n"
126 "%[jumped] = #1\n"
127 "2:\n"
128 : [jumped] "=r"(jumped)
129 : [pred] "r"(PRED_VAL)
130 : "p0", "r0"
131 );
132 check32(jumped, 1);
133 }
134
135 /* gen_cond_jumpr31 (SL2_jumpr31_tnew) */
136
137 /*
138 * Duplex sub-instructions: only SA1_cmpeqi and similar can produce .new
139 * predicates in a duplex packet, and those only yield 0x00/0xFF.
140 * We test with standard values to exercise the duplex decode path.
141 *
142 * { p0 = cmp.eq(r0, #0); if (p0.new) jumpr:nt r31 }
143 * With r0=0: p0.new = 0xFF => bit0=1 => taken.
144 */
145 static void test_jumpr31_tnew(void)
146 {
147 uint32_t jumped;
148
149 asm(
150 "r0 = #0\n"
151 "r31 = ##1f\n"
152 "{ p0 = cmp.eq(r0, #0)\n"
153 " if (p0.new) jumpr:nt r31 }\n"
154 "%[jumped] = #0\n"
155 "jump 2f\n"
156 "1:\n"
157 "%[jumped] = #1\n"
158 "2:\n"
159 : [jumped] "=r"(jumped)
160 :
161 : "r0", "r31", "p0"
162 );
163 check32(jumped, 1);
164 }
165
166 /* p0.new = 0xFF => bit0=1 => !true => not taken */
167 static void test_jumpr31_fnew(void)
168 {
169 uint32_t jumped;
170
171 asm(
172 "r0 = #0\n"
173 "r31 = ##1f\n"
174 "{ p0 = cmp.eq(r0, #0)\n"
175 " if (!p0.new) jumpr:nt r31 }\n"
176 "%[jumped] = #0\n"
177 "jump 2f\n"
178 "1:\n"
179 "%[jumped] = #1\n"
180 "2:\n"
181 : [jumped] "=r"(jumped)
182 :
183 : "r0", "r31", "p0"
184 );
185 check32(jumped, 0);
186 }
187
188 /* gen_testbit0_jumpnv (J4_tstbit0) */
189
190 /*
191 * { r0 = #0xFE; if (tstbit(r0.new, #0)) jump:t TARGET }
192 * r0.new = 0xFE => bit0=0 => tstbit false => not taken.
193 */
194 static void test_tstbit0_t_jumpnv(void)
195 {
196 uint32_t jumped;
197
198 asm(
199 "{ r0 = #0xFE\n"
200 " if (tstbit(r0.new, #0)) jump:t 1f }\n"
201 "%[jumped] = #0\n"
202 "jump 2f\n"
203 "1:\n"
204 "%[jumped] = #1\n"
205 "2:\n"
206 : [jumped] "=r"(jumped)
207 :
208 : "r0"
209 );
210 check32(jumped, 0);
211 }
212
213 /* bit0=0 => tstbit false => negated => taken */
214 static void test_tstbit0_f_jumpnv(void)
215 {
216 uint32_t jumped;
217
218 asm(
219 "{ r0 = #0xFE\n"
220 " if (!tstbit(r0.new, #0)) jump:t 1f }\n"
221 "%[jumped] = #0\n"
222 "jump 2f\n"
223 "1:\n"
224 "%[jumped] = #1\n"
225 "2:\n"
226 : [jumped] "=r"(jumped)
227 :
228 : "r0"
229 );
230 check32(jumped, 1);
231 }
232
233 /* conditional .new loads and stores */
234
235 static uint32_t load_val;
236 static uint32_t store_dst;
237
238 /* bit0=0 => condition false => load skipped => sentinel remains */
239 static void test_cond_load_tnew(void)
240 {
241 uint32_t result;
242
243 load_val = LOAD_VAL;
244 asm(
245 "p0 = %[pred]\n"
246 "%[res] = %[sentinel]\n"
247 "{ p0 = and(p0, p0)\n"
248 " if (p0.new) %[res] = memw(%[addr]+#0) }\n"
249 : [res] "=&r"(result)
250 : [pred] "r"(PRED_VAL),
251 [addr] "r"(&load_val),
252 [sentinel] "r"(SENTINEL)
253 : "p0", "memory"
254 );
255 check32(result, SENTINEL);
256 }
257
258 /* bit0=0 => condition false => negated => load executed */
259 static void test_cond_load_fnew(void)
260 {
261 uint32_t result;
262
263 load_val = LOAD_VAL;
264 asm(
265 "p0 = %[pred]\n"
266 "%[res] = %[sentinel]\n"
267 "{ p0 = and(p0, p0)\n"
268 " if (!p0.new) %[res] = memw(%[addr]+#0) }\n"
269 : [res] "=&r"(result)
270 : [pred] "r"(PRED_VAL),
271 [addr] "r"(&load_val),
272 [sentinel] "r"(SENTINEL)
273 : "p0", "memory"
274 );
275 check32(result, LOAD_VAL);
276 }
277
278 /* bit0=0 => condition false => store skipped => sentinel remains */
279 static void test_cond_store_tnew(void)
280 {
281 store_dst = SENTINEL;
282 asm(
283 "p0 = %[pred]\n"
284 "{ p0 = and(p0, p0)\n"
285 " if (p0.new) memw(%[addr]+#0) = %[val] }\n"
286 :
287 : [pred] "r"(PRED_VAL),
288 [addr] "r"(&store_dst),
289 [val] "r"(LOAD_VAL)
290 : "p0", "memory"
291 );
292 check32(store_dst, SENTINEL);
293 }
294
295 /* bit0=0 => condition false => negated => store executed */
296 static void test_cond_store_fnew(void)
297 {
298 store_dst = SENTINEL;
299 asm(
300 "p0 = %[pred]\n"
301 "{ p0 = and(p0, p0)\n"
302 " if (!p0.new) memw(%[addr]+#0) = %[val] }\n"
303 :
304 : [pred] "r"(PRED_VAL),
305 [addr] "r"(&store_dst),
306 [val] "r"(LOAD_VAL)
307 : "p0", "memory"
308 );
309 check32(store_dst, LOAD_VAL);
310 }
311
312 int main(void)
313 {
314 /* gen_cond_jump with all predicate registers */
315 test_jumptnew_p0();
316 test_jumptnew_p1();
317 test_jumptnew_p2();
318 test_jumptnew_p3();
319 test_jumpfnew_p0();
320
321 /* gen_cond_jumpr */
322 test_jumprtnew_p0();
323 test_jumprfnew_p0();
324
325 /* gen_cond_jumpr31 (duplex, standard values) */
326 test_jumpr31_tnew();
327 test_jumpr31_fnew();
328
329 /* gen_testbit0_jumpnv */
330 test_tstbit0_t_jumpnv();
331 test_tstbit0_f_jumpnv();
332
333 /* conditional .new loads and stores */
334 test_cond_load_tnew();
335 test_cond_load_fnew();
336 test_cond_store_tnew();
337 test_cond_store_fnew();
338
339 puts(err ? "FAIL" : "PASS");
340 return err ? 1 : 0;
341 }