1 /*
2 * ARM SVE Operations
3 *
4 * Copyright (c) 2018 Linaro, Ltd.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "qemu/osdep.h"
21 #include "cpu.h"
22 #include "internals.h"
23 #include "exec/exec-all.h"
24 #include "exec/page-protection.h"
25 #include "exec/helper-proto.h"
26 #include "tcg/tcg-gvec-desc.h"
27 #include "fpu/softfloat.h"
28 #include "tcg/tcg.h"
29 #include "vec_internal.h"
30 #include "sve_ldst_internal.h"
31 #include "hw/core/tcg-cpu-ops.h"
32
33
34 /* Return a value for NZCV as per the ARM PredTest pseudofunction.
35 *
36 * The return value has bit 31 set if N is set, bit 1 set if Z is clear,
37 * and bit 0 set if C is set. Compare the definitions of these variables
38 * within CPUARMState.
39 */
40
41 /* For no G bits set, NZCV = C. */
42 #define PREDTEST_INIT 1
43
44 /* This is an iterative function, called for each Pd and Pg word
45 * moving forward.
46 */
iter_predtest_fwd(uint64_t d,uint64_t g,uint32_t flags)47 static uint32_t iter_predtest_fwd(uint64_t d, uint64_t g, uint32_t flags)
48 {
49 if (likely(g)) {
50 /* Compute N from first D & G.
51 Use bit 2 to signal first G bit seen. */
52 if (!(flags & 4)) {
53 flags |= ((d & (g & -g)) != 0) << 31;
54 flags |= 4;
55 }
56
57 /* Accumulate Z from each D & G. */
58 flags |= ((d & g) != 0) << 1;
59
60 /* Compute C from last !(D & G). Replace previous. */
61 flags = deposit32(flags, 0, 1, (d & pow2floor(g)) == 0);
62 }
63 return flags;
64 }
65
66 /* This is an iterative function, called for each Pd and Pg word
67 * moving backward.
68 */
iter_predtest_bwd(uint64_t d,uint64_t g,uint32_t flags)69 static uint32_t iter_predtest_bwd(uint64_t d, uint64_t g, uint32_t flags)
70 {
71 if (likely(g)) {
72 /* Compute C from first (i.e last) !(D & G).
73 Use bit 2 to signal first G bit seen. */
74 if (!(flags & 4)) {
75 flags += 4 - 1; /* add bit 2, subtract C from PREDTEST_INIT */
76 flags |= (d & pow2floor(g)) == 0;
77 }
78
79 /* Accumulate Z from each D & G. */
80 flags |= ((d & g) != 0) << 1;
81
82 /* Compute N from last (i.e first) D & G. Replace previous. */
83 flags = deposit32(flags, 31, 1, (d & (g & -g)) != 0);
84 }
85 return flags;
86 }
87
88 /* The same for a single word predicate. */
HELPER(sve_predtest1)89 uint32_t HELPER(sve_predtest1)(uint64_t d, uint64_t g)
90 {
91 return iter_predtest_fwd(d, g, PREDTEST_INIT);
92 }
93
94 /* The same for a multi-word predicate. */
HELPER(sve_predtest)95 uint32_t HELPER(sve_predtest)(void *vd, void *vg, uint32_t words)
96 {
97 uint32_t flags = PREDTEST_INIT;
98 uint64_t *d = vd, *g = vg;
99 uintptr_t i = 0;
100
101 do {
102 flags = iter_predtest_fwd(d[i], g[i], flags);
103 } while (++i < words);
104
105 return flags;
106 }
107
108 /* Similarly for single word elements. */
expand_pred_s(uint8_t byte)109 static inline uint64_t expand_pred_s(uint8_t byte)
110 {
111 static const uint64_t word[] = {
112 [0x01] = 0x00000000ffffffffull,
113 [0x10] = 0xffffffff00000000ull,
114 [0x11] = 0xffffffffffffffffull,
115 };
116 return word[byte & 0x11];
117 }
118
119 #define LOGICAL_PPPP(NAME, FUNC) \
120 void HELPER(NAME)(void *vd, void *vn, void *vm, void *vg, uint32_t desc) \
121 { \
122 uintptr_t opr_sz = simd_oprsz(desc); \
123 uint64_t *d = vd, *n = vn, *m = vm, *g = vg; \
124 uintptr_t i; \
125 for (i = 0; i < opr_sz / 8; ++i) { \
126 d[i] = FUNC(n[i], m[i], g[i]); \
127 } \
128 }
129
130 #define DO_AND(N, M, G) (((N) & (M)) & (G))
131 #define DO_BIC(N, M, G) (((N) & ~(M)) & (G))
132 #define DO_EOR(N, M, G) (((N) ^ (M)) & (G))
133 #define DO_ORR(N, M, G) (((N) | (M)) & (G))
134 #define DO_ORN(N, M, G) (((N) | ~(M)) & (G))
135 #define DO_NOR(N, M, G) (~((N) | (M)) & (G))
136 #define DO_NAND(N, M, G) (~((N) & (M)) & (G))
137 #define DO_SEL(N, M, G) (((N) & (G)) | ((M) & ~(G)))
138
LOGICAL_PPPP(sve_and_pppp,DO_AND)139 LOGICAL_PPPP(sve_and_pppp, DO_AND)
140 LOGICAL_PPPP(sve_bic_pppp, DO_BIC)
141 LOGICAL_PPPP(sve_eor_pppp, DO_EOR)
142 LOGICAL_PPPP(sve_sel_pppp, DO_SEL)
143 LOGICAL_PPPP(sve_orr_pppp, DO_ORR)
144 LOGICAL_PPPP(sve_orn_pppp, DO_ORN)
145 LOGICAL_PPPP(sve_nor_pppp, DO_NOR)
146 LOGICAL_PPPP(sve_nand_pppp, DO_NAND)
147
148 #undef DO_AND
149 #undef DO_BIC
150 #undef DO_EOR
151 #undef DO_ORR
152 #undef DO_ORN
153 #undef DO_NOR
154 #undef DO_NAND
155 #undef DO_SEL
156 #undef LOGICAL_PPPP
157
158 /* Fully general three-operand expander, controlled by a predicate.
159 * This is complicated by the host-endian storage of the register file.
160 */
161 /* ??? I don't expect the compiler could ever vectorize this itself.
162 * With some tables we can convert bit masks to byte masks, and with
163 * extra care wrt byte/word ordering we could use gcc generic vectors
164 * and do 16 bytes at a time.
165 */
166 #define DO_ZPZZ(NAME, TYPE, H, OP) \
167 void HELPER(NAME)(void *vd, void *vn, void *vm, void *vg, uint32_t desc) \
168 { \
169 intptr_t i, opr_sz = simd_oprsz(desc); \
170 for (i = 0; i < opr_sz; ) { \
171 uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); \
172 do { \
173 if (pg & 1) { \
174 TYPE nn = *(TYPE *)(vn + H(i)); \
175 TYPE mm = *(TYPE *)(vm + H(i)); \
176 *(TYPE *)(vd + H(i)) = OP(nn, mm); \
177 } \
178 i += sizeof(TYPE), pg >>= sizeof(TYPE); \
179 } while (i & 15); \
180 } \
181 }
182
183 /* Similarly, specialized for 64-bit operands. */
184 #define DO_ZPZZ_D(NAME, TYPE, OP) \
185 void HELPER(NAME)(void *vd, void *vn, void *vm, void *vg, uint32_t desc) \
186 { \
187 intptr_t i, opr_sz = simd_oprsz(desc) / 8; \
188 TYPE *d = vd, *n = vn, *m = vm; \
189 uint8_t *pg = vg; \
190 for (i = 0; i < opr_sz; i += 1) { \
191 if (pg[H1(i)] & 1) { \
192 TYPE nn = n[i], mm = m[i]; \
193 d[i] = OP(nn, mm); \
194 } \
195 } \
196 }
197
198 #define DO_AND(N, M) (N & M)
199 #define DO_EOR(N, M) (N ^ M)
200 #define DO_ORR(N, M) (N | M)
201 #define DO_BIC(N, M) (N & ~M)
202 #define DO_ADD(N, M) (N + M)
203 #define DO_SUB(N, M) (N - M)
204 #define DO_MAX(N, M) ((N) >= (M) ? (N) : (M))
205 #define DO_MIN(N, M) ((N) >= (M) ? (M) : (N))
206 #define DO_ABD(N, M) ((N) >= (M) ? (N) - (M) : (M) - (N))
207 #define DO_MUL(N, M) (N * M)
208
209
210 /*
211 * We must avoid the C undefined behaviour cases: division by
212 * zero and signed division of INT_MIN by -1. Both of these
213 * have architecturally defined required results for Arm.
214 * We special case all signed divisions by -1 to avoid having
215 * to deduce the minimum integer for the type involved.
216 */
217 #define DO_SDIV(N, M) (unlikely(M == 0) ? 0 : unlikely(M == -1) ? -N : N / M)
218 #define DO_UDIV(N, M) (unlikely(M == 0) ? 0 : N / M)
219
220 DO_ZPZZ(sve_and_zpzz_b, uint8_t, H1, DO_AND)
221 DO_ZPZZ(sve_and_zpzz_h, uint16_t, H1_2, DO_AND)
222 DO_ZPZZ(sve_and_zpzz_s, uint32_t, H1_4, DO_AND)
223 DO_ZPZZ_D(sve_and_zpzz_d, uint64_t, DO_AND)
224
225 DO_ZPZZ(sve_orr_zpzz_b, uint8_t, H1, DO_ORR)
226 DO_ZPZZ(sve_orr_zpzz_h, uint16_t, H1_2, DO_ORR)
227 DO_ZPZZ(sve_orr_zpzz_s, uint32_t, H1_4, DO_ORR)
228 DO_ZPZZ_D(sve_orr_zpzz_d, uint64_t, DO_ORR)
229
230 DO_ZPZZ(sve_eor_zpzz_b, uint8_t, H1, DO_EOR)
231 DO_ZPZZ(sve_eor_zpzz_h, uint16_t, H1_2, DO_EOR)
232 DO_ZPZZ(sve_eor_zpzz_s, uint32_t, H1_4, DO_EOR)
233 DO_ZPZZ_D(sve_eor_zpzz_d, uint64_t, DO_EOR)
234
235 DO_ZPZZ(sve_bic_zpzz_b, uint8_t, H1, DO_BIC)
236 DO_ZPZZ(sve_bic_zpzz_h, uint16_t, H1_2, DO_BIC)
237 DO_ZPZZ(sve_bic_zpzz_s, uint32_t, H1_4, DO_BIC)
238 DO_ZPZZ_D(sve_bic_zpzz_d, uint64_t, DO_BIC)
239
240 DO_ZPZZ(sve_add_zpzz_b, uint8_t, H1, DO_ADD)
241 DO_ZPZZ(sve_add_zpzz_h, uint16_t, H1_2, DO_ADD)
242 DO_ZPZZ(sve_add_zpzz_s, uint32_t, H1_4, DO_ADD)
243 DO_ZPZZ_D(sve_add_zpzz_d, uint64_t, DO_ADD)
244
245 DO_ZPZZ(sve_sub_zpzz_b, uint8_t, H1, DO_SUB)
246 DO_ZPZZ(sve_sub_zpzz_h, uint16_t, H1_2, DO_SUB)
247 DO_ZPZZ(sve_sub_zpzz_s, uint32_t, H1_4, DO_SUB)
248 DO_ZPZZ_D(sve_sub_zpzz_d, uint64_t, DO_SUB)
249
250 DO_ZPZZ(sve_smax_zpzz_b, int8_t, H1, DO_MAX)
251 DO_ZPZZ(sve_smax_zpzz_h, int16_t, H1_2, DO_MAX)
252 DO_ZPZZ(sve_smax_zpzz_s, int32_t, H1_4, DO_MAX)
253 DO_ZPZZ_D(sve_smax_zpzz_d, int64_t, DO_MAX)
254
255 DO_ZPZZ(sve_umax_zpzz_b, uint8_t, H1, DO_MAX)
256 DO_ZPZZ(sve_umax_zpzz_h, uint16_t, H1_2, DO_MAX)
257 DO_ZPZZ(sve_umax_zpzz_s, uint32_t, H1_4, DO_MAX)
258 DO_ZPZZ_D(sve_umax_zpzz_d, uint64_t, DO_MAX)
259
260 DO_ZPZZ(sve_smin_zpzz_b, int8_t, H1, DO_MIN)
261 DO_ZPZZ(sve_smin_zpzz_h, int16_t, H1_2, DO_MIN)
262 DO_ZPZZ(sve_smin_zpzz_s, int32_t, H1_4, DO_MIN)
263 DO_ZPZZ_D(sve_smin_zpzz_d, int64_t, DO_MIN)
264
265 DO_ZPZZ(sve_umin_zpzz_b, uint8_t, H1, DO_MIN)
266 DO_ZPZZ(sve_umin_zpzz_h, uint16_t, H1_2, DO_MIN)
267 DO_ZPZZ(sve_umin_zpzz_s, uint32_t, H1_4, DO_MIN)
268 DO_ZPZZ_D(sve_umin_zpzz_d, uint64_t, DO_MIN)
269
270 DO_ZPZZ(sve_sabd_zpzz_b, int8_t, H1, DO_ABD)
271 DO_ZPZZ(sve_sabd_zpzz_h, int16_t, H1_2, DO_ABD)
272 DO_ZPZZ(sve_sabd_zpzz_s, int32_t, H1_4, DO_ABD)
273 DO_ZPZZ_D(sve_sabd_zpzz_d, int64_t, DO_ABD)
274
275 DO_ZPZZ(sve_uabd_zpzz_b, uint8_t, H1, DO_ABD)
276 DO_ZPZZ(sve_uabd_zpzz_h, uint16_t, H1_2, DO_ABD)
277 DO_ZPZZ(sve_uabd_zpzz_s, uint32_t, H1_4, DO_ABD)
278 DO_ZPZZ_D(sve_uabd_zpzz_d, uint64_t, DO_ABD)
279
280 /* Because the computation type is at least twice as large as required,
281 these work for both signed and unsigned source types. */
282 static inline uint8_t do_mulh_b(int32_t n, int32_t m)
283 {
284 return (n * m) >> 8;
285 }
286
do_mulh_h(int32_t n,int32_t m)287 static inline uint16_t do_mulh_h(int32_t n, int32_t m)
288 {
289 return (n * m) >> 16;
290 }
291
do_mulh_s(int64_t n,int64_t m)292 static inline uint32_t do_mulh_s(int64_t n, int64_t m)
293 {
294 return (n * m) >> 32;
295 }
296
do_smulh_d(uint64_t n,uint64_t m)297 static inline uint64_t do_smulh_d(uint64_t n, uint64_t m)
298 {
299 uint64_t lo, hi;
300 muls64(&lo, &hi, n, m);
301 return hi;
302 }
303
do_umulh_d(uint64_t n,uint64_t m)304 static inline uint64_t do_umulh_d(uint64_t n, uint64_t m)
305 {
306 uint64_t lo, hi;
307 mulu64(&lo, &hi, n, m);
308 return hi;
309 }
310
DO_ZPZZ(sve_mul_zpzz_b,uint8_t,H1,DO_MUL)311 DO_ZPZZ(sve_mul_zpzz_b, uint8_t, H1, DO_MUL)
312 DO_ZPZZ(sve_mul_zpzz_h, uint16_t, H1_2, DO_MUL)
313 DO_ZPZZ(sve_mul_zpzz_s, uint32_t, H1_4, DO_MUL)
314 DO_ZPZZ_D(sve_mul_zpzz_d, uint64_t, DO_MUL)
315
316 DO_ZPZZ(sve_smulh_zpzz_b, int8_t, H1, do_mulh_b)
317 DO_ZPZZ(sve_smulh_zpzz_h, int16_t, H1_2, do_mulh_h)
318 DO_ZPZZ(sve_smulh_zpzz_s, int32_t, H1_4, do_mulh_s)
319 DO_ZPZZ_D(sve_smulh_zpzz_d, uint64_t, do_smulh_d)
320
321 DO_ZPZZ(sve_umulh_zpzz_b, uint8_t, H1, do_mulh_b)
322 DO_ZPZZ(sve_umulh_zpzz_h, uint16_t, H1_2, do_mulh_h)
323 DO_ZPZZ(sve_umulh_zpzz_s, uint32_t, H1_4, do_mulh_s)
324 DO_ZPZZ_D(sve_umulh_zpzz_d, uint64_t, do_umulh_d)
325
326 DO_ZPZZ(sve_sdiv_zpzz_s, int32_t, H1_4, DO_SDIV)
327 DO_ZPZZ_D(sve_sdiv_zpzz_d, int64_t, DO_SDIV)
328
329 DO_ZPZZ(sve_udiv_zpzz_s, uint32_t, H1_4, DO_UDIV)
330 DO_ZPZZ_D(sve_udiv_zpzz_d, uint64_t, DO_UDIV)
331
332 /* Note that all bits of the shift are significant
333 and not modulo the element size. */
334 #define DO_ASR(N, M) (N >> MIN(M, sizeof(N) * 8 - 1))
335 #define DO_LSR(N, M) (M < sizeof(N) * 8 ? N >> M : 0)
336 #define DO_LSL(N, M) (M < sizeof(N) * 8 ? N << M : 0)
337
338 DO_ZPZZ(sve_asr_zpzz_b, int8_t, H1, DO_ASR)
339 DO_ZPZZ(sve_lsr_zpzz_b, uint8_t, H1_2, DO_LSR)
340 DO_ZPZZ(sve_lsl_zpzz_b, uint8_t, H1_4, DO_LSL)
341
342 DO_ZPZZ(sve_asr_zpzz_h, int16_t, H1, DO_ASR)
343 DO_ZPZZ(sve_lsr_zpzz_h, uint16_t, H1_2, DO_LSR)
344 DO_ZPZZ(sve_lsl_zpzz_h, uint16_t, H1_4, DO_LSL)
345
346 DO_ZPZZ(sve_asr_zpzz_s, int32_t, H1, DO_ASR)
347 DO_ZPZZ(sve_lsr_zpzz_s, uint32_t, H1_2, DO_LSR)
348 DO_ZPZZ(sve_lsl_zpzz_s, uint32_t, H1_4, DO_LSL)
349
350 DO_ZPZZ_D(sve_asr_zpzz_d, int64_t, DO_ASR)
351 DO_ZPZZ_D(sve_lsr_zpzz_d, uint64_t, DO_LSR)
352 DO_ZPZZ_D(sve_lsl_zpzz_d, uint64_t, DO_LSL)
353
354 static inline uint16_t do_sadalp_h(int16_t n, int16_t m)
355 {
356 int8_t n1 = n, n2 = n >> 8;
357 return m + n1 + n2;
358 }
359
do_sadalp_s(int32_t n,int32_t m)360 static inline uint32_t do_sadalp_s(int32_t n, int32_t m)
361 {
362 int16_t n1 = n, n2 = n >> 16;
363 return m + n1 + n2;
364 }
365
do_sadalp_d(int64_t n,int64_t m)366 static inline uint64_t do_sadalp_d(int64_t n, int64_t m)
367 {
368 int32_t n1 = n, n2 = n >> 32;
369 return m + n1 + n2;
370 }
371
DO_ZPZZ(sve2_sadalp_zpzz_h,int16_t,H1_2,do_sadalp_h)372 DO_ZPZZ(sve2_sadalp_zpzz_h, int16_t, H1_2, do_sadalp_h)
373 DO_ZPZZ(sve2_sadalp_zpzz_s, int32_t, H1_4, do_sadalp_s)
374 DO_ZPZZ_D(sve2_sadalp_zpzz_d, int64_t, do_sadalp_d)
375
376 static inline uint16_t do_uadalp_h(uint16_t n, uint16_t m)
377 {
378 uint8_t n1 = n, n2 = n >> 8;
379 return m + n1 + n2;
380 }
381
do_uadalp_s(uint32_t n,uint32_t m)382 static inline uint32_t do_uadalp_s(uint32_t n, uint32_t m)
383 {
384 uint16_t n1 = n, n2 = n >> 16;
385 return m + n1 + n2;
386 }
387
do_uadalp_d(uint64_t n,uint64_t m)388 static inline uint64_t do_uadalp_d(uint64_t n, uint64_t m)
389 {
390 uint32_t n1 = n, n2 = n >> 32;
391 return m + n1 + n2;
392 }
393
DO_ZPZZ(sve2_uadalp_zpzz_h,uint16_t,H1_2,do_uadalp_h)394 DO_ZPZZ(sve2_uadalp_zpzz_h, uint16_t, H1_2, do_uadalp_h)
395 DO_ZPZZ(sve2_uadalp_zpzz_s, uint32_t, H1_4, do_uadalp_s)
396 DO_ZPZZ_D(sve2_uadalp_zpzz_d, uint64_t, do_uadalp_d)
397
398 #define do_srshl_b(n, m) do_sqrshl_bhs(n, m, 8, true, NULL)
399 #define do_srshl_h(n, m) do_sqrshl_bhs(n, m, 16, true, NULL)
400 #define do_srshl_s(n, m) do_sqrshl_bhs(n, m, 32, true, NULL)
401 #define do_srshl_d(n, m) do_sqrshl_d(n, m, true, NULL)
402
403 DO_ZPZZ(sve2_srshl_zpzz_b, int8_t, H1, do_srshl_b)
404 DO_ZPZZ(sve2_srshl_zpzz_h, int16_t, H1_2, do_srshl_h)
405 DO_ZPZZ(sve2_srshl_zpzz_s, int32_t, H1_4, do_srshl_s)
406 DO_ZPZZ_D(sve2_srshl_zpzz_d, int64_t, do_srshl_d)
407
408 #define do_urshl_b(n, m) do_uqrshl_bhs(n, (int8_t)m, 8, true, NULL)
409 #define do_urshl_h(n, m) do_uqrshl_bhs(n, (int16_t)m, 16, true, NULL)
410 #define do_urshl_s(n, m) do_uqrshl_bhs(n, m, 32, true, NULL)
411 #define do_urshl_d(n, m) do_uqrshl_d(n, m, true, NULL)
412
413 DO_ZPZZ(sve2_urshl_zpzz_b, uint8_t, H1, do_urshl_b)
414 DO_ZPZZ(sve2_urshl_zpzz_h, uint16_t, H1_2, do_urshl_h)
415 DO_ZPZZ(sve2_urshl_zpzz_s, uint32_t, H1_4, do_urshl_s)
416 DO_ZPZZ_D(sve2_urshl_zpzz_d, uint64_t, do_urshl_d)
417
418 /*
419 * Unlike the NEON and AdvSIMD versions, there is no QC bit to set.
420 * We pass in a pointer to a dummy saturation field to trigger
421 * the saturating arithmetic but discard the information about
422 * whether it has occurred.
423 */
424 #define do_sqshl_b(n, m) \
425 ({ uint32_t discard; do_sqrshl_bhs(n, m, 8, false, &discard); })
426 #define do_sqshl_h(n, m) \
427 ({ uint32_t discard; do_sqrshl_bhs(n, m, 16, false, &discard); })
428 #define do_sqshl_s(n, m) \
429 ({ uint32_t discard; do_sqrshl_bhs(n, m, 32, false, &discard); })
430 #define do_sqshl_d(n, m) \
431 ({ uint32_t discard; do_sqrshl_d(n, m, false, &discard); })
432
433 DO_ZPZZ(sve2_sqshl_zpzz_b, int8_t, H1_2, do_sqshl_b)
434 DO_ZPZZ(sve2_sqshl_zpzz_h, int16_t, H1_2, do_sqshl_h)
435 DO_ZPZZ(sve2_sqshl_zpzz_s, int32_t, H1_4, do_sqshl_s)
436 DO_ZPZZ_D(sve2_sqshl_zpzz_d, int64_t, do_sqshl_d)
437
438 #define do_uqshl_b(n, m) \
439 ({ uint32_t discard; do_uqrshl_bhs(n, (int8_t)m, 8, false, &discard); })
440 #define do_uqshl_h(n, m) \
441 ({ uint32_t discard; do_uqrshl_bhs(n, (int16_t)m, 16, false, &discard); })
442 #define do_uqshl_s(n, m) \
443 ({ uint32_t discard; do_uqrshl_bhs(n, m, 32, false, &discard); })
444 #define do_uqshl_d(n, m) \
445 ({ uint32_t discard; do_uqrshl_d(n, m, false, &discard); })
446
447 DO_ZPZZ(sve2_uqshl_zpzz_b, uint8_t, H1_2, do_uqshl_b)
448 DO_ZPZZ(sve2_uqshl_zpzz_h, uint16_t, H1_2, do_uqshl_h)
449 DO_ZPZZ(sve2_uqshl_zpzz_s, uint32_t, H1_4, do_uqshl_s)
450 DO_ZPZZ_D(sve2_uqshl_zpzz_d, uint64_t, do_uqshl_d)
451
452 #define do_sqrshl_b(n, m) \
453 ({ uint32_t discard; do_sqrshl_bhs(n, m, 8, true, &discard); })
454 #define do_sqrshl_h(n, m) \
455 ({ uint32_t discard; do_sqrshl_bhs(n, m, 16, true, &discard); })
456 #define do_sqrshl_s(n, m) \
457 ({ uint32_t discard; do_sqrshl_bhs(n, m, 32, true, &discard); })
458 #define do_sqrshl_d(n, m) \
459 ({ uint32_t discard; do_sqrshl_d(n, m, true, &discard); })
460
461 DO_ZPZZ(sve2_sqrshl_zpzz_b, int8_t, H1_2, do_sqrshl_b)
462 DO_ZPZZ(sve2_sqrshl_zpzz_h, int16_t, H1_2, do_sqrshl_h)
463 DO_ZPZZ(sve2_sqrshl_zpzz_s, int32_t, H1_4, do_sqrshl_s)
464 DO_ZPZZ_D(sve2_sqrshl_zpzz_d, int64_t, do_sqrshl_d)
465
466 #undef do_sqrshl_d
467
468 #define do_uqrshl_b(n, m) \
469 ({ uint32_t discard; do_uqrshl_bhs(n, (int8_t)m, 8, true, &discard); })
470 #define do_uqrshl_h(n, m) \
471 ({ uint32_t discard; do_uqrshl_bhs(n, (int16_t)m, 16, true, &discard); })
472 #define do_uqrshl_s(n, m) \
473 ({ uint32_t discard; do_uqrshl_bhs(n, m, 32, true, &discard); })
474 #define do_uqrshl_d(n, m) \
475 ({ uint32_t discard; do_uqrshl_d(n, m, true, &discard); })
476
477 DO_ZPZZ(sve2_uqrshl_zpzz_b, uint8_t, H1_2, do_uqrshl_b)
478 DO_ZPZZ(sve2_uqrshl_zpzz_h, uint16_t, H1_2, do_uqrshl_h)
479 DO_ZPZZ(sve2_uqrshl_zpzz_s, uint32_t, H1_4, do_uqrshl_s)
480 DO_ZPZZ_D(sve2_uqrshl_zpzz_d, uint64_t, do_uqrshl_d)
481
482 #undef do_uqrshl_d
483
484 #define DO_HADD_BHS(n, m) (((int64_t)n + m) >> 1)
485 #define DO_HADD_D(n, m) ((n >> 1) + (m >> 1) + (n & m & 1))
486
487 DO_ZPZZ(sve2_shadd_zpzz_b, int8_t, H1, DO_HADD_BHS)
488 DO_ZPZZ(sve2_shadd_zpzz_h, int16_t, H1_2, DO_HADD_BHS)
489 DO_ZPZZ(sve2_shadd_zpzz_s, int32_t, H1_4, DO_HADD_BHS)
490 DO_ZPZZ_D(sve2_shadd_zpzz_d, int64_t, DO_HADD_D)
491
492 DO_ZPZZ(sve2_uhadd_zpzz_b, uint8_t, H1, DO_HADD_BHS)
493 DO_ZPZZ(sve2_uhadd_zpzz_h, uint16_t, H1_2, DO_HADD_BHS)
494 DO_ZPZZ(sve2_uhadd_zpzz_s, uint32_t, H1_4, DO_HADD_BHS)
495 DO_ZPZZ_D(sve2_uhadd_zpzz_d, uint64_t, DO_HADD_D)
496
497 #define DO_RHADD_BHS(n, m) (((int64_t)n + m + 1) >> 1)
498 #define DO_RHADD_D(n, m) ((n >> 1) + (m >> 1) + ((n | m) & 1))
499
500 DO_ZPZZ(sve2_srhadd_zpzz_b, int8_t, H1, DO_RHADD_BHS)
501 DO_ZPZZ(sve2_srhadd_zpzz_h, int16_t, H1_2, DO_RHADD_BHS)
502 DO_ZPZZ(sve2_srhadd_zpzz_s, int32_t, H1_4, DO_RHADD_BHS)
503 DO_ZPZZ_D(sve2_srhadd_zpzz_d, int64_t, DO_RHADD_D)
504
505 DO_ZPZZ(sve2_urhadd_zpzz_b, uint8_t, H1, DO_RHADD_BHS)
506 DO_ZPZZ(sve2_urhadd_zpzz_h, uint16_t, H1_2, DO_RHADD_BHS)
507 DO_ZPZZ(sve2_urhadd_zpzz_s, uint32_t, H1_4, DO_RHADD_BHS)
508 DO_ZPZZ_D(sve2_urhadd_zpzz_d, uint64_t, DO_RHADD_D)
509
510 #define DO_HSUB_BHS(n, m) (((int64_t)n - m) >> 1)
511 #define DO_HSUB_D(n, m) ((n >> 1) - (m >> 1) - (~n & m & 1))
512
513 DO_ZPZZ(sve2_shsub_zpzz_b, int8_t, H1, DO_HSUB_BHS)
514 DO_ZPZZ(sve2_shsub_zpzz_h, int16_t, H1_2, DO_HSUB_BHS)
515 DO_ZPZZ(sve2_shsub_zpzz_s, int32_t, H1_4, DO_HSUB_BHS)
516 DO_ZPZZ_D(sve2_shsub_zpzz_d, int64_t, DO_HSUB_D)
517
518 DO_ZPZZ(sve2_uhsub_zpzz_b, uint8_t, H1, DO_HSUB_BHS)
519 DO_ZPZZ(sve2_uhsub_zpzz_h, uint16_t, H1_2, DO_HSUB_BHS)
520 DO_ZPZZ(sve2_uhsub_zpzz_s, uint32_t, H1_4, DO_HSUB_BHS)
521 DO_ZPZZ_D(sve2_uhsub_zpzz_d, uint64_t, DO_HSUB_D)
522
523 static inline int32_t do_sat_bhs(int64_t val, int64_t min, int64_t max)
524 {
525 return val >= max ? max : val <= min ? min : val;
526 }
527
528 #define DO_SQADD_B(n, m) do_sat_bhs((int64_t)n + m, INT8_MIN, INT8_MAX)
529 #define DO_SQADD_H(n, m) do_sat_bhs((int64_t)n + m, INT16_MIN, INT16_MAX)
530 #define DO_SQADD_S(n, m) do_sat_bhs((int64_t)n + m, INT32_MIN, INT32_MAX)
531
do_sqadd_d(int64_t n,int64_t m)532 static inline int64_t do_sqadd_d(int64_t n, int64_t m)
533 {
534 int64_t r = n + m;
535 if (((r ^ n) & ~(n ^ m)) < 0) {
536 /* Signed overflow. */
537 return r < 0 ? INT64_MAX : INT64_MIN;
538 }
539 return r;
540 }
541
DO_ZPZZ(sve2_sqadd_zpzz_b,int8_t,H1,DO_SQADD_B)542 DO_ZPZZ(sve2_sqadd_zpzz_b, int8_t, H1, DO_SQADD_B)
543 DO_ZPZZ(sve2_sqadd_zpzz_h, int16_t, H1_2, DO_SQADD_H)
544 DO_ZPZZ(sve2_sqadd_zpzz_s, int32_t, H1_4, DO_SQADD_S)
545 DO_ZPZZ_D(sve2_sqadd_zpzz_d, int64_t, do_sqadd_d)
546
547 #define DO_UQADD_B(n, m) do_sat_bhs((int64_t)n + m, 0, UINT8_MAX)
548 #define DO_UQADD_H(n, m) do_sat_bhs((int64_t)n + m, 0, UINT16_MAX)
549 #define DO_UQADD_S(n, m) do_sat_bhs((int64_t)n + m, 0, UINT32_MAX)
550
551 static inline uint64_t do_uqadd_d(uint64_t n, uint64_t m)
552 {
553 uint64_t r = n + m;
554 return r < n ? UINT64_MAX : r;
555 }
556
DO_ZPZZ(sve2_uqadd_zpzz_b,uint8_t,H1,DO_UQADD_B)557 DO_ZPZZ(sve2_uqadd_zpzz_b, uint8_t, H1, DO_UQADD_B)
558 DO_ZPZZ(sve2_uqadd_zpzz_h, uint16_t, H1_2, DO_UQADD_H)
559 DO_ZPZZ(sve2_uqadd_zpzz_s, uint32_t, H1_4, DO_UQADD_S)
560 DO_ZPZZ_D(sve2_uqadd_zpzz_d, uint64_t, do_uqadd_d)
561
562 #define DO_SQSUB_B(n, m) do_sat_bhs((int64_t)n - m, INT8_MIN, INT8_MAX)
563 #define DO_SQSUB_H(n, m) do_sat_bhs((int64_t)n - m, INT16_MIN, INT16_MAX)
564 #define DO_SQSUB_S(n, m) do_sat_bhs((int64_t)n - m, INT32_MIN, INT32_MAX)
565
566 static inline int64_t do_sqsub_d(int64_t n, int64_t m)
567 {
568 int64_t r = n - m;
569 if (((r ^ n) & (n ^ m)) < 0) {
570 /* Signed overflow. */
571 return r < 0 ? INT64_MAX : INT64_MIN;
572 }
573 return r;
574 }
575
DO_ZPZZ(sve2_sqsub_zpzz_b,int8_t,H1,DO_SQSUB_B)576 DO_ZPZZ(sve2_sqsub_zpzz_b, int8_t, H1, DO_SQSUB_B)
577 DO_ZPZZ(sve2_sqsub_zpzz_h, int16_t, H1_2, DO_SQSUB_H)
578 DO_ZPZZ(sve2_sqsub_zpzz_s, int32_t, H1_4, DO_SQSUB_S)
579 DO_ZPZZ_D(sve2_sqsub_zpzz_d, int64_t, do_sqsub_d)
580
581 #define DO_UQSUB_B(n, m) do_sat_bhs((int64_t)n - m, 0, UINT8_MAX)
582 #define DO_UQSUB_H(n, m) do_sat_bhs((int64_t)n - m, 0, UINT16_MAX)
583 #define DO_UQSUB_S(n, m) do_sat_bhs((int64_t)n - m, 0, UINT32_MAX)
584
585 static inline uint64_t do_uqsub_d(uint64_t n, uint64_t m)
586 {
587 return n > m ? n - m : 0;
588 }
589
DO_ZPZZ(sve2_uqsub_zpzz_b,uint8_t,H1,DO_UQSUB_B)590 DO_ZPZZ(sve2_uqsub_zpzz_b, uint8_t, H1, DO_UQSUB_B)
591 DO_ZPZZ(sve2_uqsub_zpzz_h, uint16_t, H1_2, DO_UQSUB_H)
592 DO_ZPZZ(sve2_uqsub_zpzz_s, uint32_t, H1_4, DO_UQSUB_S)
593 DO_ZPZZ_D(sve2_uqsub_zpzz_d, uint64_t, do_uqsub_d)
594
595 #define DO_SUQADD_B(n, m) \
596 do_sat_bhs((int64_t)(int8_t)n + m, INT8_MIN, INT8_MAX)
597 #define DO_SUQADD_H(n, m) \
598 do_sat_bhs((int64_t)(int16_t)n + m, INT16_MIN, INT16_MAX)
599 #define DO_SUQADD_S(n, m) \
600 do_sat_bhs((int64_t)(int32_t)n + m, INT32_MIN, INT32_MAX)
601
602 static inline int64_t do_suqadd_d(int64_t n, uint64_t m)
603 {
604 uint64_t r = n + m;
605
606 if (n < 0) {
607 /* Note that m - abs(n) cannot underflow. */
608 if (r > INT64_MAX) {
609 /* Result is either very large positive or negative. */
610 if (m > -n) {
611 /* m > abs(n), so r is a very large positive. */
612 return INT64_MAX;
613 }
614 /* Result is negative. */
615 }
616 } else {
617 /* Both inputs are positive: check for overflow. */
618 if (r < m || r > INT64_MAX) {
619 return INT64_MAX;
620 }
621 }
622 return r;
623 }
624
DO_ZPZZ(sve2_suqadd_zpzz_b,uint8_t,H1,DO_SUQADD_B)625 DO_ZPZZ(sve2_suqadd_zpzz_b, uint8_t, H1, DO_SUQADD_B)
626 DO_ZPZZ(sve2_suqadd_zpzz_h, uint16_t, H1_2, DO_SUQADD_H)
627 DO_ZPZZ(sve2_suqadd_zpzz_s, uint32_t, H1_4, DO_SUQADD_S)
628 DO_ZPZZ_D(sve2_suqadd_zpzz_d, uint64_t, do_suqadd_d)
629
630 #define DO_USQADD_B(n, m) \
631 do_sat_bhs((int64_t)n + (int8_t)m, 0, UINT8_MAX)
632 #define DO_USQADD_H(n, m) \
633 do_sat_bhs((int64_t)n + (int16_t)m, 0, UINT16_MAX)
634 #define DO_USQADD_S(n, m) \
635 do_sat_bhs((int64_t)n + (int32_t)m, 0, UINT32_MAX)
636
637 static inline uint64_t do_usqadd_d(uint64_t n, int64_t m)
638 {
639 uint64_t r = n + m;
640
641 if (m < 0) {
642 return n < -m ? 0 : r;
643 }
644 return r < n ? UINT64_MAX : r;
645 }
646
DO_ZPZZ(sve2_usqadd_zpzz_b,uint8_t,H1,DO_USQADD_B)647 DO_ZPZZ(sve2_usqadd_zpzz_b, uint8_t, H1, DO_USQADD_B)
648 DO_ZPZZ(sve2_usqadd_zpzz_h, uint16_t, H1_2, DO_USQADD_H)
649 DO_ZPZZ(sve2_usqadd_zpzz_s, uint32_t, H1_4, DO_USQADD_S)
650 DO_ZPZZ_D(sve2_usqadd_zpzz_d, uint64_t, do_usqadd_d)
651
652 #undef DO_ZPZZ
653 #undef DO_ZPZZ_D
654
655 /*
656 * Three operand expander, operating on element pairs.
657 * If the slot I is even, the elements from from VN {I, I+1}.
658 * If the slot I is odd, the elements from from VM {I-1, I}.
659 * Load all of the input elements in each pair before overwriting output.
660 */
661 #define DO_ZPZZ_PAIR(NAME, TYPE, H, OP) \
662 void HELPER(NAME)(void *vd, void *vn, void *vm, void *vg, uint32_t desc) \
663 { \
664 intptr_t i, opr_sz = simd_oprsz(desc); \
665 for (i = 0; i < opr_sz; ) { \
666 uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); \
667 do { \
668 TYPE n0 = *(TYPE *)(vn + H(i)); \
669 TYPE m0 = *(TYPE *)(vm + H(i)); \
670 TYPE n1 = *(TYPE *)(vn + H(i + sizeof(TYPE))); \
671 TYPE m1 = *(TYPE *)(vm + H(i + sizeof(TYPE))); \
672 if (pg & 1) { \
673 *(TYPE *)(vd + H(i)) = OP(n0, n1); \
674 } \
675 i += sizeof(TYPE), pg >>= sizeof(TYPE); \
676 if (pg & 1) { \
677 *(TYPE *)(vd + H(i)) = OP(m0, m1); \
678 } \
679 i += sizeof(TYPE), pg >>= sizeof(TYPE); \
680 } while (i & 15); \
681 } \
682 }
683
684 /* Similarly, specialized for 64-bit operands. */
685 #define DO_ZPZZ_PAIR_D(NAME, TYPE, OP) \
686 void HELPER(NAME)(void *vd, void *vn, void *vm, void *vg, uint32_t desc) \
687 { \
688 intptr_t i, opr_sz = simd_oprsz(desc) / 8; \
689 TYPE *d = vd, *n = vn, *m = vm; \
690 uint8_t *pg = vg; \
691 for (i = 0; i < opr_sz; i += 2) { \
692 TYPE n0 = n[i], n1 = n[i + 1]; \
693 TYPE m0 = m[i], m1 = m[i + 1]; \
694 if (pg[H1(i)] & 1) { \
695 d[i] = OP(n0, n1); \
696 } \
697 if (pg[H1(i + 1)] & 1) { \
698 d[i + 1] = OP(m0, m1); \
699 } \
700 } \
701 }
702
703 DO_ZPZZ_PAIR(sve2_addp_zpzz_b, uint8_t, H1, DO_ADD)
704 DO_ZPZZ_PAIR(sve2_addp_zpzz_h, uint16_t, H1_2, DO_ADD)
705 DO_ZPZZ_PAIR(sve2_addp_zpzz_s, uint32_t, H1_4, DO_ADD)
706 DO_ZPZZ_PAIR_D(sve2_addp_zpzz_d, uint64_t, DO_ADD)
707
708 DO_ZPZZ_PAIR(sve2_umaxp_zpzz_b, uint8_t, H1, DO_MAX)
709 DO_ZPZZ_PAIR(sve2_umaxp_zpzz_h, uint16_t, H1_2, DO_MAX)
710 DO_ZPZZ_PAIR(sve2_umaxp_zpzz_s, uint32_t, H1_4, DO_MAX)
711 DO_ZPZZ_PAIR_D(sve2_umaxp_zpzz_d, uint64_t, DO_MAX)
712
713 DO_ZPZZ_PAIR(sve2_uminp_zpzz_b, uint8_t, H1, DO_MIN)
714 DO_ZPZZ_PAIR(sve2_uminp_zpzz_h, uint16_t, H1_2, DO_MIN)
715 DO_ZPZZ_PAIR(sve2_uminp_zpzz_s, uint32_t, H1_4, DO_MIN)
716 DO_ZPZZ_PAIR_D(sve2_uminp_zpzz_d, uint64_t, DO_MIN)
717
718 DO_ZPZZ_PAIR(sve2_smaxp_zpzz_b, int8_t, H1, DO_MAX)
719 DO_ZPZZ_PAIR(sve2_smaxp_zpzz_h, int16_t, H1_2, DO_MAX)
720 DO_ZPZZ_PAIR(sve2_smaxp_zpzz_s, int32_t, H1_4, DO_MAX)
721 DO_ZPZZ_PAIR_D(sve2_smaxp_zpzz_d, int64_t, DO_MAX)
722
723 DO_ZPZZ_PAIR(sve2_sminp_zpzz_b, int8_t, H1, DO_MIN)
724 DO_ZPZZ_PAIR(sve2_sminp_zpzz_h, int16_t, H1_2, DO_MIN)
725 DO_ZPZZ_PAIR(sve2_sminp_zpzz_s, int32_t, H1_4, DO_MIN)
726 DO_ZPZZ_PAIR_D(sve2_sminp_zpzz_d, int64_t, DO_MIN)
727
728 #undef DO_ZPZZ_PAIR
729 #undef DO_ZPZZ_PAIR_D
730
731 #define DO_ZPZZ_PAIR_FP(NAME, TYPE, H, OP) \
732 void HELPER(NAME)(void *vd, void *vn, void *vm, void *vg, \
733 void *status, uint32_t desc) \
734 { \
735 intptr_t i, opr_sz = simd_oprsz(desc); \
736 for (i = 0; i < opr_sz; ) { \
737 uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); \
738 do { \
739 TYPE n0 = *(TYPE *)(vn + H(i)); \
740 TYPE m0 = *(TYPE *)(vm + H(i)); \
741 TYPE n1 = *(TYPE *)(vn + H(i + sizeof(TYPE))); \
742 TYPE m1 = *(TYPE *)(vm + H(i + sizeof(TYPE))); \
743 if (pg & 1) { \
744 *(TYPE *)(vd + H(i)) = OP(n0, n1, status); \
745 } \
746 i += sizeof(TYPE), pg >>= sizeof(TYPE); \
747 if (pg & 1) { \
748 *(TYPE *)(vd + H(i)) = OP(m0, m1, status); \
749 } \
750 i += sizeof(TYPE), pg >>= sizeof(TYPE); \
751 } while (i & 15); \
752 } \
753 }
754
755 DO_ZPZZ_PAIR_FP(sve2_faddp_zpzz_h, float16, H1_2, float16_add)
756 DO_ZPZZ_PAIR_FP(sve2_faddp_zpzz_s, float32, H1_4, float32_add)
757 DO_ZPZZ_PAIR_FP(sve2_faddp_zpzz_d, float64, H1_8, float64_add)
758
759 DO_ZPZZ_PAIR_FP(sve2_fmaxnmp_zpzz_h, float16, H1_2, float16_maxnum)
760 DO_ZPZZ_PAIR_FP(sve2_fmaxnmp_zpzz_s, float32, H1_4, float32_maxnum)
761 DO_ZPZZ_PAIR_FP(sve2_fmaxnmp_zpzz_d, float64, H1_8, float64_maxnum)
762
763 DO_ZPZZ_PAIR_FP(sve2_fminnmp_zpzz_h, float16, H1_2, float16_minnum)
764 DO_ZPZZ_PAIR_FP(sve2_fminnmp_zpzz_s, float32, H1_4, float32_minnum)
765 DO_ZPZZ_PAIR_FP(sve2_fminnmp_zpzz_d, float64, H1_8, float64_minnum)
766
767 DO_ZPZZ_PAIR_FP(sve2_fmaxp_zpzz_h, float16, H1_2, float16_max)
768 DO_ZPZZ_PAIR_FP(sve2_fmaxp_zpzz_s, float32, H1_4, float32_max)
769 DO_ZPZZ_PAIR_FP(sve2_fmaxp_zpzz_d, float64, H1_8, float64_max)
770
771 DO_ZPZZ_PAIR_FP(sve2_fminp_zpzz_h, float16, H1_2, float16_min)
772 DO_ZPZZ_PAIR_FP(sve2_fminp_zpzz_s, float32, H1_4, float32_min)
773 DO_ZPZZ_PAIR_FP(sve2_fminp_zpzz_d, float64, H1_8, float64_min)
774
775 #undef DO_ZPZZ_PAIR_FP
776
777 /* Three-operand expander, controlled by a predicate, in which the
778 * third operand is "wide". That is, for D = N op M, the same 64-bit
779 * value of M is used with all of the narrower values of N.
780 */
781 #define DO_ZPZW(NAME, TYPE, TYPEW, H, OP) \
782 void HELPER(NAME)(void *vd, void *vn, void *vm, void *vg, uint32_t desc) \
783 { \
784 intptr_t i, opr_sz = simd_oprsz(desc); \
785 for (i = 0; i < opr_sz; ) { \
786 uint8_t pg = *(uint8_t *)(vg + H1(i >> 3)); \
787 TYPEW mm = *(TYPEW *)(vm + i); \
788 do { \
789 if (pg & 1) { \
790 TYPE nn = *(TYPE *)(vn + H(i)); \
791 *(TYPE *)(vd + H(i)) = OP(nn, mm); \
792 } \
793 i += sizeof(TYPE), pg >>= sizeof(TYPE); \
794 } while (i & 7); \
795 } \
796 }
797
798 DO_ZPZW(sve_asr_zpzw_b, int8_t, uint64_t, H1, DO_ASR)
799 DO_ZPZW(sve_lsr_zpzw_b, uint8_t, uint64_t, H1, DO_LSR)
800 DO_ZPZW(sve_lsl_zpzw_b, uint8_t, uint64_t, H1, DO_LSL)
801
802 DO_ZPZW(sve_asr_zpzw_h, int16_t, uint64_t, H1_2, DO_ASR)
803 DO_ZPZW(sve_lsr_zpzw_h, uint16_t, uint64_t, H1_2, DO_LSR)
804 DO_ZPZW(sve_lsl_zpzw_h, uint16_t, uint64_t, H1_2, DO_LSL)
805
806 DO_ZPZW(sve_asr_zpzw_s, int32_t, uint64_t, H1_4, DO_ASR)
807 DO_ZPZW(sve_lsr_zpzw_s, uint32_t, uint64_t, H1_4, DO_LSR)
808 DO_ZPZW(sve_lsl_zpzw_s, uint32_t, uint64_t, H1_4, DO_LSL)
809
810 #undef DO_ZPZW
811
812 /* Fully general two-operand expander, controlled by a predicate.
813 */
814 #define DO_ZPZ(NAME, TYPE, H, OP) \
815 void HELPER(NAME)(void *vd, void *vn, void *vg, uint32_t desc) \
816 { \
817 intptr_t i, opr_sz = simd_oprsz(desc); \
818 for (i = 0; i < opr_sz; ) { \
819 uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); \
820 do { \
821 if (pg & 1) { \
822 TYPE nn = *(TYPE *)(vn + H(i)); \
823 *(TYPE *)(vd + H(i)) = OP(nn); \
824 } \
825 i += sizeof(TYPE), pg >>= sizeof(TYPE); \
826 } while (i & 15); \
827 } \
828 }
829
830 /* Similarly, specialized for 64-bit operands. */
831 #define DO_ZPZ_D(NAME, TYPE, OP) \
832 void HELPER(NAME)(void *vd, void *vn, void *vg, uint32_t desc) \
833 { \
834 intptr_t i, opr_sz = simd_oprsz(desc) / 8; \
835 TYPE *d = vd, *n = vn; \
836 uint8_t *pg = vg; \
837 for (i = 0; i < opr_sz; i += 1) { \
838 if (pg[H1(i)] & 1) { \
839 TYPE nn = n[i]; \
840 d[i] = OP(nn); \
841 } \
842 } \
843 }
844
845 #define DO_CLS_B(N) (clrsb32(N) - 24)
846 #define DO_CLS_H(N) (clrsb32(N) - 16)
847
848 DO_ZPZ(sve_cls_b, int8_t, H1, DO_CLS_B)
849 DO_ZPZ(sve_cls_h, int16_t, H1_2, DO_CLS_H)
850 DO_ZPZ(sve_cls_s, int32_t, H1_4, clrsb32)
851 DO_ZPZ_D(sve_cls_d, int64_t, clrsb64)
852
853 #define DO_CLZ_B(N) (clz32(N) - 24)
854 #define DO_CLZ_H(N) (clz32(N) - 16)
855
856 DO_ZPZ(sve_clz_b, uint8_t, H1, DO_CLZ_B)
857 DO_ZPZ(sve_clz_h, uint16_t, H1_2, DO_CLZ_H)
858 DO_ZPZ(sve_clz_s, uint32_t, H1_4, clz32)
859 DO_ZPZ_D(sve_clz_d, uint64_t, clz64)
860
861 DO_ZPZ(sve_cnt_zpz_b, uint8_t, H1, ctpop8)
862 DO_ZPZ(sve_cnt_zpz_h, uint16_t, H1_2, ctpop16)
863 DO_ZPZ(sve_cnt_zpz_s, uint32_t, H1_4, ctpop32)
864 DO_ZPZ_D(sve_cnt_zpz_d, uint64_t, ctpop64)
865
866 #define DO_CNOT(N) (N == 0)
867
868 DO_ZPZ(sve_cnot_b, uint8_t, H1, DO_CNOT)
869 DO_ZPZ(sve_cnot_h, uint16_t, H1_2, DO_CNOT)
870 DO_ZPZ(sve_cnot_s, uint32_t, H1_4, DO_CNOT)
871 DO_ZPZ_D(sve_cnot_d, uint64_t, DO_CNOT)
872
873 #define DO_FABS(N) (N & ((__typeof(N))-1 >> 1))
874
875 DO_ZPZ(sve_fabs_h, uint16_t, H1_2, DO_FABS)
876 DO_ZPZ(sve_fabs_s, uint32_t, H1_4, DO_FABS)
877 DO_ZPZ_D(sve_fabs_d, uint64_t, DO_FABS)
878
879 #define DO_FNEG(N) (N ^ ~((__typeof(N))-1 >> 1))
880
881 DO_ZPZ(sve_fneg_h, uint16_t, H1_2, DO_FNEG)
882 DO_ZPZ(sve_fneg_s, uint32_t, H1_4, DO_FNEG)
883 DO_ZPZ_D(sve_fneg_d, uint64_t, DO_FNEG)
884
885 #define DO_NOT(N) (~N)
886
887 DO_ZPZ(sve_not_zpz_b, uint8_t, H1, DO_NOT)
888 DO_ZPZ(sve_not_zpz_h, uint16_t, H1_2, DO_NOT)
889 DO_ZPZ(sve_not_zpz_s, uint32_t, H1_4, DO_NOT)
890 DO_ZPZ_D(sve_not_zpz_d, uint64_t, DO_NOT)
891
892 #define DO_SXTB(N) ((int8_t)N)
893 #define DO_SXTH(N) ((int16_t)N)
894 #define DO_SXTS(N) ((int32_t)N)
895 #define DO_UXTB(N) ((uint8_t)N)
896 #define DO_UXTH(N) ((uint16_t)N)
897 #define DO_UXTS(N) ((uint32_t)N)
898
899 DO_ZPZ(sve_sxtb_h, uint16_t, H1_2, DO_SXTB)
900 DO_ZPZ(sve_sxtb_s, uint32_t, H1_4, DO_SXTB)
901 DO_ZPZ(sve_sxth_s, uint32_t, H1_4, DO_SXTH)
902 DO_ZPZ_D(sve_sxtb_d, uint64_t, DO_SXTB)
903 DO_ZPZ_D(sve_sxth_d, uint64_t, DO_SXTH)
904 DO_ZPZ_D(sve_sxtw_d, uint64_t, DO_SXTS)
905
906 DO_ZPZ(sve_uxtb_h, uint16_t, H1_2, DO_UXTB)
907 DO_ZPZ(sve_uxtb_s, uint32_t, H1_4, DO_UXTB)
908 DO_ZPZ(sve_uxth_s, uint32_t, H1_4, DO_UXTH)
909 DO_ZPZ_D(sve_uxtb_d, uint64_t, DO_UXTB)
910 DO_ZPZ_D(sve_uxth_d, uint64_t, DO_UXTH)
911 DO_ZPZ_D(sve_uxtw_d, uint64_t, DO_UXTS)
912
913 #define DO_ABS(N) (N < 0 ? -N : N)
914
915 DO_ZPZ(sve_abs_b, int8_t, H1, DO_ABS)
916 DO_ZPZ(sve_abs_h, int16_t, H1_2, DO_ABS)
917 DO_ZPZ(sve_abs_s, int32_t, H1_4, DO_ABS)
918 DO_ZPZ_D(sve_abs_d, int64_t, DO_ABS)
919
920 #define DO_NEG(N) (-N)
921
922 DO_ZPZ(sve_neg_b, uint8_t, H1, DO_NEG)
923 DO_ZPZ(sve_neg_h, uint16_t, H1_2, DO_NEG)
924 DO_ZPZ(sve_neg_s, uint32_t, H1_4, DO_NEG)
925 DO_ZPZ_D(sve_neg_d, uint64_t, DO_NEG)
926
927 DO_ZPZ(sve_revb_h, uint16_t, H1_2, bswap16)
928 DO_ZPZ(sve_revb_s, uint32_t, H1_4, bswap32)
929 DO_ZPZ_D(sve_revb_d, uint64_t, bswap64)
930
931 DO_ZPZ(sve_revh_s, uint32_t, H1_4, hswap32)
932 DO_ZPZ_D(sve_revh_d, uint64_t, hswap64)
933
934 DO_ZPZ_D(sve_revw_d, uint64_t, wswap64)
935
936 void HELPER(sme_revd_q)(void *vd, void *vn, void *vg, uint32_t desc)
937 {
938 intptr_t i, opr_sz = simd_oprsz(desc) / 8;
939 uint64_t *d = vd, *n = vn;
940 uint8_t *pg = vg;
941
942 for (i = 0; i < opr_sz; i += 2) {
943 if (pg[H1(i)] & 1) {
944 uint64_t n0 = n[i + 0];
945 uint64_t n1 = n[i + 1];
946 d[i + 0] = n1;
947 d[i + 1] = n0;
948 }
949 }
950 }
951
DO_ZPZ(sve_rbit_b,uint8_t,H1,revbit8)952 DO_ZPZ(sve_rbit_b, uint8_t, H1, revbit8)
953 DO_ZPZ(sve_rbit_h, uint16_t, H1_2, revbit16)
954 DO_ZPZ(sve_rbit_s, uint32_t, H1_4, revbit32)
955 DO_ZPZ_D(sve_rbit_d, uint64_t, revbit64)
956
957 #define DO_SQABS(X) \
958 ({ __typeof(X) x_ = (X), min_ = 1ull << (sizeof(X) * 8 - 1); \
959 x_ >= 0 ? x_ : x_ == min_ ? -min_ - 1 : -x_; })
960
961 DO_ZPZ(sve2_sqabs_b, int8_t, H1, DO_SQABS)
962 DO_ZPZ(sve2_sqabs_h, int16_t, H1_2, DO_SQABS)
963 DO_ZPZ(sve2_sqabs_s, int32_t, H1_4, DO_SQABS)
964 DO_ZPZ_D(sve2_sqabs_d, int64_t, DO_SQABS)
965
966 #define DO_SQNEG(X) \
967 ({ __typeof(X) x_ = (X), min_ = 1ull << (sizeof(X) * 8 - 1); \
968 x_ == min_ ? -min_ - 1 : -x_; })
969
970 DO_ZPZ(sve2_sqneg_b, uint8_t, H1, DO_SQNEG)
971 DO_ZPZ(sve2_sqneg_h, uint16_t, H1_2, DO_SQNEG)
972 DO_ZPZ(sve2_sqneg_s, uint32_t, H1_4, DO_SQNEG)
973 DO_ZPZ_D(sve2_sqneg_d, uint64_t, DO_SQNEG)
974
975 DO_ZPZ(sve2_urecpe_s, uint32_t, H1_4, helper_recpe_u32)
976 DO_ZPZ(sve2_ursqrte_s, uint32_t, H1_4, helper_rsqrte_u32)
977
978 /* Three-operand expander, unpredicated, in which the third operand is "wide".
979 */
980 #define DO_ZZW(NAME, TYPE, TYPEW, H, OP) \
981 void HELPER(NAME)(void *vd, void *vn, void *vm, uint32_t desc) \
982 { \
983 intptr_t i, opr_sz = simd_oprsz(desc); \
984 for (i = 0; i < opr_sz; ) { \
985 TYPEW mm = *(TYPEW *)(vm + i); \
986 do { \
987 TYPE nn = *(TYPE *)(vn + H(i)); \
988 *(TYPE *)(vd + H(i)) = OP(nn, mm); \
989 i += sizeof(TYPE); \
990 } while (i & 7); \
991 } \
992 }
993
994 DO_ZZW(sve_asr_zzw_b, int8_t, uint64_t, H1, DO_ASR)
995 DO_ZZW(sve_lsr_zzw_b, uint8_t, uint64_t, H1, DO_LSR)
996 DO_ZZW(sve_lsl_zzw_b, uint8_t, uint64_t, H1, DO_LSL)
997
998 DO_ZZW(sve_asr_zzw_h, int16_t, uint64_t, H1_2, DO_ASR)
999 DO_ZZW(sve_lsr_zzw_h, uint16_t, uint64_t, H1_2, DO_LSR)
1000 DO_ZZW(sve_lsl_zzw_h, uint16_t, uint64_t, H1_2, DO_LSL)
1001
1002 DO_ZZW(sve_asr_zzw_s, int32_t, uint64_t, H1_4, DO_ASR)
1003 DO_ZZW(sve_lsr_zzw_s, uint32_t, uint64_t, H1_4, DO_LSR)
1004 DO_ZZW(sve_lsl_zzw_s, uint32_t, uint64_t, H1_4, DO_LSL)
1005
1006 #undef DO_ZZW
1007
1008 #undef DO_CLS_B
1009 #undef DO_CLS_H
1010 #undef DO_CLZ_B
1011 #undef DO_CLZ_H
1012 #undef DO_CNOT
1013 #undef DO_FABS
1014 #undef DO_FNEG
1015 #undef DO_ABS
1016 #undef DO_NEG
1017 #undef DO_ZPZ
1018 #undef DO_ZPZ_D
1019
1020 /*
1021 * Three-operand expander, unpredicated, in which the two inputs are
1022 * selected from the top or bottom half of the wide column.
1023 */
1024 #define DO_ZZZ_TB(NAME, TYPEW, TYPEN, HW, HN, OP) \
1025 void HELPER(NAME)(void *vd, void *vn, void *vm, uint32_t desc) \
1026 { \
1027 intptr_t i, opr_sz = simd_oprsz(desc); \
1028 int sel1 = extract32(desc, SIMD_DATA_SHIFT, 1) * sizeof(TYPEN); \
1029 int sel2 = extract32(desc, SIMD_DATA_SHIFT + 1, 1) * sizeof(TYPEN); \
1030 for (i = 0; i < opr_sz; i += sizeof(TYPEW)) { \
1031 TYPEW nn = *(TYPEN *)(vn + HN(i + sel1)); \
1032 TYPEW mm = *(TYPEN *)(vm + HN(i + sel2)); \
1033 *(TYPEW *)(vd + HW(i)) = OP(nn, mm); \
1034 } \
1035 }
1036
1037 DO_ZZZ_TB(sve2_saddl_h, int16_t, int8_t, H1_2, H1, DO_ADD)
1038 DO_ZZZ_TB(sve2_saddl_s, int32_t, int16_t, H1_4, H1_2, DO_ADD)
1039 DO_ZZZ_TB(sve2_saddl_d, int64_t, int32_t, H1_8, H1_4, DO_ADD)
1040
1041 DO_ZZZ_TB(sve2_ssubl_h, int16_t, int8_t, H1_2, H1, DO_SUB)
1042 DO_ZZZ_TB(sve2_ssubl_s, int32_t, int16_t, H1_4, H1_2, DO_SUB)
1043 DO_ZZZ_TB(sve2_ssubl_d, int64_t, int32_t, H1_8, H1_4, DO_SUB)
1044
1045 DO_ZZZ_TB(sve2_sabdl_h, int16_t, int8_t, H1_2, H1, DO_ABD)
1046 DO_ZZZ_TB(sve2_sabdl_s, int32_t, int16_t, H1_4, H1_2, DO_ABD)
1047 DO_ZZZ_TB(sve2_sabdl_d, int64_t, int32_t, H1_8, H1_4, DO_ABD)
1048
1049 DO_ZZZ_TB(sve2_uaddl_h, uint16_t, uint8_t, H1_2, H1, DO_ADD)
1050 DO_ZZZ_TB(sve2_uaddl_s, uint32_t, uint16_t, H1_4, H1_2, DO_ADD)
1051 DO_ZZZ_TB(sve2_uaddl_d, uint64_t, uint32_t, H1_8, H1_4, DO_ADD)
1052
1053 DO_ZZZ_TB(sve2_usubl_h, uint16_t, uint8_t, H1_2, H1, DO_SUB)
1054 DO_ZZZ_TB(sve2_usubl_s, uint32_t, uint16_t, H1_4, H1_2, DO_SUB)
1055 DO_ZZZ_TB(sve2_usubl_d, uint64_t, uint32_t, H1_8, H1_4, DO_SUB)
1056
1057 DO_ZZZ_TB(sve2_uabdl_h, uint16_t, uint8_t, H1_2, H1, DO_ABD)
1058 DO_ZZZ_TB(sve2_uabdl_s, uint32_t, uint16_t, H1_4, H1_2, DO_ABD)
1059 DO_ZZZ_TB(sve2_uabdl_d, uint64_t, uint32_t, H1_8, H1_4, DO_ABD)
1060
1061 DO_ZZZ_TB(sve2_smull_zzz_h, int16_t, int8_t, H1_2, H1, DO_MUL)
1062 DO_ZZZ_TB(sve2_smull_zzz_s, int32_t, int16_t, H1_4, H1_2, DO_MUL)
1063 DO_ZZZ_TB(sve2_smull_zzz_d, int64_t, int32_t, H1_8, H1_4, DO_MUL)
1064
1065 DO_ZZZ_TB(sve2_umull_zzz_h, uint16_t, uint8_t, H1_2, H1, DO_MUL)
1066 DO_ZZZ_TB(sve2_umull_zzz_s, uint32_t, uint16_t, H1_4, H1_2, DO_MUL)
1067 DO_ZZZ_TB(sve2_umull_zzz_d, uint64_t, uint32_t, H1_8, H1_4, DO_MUL)
1068
1069 /* Note that the multiply cannot overflow, but the doubling can. */
1070 static inline int16_t do_sqdmull_h(int16_t n, int16_t m)
1071 {
1072 int16_t val = n * m;
1073 return DO_SQADD_H(val, val);
1074 }
1075
do_sqdmull_s(int32_t n,int32_t m)1076 static inline int32_t do_sqdmull_s(int32_t n, int32_t m)
1077 {
1078 int32_t val = n * m;
1079 return DO_SQADD_S(val, val);
1080 }
1081
do_sqdmull_d(int64_t n,int64_t m)1082 static inline int64_t do_sqdmull_d(int64_t n, int64_t m)
1083 {
1084 int64_t val = n * m;
1085 return do_sqadd_d(val, val);
1086 }
1087
DO_ZZZ_TB(sve2_sqdmull_zzz_h,int16_t,int8_t,H1_2,H1,do_sqdmull_h)1088 DO_ZZZ_TB(sve2_sqdmull_zzz_h, int16_t, int8_t, H1_2, H1, do_sqdmull_h)
1089 DO_ZZZ_TB(sve2_sqdmull_zzz_s, int32_t, int16_t, H1_4, H1_2, do_sqdmull_s)
1090 DO_ZZZ_TB(sve2_sqdmull_zzz_d, int64_t, int32_t, H1_8, H1_4, do_sqdmull_d)
1091
1092 #undef DO_ZZZ_TB
1093
1094 #define DO_ZZZ_WTB(NAME, TYPEW, TYPEN, HW, HN, OP) \
1095 void HELPER(NAME)(void *vd, void *vn, void *vm, uint32_t desc) \
1096 { \
1097 intptr_t i, opr_sz = simd_oprsz(desc); \
1098 int sel2 = extract32(desc, SIMD_DATA_SHIFT, 1) * sizeof(TYPEN); \
1099 for (i = 0; i < opr_sz; i += sizeof(TYPEW)) { \
1100 TYPEW nn = *(TYPEW *)(vn + HW(i)); \
1101 TYPEW mm = *(TYPEN *)(vm + HN(i + sel2)); \
1102 *(TYPEW *)(vd + HW(i)) = OP(nn, mm); \
1103 } \
1104 }
1105
1106 DO_ZZZ_WTB(sve2_saddw_h, int16_t, int8_t, H1_2, H1, DO_ADD)
1107 DO_ZZZ_WTB(sve2_saddw_s, int32_t, int16_t, H1_4, H1_2, DO_ADD)
1108 DO_ZZZ_WTB(sve2_saddw_d, int64_t, int32_t, H1_8, H1_4, DO_ADD)
1109
1110 DO_ZZZ_WTB(sve2_ssubw_h, int16_t, int8_t, H1_2, H1, DO_SUB)
1111 DO_ZZZ_WTB(sve2_ssubw_s, int32_t, int16_t, H1_4, H1_2, DO_SUB)
1112 DO_ZZZ_WTB(sve2_ssubw_d, int64_t, int32_t, H1_8, H1_4, DO_SUB)
1113
1114 DO_ZZZ_WTB(sve2_uaddw_h, uint16_t, uint8_t, H1_2, H1, DO_ADD)
1115 DO_ZZZ_WTB(sve2_uaddw_s, uint32_t, uint16_t, H1_4, H1_2, DO_ADD)
1116 DO_ZZZ_WTB(sve2_uaddw_d, uint64_t, uint32_t, H1_8, H1_4, DO_ADD)
1117
1118 DO_ZZZ_WTB(sve2_usubw_h, uint16_t, uint8_t, H1_2, H1, DO_SUB)
1119 DO_ZZZ_WTB(sve2_usubw_s, uint32_t, uint16_t, H1_4, H1_2, DO_SUB)
1120 DO_ZZZ_WTB(sve2_usubw_d, uint64_t, uint32_t, H1_8, H1_4, DO_SUB)
1121
1122 #undef DO_ZZZ_WTB
1123
1124 #define DO_ZZZ_NTB(NAME, TYPE, H, OP) \
1125 void HELPER(NAME)(void *vd, void *vn, void *vm, uint32_t desc) \
1126 { \
1127 intptr_t i, opr_sz = simd_oprsz(desc); \
1128 intptr_t sel1 = extract32(desc, SIMD_DATA_SHIFT, 1) * sizeof(TYPE); \
1129 intptr_t sel2 = extract32(desc, SIMD_DATA_SHIFT + 1, 1) * sizeof(TYPE); \
1130 for (i = 0; i < opr_sz; i += 2 * sizeof(TYPE)) { \
1131 TYPE nn = *(TYPE *)(vn + H(i + sel1)); \
1132 TYPE mm = *(TYPE *)(vm + H(i + sel2)); \
1133 *(TYPE *)(vd + H(i + sel1)) = OP(nn, mm); \
1134 } \
1135 }
1136
1137 DO_ZZZ_NTB(sve2_eoril_b, uint8_t, H1, DO_EOR)
1138 DO_ZZZ_NTB(sve2_eoril_h, uint16_t, H1_2, DO_EOR)
1139 DO_ZZZ_NTB(sve2_eoril_s, uint32_t, H1_4, DO_EOR)
1140 DO_ZZZ_NTB(sve2_eoril_d, uint64_t, H1_8, DO_EOR)
1141
1142 #undef DO_ZZZ_NTB
1143
1144 #define DO_ZZZW_ACC(NAME, TYPEW, TYPEN, HW, HN, OP) \
1145 void HELPER(NAME)(void *vd, void *vn, void *vm, void *va, uint32_t desc) \
1146 { \
1147 intptr_t i, opr_sz = simd_oprsz(desc); \
1148 intptr_t sel1 = simd_data(desc) * sizeof(TYPEN); \
1149 for (i = 0; i < opr_sz; i += sizeof(TYPEW)) { \
1150 TYPEW nn = *(TYPEN *)(vn + HN(i + sel1)); \
1151 TYPEW mm = *(TYPEN *)(vm + HN(i + sel1)); \
1152 TYPEW aa = *(TYPEW *)(va + HW(i)); \
1153 *(TYPEW *)(vd + HW(i)) = OP(nn, mm) + aa; \
1154 } \
1155 }
1156
1157 DO_ZZZW_ACC(sve2_sabal_h, int16_t, int8_t, H1_2, H1, DO_ABD)
1158 DO_ZZZW_ACC(sve2_sabal_s, int32_t, int16_t, H1_4, H1_2, DO_ABD)
1159 DO_ZZZW_ACC(sve2_sabal_d, int64_t, int32_t, H1_8, H1_4, DO_ABD)
1160
1161 DO_ZZZW_ACC(sve2_uabal_h, uint16_t, uint8_t, H1_2, H1, DO_ABD)
1162 DO_ZZZW_ACC(sve2_uabal_s, uint32_t, uint16_t, H1_4, H1_2, DO_ABD)
1163 DO_ZZZW_ACC(sve2_uabal_d, uint64_t, uint32_t, H1_8, H1_4, DO_ABD)
1164
1165 DO_ZZZW_ACC(sve2_smlal_zzzw_h, int16_t, int8_t, H1_2, H1, DO_MUL)
1166 DO_ZZZW_ACC(sve2_smlal_zzzw_s, int32_t, int16_t, H1_4, H1_2, DO_MUL)
1167 DO_ZZZW_ACC(sve2_smlal_zzzw_d, int64_t, int32_t, H1_8, H1_4, DO_MUL)
1168
1169 DO_ZZZW_ACC(sve2_umlal_zzzw_h, uint16_t, uint8_t, H1_2, H1, DO_MUL)
1170 DO_ZZZW_ACC(sve2_umlal_zzzw_s, uint32_t, uint16_t, H1_4, H1_2, DO_MUL)
1171 DO_ZZZW_ACC(sve2_umlal_zzzw_d, uint64_t, uint32_t, H1_8, H1_4, DO_MUL)
1172
1173 #define DO_NMUL(N, M) -(N * M)
1174
1175 DO_ZZZW_ACC(sve2_smlsl_zzzw_h, int16_t, int8_t, H1_2, H1, DO_NMUL)
1176 DO_ZZZW_ACC(sve2_smlsl_zzzw_s, int32_t, int16_t, H1_4, H1_2, DO_NMUL)
1177 DO_ZZZW_ACC(sve2_smlsl_zzzw_d, int64_t, int32_t, H1_8, H1_4, DO_NMUL)
1178
1179 DO_ZZZW_ACC(sve2_umlsl_zzzw_h, uint16_t, uint8_t, H1_2, H1, DO_NMUL)
1180 DO_ZZZW_ACC(sve2_umlsl_zzzw_s, uint32_t, uint16_t, H1_4, H1_2, DO_NMUL)
1181 DO_ZZZW_ACC(sve2_umlsl_zzzw_d, uint64_t, uint32_t, H1_8, H1_4, DO_NMUL)
1182
1183 #undef DO_ZZZW_ACC
1184
1185 #define DO_XTNB(NAME, TYPE, OP) \
1186 void HELPER(NAME)(void *vd, void *vn, uint32_t desc) \
1187 { \
1188 intptr_t i, opr_sz = simd_oprsz(desc); \
1189 for (i = 0; i < opr_sz; i += sizeof(TYPE)) { \
1190 TYPE nn = *(TYPE *)(vn + i); \
1191 nn = OP(nn) & MAKE_64BIT_MASK(0, sizeof(TYPE) * 4); \
1192 *(TYPE *)(vd + i) = nn; \
1193 } \
1194 }
1195
1196 #define DO_XTNT(NAME, TYPE, TYPEN, H, OP) \
1197 void HELPER(NAME)(void *vd, void *vn, uint32_t desc) \
1198 { \
1199 intptr_t i, opr_sz = simd_oprsz(desc), odd = H(sizeof(TYPEN)); \
1200 for (i = 0; i < opr_sz; i += sizeof(TYPE)) { \
1201 TYPE nn = *(TYPE *)(vn + i); \
1202 *(TYPEN *)(vd + i + odd) = OP(nn); \
1203 } \
1204 }
1205
1206 #define DO_SQXTN_H(n) do_sat_bhs(n, INT8_MIN, INT8_MAX)
1207 #define DO_SQXTN_S(n) do_sat_bhs(n, INT16_MIN, INT16_MAX)
1208 #define DO_SQXTN_D(n) do_sat_bhs(n, INT32_MIN, INT32_MAX)
1209
1210 DO_XTNB(sve2_sqxtnb_h, int16_t, DO_SQXTN_H)
1211 DO_XTNB(sve2_sqxtnb_s, int32_t, DO_SQXTN_S)
1212 DO_XTNB(sve2_sqxtnb_d, int64_t, DO_SQXTN_D)
1213
1214 DO_XTNT(sve2_sqxtnt_h, int16_t, int8_t, H1, DO_SQXTN_H)
1215 DO_XTNT(sve2_sqxtnt_s, int32_t, int16_t, H1_2, DO_SQXTN_S)
1216 DO_XTNT(sve2_sqxtnt_d, int64_t, int32_t, H1_4, DO_SQXTN_D)
1217
1218 #define DO_UQXTN_H(n) do_sat_bhs(n, 0, UINT8_MAX)
1219 #define DO_UQXTN_S(n) do_sat_bhs(n, 0, UINT16_MAX)
1220 #define DO_UQXTN_D(n) do_sat_bhs(n, 0, UINT32_MAX)
1221
1222 DO_XTNB(sve2_uqxtnb_h, uint16_t, DO_UQXTN_H)
1223 DO_XTNB(sve2_uqxtnb_s, uint32_t, DO_UQXTN_S)
1224 DO_XTNB(sve2_uqxtnb_d, uint64_t, DO_UQXTN_D)
1225
1226 DO_XTNT(sve2_uqxtnt_h, uint16_t, uint8_t, H1, DO_UQXTN_H)
1227 DO_XTNT(sve2_uqxtnt_s, uint32_t, uint16_t, H1_2, DO_UQXTN_S)
1228 DO_XTNT(sve2_uqxtnt_d, uint64_t, uint32_t, H1_4, DO_UQXTN_D)
1229
1230 DO_XTNB(sve2_sqxtunb_h, int16_t, DO_UQXTN_H)
1231 DO_XTNB(sve2_sqxtunb_s, int32_t, DO_UQXTN_S)
1232 DO_XTNB(sve2_sqxtunb_d, int64_t, DO_UQXTN_D)
1233
1234 DO_XTNT(sve2_sqxtunt_h, int16_t, int8_t, H1, DO_UQXTN_H)
1235 DO_XTNT(sve2_sqxtunt_s, int32_t, int16_t, H1_2, DO_UQXTN_S)
1236 DO_XTNT(sve2_sqxtunt_d, int64_t, int32_t, H1_4, DO_UQXTN_D)
1237
1238 #undef DO_XTNB
1239 #undef DO_XTNT
1240
1241 void HELPER(sve2_adcl_s)(void *vd, void *vn, void *vm, void *va, uint32_t desc)
1242 {
1243 intptr_t i, opr_sz = simd_oprsz(desc);
1244 int sel = H4(extract32(desc, SIMD_DATA_SHIFT, 1));
1245 uint32_t inv = -extract32(desc, SIMD_DATA_SHIFT + 1, 1);
1246 uint32_t *a = va, *n = vn;
1247 uint64_t *d = vd, *m = vm;
1248
1249 for (i = 0; i < opr_sz / 8; ++i) {
1250 uint32_t e1 = a[2 * i + H4(0)];
1251 uint32_t e2 = n[2 * i + sel] ^ inv;
1252 uint64_t c = extract64(m[i], 32, 1);
1253 /* Compute and store the entire 33-bit result at once. */
1254 d[i] = c + e1 + e2;
1255 }
1256 }
1257
HELPER(sve2_adcl_d)1258 void HELPER(sve2_adcl_d)(void *vd, void *vn, void *vm, void *va, uint32_t desc)
1259 {
1260 intptr_t i, opr_sz = simd_oprsz(desc);
1261 int sel = extract32(desc, SIMD_DATA_SHIFT, 1);
1262 uint64_t inv = -(uint64_t)extract32(desc, SIMD_DATA_SHIFT + 1, 1);
1263 uint64_t *d = vd, *a = va, *n = vn, *m = vm;
1264
1265 for (i = 0; i < opr_sz / 8; i += 2) {
1266 Int128 e1 = int128_make64(a[i]);
1267 Int128 e2 = int128_make64(n[i + sel] ^ inv);
1268 Int128 c = int128_make64(m[i + 1] & 1);
1269 Int128 r = int128_add(int128_add(e1, e2), c);
1270 d[i + 0] = int128_getlo(r);
1271 d[i + 1] = int128_gethi(r);
1272 }
1273 }
1274
1275 #define DO_SQDMLAL(NAME, TYPEW, TYPEN, HW, HN, DMUL_OP, SUM_OP) \
1276 void HELPER(NAME)(void *vd, void *vn, void *vm, void *va, uint32_t desc) \
1277 { \
1278 intptr_t i, opr_sz = simd_oprsz(desc); \
1279 int sel1 = extract32(desc, SIMD_DATA_SHIFT, 1) * sizeof(TYPEN); \
1280 int sel2 = extract32(desc, SIMD_DATA_SHIFT + 1, 1) * sizeof(TYPEN); \
1281 for (i = 0; i < opr_sz; i += sizeof(TYPEW)) { \
1282 TYPEW nn = *(TYPEN *)(vn + HN(i + sel1)); \
1283 TYPEW mm = *(TYPEN *)(vm + HN(i + sel2)); \
1284 TYPEW aa = *(TYPEW *)(va + HW(i)); \
1285 *(TYPEW *)(vd + HW(i)) = SUM_OP(aa, DMUL_OP(nn, mm)); \
1286 } \
1287 }
1288
DO_SQDMLAL(sve2_sqdmlal_zzzw_h,int16_t,int8_t,H1_2,H1,do_sqdmull_h,DO_SQADD_H)1289 DO_SQDMLAL(sve2_sqdmlal_zzzw_h, int16_t, int8_t, H1_2, H1,
1290 do_sqdmull_h, DO_SQADD_H)
1291 DO_SQDMLAL(sve2_sqdmlal_zzzw_s, int32_t, int16_t, H1_4, H1_2,
1292 do_sqdmull_s, DO_SQADD_S)
1293 DO_SQDMLAL(sve2_sqdmlal_zzzw_d, int64_t, int32_t, H1_8, H1_4,
1294 do_sqdmull_d, do_sqadd_d)
1295
1296 DO_SQDMLAL(sve2_sqdmlsl_zzzw_h, int16_t, int8_t, H1_2, H1,
1297 do_sqdmull_h, DO_SQSUB_H)
1298 DO_SQDMLAL(sve2_sqdmlsl_zzzw_s, int32_t, int16_t, H1_4, H1_2,
1299 do_sqdmull_s, DO_SQSUB_S)
1300 DO_SQDMLAL(sve2_sqdmlsl_zzzw_d, int64_t, int32_t, H1_8, H1_4,
1301 do_sqdmull_d, do_sqsub_d)
1302
1303 #undef DO_SQDMLAL
1304
1305 #define DO_CMLA_FUNC(NAME, TYPE, H, OP) \
1306 void HELPER(NAME)(void *vd, void *vn, void *vm, void *va, uint32_t desc) \
1307 { \
1308 intptr_t i, opr_sz = simd_oprsz(desc) / sizeof(TYPE); \
1309 int rot = simd_data(desc); \
1310 int sel_a = rot & 1, sel_b = sel_a ^ 1; \
1311 bool sub_r = rot == 1 || rot == 2; \
1312 bool sub_i = rot >= 2; \
1313 TYPE *d = vd, *n = vn, *m = vm, *a = va; \
1314 for (i = 0; i < opr_sz; i += 2) { \
1315 TYPE elt1_a = n[H(i + sel_a)]; \
1316 TYPE elt2_a = m[H(i + sel_a)]; \
1317 TYPE elt2_b = m[H(i + sel_b)]; \
1318 d[H(i)] = OP(elt1_a, elt2_a, a[H(i)], sub_r); \
1319 d[H(i + 1)] = OP(elt1_a, elt2_b, a[H(i + 1)], sub_i); \
1320 } \
1321 }
1322
1323 #define DO_CMLA(N, M, A, S) (A + (N * M) * (S ? -1 : 1))
1324
1325 DO_CMLA_FUNC(sve2_cmla_zzzz_b, uint8_t, H1, DO_CMLA)
1326 DO_CMLA_FUNC(sve2_cmla_zzzz_h, uint16_t, H2, DO_CMLA)
1327 DO_CMLA_FUNC(sve2_cmla_zzzz_s, uint32_t, H4, DO_CMLA)
1328 DO_CMLA_FUNC(sve2_cmla_zzzz_d, uint64_t, H8, DO_CMLA)
1329
1330 #define DO_SQRDMLAH_B(N, M, A, S) \
1331 do_sqrdmlah_b(N, M, A, S, true)
1332 #define DO_SQRDMLAH_H(N, M, A, S) \
1333 ({ uint32_t discard; do_sqrdmlah_h(N, M, A, S, true, &discard); })
1334 #define DO_SQRDMLAH_S(N, M, A, S) \
1335 ({ uint32_t discard; do_sqrdmlah_s(N, M, A, S, true, &discard); })
1336 #define DO_SQRDMLAH_D(N, M, A, S) \
1337 do_sqrdmlah_d(N, M, A, S, true)
1338
1339 DO_CMLA_FUNC(sve2_sqrdcmlah_zzzz_b, int8_t, H1, DO_SQRDMLAH_B)
1340 DO_CMLA_FUNC(sve2_sqrdcmlah_zzzz_h, int16_t, H2, DO_SQRDMLAH_H)
1341 DO_CMLA_FUNC(sve2_sqrdcmlah_zzzz_s, int32_t, H4, DO_SQRDMLAH_S)
1342 DO_CMLA_FUNC(sve2_sqrdcmlah_zzzz_d, int64_t, H8, DO_SQRDMLAH_D)
1343
1344 #define DO_CMLA_IDX_FUNC(NAME, TYPE, H, OP) \
1345 void HELPER(NAME)(void *vd, void *vn, void *vm, void *va, uint32_t desc) \
1346 { \
1347 intptr_t i, j, oprsz = simd_oprsz(desc); \
1348 int rot = extract32(desc, SIMD_DATA_SHIFT, 2); \
1349 int idx = extract32(desc, SIMD_DATA_SHIFT + 2, 2) * 2; \
1350 int sel_a = rot & 1, sel_b = sel_a ^ 1; \
1351 bool sub_r = rot == 1 || rot == 2; \
1352 bool sub_i = rot >= 2; \
1353 TYPE *d = vd, *n = vn, *m = vm, *a = va; \
1354 for (i = 0; i < oprsz / sizeof(TYPE); i += 16 / sizeof(TYPE)) { \
1355 TYPE elt2_a = m[H(i + idx + sel_a)]; \
1356 TYPE elt2_b = m[H(i + idx + sel_b)]; \
1357 for (j = 0; j < 16 / sizeof(TYPE); j += 2) { \
1358 TYPE elt1_a = n[H(i + j + sel_a)]; \
1359 d[H2(i + j)] = OP(elt1_a, elt2_a, a[H(i + j)], sub_r); \
1360 d[H2(i + j + 1)] = OP(elt1_a, elt2_b, a[H(i + j + 1)], sub_i); \
1361 } \
1362 } \
1363 }
1364
1365 DO_CMLA_IDX_FUNC(sve2_cmla_idx_h, int16_t, H2, DO_CMLA)
1366 DO_CMLA_IDX_FUNC(sve2_cmla_idx_s, int32_t, H4, DO_CMLA)
1367
1368 DO_CMLA_IDX_FUNC(sve2_sqrdcmlah_idx_h, int16_t, H2, DO_SQRDMLAH_H)
1369 DO_CMLA_IDX_FUNC(sve2_sqrdcmlah_idx_s, int32_t, H4, DO_SQRDMLAH_S)
1370
1371 #undef DO_CMLA
1372 #undef DO_CMLA_FUNC
1373 #undef DO_CMLA_IDX_FUNC
1374 #undef DO_SQRDMLAH_B
1375 #undef DO_SQRDMLAH_H
1376 #undef DO_SQRDMLAH_S
1377 #undef DO_SQRDMLAH_D
1378
1379 /* Note N and M are 4 elements bundled into one unit. */
1380 static int32_t do_cdot_s(uint32_t n, uint32_t m, int32_t a,
1381 int sel_a, int sel_b, int sub_i)
1382 {
1383 for (int i = 0; i <= 1; i++) {
1384 int32_t elt1_r = (int8_t)(n >> (16 * i));
1385 int32_t elt1_i = (int8_t)(n >> (16 * i + 8));
1386 int32_t elt2_a = (int8_t)(m >> (16 * i + 8 * sel_a));
1387 int32_t elt2_b = (int8_t)(m >> (16 * i + 8 * sel_b));
1388
1389 a += elt1_r * elt2_a + elt1_i * elt2_b * sub_i;
1390 }
1391 return a;
1392 }
1393
do_cdot_d(uint64_t n,uint64_t m,int64_t a,int sel_a,int sel_b,int sub_i)1394 static int64_t do_cdot_d(uint64_t n, uint64_t m, int64_t a,
1395 int sel_a, int sel_b, int sub_i)
1396 {
1397 for (int i = 0; i <= 1; i++) {
1398 int64_t elt1_r = (int16_t)(n >> (32 * i + 0));
1399 int64_t elt1_i = (int16_t)(n >> (32 * i + 16));
1400 int64_t elt2_a = (int16_t)(m >> (32 * i + 16 * sel_a));
1401 int64_t elt2_b = (int16_t)(m >> (32 * i + 16 * sel_b));
1402
1403 a += elt1_r * elt2_a + elt1_i * elt2_b * sub_i;
1404 }
1405 return a;
1406 }
1407
HELPER(sve2_cdot_zzzz_s)1408 void HELPER(sve2_cdot_zzzz_s)(void *vd, void *vn, void *vm,
1409 void *va, uint32_t desc)
1410 {
1411 int opr_sz = simd_oprsz(desc);
1412 int rot = simd_data(desc);
1413 int sel_a = rot & 1;
1414 int sel_b = sel_a ^ 1;
1415 int sub_i = (rot == 0 || rot == 3 ? -1 : 1);
1416 uint32_t *d = vd, *n = vn, *m = vm, *a = va;
1417
1418 for (int e = 0; e < opr_sz / 4; e++) {
1419 d[e] = do_cdot_s(n[e], m[e], a[e], sel_a, sel_b, sub_i);
1420 }
1421 }
1422
HELPER(sve2_cdot_zzzz_d)1423 void HELPER(sve2_cdot_zzzz_d)(void *vd, void *vn, void *vm,
1424 void *va, uint32_t desc)
1425 {
1426 int opr_sz = simd_oprsz(desc);
1427 int rot = simd_data(desc);
1428 int sel_a = rot & 1;
1429 int sel_b = sel_a ^ 1;
1430 int sub_i = (rot == 0 || rot == 3 ? -1 : 1);
1431 uint64_t *d = vd, *n = vn, *m = vm, *a = va;
1432
1433 for (int e = 0; e < opr_sz / 8; e++) {
1434 d[e] = do_cdot_d(n[e], m[e], a[e], sel_a, sel_b, sub_i);
1435 }
1436 }
1437
HELPER(sve2_cdot_idx_s)1438 void HELPER(sve2_cdot_idx_s)(void *vd, void *vn, void *vm,
1439 void *va, uint32_t desc)
1440 {
1441 int opr_sz = simd_oprsz(desc);
1442 int rot = extract32(desc, SIMD_DATA_SHIFT, 2);
1443 int idx = H4(extract32(desc, SIMD_DATA_SHIFT + 2, 2));
1444 int sel_a = rot & 1;
1445 int sel_b = sel_a ^ 1;
1446 int sub_i = (rot == 0 || rot == 3 ? -1 : 1);
1447 uint32_t *d = vd, *n = vn, *m = vm, *a = va;
1448
1449 for (int seg = 0; seg < opr_sz / 4; seg += 4) {
1450 uint32_t seg_m = m[seg + idx];
1451 for (int e = 0; e < 4; e++) {
1452 d[seg + e] = do_cdot_s(n[seg + e], seg_m, a[seg + e],
1453 sel_a, sel_b, sub_i);
1454 }
1455 }
1456 }
1457
HELPER(sve2_cdot_idx_d)1458 void HELPER(sve2_cdot_idx_d)(void *vd, void *vn, void *vm,
1459 void *va, uint32_t desc)
1460 {
1461 int seg, opr_sz = simd_oprsz(desc);
1462 int rot = extract32(desc, SIMD_DATA_SHIFT, 2);
1463 int idx = extract32(desc, SIMD_DATA_SHIFT + 2, 2);
1464 int sel_a = rot & 1;
1465 int sel_b = sel_a ^ 1;
1466 int sub_i = (rot == 0 || rot == 3 ? -1 : 1);
1467 uint64_t *d = vd, *n = vn, *m = vm, *a = va;
1468
1469 for (seg = 0; seg < opr_sz / 8; seg += 2) {
1470 uint64_t seg_m = m[seg + idx];
1471 for (int e = 0; e < 2; e++) {
1472 d[seg + e] = do_cdot_d(n[seg + e], seg_m, a[seg + e],
1473 sel_a, sel_b, sub_i);
1474 }
1475 }
1476 }
1477
1478 #define DO_ZZXZ(NAME, TYPE, H, OP) \
1479 void HELPER(NAME)(void *vd, void *vn, void *vm, void *va, uint32_t desc) \
1480 { \
1481 intptr_t oprsz = simd_oprsz(desc), segment = 16 / sizeof(TYPE); \
1482 intptr_t i, j, idx = simd_data(desc); \
1483 TYPE *d = vd, *a = va, *n = vn, *m = (TYPE *)vm + H(idx); \
1484 for (i = 0; i < oprsz / sizeof(TYPE); i += segment) { \
1485 TYPE mm = m[i]; \
1486 for (j = 0; j < segment; j++) { \
1487 d[i + j] = OP(n[i + j], mm, a[i + j]); \
1488 } \
1489 } \
1490 }
1491
1492 #define DO_SQRDMLAH_H(N, M, A) \
1493 ({ uint32_t discard; do_sqrdmlah_h(N, M, A, false, true, &discard); })
1494 #define DO_SQRDMLAH_S(N, M, A) \
1495 ({ uint32_t discard; do_sqrdmlah_s(N, M, A, false, true, &discard); })
1496 #define DO_SQRDMLAH_D(N, M, A) do_sqrdmlah_d(N, M, A, false, true)
1497
DO_ZZXZ(sve2_sqrdmlah_idx_h,int16_t,H2,DO_SQRDMLAH_H)1498 DO_ZZXZ(sve2_sqrdmlah_idx_h, int16_t, H2, DO_SQRDMLAH_H)
1499 DO_ZZXZ(sve2_sqrdmlah_idx_s, int32_t, H4, DO_SQRDMLAH_S)
1500 DO_ZZXZ(sve2_sqrdmlah_idx_d, int64_t, H8, DO_SQRDMLAH_D)
1501
1502 #define DO_SQRDMLSH_H(N, M, A) \
1503 ({ uint32_t discard; do_sqrdmlah_h(N, M, A, true, true, &discard); })
1504 #define DO_SQRDMLSH_S(N, M, A) \
1505 ({ uint32_t discard; do_sqrdmlah_s(N, M, A, true, true, &discard); })
1506 #define DO_SQRDMLSH_D(N, M, A) do_sqrdmlah_d(N, M, A, true, true)
1507
1508 DO_ZZXZ(sve2_sqrdmlsh_idx_h, int16_t, H2, DO_SQRDMLSH_H)
1509 DO_ZZXZ(sve2_sqrdmlsh_idx_s, int32_t, H4, DO_SQRDMLSH_S)
1510 DO_ZZXZ(sve2_sqrdmlsh_idx_d, int64_t, H8, DO_SQRDMLSH_D)
1511
1512 #undef DO_ZZXZ
1513
1514 #define DO_ZZXW(NAME, TYPEW, TYPEN, HW, HN, OP) \
1515 void HELPER(NAME)(void *vd, void *vn, void *vm, void *va, uint32_t desc) \
1516 { \
1517 intptr_t i, j, oprsz = simd_oprsz(desc); \
1518 intptr_t sel = extract32(desc, SIMD_DATA_SHIFT, 1) * sizeof(TYPEN); \
1519 intptr_t idx = extract32(desc, SIMD_DATA_SHIFT + 1, 3) * sizeof(TYPEN); \
1520 for (i = 0; i < oprsz; i += 16) { \
1521 TYPEW mm = *(TYPEN *)(vm + HN(i + idx)); \
1522 for (j = 0; j < 16; j += sizeof(TYPEW)) { \
1523 TYPEW nn = *(TYPEN *)(vn + HN(i + j + sel)); \
1524 TYPEW aa = *(TYPEW *)(va + HW(i + j)); \
1525 *(TYPEW *)(vd + HW(i + j)) = OP(nn, mm, aa); \
1526 } \
1527 } \
1528 }
1529
1530 #define DO_MLA(N, M, A) (A + N * M)
1531
1532 DO_ZZXW(sve2_smlal_idx_s, int32_t, int16_t, H1_4, H1_2, DO_MLA)
1533 DO_ZZXW(sve2_smlal_idx_d, int64_t, int32_t, H1_8, H1_4, DO_MLA)
1534 DO_ZZXW(sve2_umlal_idx_s, uint32_t, uint16_t, H1_4, H1_2, DO_MLA)
1535 DO_ZZXW(sve2_umlal_idx_d, uint64_t, uint32_t, H1_8, H1_4, DO_MLA)
1536
1537 #define DO_MLS(N, M, A) (A - N * M)
1538
1539 DO_ZZXW(sve2_smlsl_idx_s, int32_t, int16_t, H1_4, H1_2, DO_MLS)
1540 DO_ZZXW(sve2_smlsl_idx_d, int64_t, int32_t, H1_8, H1_4, DO_MLS)
1541 DO_ZZXW(sve2_umlsl_idx_s, uint32_t, uint16_t, H1_4, H1_2, DO_MLS)
1542 DO_ZZXW(sve2_umlsl_idx_d, uint64_t, uint32_t, H1_8, H1_4, DO_MLS)
1543
1544 #define DO_SQDMLAL_S(N, M, A) DO_SQADD_S(A, do_sqdmull_s(N, M))
1545 #define DO_SQDMLAL_D(N, M, A) do_sqadd_d(A, do_sqdmull_d(N, M))
1546
1547 DO_ZZXW(sve2_sqdmlal_idx_s, int32_t, int16_t, H1_4, H1_2, DO_SQDMLAL_S)
1548 DO_ZZXW(sve2_sqdmlal_idx_d, int64_t, int32_t, H1_8, H1_4, DO_SQDMLAL_D)
1549
1550 #define DO_SQDMLSL_S(N, M, A) DO_SQSUB_S(A, do_sqdmull_s(N, M))
1551 #define DO_SQDMLSL_D(N, M, A) do_sqsub_d(A, do_sqdmull_d(N, M))
1552
1553 DO_ZZXW(sve2_sqdmlsl_idx_s, int32_t, int16_t, H1_4, H1_2, DO_SQDMLSL_S)
1554 DO_ZZXW(sve2_sqdmlsl_idx_d, int64_t, int32_t, H1_8, H1_4, DO_SQDMLSL_D)
1555
1556 #undef DO_MLA
1557 #undef DO_MLS
1558 #undef DO_ZZXW
1559
1560 #define DO_ZZX(NAME, TYPEW, TYPEN, HW, HN, OP) \
1561 void HELPER(NAME)(void *vd, void *vn, void *vm, uint32_t desc) \
1562 { \
1563 intptr_t i, j, oprsz = simd_oprsz(desc); \
1564 intptr_t sel = extract32(desc, SIMD_DATA_SHIFT, 1) * sizeof(TYPEN); \
1565 intptr_t idx = extract32(desc, SIMD_DATA_SHIFT + 1, 3) * sizeof(TYPEN); \
1566 for (i = 0; i < oprsz; i += 16) { \
1567 TYPEW mm = *(TYPEN *)(vm + HN(i + idx)); \
1568 for (j = 0; j < 16; j += sizeof(TYPEW)) { \
1569 TYPEW nn = *(TYPEN *)(vn + HN(i + j + sel)); \
1570 *(TYPEW *)(vd + HW(i + j)) = OP(nn, mm); \
1571 } \
1572 } \
1573 }
1574
1575 DO_ZZX(sve2_sqdmull_idx_s, int32_t, int16_t, H1_4, H1_2, do_sqdmull_s)
1576 DO_ZZX(sve2_sqdmull_idx_d, int64_t, int32_t, H1_8, H1_4, do_sqdmull_d)
1577
1578 DO_ZZX(sve2_smull_idx_s, int32_t, int16_t, H1_4, H1_2, DO_MUL)
1579 DO_ZZX(sve2_smull_idx_d, int64_t, int32_t, H1_8, H1_4, DO_MUL)
1580
1581 DO_ZZX(sve2_umull_idx_s, uint32_t, uint16_t, H1_4, H1_2, DO_MUL)
1582 DO_ZZX(sve2_umull_idx_d, uint64_t, uint32_t, H1_8, H1_4, DO_MUL)
1583
1584 #undef DO_ZZX
1585
1586 #define DO_BITPERM(NAME, TYPE, OP) \
1587 void HELPER(NAME)(void *vd, void *vn, void *vm, uint32_t desc) \
1588 { \
1589 intptr_t i, opr_sz = simd_oprsz(desc); \
1590 for (i = 0; i < opr_sz; i += sizeof(TYPE)) { \
1591 TYPE nn = *(TYPE *)(vn + i); \
1592 TYPE mm = *(TYPE *)(vm + i); \
1593 *(TYPE *)(vd + i) = OP(nn, mm, sizeof(TYPE) * 8); \
1594 } \
1595 }
1596
1597 static uint64_t bitextract(uint64_t data, uint64_t mask, int n)
1598 {
1599 uint64_t res = 0;
1600 int db, rb = 0;
1601
1602 for (db = 0; db < n; ++db) {
1603 if ((mask >> db) & 1) {
1604 res |= ((data >> db) & 1) << rb;
1605 ++rb;
1606 }
1607 }
1608 return res;
1609 }
1610
DO_BITPERM(sve2_bext_b,uint8_t,bitextract)1611 DO_BITPERM(sve2_bext_b, uint8_t, bitextract)
1612 DO_BITPERM(sve2_bext_h, uint16_t, bitextract)
1613 DO_BITPERM(sve2_bext_s, uint32_t, bitextract)
1614 DO_BITPERM(sve2_bext_d, uint64_t, bitextract)
1615
1616 static uint64_t bitdeposit(uint64_t data, uint64_t mask, int n)
1617 {
1618 uint64_t res = 0;
1619 int rb, db = 0;
1620
1621 for (rb = 0; rb < n; ++rb) {
1622 if ((mask >> rb) & 1) {
1623 res |= ((data >> db) & 1) << rb;
1624 ++db;
1625 }
1626 }
1627 return res;
1628 }
1629
DO_BITPERM(sve2_bdep_b,uint8_t,bitdeposit)1630 DO_BITPERM(sve2_bdep_b, uint8_t, bitdeposit)
1631 DO_BITPERM(sve2_bdep_h, uint16_t, bitdeposit)
1632 DO_BITPERM(sve2_bdep_s, uint32_t, bitdeposit)
1633 DO_BITPERM(sve2_bdep_d, uint64_t, bitdeposit)
1634
1635 static uint64_t bitgroup(uint64_t data, uint64_t mask, int n)
1636 {
1637 uint64_t resm = 0, resu = 0;
1638 int db, rbm = 0, rbu = 0;
1639
1640 for (db = 0; db < n; ++db) {
1641 uint64_t val = (data >> db) & 1;
1642 if ((mask >> db) & 1) {
1643 resm |= val << rbm++;
1644 } else {
1645 resu |= val << rbu++;
1646 }
1647 }
1648
1649 return resm | (resu << rbm);
1650 }
1651
DO_BITPERM(sve2_bgrp_b,uint8_t,bitgroup)1652 DO_BITPERM(sve2_bgrp_b, uint8_t, bitgroup)
1653 DO_BITPERM(sve2_bgrp_h, uint16_t, bitgroup)
1654 DO_BITPERM(sve2_bgrp_s, uint32_t, bitgroup)
1655 DO_BITPERM(sve2_bgrp_d, uint64_t, bitgroup)
1656
1657 #undef DO_BITPERM
1658
1659 #define DO_CADD(NAME, TYPE, H, ADD_OP, SUB_OP) \
1660 void HELPER(NAME)(void *vd, void *vn, void *vm, uint32_t desc) \
1661 { \
1662 intptr_t i, opr_sz = simd_oprsz(desc); \
1663 int sub_r = simd_data(desc); \
1664 if (sub_r) { \
1665 for (i = 0; i < opr_sz; i += 2 * sizeof(TYPE)) { \
1666 TYPE acc_r = *(TYPE *)(vn + H(i)); \
1667 TYPE acc_i = *(TYPE *)(vn + H(i + sizeof(TYPE))); \
1668 TYPE el2_r = *(TYPE *)(vm + H(i)); \
1669 TYPE el2_i = *(TYPE *)(vm + H(i + sizeof(TYPE))); \
1670 acc_r = ADD_OP(acc_r, el2_i); \
1671 acc_i = SUB_OP(acc_i, el2_r); \
1672 *(TYPE *)(vd + H(i)) = acc_r; \
1673 *(TYPE *)(vd + H(i + sizeof(TYPE))) = acc_i; \
1674 } \
1675 } else { \
1676 for (i = 0; i < opr_sz; i += 2 * sizeof(TYPE)) { \
1677 TYPE acc_r = *(TYPE *)(vn + H(i)); \
1678 TYPE acc_i = *(TYPE *)(vn + H(i + sizeof(TYPE))); \
1679 TYPE el2_r = *(TYPE *)(vm + H(i)); \
1680 TYPE el2_i = *(TYPE *)(vm + H(i + sizeof(TYPE))); \
1681 acc_r = SUB_OP(acc_r, el2_i); \
1682 acc_i = ADD_OP(acc_i, el2_r); \
1683 *(TYPE *)(vd + H(i)) = acc_r; \
1684 *(TYPE *)(vd + H(i + sizeof(TYPE))) = acc_i; \
1685 } \
1686 } \
1687 }
1688
1689 DO_CADD(sve2_cadd_b, int8_t, H1, DO_ADD, DO_SUB)
1690 DO_CADD(sve2_cadd_h, int16_t, H1_2, DO_ADD, DO_SUB)
1691 DO_CADD(sve2_cadd_s, int32_t, H1_4, DO_ADD, DO_SUB)
1692 DO_CADD(sve2_cadd_d, int64_t, H1_8, DO_ADD, DO_SUB)
1693
1694 DO_CADD(sve2_sqcadd_b, int8_t, H1, DO_SQADD_B, DO_SQSUB_B)
1695 DO_CADD(sve2_sqcadd_h, int16_t, H1_2, DO_SQADD_H, DO_SQSUB_H)
1696 DO_CADD(sve2_sqcadd_s, int32_t, H1_4, DO_SQADD_S, DO_SQSUB_S)
1697 DO_CADD(sve2_sqcadd_d, int64_t, H1_8, do_sqadd_d, do_sqsub_d)
1698
1699 #undef DO_CADD
1700
1701 #define DO_ZZI_SHLL(NAME, TYPEW, TYPEN, HW, HN) \
1702 void HELPER(NAME)(void *vd, void *vn, uint32_t desc) \
1703 { \
1704 intptr_t i, opr_sz = simd_oprsz(desc); \
1705 intptr_t sel = (simd_data(desc) & 1) * sizeof(TYPEN); \
1706 int shift = simd_data(desc) >> 1; \
1707 for (i = 0; i < opr_sz; i += sizeof(TYPEW)) { \
1708 TYPEW nn = *(TYPEN *)(vn + HN(i + sel)); \
1709 *(TYPEW *)(vd + HW(i)) = nn << shift; \
1710 } \
1711 }
1712
1713 DO_ZZI_SHLL(sve2_sshll_h, int16_t, int8_t, H1_2, H1)
1714 DO_ZZI_SHLL(sve2_sshll_s, int32_t, int16_t, H1_4, H1_2)
1715 DO_ZZI_SHLL(sve2_sshll_d, int64_t, int32_t, H1_8, H1_4)
1716
1717 DO_ZZI_SHLL(sve2_ushll_h, uint16_t, uint8_t, H1_2, H1)
1718 DO_ZZI_SHLL(sve2_ushll_s, uint32_t, uint16_t, H1_4, H1_2)
1719 DO_ZZI_SHLL(sve2_ushll_d, uint64_t, uint32_t, H1_8, H1_4)
1720
1721 #undef DO_ZZI_SHLL
1722
1723 /* Two-operand reduction expander, controlled by a predicate.
1724 * The difference between TYPERED and TYPERET has to do with
1725 * sign-extension. E.g. for SMAX, TYPERED must be signed,
1726 * but TYPERET must be unsigned so that e.g. a 32-bit value
1727 * is not sign-extended to the ABI uint64_t return type.
1728 */
1729 /* ??? If we were to vectorize this by hand the reduction ordering
1730 * would change. For integer operands, this is perfectly fine.
1731 */
1732 #define DO_VPZ(NAME, TYPEELT, TYPERED, TYPERET, H, INIT, OP) \
1733 uint64_t HELPER(NAME)(void *vn, void *vg, uint32_t desc) \
1734 { \
1735 intptr_t i, opr_sz = simd_oprsz(desc); \
1736 TYPERED ret = INIT; \
1737 for (i = 0; i < opr_sz; ) { \
1738 uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); \
1739 do { \
1740 if (pg & 1) { \
1741 TYPEELT nn = *(TYPEELT *)(vn + H(i)); \
1742 ret = OP(ret, nn); \
1743 } \
1744 i += sizeof(TYPEELT), pg >>= sizeof(TYPEELT); \
1745 } while (i & 15); \
1746 } \
1747 return (TYPERET)ret; \
1748 }
1749
1750 #define DO_VPZ_D(NAME, TYPEE, TYPER, INIT, OP) \
1751 uint64_t HELPER(NAME)(void *vn, void *vg, uint32_t desc) \
1752 { \
1753 intptr_t i, opr_sz = simd_oprsz(desc) / 8; \
1754 TYPEE *n = vn; \
1755 uint8_t *pg = vg; \
1756 TYPER ret = INIT; \
1757 for (i = 0; i < opr_sz; i += 1) { \
1758 if (pg[H1(i)] & 1) { \
1759 TYPEE nn = n[i]; \
1760 ret = OP(ret, nn); \
1761 } \
1762 } \
1763 return ret; \
1764 }
1765
1766 DO_VPZ(sve_orv_b, uint8_t, uint8_t, uint8_t, H1, 0, DO_ORR)
1767 DO_VPZ(sve_orv_h, uint16_t, uint16_t, uint16_t, H1_2, 0, DO_ORR)
1768 DO_VPZ(sve_orv_s, uint32_t, uint32_t, uint32_t, H1_4, 0, DO_ORR)
1769 DO_VPZ_D(sve_orv_d, uint64_t, uint64_t, 0, DO_ORR)
1770
1771 DO_VPZ(sve_eorv_b, uint8_t, uint8_t, uint8_t, H1, 0, DO_EOR)
1772 DO_VPZ(sve_eorv_h, uint16_t, uint16_t, uint16_t, H1_2, 0, DO_EOR)
1773 DO_VPZ(sve_eorv_s, uint32_t, uint32_t, uint32_t, H1_4, 0, DO_EOR)
1774 DO_VPZ_D(sve_eorv_d, uint64_t, uint64_t, 0, DO_EOR)
1775
1776 DO_VPZ(sve_andv_b, uint8_t, uint8_t, uint8_t, H1, -1, DO_AND)
1777 DO_VPZ(sve_andv_h, uint16_t, uint16_t, uint16_t, H1_2, -1, DO_AND)
1778 DO_VPZ(sve_andv_s, uint32_t, uint32_t, uint32_t, H1_4, -1, DO_AND)
1779 DO_VPZ_D(sve_andv_d, uint64_t, uint64_t, -1, DO_AND)
1780
1781 DO_VPZ(sve_saddv_b, int8_t, uint64_t, uint64_t, H1, 0, DO_ADD)
1782 DO_VPZ(sve_saddv_h, int16_t, uint64_t, uint64_t, H1_2, 0, DO_ADD)
1783 DO_VPZ(sve_saddv_s, int32_t, uint64_t, uint64_t, H1_4, 0, DO_ADD)
1784
1785 DO_VPZ(sve_uaddv_b, uint8_t, uint64_t, uint64_t, H1, 0, DO_ADD)
1786 DO_VPZ(sve_uaddv_h, uint16_t, uint64_t, uint64_t, H1_2, 0, DO_ADD)
1787 DO_VPZ(sve_uaddv_s, uint32_t, uint64_t, uint64_t, H1_4, 0, DO_ADD)
1788 DO_VPZ_D(sve_uaddv_d, uint64_t, uint64_t, 0, DO_ADD)
1789
1790 DO_VPZ(sve_smaxv_b, int8_t, int8_t, uint8_t, H1, INT8_MIN, DO_MAX)
1791 DO_VPZ(sve_smaxv_h, int16_t, int16_t, uint16_t, H1_2, INT16_MIN, DO_MAX)
1792 DO_VPZ(sve_smaxv_s, int32_t, int32_t, uint32_t, H1_4, INT32_MIN, DO_MAX)
1793 DO_VPZ_D(sve_smaxv_d, int64_t, int64_t, INT64_MIN, DO_MAX)
1794
1795 DO_VPZ(sve_umaxv_b, uint8_t, uint8_t, uint8_t, H1, 0, DO_MAX)
1796 DO_VPZ(sve_umaxv_h, uint16_t, uint16_t, uint16_t, H1_2, 0, DO_MAX)
1797 DO_VPZ(sve_umaxv_s, uint32_t, uint32_t, uint32_t, H1_4, 0, DO_MAX)
1798 DO_VPZ_D(sve_umaxv_d, uint64_t, uint64_t, 0, DO_MAX)
1799
1800 DO_VPZ(sve_sminv_b, int8_t, int8_t, uint8_t, H1, INT8_MAX, DO_MIN)
1801 DO_VPZ(sve_sminv_h, int16_t, int16_t, uint16_t, H1_2, INT16_MAX, DO_MIN)
1802 DO_VPZ(sve_sminv_s, int32_t, int32_t, uint32_t, H1_4, INT32_MAX, DO_MIN)
1803 DO_VPZ_D(sve_sminv_d, int64_t, int64_t, INT64_MAX, DO_MIN)
1804
1805 DO_VPZ(sve_uminv_b, uint8_t, uint8_t, uint8_t, H1, -1, DO_MIN)
1806 DO_VPZ(sve_uminv_h, uint16_t, uint16_t, uint16_t, H1_2, -1, DO_MIN)
1807 DO_VPZ(sve_uminv_s, uint32_t, uint32_t, uint32_t, H1_4, -1, DO_MIN)
1808 DO_VPZ_D(sve_uminv_d, uint64_t, uint64_t, -1, DO_MIN)
1809
1810 #undef DO_VPZ
1811 #undef DO_VPZ_D
1812
1813 /* Two vector operand, one scalar operand, unpredicated. */
1814 #define DO_ZZI(NAME, TYPE, OP) \
1815 void HELPER(NAME)(void *vd, void *vn, uint64_t s64, uint32_t desc) \
1816 { \
1817 intptr_t i, opr_sz = simd_oprsz(desc) / sizeof(TYPE); \
1818 TYPE s = s64, *d = vd, *n = vn; \
1819 for (i = 0; i < opr_sz; ++i) { \
1820 d[i] = OP(n[i], s); \
1821 } \
1822 }
1823
1824 #define DO_SUBR(X, Y) (Y - X)
1825
1826 DO_ZZI(sve_subri_b, uint8_t, DO_SUBR)
1827 DO_ZZI(sve_subri_h, uint16_t, DO_SUBR)
1828 DO_ZZI(sve_subri_s, uint32_t, DO_SUBR)
1829 DO_ZZI(sve_subri_d, uint64_t, DO_SUBR)
1830
1831 DO_ZZI(sve_smaxi_b, int8_t, DO_MAX)
1832 DO_ZZI(sve_smaxi_h, int16_t, DO_MAX)
1833 DO_ZZI(sve_smaxi_s, int32_t, DO_MAX)
1834 DO_ZZI(sve_smaxi_d, int64_t, DO_MAX)
1835
1836 DO_ZZI(sve_smini_b, int8_t, DO_MIN)
1837 DO_ZZI(sve_smini_h, int16_t, DO_MIN)
1838 DO_ZZI(sve_smini_s, int32_t, DO_MIN)
1839 DO_ZZI(sve_smini_d, int64_t, DO_MIN)
1840
1841 DO_ZZI(sve_umaxi_b, uint8_t, DO_MAX)
1842 DO_ZZI(sve_umaxi_h, uint16_t, DO_MAX)
1843 DO_ZZI(sve_umaxi_s, uint32_t, DO_MAX)
1844 DO_ZZI(sve_umaxi_d, uint64_t, DO_MAX)
1845
1846 DO_ZZI(sve_umini_b, uint8_t, DO_MIN)
1847 DO_ZZI(sve_umini_h, uint16_t, DO_MIN)
1848 DO_ZZI(sve_umini_s, uint32_t, DO_MIN)
1849 DO_ZZI(sve_umini_d, uint64_t, DO_MIN)
1850
1851 #undef DO_ZZI
1852
1853 #undef DO_AND
1854 #undef DO_ORR
1855 #undef DO_EOR
1856 #undef DO_BIC
1857 #undef DO_ADD
1858 #undef DO_SUB
1859 #undef DO_MAX
1860 #undef DO_MIN
1861 #undef DO_ABD
1862 #undef DO_MUL
1863 #undef DO_DIV
1864 #undef DO_ASR
1865 #undef DO_LSR
1866 #undef DO_LSL
1867 #undef DO_SUBR
1868
1869 /* Similar to the ARM LastActiveElement pseudocode function, except the
1870 result is multiplied by the element size. This includes the not found
1871 indication; e.g. not found for esz=3 is -8. */
1872 static intptr_t last_active_element(uint64_t *g, intptr_t words, intptr_t esz)
1873 {
1874 uint64_t mask = pred_esz_masks[esz];
1875 intptr_t i = words;
1876
1877 do {
1878 uint64_t this_g = g[--i] & mask;
1879 if (this_g) {
1880 return i * 64 + (63 - clz64(this_g));
1881 }
1882 } while (i > 0);
1883 return (intptr_t)-1 << esz;
1884 }
1885
HELPER(sve_pfirst)1886 uint32_t HELPER(sve_pfirst)(void *vd, void *vg, uint32_t pred_desc)
1887 {
1888 intptr_t words = DIV_ROUND_UP(FIELD_EX32(pred_desc, PREDDESC, OPRSZ), 8);
1889 uint32_t flags = PREDTEST_INIT;
1890 uint64_t *d = vd, *g = vg;
1891 intptr_t i = 0;
1892
1893 do {
1894 uint64_t this_d = d[i];
1895 uint64_t this_g = g[i];
1896
1897 if (this_g) {
1898 if (!(flags & 4)) {
1899 /* Set in D the first bit of G. */
1900 this_d |= this_g & -this_g;
1901 d[i] = this_d;
1902 }
1903 flags = iter_predtest_fwd(this_d, this_g, flags);
1904 }
1905 } while (++i < words);
1906
1907 return flags;
1908 }
1909
HELPER(sve_pnext)1910 uint32_t HELPER(sve_pnext)(void *vd, void *vg, uint32_t pred_desc)
1911 {
1912 intptr_t words = DIV_ROUND_UP(FIELD_EX32(pred_desc, PREDDESC, OPRSZ), 8);
1913 intptr_t esz = FIELD_EX32(pred_desc, PREDDESC, ESZ);
1914 uint32_t flags = PREDTEST_INIT;
1915 uint64_t *d = vd, *g = vg, esz_mask;
1916 intptr_t i, next;
1917
1918 next = last_active_element(vd, words, esz) + (1 << esz);
1919 esz_mask = pred_esz_masks[esz];
1920
1921 /* Similar to the pseudocode for pnext, but scaled by ESZ
1922 so that we find the correct bit. */
1923 if (next < words * 64) {
1924 uint64_t mask = -1;
1925
1926 if (next & 63) {
1927 mask = ~((1ull << (next & 63)) - 1);
1928 next &= -64;
1929 }
1930 do {
1931 uint64_t this_g = g[next / 64] & esz_mask & mask;
1932 if (this_g != 0) {
1933 next = (next & -64) + ctz64(this_g);
1934 break;
1935 }
1936 next += 64;
1937 mask = -1;
1938 } while (next < words * 64);
1939 }
1940
1941 i = 0;
1942 do {
1943 uint64_t this_d = 0;
1944 if (i == next / 64) {
1945 this_d = 1ull << (next & 63);
1946 }
1947 d[i] = this_d;
1948 flags = iter_predtest_fwd(this_d, g[i] & esz_mask, flags);
1949 } while (++i < words);
1950
1951 return flags;
1952 }
1953
1954 /*
1955 * Copy Zn into Zd, and store zero into inactive elements.
1956 * If inv, store zeros into the active elements.
1957 */
HELPER(sve_movz_b)1958 void HELPER(sve_movz_b)(void *vd, void *vn, void *vg, uint32_t desc)
1959 {
1960 intptr_t i, opr_sz = simd_oprsz(desc) / 8;
1961 uint64_t inv = -(uint64_t)(simd_data(desc) & 1);
1962 uint64_t *d = vd, *n = vn;
1963 uint8_t *pg = vg;
1964
1965 for (i = 0; i < opr_sz; i += 1) {
1966 d[i] = n[i] & (expand_pred_b(pg[H1(i)]) ^ inv);
1967 }
1968 }
1969
HELPER(sve_movz_h)1970 void HELPER(sve_movz_h)(void *vd, void *vn, void *vg, uint32_t desc)
1971 {
1972 intptr_t i, opr_sz = simd_oprsz(desc) / 8;
1973 uint64_t inv = -(uint64_t)(simd_data(desc) & 1);
1974 uint64_t *d = vd, *n = vn;
1975 uint8_t *pg = vg;
1976
1977 for (i = 0; i < opr_sz; i += 1) {
1978 d[i] = n[i] & (expand_pred_h(pg[H1(i)]) ^ inv);
1979 }
1980 }
1981
HELPER(sve_movz_s)1982 void HELPER(sve_movz_s)(void *vd, void *vn, void *vg, uint32_t desc)
1983 {
1984 intptr_t i, opr_sz = simd_oprsz(desc) / 8;
1985 uint64_t inv = -(uint64_t)(simd_data(desc) & 1);
1986 uint64_t *d = vd, *n = vn;
1987 uint8_t *pg = vg;
1988
1989 for (i = 0; i < opr_sz; i += 1) {
1990 d[i] = n[i] & (expand_pred_s(pg[H1(i)]) ^ inv);
1991 }
1992 }
1993
HELPER(sve_movz_d)1994 void HELPER(sve_movz_d)(void *vd, void *vn, void *vg, uint32_t desc)
1995 {
1996 intptr_t i, opr_sz = simd_oprsz(desc) / 8;
1997 uint64_t *d = vd, *n = vn;
1998 uint8_t *pg = vg;
1999 uint8_t inv = simd_data(desc);
2000
2001 for (i = 0; i < opr_sz; i += 1) {
2002 d[i] = n[i] & -(uint64_t)((pg[H1(i)] ^ inv) & 1);
2003 }
2004 }
2005
2006 /* Three-operand expander, immediate operand, controlled by a predicate.
2007 */
2008 #define DO_ZPZI(NAME, TYPE, H, OP) \
2009 void HELPER(NAME)(void *vd, void *vn, void *vg, uint32_t desc) \
2010 { \
2011 intptr_t i, opr_sz = simd_oprsz(desc); \
2012 TYPE imm = simd_data(desc); \
2013 for (i = 0; i < opr_sz; ) { \
2014 uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); \
2015 do { \
2016 if (pg & 1) { \
2017 TYPE nn = *(TYPE *)(vn + H(i)); \
2018 *(TYPE *)(vd + H(i)) = OP(nn, imm); \
2019 } \
2020 i += sizeof(TYPE), pg >>= sizeof(TYPE); \
2021 } while (i & 15); \
2022 } \
2023 }
2024
2025 /* Similarly, specialized for 64-bit operands. */
2026 #define DO_ZPZI_D(NAME, TYPE, OP) \
2027 void HELPER(NAME)(void *vd, void *vn, void *vg, uint32_t desc) \
2028 { \
2029 intptr_t i, opr_sz = simd_oprsz(desc) / 8; \
2030 TYPE *d = vd, *n = vn; \
2031 TYPE imm = simd_data(desc); \
2032 uint8_t *pg = vg; \
2033 for (i = 0; i < opr_sz; i += 1) { \
2034 if (pg[H1(i)] & 1) { \
2035 TYPE nn = n[i]; \
2036 d[i] = OP(nn, imm); \
2037 } \
2038 } \
2039 }
2040
2041 #define DO_SHR(N, M) (N >> M)
2042 #define DO_SHL(N, M) (N << M)
2043
2044 /* Arithmetic shift right for division. This rounds negative numbers
2045 toward zero as per signed division. Therefore before shifting,
2046 when N is negative, add 2**M-1. */
2047 #define DO_ASRD(N, M) ((N + (N < 0 ? ((__typeof(N))1 << M) - 1 : 0)) >> M)
2048
do_urshr(uint64_t x,unsigned sh)2049 static inline uint64_t do_urshr(uint64_t x, unsigned sh)
2050 {
2051 if (likely(sh < 64)) {
2052 return (x >> sh) + ((x >> (sh - 1)) & 1);
2053 } else if (sh == 64) {
2054 return x >> 63;
2055 } else {
2056 return 0;
2057 }
2058 }
2059
do_srshr(int64_t x,unsigned sh)2060 static inline int64_t do_srshr(int64_t x, unsigned sh)
2061 {
2062 if (likely(sh < 64)) {
2063 return (x >> sh) + ((x >> (sh - 1)) & 1);
2064 } else {
2065 /* Rounding the sign bit always produces 0. */
2066 return 0;
2067 }
2068 }
2069
DO_ZPZI(sve_asr_zpzi_b,int8_t,H1,DO_SHR)2070 DO_ZPZI(sve_asr_zpzi_b, int8_t, H1, DO_SHR)
2071 DO_ZPZI(sve_asr_zpzi_h, int16_t, H1_2, DO_SHR)
2072 DO_ZPZI(sve_asr_zpzi_s, int32_t, H1_4, DO_SHR)
2073 DO_ZPZI_D(sve_asr_zpzi_d, int64_t, DO_SHR)
2074
2075 DO_ZPZI(sve_lsr_zpzi_b, uint8_t, H1, DO_SHR)
2076 DO_ZPZI(sve_lsr_zpzi_h, uint16_t, H1_2, DO_SHR)
2077 DO_ZPZI(sve_lsr_zpzi_s, uint32_t, H1_4, DO_SHR)
2078 DO_ZPZI_D(sve_lsr_zpzi_d, uint64_t, DO_SHR)
2079
2080 DO_ZPZI(sve_lsl_zpzi_b, uint8_t, H1, DO_SHL)
2081 DO_ZPZI(sve_lsl_zpzi_h, uint16_t, H1_2, DO_SHL)
2082 DO_ZPZI(sve_lsl_zpzi_s, uint32_t, H1_4, DO_SHL)
2083 DO_ZPZI_D(sve_lsl_zpzi_d, uint64_t, DO_SHL)
2084
2085 DO_ZPZI(sve_asrd_b, int8_t, H1, DO_ASRD)
2086 DO_ZPZI(sve_asrd_h, int16_t, H1_2, DO_ASRD)
2087 DO_ZPZI(sve_asrd_s, int32_t, H1_4, DO_ASRD)
2088 DO_ZPZI_D(sve_asrd_d, int64_t, DO_ASRD)
2089
2090 /* SVE2 bitwise shift by immediate */
2091 DO_ZPZI(sve2_sqshl_zpzi_b, int8_t, H1, do_sqshl_b)
2092 DO_ZPZI(sve2_sqshl_zpzi_h, int16_t, H1_2, do_sqshl_h)
2093 DO_ZPZI(sve2_sqshl_zpzi_s, int32_t, H1_4, do_sqshl_s)
2094 DO_ZPZI_D(sve2_sqshl_zpzi_d, int64_t, do_sqshl_d)
2095
2096 DO_ZPZI(sve2_uqshl_zpzi_b, uint8_t, H1, do_uqshl_b)
2097 DO_ZPZI(sve2_uqshl_zpzi_h, uint16_t, H1_2, do_uqshl_h)
2098 DO_ZPZI(sve2_uqshl_zpzi_s, uint32_t, H1_4, do_uqshl_s)
2099 DO_ZPZI_D(sve2_uqshl_zpzi_d, uint64_t, do_uqshl_d)
2100
2101 DO_ZPZI(sve2_srshr_b, int8_t, H1, do_srshr)
2102 DO_ZPZI(sve2_srshr_h, int16_t, H1_2, do_srshr)
2103 DO_ZPZI(sve2_srshr_s, int32_t, H1_4, do_srshr)
2104 DO_ZPZI_D(sve2_srshr_d, int64_t, do_srshr)
2105
2106 DO_ZPZI(sve2_urshr_b, uint8_t, H1, do_urshr)
2107 DO_ZPZI(sve2_urshr_h, uint16_t, H1_2, do_urshr)
2108 DO_ZPZI(sve2_urshr_s, uint32_t, H1_4, do_urshr)
2109 DO_ZPZI_D(sve2_urshr_d, uint64_t, do_urshr)
2110
2111 #define do_suqrshl_b(n, m) \
2112 ({ uint32_t discard; do_suqrshl_bhs(n, (int8_t)m, 8, false, &discard); })
2113 #define do_suqrshl_h(n, m) \
2114 ({ uint32_t discard; do_suqrshl_bhs(n, (int16_t)m, 16, false, &discard); })
2115 #define do_suqrshl_s(n, m) \
2116 ({ uint32_t discard; do_suqrshl_bhs(n, m, 32, false, &discard); })
2117 #define do_suqrshl_d(n, m) \
2118 ({ uint32_t discard; do_suqrshl_d(n, m, false, &discard); })
2119
2120 DO_ZPZI(sve2_sqshlu_b, int8_t, H1, do_suqrshl_b)
2121 DO_ZPZI(sve2_sqshlu_h, int16_t, H1_2, do_suqrshl_h)
2122 DO_ZPZI(sve2_sqshlu_s, int32_t, H1_4, do_suqrshl_s)
2123 DO_ZPZI_D(sve2_sqshlu_d, int64_t, do_suqrshl_d)
2124
2125 #undef DO_ASRD
2126 #undef DO_ZPZI
2127 #undef DO_ZPZI_D
2128
2129 #define DO_SHRNB(NAME, TYPEW, TYPEN, OP) \
2130 void HELPER(NAME)(void *vd, void *vn, uint32_t desc) \
2131 { \
2132 intptr_t i, opr_sz = simd_oprsz(desc); \
2133 int shift = simd_data(desc); \
2134 for (i = 0; i < opr_sz; i += sizeof(TYPEW)) { \
2135 TYPEW nn = *(TYPEW *)(vn + i); \
2136 *(TYPEW *)(vd + i) = (TYPEN)OP(nn, shift); \
2137 } \
2138 }
2139
2140 #define DO_SHRNT(NAME, TYPEW, TYPEN, HW, HN, OP) \
2141 void HELPER(NAME)(void *vd, void *vn, uint32_t desc) \
2142 { \
2143 intptr_t i, opr_sz = simd_oprsz(desc); \
2144 int shift = simd_data(desc); \
2145 for (i = 0; i < opr_sz; i += sizeof(TYPEW)) { \
2146 TYPEW nn = *(TYPEW *)(vn + HW(i)); \
2147 *(TYPEN *)(vd + HN(i + sizeof(TYPEN))) = OP(nn, shift); \
2148 } \
2149 }
2150
2151 DO_SHRNB(sve2_shrnb_h, uint16_t, uint8_t, DO_SHR)
2152 DO_SHRNB(sve2_shrnb_s, uint32_t, uint16_t, DO_SHR)
2153 DO_SHRNB(sve2_shrnb_d, uint64_t, uint32_t, DO_SHR)
2154
2155 DO_SHRNT(sve2_shrnt_h, uint16_t, uint8_t, H1_2, H1, DO_SHR)
2156 DO_SHRNT(sve2_shrnt_s, uint32_t, uint16_t, H1_4, H1_2, DO_SHR)
2157 DO_SHRNT(sve2_shrnt_d, uint64_t, uint32_t, H1_8, H1_4, DO_SHR)
2158
2159 DO_SHRNB(sve2_rshrnb_h, uint16_t, uint8_t, do_urshr)
2160 DO_SHRNB(sve2_rshrnb_s, uint32_t, uint16_t, do_urshr)
2161 DO_SHRNB(sve2_rshrnb_d, uint64_t, uint32_t, do_urshr)
2162
2163 DO_SHRNT(sve2_rshrnt_h, uint16_t, uint8_t, H1_2, H1, do_urshr)
2164 DO_SHRNT(sve2_rshrnt_s, uint32_t, uint16_t, H1_4, H1_2, do_urshr)
2165 DO_SHRNT(sve2_rshrnt_d, uint64_t, uint32_t, H1_8, H1_4, do_urshr)
2166
2167 #define DO_SQSHRUN_H(x, sh) do_sat_bhs((int64_t)(x) >> sh, 0, UINT8_MAX)
2168 #define DO_SQSHRUN_S(x, sh) do_sat_bhs((int64_t)(x) >> sh, 0, UINT16_MAX)
2169 #define DO_SQSHRUN_D(x, sh) \
2170 do_sat_bhs((int64_t)(x) >> (sh < 64 ? sh : 63), 0, UINT32_MAX)
2171
2172 DO_SHRNB(sve2_sqshrunb_h, int16_t, uint8_t, DO_SQSHRUN_H)
2173 DO_SHRNB(sve2_sqshrunb_s, int32_t, uint16_t, DO_SQSHRUN_S)
2174 DO_SHRNB(sve2_sqshrunb_d, int64_t, uint32_t, DO_SQSHRUN_D)
2175
2176 DO_SHRNT(sve2_sqshrunt_h, int16_t, uint8_t, H1_2, H1, DO_SQSHRUN_H)
2177 DO_SHRNT(sve2_sqshrunt_s, int32_t, uint16_t, H1_4, H1_2, DO_SQSHRUN_S)
2178 DO_SHRNT(sve2_sqshrunt_d, int64_t, uint32_t, H1_8, H1_4, DO_SQSHRUN_D)
2179
2180 #define DO_SQRSHRUN_H(x, sh) do_sat_bhs(do_srshr(x, sh), 0, UINT8_MAX)
2181 #define DO_SQRSHRUN_S(x, sh) do_sat_bhs(do_srshr(x, sh), 0, UINT16_MAX)
2182 #define DO_SQRSHRUN_D(x, sh) do_sat_bhs(do_srshr(x, sh), 0, UINT32_MAX)
2183
2184 DO_SHRNB(sve2_sqrshrunb_h, int16_t, uint8_t, DO_SQRSHRUN_H)
2185 DO_SHRNB(sve2_sqrshrunb_s, int32_t, uint16_t, DO_SQRSHRUN_S)
2186 DO_SHRNB(sve2_sqrshrunb_d, int64_t, uint32_t, DO_SQRSHRUN_D)
2187
2188 DO_SHRNT(sve2_sqrshrunt_h, int16_t, uint8_t, H1_2, H1, DO_SQRSHRUN_H)
2189 DO_SHRNT(sve2_sqrshrunt_s, int32_t, uint16_t, H1_4, H1_2, DO_SQRSHRUN_S)
2190 DO_SHRNT(sve2_sqrshrunt_d, int64_t, uint32_t, H1_8, H1_4, DO_SQRSHRUN_D)
2191
2192 #define DO_SQSHRN_H(x, sh) do_sat_bhs(x >> sh, INT8_MIN, INT8_MAX)
2193 #define DO_SQSHRN_S(x, sh) do_sat_bhs(x >> sh, INT16_MIN, INT16_MAX)
2194 #define DO_SQSHRN_D(x, sh) do_sat_bhs(x >> sh, INT32_MIN, INT32_MAX)
2195
2196 DO_SHRNB(sve2_sqshrnb_h, int16_t, uint8_t, DO_SQSHRN_H)
2197 DO_SHRNB(sve2_sqshrnb_s, int32_t, uint16_t, DO_SQSHRN_S)
2198 DO_SHRNB(sve2_sqshrnb_d, int64_t, uint32_t, DO_SQSHRN_D)
2199
2200 DO_SHRNT(sve2_sqshrnt_h, int16_t, uint8_t, H1_2, H1, DO_SQSHRN_H)
2201 DO_SHRNT(sve2_sqshrnt_s, int32_t, uint16_t, H1_4, H1_2, DO_SQSHRN_S)
2202 DO_SHRNT(sve2_sqshrnt_d, int64_t, uint32_t, H1_8, H1_4, DO_SQSHRN_D)
2203
2204 #define DO_SQRSHRN_H(x, sh) do_sat_bhs(do_srshr(x, sh), INT8_MIN, INT8_MAX)
2205 #define DO_SQRSHRN_S(x, sh) do_sat_bhs(do_srshr(x, sh), INT16_MIN, INT16_MAX)
2206 #define DO_SQRSHRN_D(x, sh) do_sat_bhs(do_srshr(x, sh), INT32_MIN, INT32_MAX)
2207
2208 DO_SHRNB(sve2_sqrshrnb_h, int16_t, uint8_t, DO_SQRSHRN_H)
2209 DO_SHRNB(sve2_sqrshrnb_s, int32_t, uint16_t, DO_SQRSHRN_S)
2210 DO_SHRNB(sve2_sqrshrnb_d, int64_t, uint32_t, DO_SQRSHRN_D)
2211
2212 DO_SHRNT(sve2_sqrshrnt_h, int16_t, uint8_t, H1_2, H1, DO_SQRSHRN_H)
2213 DO_SHRNT(sve2_sqrshrnt_s, int32_t, uint16_t, H1_4, H1_2, DO_SQRSHRN_S)
2214 DO_SHRNT(sve2_sqrshrnt_d, int64_t, uint32_t, H1_8, H1_4, DO_SQRSHRN_D)
2215
2216 #define DO_UQSHRN_H(x, sh) MIN(x >> sh, UINT8_MAX)
2217 #define DO_UQSHRN_S(x, sh) MIN(x >> sh, UINT16_MAX)
2218 #define DO_UQSHRN_D(x, sh) MIN(x >> sh, UINT32_MAX)
2219
2220 DO_SHRNB(sve2_uqshrnb_h, uint16_t, uint8_t, DO_UQSHRN_H)
2221 DO_SHRNB(sve2_uqshrnb_s, uint32_t, uint16_t, DO_UQSHRN_S)
2222 DO_SHRNB(sve2_uqshrnb_d, uint64_t, uint32_t, DO_UQSHRN_D)
2223
2224 DO_SHRNT(sve2_uqshrnt_h, uint16_t, uint8_t, H1_2, H1, DO_UQSHRN_H)
2225 DO_SHRNT(sve2_uqshrnt_s, uint32_t, uint16_t, H1_4, H1_2, DO_UQSHRN_S)
2226 DO_SHRNT(sve2_uqshrnt_d, uint64_t, uint32_t, H1_8, H1_4, DO_UQSHRN_D)
2227
2228 #define DO_UQRSHRN_H(x, sh) MIN(do_urshr(x, sh), UINT8_MAX)
2229 #define DO_UQRSHRN_S(x, sh) MIN(do_urshr(x, sh), UINT16_MAX)
2230 #define DO_UQRSHRN_D(x, sh) MIN(do_urshr(x, sh), UINT32_MAX)
2231
2232 DO_SHRNB(sve2_uqrshrnb_h, uint16_t, uint8_t, DO_UQRSHRN_H)
2233 DO_SHRNB(sve2_uqrshrnb_s, uint32_t, uint16_t, DO_UQRSHRN_S)
2234 DO_SHRNB(sve2_uqrshrnb_d, uint64_t, uint32_t, DO_UQRSHRN_D)
2235
2236 DO_SHRNT(sve2_uqrshrnt_h, uint16_t, uint8_t, H1_2, H1, DO_UQRSHRN_H)
2237 DO_SHRNT(sve2_uqrshrnt_s, uint32_t, uint16_t, H1_4, H1_2, DO_UQRSHRN_S)
2238 DO_SHRNT(sve2_uqrshrnt_d, uint64_t, uint32_t, H1_8, H1_4, DO_UQRSHRN_D)
2239
2240 #undef DO_SHRNB
2241 #undef DO_SHRNT
2242
2243 #define DO_BINOPNB(NAME, TYPEW, TYPEN, SHIFT, OP) \
2244 void HELPER(NAME)(void *vd, void *vn, void *vm, uint32_t desc) \
2245 { \
2246 intptr_t i, opr_sz = simd_oprsz(desc); \
2247 for (i = 0; i < opr_sz; i += sizeof(TYPEW)) { \
2248 TYPEW nn = *(TYPEW *)(vn + i); \
2249 TYPEW mm = *(TYPEW *)(vm + i); \
2250 *(TYPEW *)(vd + i) = (TYPEN)OP(nn, mm, SHIFT); \
2251 } \
2252 }
2253
2254 #define DO_BINOPNT(NAME, TYPEW, TYPEN, SHIFT, HW, HN, OP) \
2255 void HELPER(NAME)(void *vd, void *vn, void *vm, uint32_t desc) \
2256 { \
2257 intptr_t i, opr_sz = simd_oprsz(desc); \
2258 for (i = 0; i < opr_sz; i += sizeof(TYPEW)) { \
2259 TYPEW nn = *(TYPEW *)(vn + HW(i)); \
2260 TYPEW mm = *(TYPEW *)(vm + HW(i)); \
2261 *(TYPEN *)(vd + HN(i + sizeof(TYPEN))) = OP(nn, mm, SHIFT); \
2262 } \
2263 }
2264
2265 #define DO_ADDHN(N, M, SH) ((N + M) >> SH)
2266 #define DO_RADDHN(N, M, SH) ((N + M + ((__typeof(N))1 << (SH - 1))) >> SH)
2267 #define DO_SUBHN(N, M, SH) ((N - M) >> SH)
2268 #define DO_RSUBHN(N, M, SH) ((N - M + ((__typeof(N))1 << (SH - 1))) >> SH)
2269
2270 DO_BINOPNB(sve2_addhnb_h, uint16_t, uint8_t, 8, DO_ADDHN)
2271 DO_BINOPNB(sve2_addhnb_s, uint32_t, uint16_t, 16, DO_ADDHN)
2272 DO_BINOPNB(sve2_addhnb_d, uint64_t, uint32_t, 32, DO_ADDHN)
2273
2274 DO_BINOPNT(sve2_addhnt_h, uint16_t, uint8_t, 8, H1_2, H1, DO_ADDHN)
2275 DO_BINOPNT(sve2_addhnt_s, uint32_t, uint16_t, 16, H1_4, H1_2, DO_ADDHN)
2276 DO_BINOPNT(sve2_addhnt_d, uint64_t, uint32_t, 32, H1_8, H1_4, DO_ADDHN)
2277
2278 DO_BINOPNB(sve2_raddhnb_h, uint16_t, uint8_t, 8, DO_RADDHN)
2279 DO_BINOPNB(sve2_raddhnb_s, uint32_t, uint16_t, 16, DO_RADDHN)
2280 DO_BINOPNB(sve2_raddhnb_d, uint64_t, uint32_t, 32, DO_RADDHN)
2281
2282 DO_BINOPNT(sve2_raddhnt_h, uint16_t, uint8_t, 8, H1_2, H1, DO_RADDHN)
2283 DO_BINOPNT(sve2_raddhnt_s, uint32_t, uint16_t, 16, H1_4, H1_2, DO_RADDHN)
2284 DO_BINOPNT(sve2_raddhnt_d, uint64_t, uint32_t, 32, H1_8, H1_4, DO_RADDHN)
2285
2286 DO_BINOPNB(sve2_subhnb_h, uint16_t, uint8_t, 8, DO_SUBHN)
2287 DO_BINOPNB(sve2_subhnb_s, uint32_t, uint16_t, 16, DO_SUBHN)
2288 DO_BINOPNB(sve2_subhnb_d, uint64_t, uint32_t, 32, DO_SUBHN)
2289
2290 DO_BINOPNT(sve2_subhnt_h, uint16_t, uint8_t, 8, H1_2, H1, DO_SUBHN)
2291 DO_BINOPNT(sve2_subhnt_s, uint32_t, uint16_t, 16, H1_4, H1_2, DO_SUBHN)
2292 DO_BINOPNT(sve2_subhnt_d, uint64_t, uint32_t, 32, H1_8, H1_4, DO_SUBHN)
2293
2294 DO_BINOPNB(sve2_rsubhnb_h, uint16_t, uint8_t, 8, DO_RSUBHN)
2295 DO_BINOPNB(sve2_rsubhnb_s, uint32_t, uint16_t, 16, DO_RSUBHN)
2296 DO_BINOPNB(sve2_rsubhnb_d, uint64_t, uint32_t, 32, DO_RSUBHN)
2297
2298 DO_BINOPNT(sve2_rsubhnt_h, uint16_t, uint8_t, 8, H1_2, H1, DO_RSUBHN)
2299 DO_BINOPNT(sve2_rsubhnt_s, uint32_t, uint16_t, 16, H1_4, H1_2, DO_RSUBHN)
2300 DO_BINOPNT(sve2_rsubhnt_d, uint64_t, uint32_t, 32, H1_8, H1_4, DO_RSUBHN)
2301
2302 #undef DO_RSUBHN
2303 #undef DO_SUBHN
2304 #undef DO_RADDHN
2305 #undef DO_ADDHN
2306
2307 #undef DO_BINOPNB
2308
2309 /* Fully general four-operand expander, controlled by a predicate.
2310 */
2311 #define DO_ZPZZZ(NAME, TYPE, H, OP) \
2312 void HELPER(NAME)(void *vd, void *va, void *vn, void *vm, \
2313 void *vg, uint32_t desc) \
2314 { \
2315 intptr_t i, opr_sz = simd_oprsz(desc); \
2316 for (i = 0; i < opr_sz; ) { \
2317 uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); \
2318 do { \
2319 if (pg & 1) { \
2320 TYPE nn = *(TYPE *)(vn + H(i)); \
2321 TYPE mm = *(TYPE *)(vm + H(i)); \
2322 TYPE aa = *(TYPE *)(va + H(i)); \
2323 *(TYPE *)(vd + H(i)) = OP(aa, nn, mm); \
2324 } \
2325 i += sizeof(TYPE), pg >>= sizeof(TYPE); \
2326 } while (i & 15); \
2327 } \
2328 }
2329
2330 /* Similarly, specialized for 64-bit operands. */
2331 #define DO_ZPZZZ_D(NAME, TYPE, OP) \
2332 void HELPER(NAME)(void *vd, void *va, void *vn, void *vm, \
2333 void *vg, uint32_t desc) \
2334 { \
2335 intptr_t i, opr_sz = simd_oprsz(desc) / 8; \
2336 TYPE *d = vd, *a = va, *n = vn, *m = vm; \
2337 uint8_t *pg = vg; \
2338 for (i = 0; i < opr_sz; i += 1) { \
2339 if (pg[H1(i)] & 1) { \
2340 TYPE aa = a[i], nn = n[i], mm = m[i]; \
2341 d[i] = OP(aa, nn, mm); \
2342 } \
2343 } \
2344 }
2345
2346 #define DO_MLA(A, N, M) (A + N * M)
2347 #define DO_MLS(A, N, M) (A - N * M)
2348
2349 DO_ZPZZZ(sve_mla_b, uint8_t, H1, DO_MLA)
2350 DO_ZPZZZ(sve_mls_b, uint8_t, H1, DO_MLS)
2351
2352 DO_ZPZZZ(sve_mla_h, uint16_t, H1_2, DO_MLA)
2353 DO_ZPZZZ(sve_mls_h, uint16_t, H1_2, DO_MLS)
2354
2355 DO_ZPZZZ(sve_mla_s, uint32_t, H1_4, DO_MLA)
2356 DO_ZPZZZ(sve_mls_s, uint32_t, H1_4, DO_MLS)
2357
2358 DO_ZPZZZ_D(sve_mla_d, uint64_t, DO_MLA)
2359 DO_ZPZZZ_D(sve_mls_d, uint64_t, DO_MLS)
2360
2361 #undef DO_MLA
2362 #undef DO_MLS
2363 #undef DO_ZPZZZ
2364 #undef DO_ZPZZZ_D
2365
2366 void HELPER(sve_index_b)(void *vd, uint32_t start,
2367 uint32_t incr, uint32_t desc)
2368 {
2369 intptr_t i, opr_sz = simd_oprsz(desc);
2370 uint8_t *d = vd;
2371 for (i = 0; i < opr_sz; i += 1) {
2372 d[H1(i)] = start + i * incr;
2373 }
2374 }
2375
HELPER(sve_index_h)2376 void HELPER(sve_index_h)(void *vd, uint32_t start,
2377 uint32_t incr, uint32_t desc)
2378 {
2379 intptr_t i, opr_sz = simd_oprsz(desc) / 2;
2380 uint16_t *d = vd;
2381 for (i = 0; i < opr_sz; i += 1) {
2382 d[H2(i)] = start + i * incr;
2383 }
2384 }
2385
HELPER(sve_index_s)2386 void HELPER(sve_index_s)(void *vd, uint32_t start,
2387 uint32_t incr, uint32_t desc)
2388 {
2389 intptr_t i, opr_sz = simd_oprsz(desc) / 4;
2390 uint32_t *d = vd;
2391 for (i = 0; i < opr_sz; i += 1) {
2392 d[H4(i)] = start + i * incr;
2393 }
2394 }
2395
HELPER(sve_index_d)2396 void HELPER(sve_index_d)(void *vd, uint64_t start,
2397 uint64_t incr, uint32_t desc)
2398 {
2399 intptr_t i, opr_sz = simd_oprsz(desc) / 8;
2400 uint64_t *d = vd;
2401 for (i = 0; i < opr_sz; i += 1) {
2402 d[i] = start + i * incr;
2403 }
2404 }
2405
HELPER(sve_adr_p32)2406 void HELPER(sve_adr_p32)(void *vd, void *vn, void *vm, uint32_t desc)
2407 {
2408 intptr_t i, opr_sz = simd_oprsz(desc) / 4;
2409 uint32_t sh = simd_data(desc);
2410 uint32_t *d = vd, *n = vn, *m = vm;
2411 for (i = 0; i < opr_sz; i += 1) {
2412 d[i] = n[i] + (m[i] << sh);
2413 }
2414 }
2415
HELPER(sve_adr_p64)2416 void HELPER(sve_adr_p64)(void *vd, void *vn, void *vm, uint32_t desc)
2417 {
2418 intptr_t i, opr_sz = simd_oprsz(desc) / 8;
2419 uint64_t sh = simd_data(desc);
2420 uint64_t *d = vd, *n = vn, *m = vm;
2421 for (i = 0; i < opr_sz; i += 1) {
2422 d[i] = n[i] + (m[i] << sh);
2423 }
2424 }
2425
HELPER(sve_adr_s32)2426 void HELPER(sve_adr_s32)(void *vd, void *vn, void *vm, uint32_t desc)
2427 {
2428 intptr_t i, opr_sz = simd_oprsz(desc) / 8;
2429 uint64_t sh = simd_data(desc);
2430 uint64_t *d = vd, *n = vn, *m = vm;
2431 for (i = 0; i < opr_sz; i += 1) {
2432 d[i] = n[i] + ((uint64_t)(int32_t)m[i] << sh);
2433 }
2434 }
2435
HELPER(sve_adr_u32)2436 void HELPER(sve_adr_u32)(void *vd, void *vn, void *vm, uint32_t desc)
2437 {
2438 intptr_t i, opr_sz = simd_oprsz(desc) / 8;
2439 uint64_t sh = simd_data(desc);
2440 uint64_t *d = vd, *n = vn, *m = vm;
2441 for (i = 0; i < opr_sz; i += 1) {
2442 d[i] = n[i] + ((uint64_t)(uint32_t)m[i] << sh);
2443 }
2444 }
2445
HELPER(sve_fexpa_h)2446 void HELPER(sve_fexpa_h)(void *vd, void *vn, uint32_t desc)
2447 {
2448 /* These constants are cut-and-paste directly from the ARM pseudocode. */
2449 static const uint16_t coeff[] = {
2450 0x0000, 0x0016, 0x002d, 0x0045, 0x005d, 0x0075, 0x008e, 0x00a8,
2451 0x00c2, 0x00dc, 0x00f8, 0x0114, 0x0130, 0x014d, 0x016b, 0x0189,
2452 0x01a8, 0x01c8, 0x01e8, 0x0209, 0x022b, 0x024e, 0x0271, 0x0295,
2453 0x02ba, 0x02e0, 0x0306, 0x032e, 0x0356, 0x037f, 0x03a9, 0x03d4,
2454 };
2455 intptr_t i, opr_sz = simd_oprsz(desc) / 2;
2456 uint16_t *d = vd, *n = vn;
2457
2458 for (i = 0; i < opr_sz; i++) {
2459 uint16_t nn = n[i];
2460 intptr_t idx = extract32(nn, 0, 5);
2461 uint16_t exp = extract32(nn, 5, 5);
2462 d[i] = coeff[idx] | (exp << 10);
2463 }
2464 }
2465
HELPER(sve_fexpa_s)2466 void HELPER(sve_fexpa_s)(void *vd, void *vn, uint32_t desc)
2467 {
2468 /* These constants are cut-and-paste directly from the ARM pseudocode. */
2469 static const uint32_t coeff[] = {
2470 0x000000, 0x0164d2, 0x02cd87, 0x043a29,
2471 0x05aac3, 0x071f62, 0x08980f, 0x0a14d5,
2472 0x0b95c2, 0x0d1adf, 0x0ea43a, 0x1031dc,
2473 0x11c3d3, 0x135a2b, 0x14f4f0, 0x16942d,
2474 0x1837f0, 0x19e046, 0x1b8d3a, 0x1d3eda,
2475 0x1ef532, 0x20b051, 0x227043, 0x243516,
2476 0x25fed7, 0x27cd94, 0x29a15b, 0x2b7a3a,
2477 0x2d583f, 0x2f3b79, 0x3123f6, 0x3311c4,
2478 0x3504f3, 0x36fd92, 0x38fbaf, 0x3aff5b,
2479 0x3d08a4, 0x3f179a, 0x412c4d, 0x4346cd,
2480 0x45672a, 0x478d75, 0x49b9be, 0x4bec15,
2481 0x4e248c, 0x506334, 0x52a81e, 0x54f35b,
2482 0x5744fd, 0x599d16, 0x5bfbb8, 0x5e60f5,
2483 0x60ccdf, 0x633f89, 0x65b907, 0x68396a,
2484 0x6ac0c7, 0x6d4f30, 0x6fe4ba, 0x728177,
2485 0x75257d, 0x77d0df, 0x7a83b3, 0x7d3e0c,
2486 };
2487 intptr_t i, opr_sz = simd_oprsz(desc) / 4;
2488 uint32_t *d = vd, *n = vn;
2489
2490 for (i = 0; i < opr_sz; i++) {
2491 uint32_t nn = n[i];
2492 intptr_t idx = extract32(nn, 0, 6);
2493 uint32_t exp = extract32(nn, 6, 8);
2494 d[i] = coeff[idx] | (exp << 23);
2495 }
2496 }
2497
HELPER(sve_fexpa_d)2498 void HELPER(sve_fexpa_d)(void *vd, void *vn, uint32_t desc)
2499 {
2500 /* These constants are cut-and-paste directly from the ARM pseudocode. */
2501 static const uint64_t coeff[] = {
2502 0x0000000000000ull, 0x02C9A3E778061ull, 0x059B0D3158574ull,
2503 0x0874518759BC8ull, 0x0B5586CF9890Full, 0x0E3EC32D3D1A2ull,
2504 0x11301D0125B51ull, 0x1429AAEA92DE0ull, 0x172B83C7D517Bull,
2505 0x1A35BEB6FCB75ull, 0x1D4873168B9AAull, 0x2063B88628CD6ull,
2506 0x2387A6E756238ull, 0x26B4565E27CDDull, 0x29E9DF51FDEE1ull,
2507 0x2D285A6E4030Bull, 0x306FE0A31B715ull, 0x33C08B26416FFull,
2508 0x371A7373AA9CBull, 0x3A7DB34E59FF7ull, 0x3DEA64C123422ull,
2509 0x4160A21F72E2Aull, 0x44E086061892Dull, 0x486A2B5C13CD0ull,
2510 0x4BFDAD5362A27ull, 0x4F9B2769D2CA7ull, 0x5342B569D4F82ull,
2511 0x56F4736B527DAull, 0x5AB07DD485429ull, 0x5E76F15AD2148ull,
2512 0x6247EB03A5585ull, 0x6623882552225ull, 0x6A09E667F3BCDull,
2513 0x6DFB23C651A2Full, 0x71F75E8EC5F74ull, 0x75FEB564267C9ull,
2514 0x7A11473EB0187ull, 0x7E2F336CF4E62ull, 0x82589994CCE13ull,
2515 0x868D99B4492EDull, 0x8ACE5422AA0DBull, 0x8F1AE99157736ull,
2516 0x93737B0CDC5E5ull, 0x97D829FDE4E50ull, 0x9C49182A3F090ull,
2517 0xA0C667B5DE565ull, 0xA5503B23E255Dull, 0xA9E6B5579FDBFull,
2518 0xAE89F995AD3ADull, 0xB33A2B84F15FBull, 0xB7F76F2FB5E47ull,
2519 0xBCC1E904BC1D2ull, 0xC199BDD85529Cull, 0xC67F12E57D14Bull,
2520 0xCB720DCEF9069ull, 0xD072D4A07897Cull, 0xD5818DCFBA487ull,
2521 0xDA9E603DB3285ull, 0xDFC97337B9B5Full, 0xE502EE78B3FF6ull,
2522 0xEA4AFA2A490DAull, 0xEFA1BEE615A27ull, 0xF50765B6E4540ull,
2523 0xFA7C1819E90D8ull,
2524 };
2525 intptr_t i, opr_sz = simd_oprsz(desc) / 8;
2526 uint64_t *d = vd, *n = vn;
2527
2528 for (i = 0; i < opr_sz; i++) {
2529 uint64_t nn = n[i];
2530 intptr_t idx = extract32(nn, 0, 6);
2531 uint64_t exp = extract32(nn, 6, 11);
2532 d[i] = coeff[idx] | (exp << 52);
2533 }
2534 }
2535
HELPER(sve_ftssel_h)2536 void HELPER(sve_ftssel_h)(void *vd, void *vn, void *vm, uint32_t desc)
2537 {
2538 intptr_t i, opr_sz = simd_oprsz(desc) / 2;
2539 uint16_t *d = vd, *n = vn, *m = vm;
2540 for (i = 0; i < opr_sz; i += 1) {
2541 uint16_t nn = n[i];
2542 uint16_t mm = m[i];
2543 if (mm & 1) {
2544 nn = float16_one;
2545 }
2546 d[i] = nn ^ (mm & 2) << 14;
2547 }
2548 }
2549
HELPER(sve_ftssel_s)2550 void HELPER(sve_ftssel_s)(void *vd, void *vn, void *vm, uint32_t desc)
2551 {
2552 intptr_t i, opr_sz = simd_oprsz(desc) / 4;
2553 uint32_t *d = vd, *n = vn, *m = vm;
2554 for (i = 0; i < opr_sz; i += 1) {
2555 uint32_t nn = n[i];
2556 uint32_t mm = m[i];
2557 if (mm & 1) {
2558 nn = float32_one;
2559 }
2560 d[i] = nn ^ (mm & 2) << 30;
2561 }
2562 }
2563
HELPER(sve_ftssel_d)2564 void HELPER(sve_ftssel_d)(void *vd, void *vn, void *vm, uint32_t desc)
2565 {
2566 intptr_t i, opr_sz = simd_oprsz(desc) / 8;
2567 uint64_t *d = vd, *n = vn, *m = vm;
2568 for (i = 0; i < opr_sz; i += 1) {
2569 uint64_t nn = n[i];
2570 uint64_t mm = m[i];
2571 if (mm & 1) {
2572 nn = float64_one;
2573 }
2574 d[i] = nn ^ (mm & 2) << 62;
2575 }
2576 }
2577
2578 /*
2579 * Signed saturating addition with scalar operand.
2580 */
2581
HELPER(sve_sqaddi_b)2582 void HELPER(sve_sqaddi_b)(void *d, void *a, int32_t b, uint32_t desc)
2583 {
2584 intptr_t i, oprsz = simd_oprsz(desc);
2585
2586 for (i = 0; i < oprsz; i += sizeof(int8_t)) {
2587 *(int8_t *)(d + i) = DO_SQADD_B(b, *(int8_t *)(a + i));
2588 }
2589 }
2590
HELPER(sve_sqaddi_h)2591 void HELPER(sve_sqaddi_h)(void *d, void *a, int32_t b, uint32_t desc)
2592 {
2593 intptr_t i, oprsz = simd_oprsz(desc);
2594
2595 for (i = 0; i < oprsz; i += sizeof(int16_t)) {
2596 *(int16_t *)(d + i) = DO_SQADD_H(b, *(int16_t *)(a + i));
2597 }
2598 }
2599
HELPER(sve_sqaddi_s)2600 void HELPER(sve_sqaddi_s)(void *d, void *a, int64_t b, uint32_t desc)
2601 {
2602 intptr_t i, oprsz = simd_oprsz(desc);
2603
2604 for (i = 0; i < oprsz; i += sizeof(int32_t)) {
2605 *(int32_t *)(d + i) = DO_SQADD_S(b, *(int32_t *)(a + i));
2606 }
2607 }
2608
HELPER(sve_sqaddi_d)2609 void HELPER(sve_sqaddi_d)(void *d, void *a, int64_t b, uint32_t desc)
2610 {
2611 intptr_t i, oprsz = simd_oprsz(desc);
2612
2613 for (i = 0; i < oprsz; i += sizeof(int64_t)) {
2614 *(int64_t *)(d + i) = do_sqadd_d(b, *(int64_t *)(a + i));
2615 }
2616 }
2617
2618 /*
2619 * Unsigned saturating addition with scalar operand.
2620 */
2621
HELPER(sve_uqaddi_b)2622 void HELPER(sve_uqaddi_b)(void *d, void *a, int32_t b, uint32_t desc)
2623 {
2624 intptr_t i, oprsz = simd_oprsz(desc);
2625
2626 for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
2627 *(uint8_t *)(d + i) = DO_UQADD_B(b, *(uint8_t *)(a + i));
2628 }
2629 }
2630
HELPER(sve_uqaddi_h)2631 void HELPER(sve_uqaddi_h)(void *d, void *a, int32_t b, uint32_t desc)
2632 {
2633 intptr_t i, oprsz = simd_oprsz(desc);
2634
2635 for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
2636 *(uint16_t *)(d + i) = DO_UQADD_H(b, *(uint16_t *)(a + i));
2637 }
2638 }
2639
HELPER(sve_uqaddi_s)2640 void HELPER(sve_uqaddi_s)(void *d, void *a, int64_t b, uint32_t desc)
2641 {
2642 intptr_t i, oprsz = simd_oprsz(desc);
2643
2644 for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
2645 *(uint32_t *)(d + i) = DO_UQADD_S(b, *(uint32_t *)(a + i));
2646 }
2647 }
2648
HELPER(sve_uqaddi_d)2649 void HELPER(sve_uqaddi_d)(void *d, void *a, uint64_t b, uint32_t desc)
2650 {
2651 intptr_t i, oprsz = simd_oprsz(desc);
2652
2653 for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
2654 *(uint64_t *)(d + i) = do_uqadd_d(b, *(uint64_t *)(a + i));
2655 }
2656 }
2657
HELPER(sve_uqsubi_d)2658 void HELPER(sve_uqsubi_d)(void *d, void *a, uint64_t b, uint32_t desc)
2659 {
2660 intptr_t i, oprsz = simd_oprsz(desc);
2661
2662 for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
2663 *(uint64_t *)(d + i) = do_uqsub_d(*(uint64_t *)(a + i), b);
2664 }
2665 }
2666
2667 /* Two operand predicated copy immediate with merge. All valid immediates
2668 * can fit within 17 signed bits in the simd_data field.
2669 */
HELPER(sve_cpy_m_b)2670 void HELPER(sve_cpy_m_b)(void *vd, void *vn, void *vg,
2671 uint64_t mm, uint32_t desc)
2672 {
2673 intptr_t i, opr_sz = simd_oprsz(desc) / 8;
2674 uint64_t *d = vd, *n = vn;
2675 uint8_t *pg = vg;
2676
2677 mm = dup_const(MO_8, mm);
2678 for (i = 0; i < opr_sz; i += 1) {
2679 uint64_t nn = n[i];
2680 uint64_t pp = expand_pred_b(pg[H1(i)]);
2681 d[i] = (mm & pp) | (nn & ~pp);
2682 }
2683 }
2684
HELPER(sve_cpy_m_h)2685 void HELPER(sve_cpy_m_h)(void *vd, void *vn, void *vg,
2686 uint64_t mm, uint32_t desc)
2687 {
2688 intptr_t i, opr_sz = simd_oprsz(desc) / 8;
2689 uint64_t *d = vd, *n = vn;
2690 uint8_t *pg = vg;
2691
2692 mm = dup_const(MO_16, mm);
2693 for (i = 0; i < opr_sz; i += 1) {
2694 uint64_t nn = n[i];
2695 uint64_t pp = expand_pred_h(pg[H1(i)]);
2696 d[i] = (mm & pp) | (nn & ~pp);
2697 }
2698 }
2699
HELPER(sve_cpy_m_s)2700 void HELPER(sve_cpy_m_s)(void *vd, void *vn, void *vg,
2701 uint64_t mm, uint32_t desc)
2702 {
2703 intptr_t i, opr_sz = simd_oprsz(desc) / 8;
2704 uint64_t *d = vd, *n = vn;
2705 uint8_t *pg = vg;
2706
2707 mm = dup_const(MO_32, mm);
2708 for (i = 0; i < opr_sz; i += 1) {
2709 uint64_t nn = n[i];
2710 uint64_t pp = expand_pred_s(pg[H1(i)]);
2711 d[i] = (mm & pp) | (nn & ~pp);
2712 }
2713 }
2714
HELPER(sve_cpy_m_d)2715 void HELPER(sve_cpy_m_d)(void *vd, void *vn, void *vg,
2716 uint64_t mm, uint32_t desc)
2717 {
2718 intptr_t i, opr_sz = simd_oprsz(desc) / 8;
2719 uint64_t *d = vd, *n = vn;
2720 uint8_t *pg = vg;
2721
2722 for (i = 0; i < opr_sz; i += 1) {
2723 uint64_t nn = n[i];
2724 d[i] = (pg[H1(i)] & 1 ? mm : nn);
2725 }
2726 }
2727
HELPER(sve_cpy_z_b)2728 void HELPER(sve_cpy_z_b)(void *vd, void *vg, uint64_t val, uint32_t desc)
2729 {
2730 intptr_t i, opr_sz = simd_oprsz(desc) / 8;
2731 uint64_t *d = vd;
2732 uint8_t *pg = vg;
2733
2734 val = dup_const(MO_8, val);
2735 for (i = 0; i < opr_sz; i += 1) {
2736 d[i] = val & expand_pred_b(pg[H1(i)]);
2737 }
2738 }
2739
HELPER(sve_cpy_z_h)2740 void HELPER(sve_cpy_z_h)(void *vd, void *vg, uint64_t val, uint32_t desc)
2741 {
2742 intptr_t i, opr_sz = simd_oprsz(desc) / 8;
2743 uint64_t *d = vd;
2744 uint8_t *pg = vg;
2745
2746 val = dup_const(MO_16, val);
2747 for (i = 0; i < opr_sz; i += 1) {
2748 d[i] = val & expand_pred_h(pg[H1(i)]);
2749 }
2750 }
2751
HELPER(sve_cpy_z_s)2752 void HELPER(sve_cpy_z_s)(void *vd, void *vg, uint64_t val, uint32_t desc)
2753 {
2754 intptr_t i, opr_sz = simd_oprsz(desc) / 8;
2755 uint64_t *d = vd;
2756 uint8_t *pg = vg;
2757
2758 val = dup_const(MO_32, val);
2759 for (i = 0; i < opr_sz; i += 1) {
2760 d[i] = val & expand_pred_s(pg[H1(i)]);
2761 }
2762 }
2763
HELPER(sve_cpy_z_d)2764 void HELPER(sve_cpy_z_d)(void *vd, void *vg, uint64_t val, uint32_t desc)
2765 {
2766 intptr_t i, opr_sz = simd_oprsz(desc) / 8;
2767 uint64_t *d = vd;
2768 uint8_t *pg = vg;
2769
2770 for (i = 0; i < opr_sz; i += 1) {
2771 d[i] = (pg[H1(i)] & 1 ? val : 0);
2772 }
2773 }
2774
2775 /* Big-endian hosts need to frob the byte indices. If the copy
2776 * happens to be 8-byte aligned, then no frobbing necessary.
2777 */
swap_memmove(void * vd,void * vs,size_t n)2778 static void swap_memmove(void *vd, void *vs, size_t n)
2779 {
2780 uintptr_t d = (uintptr_t)vd;
2781 uintptr_t s = (uintptr_t)vs;
2782 uintptr_t o = (d | s | n) & 7;
2783 size_t i;
2784
2785 #if !HOST_BIG_ENDIAN
2786 o = 0;
2787 #endif
2788 switch (o) {
2789 case 0:
2790 memmove(vd, vs, n);
2791 break;
2792
2793 case 4:
2794 if (d < s || d >= s + n) {
2795 for (i = 0; i < n; i += 4) {
2796 *(uint32_t *)H1_4(d + i) = *(uint32_t *)H1_4(s + i);
2797 }
2798 } else {
2799 for (i = n; i > 0; ) {
2800 i -= 4;
2801 *(uint32_t *)H1_4(d + i) = *(uint32_t *)H1_4(s + i);
2802 }
2803 }
2804 break;
2805
2806 case 2:
2807 case 6:
2808 if (d < s || d >= s + n) {
2809 for (i = 0; i < n; i += 2) {
2810 *(uint16_t *)H1_2(d + i) = *(uint16_t *)H1_2(s + i);
2811 }
2812 } else {
2813 for (i = n; i > 0; ) {
2814 i -= 2;
2815 *(uint16_t *)H1_2(d + i) = *(uint16_t *)H1_2(s + i);
2816 }
2817 }
2818 break;
2819
2820 default:
2821 if (d < s || d >= s + n) {
2822 for (i = 0; i < n; i++) {
2823 *(uint8_t *)H1(d + i) = *(uint8_t *)H1(s + i);
2824 }
2825 } else {
2826 for (i = n; i > 0; ) {
2827 i -= 1;
2828 *(uint8_t *)H1(d + i) = *(uint8_t *)H1(s + i);
2829 }
2830 }
2831 break;
2832 }
2833 }
2834
2835 /* Similarly for memset of 0. */
swap_memzero(void * vd,size_t n)2836 static void swap_memzero(void *vd, size_t n)
2837 {
2838 uintptr_t d = (uintptr_t)vd;
2839 uintptr_t o = (d | n) & 7;
2840 size_t i;
2841
2842 /* Usually, the first bit of a predicate is set, so N is 0. */
2843 if (likely(n == 0)) {
2844 return;
2845 }
2846
2847 #if !HOST_BIG_ENDIAN
2848 o = 0;
2849 #endif
2850 switch (o) {
2851 case 0:
2852 memset(vd, 0, n);
2853 break;
2854
2855 case 4:
2856 for (i = 0; i < n; i += 4) {
2857 *(uint32_t *)H1_4(d + i) = 0;
2858 }
2859 break;
2860
2861 case 2:
2862 case 6:
2863 for (i = 0; i < n; i += 2) {
2864 *(uint16_t *)H1_2(d + i) = 0;
2865 }
2866 break;
2867
2868 default:
2869 for (i = 0; i < n; i++) {
2870 *(uint8_t *)H1(d + i) = 0;
2871 }
2872 break;
2873 }
2874 }
2875
HELPER(sve_ext)2876 void HELPER(sve_ext)(void *vd, void *vn, void *vm, uint32_t desc)
2877 {
2878 intptr_t opr_sz = simd_oprsz(desc);
2879 size_t n_ofs = simd_data(desc);
2880 size_t n_siz = opr_sz - n_ofs;
2881
2882 if (vd != vm) {
2883 swap_memmove(vd, vn + n_ofs, n_siz);
2884 swap_memmove(vd + n_siz, vm, n_ofs);
2885 } else if (vd != vn) {
2886 swap_memmove(vd + n_siz, vd, n_ofs);
2887 swap_memmove(vd, vn + n_ofs, n_siz);
2888 } else {
2889 /* vd == vn == vm. Need temp space. */
2890 ARMVectorReg tmp;
2891 swap_memmove(&tmp, vm, n_ofs);
2892 swap_memmove(vd, vd + n_ofs, n_siz);
2893 memcpy(vd + n_siz, &tmp, n_ofs);
2894 }
2895 }
2896
2897 #define DO_INSR(NAME, TYPE, H) \
2898 void HELPER(NAME)(void *vd, void *vn, uint64_t val, uint32_t desc) \
2899 { \
2900 intptr_t opr_sz = simd_oprsz(desc); \
2901 swap_memmove(vd + sizeof(TYPE), vn, opr_sz - sizeof(TYPE)); \
2902 *(TYPE *)(vd + H(0)) = val; \
2903 }
2904
DO_INSR(sve_insr_b,uint8_t,H1)2905 DO_INSR(sve_insr_b, uint8_t, H1)
2906 DO_INSR(sve_insr_h, uint16_t, H1_2)
2907 DO_INSR(sve_insr_s, uint32_t, H1_4)
2908 DO_INSR(sve_insr_d, uint64_t, H1_8)
2909
2910 #undef DO_INSR
2911
2912 void HELPER(sve_rev_b)(void *vd, void *vn, uint32_t desc)
2913 {
2914 intptr_t i, j, opr_sz = simd_oprsz(desc);
2915 for (i = 0, j = opr_sz - 8; i < opr_sz / 2; i += 8, j -= 8) {
2916 uint64_t f = *(uint64_t *)(vn + i);
2917 uint64_t b = *(uint64_t *)(vn + j);
2918 *(uint64_t *)(vd + i) = bswap64(b);
2919 *(uint64_t *)(vd + j) = bswap64(f);
2920 }
2921 }
2922
HELPER(sve_rev_h)2923 void HELPER(sve_rev_h)(void *vd, void *vn, uint32_t desc)
2924 {
2925 intptr_t i, j, opr_sz = simd_oprsz(desc);
2926 for (i = 0, j = opr_sz - 8; i < opr_sz / 2; i += 8, j -= 8) {
2927 uint64_t f = *(uint64_t *)(vn + i);
2928 uint64_t b = *(uint64_t *)(vn + j);
2929 *(uint64_t *)(vd + i) = hswap64(b);
2930 *(uint64_t *)(vd + j) = hswap64(f);
2931 }
2932 }
2933
HELPER(sve_rev_s)2934 void HELPER(sve_rev_s)(void *vd, void *vn, uint32_t desc)
2935 {
2936 intptr_t i, j, opr_sz = simd_oprsz(desc);
2937 for (i = 0, j = opr_sz - 8; i < opr_sz / 2; i += 8, j -= 8) {
2938 uint64_t f = *(uint64_t *)(vn + i);
2939 uint64_t b = *(uint64_t *)(vn + j);
2940 *(uint64_t *)(vd + i) = rol64(b, 32);
2941 *(uint64_t *)(vd + j) = rol64(f, 32);
2942 }
2943 }
2944
HELPER(sve_rev_d)2945 void HELPER(sve_rev_d)(void *vd, void *vn, uint32_t desc)
2946 {
2947 intptr_t i, j, opr_sz = simd_oprsz(desc);
2948 for (i = 0, j = opr_sz - 8; i < opr_sz / 2; i += 8, j -= 8) {
2949 uint64_t f = *(uint64_t *)(vn + i);
2950 uint64_t b = *(uint64_t *)(vn + j);
2951 *(uint64_t *)(vd + i) = b;
2952 *(uint64_t *)(vd + j) = f;
2953 }
2954 }
2955
2956 typedef void tb_impl_fn(void *, void *, void *, void *, uintptr_t, bool);
2957
do_tbl1(void * vd,void * vn,void * vm,uint32_t desc,bool is_tbx,tb_impl_fn * fn)2958 static inline void do_tbl1(void *vd, void *vn, void *vm, uint32_t desc,
2959 bool is_tbx, tb_impl_fn *fn)
2960 {
2961 ARMVectorReg scratch;
2962 uintptr_t oprsz = simd_oprsz(desc);
2963
2964 if (unlikely(vd == vn)) {
2965 vn = memcpy(&scratch, vn, oprsz);
2966 }
2967
2968 fn(vd, vn, NULL, vm, oprsz, is_tbx);
2969 }
2970
do_tbl2(void * vd,void * vn0,void * vn1,void * vm,uint32_t desc,bool is_tbx,tb_impl_fn * fn)2971 static inline void do_tbl2(void *vd, void *vn0, void *vn1, void *vm,
2972 uint32_t desc, bool is_tbx, tb_impl_fn *fn)
2973 {
2974 ARMVectorReg scratch;
2975 uintptr_t oprsz = simd_oprsz(desc);
2976
2977 if (unlikely(vd == vn0)) {
2978 vn0 = memcpy(&scratch, vn0, oprsz);
2979 if (vd == vn1) {
2980 vn1 = vn0;
2981 }
2982 } else if (unlikely(vd == vn1)) {
2983 vn1 = memcpy(&scratch, vn1, oprsz);
2984 }
2985
2986 fn(vd, vn0, vn1, vm, oprsz, is_tbx);
2987 }
2988
2989 #define DO_TB(SUFF, TYPE, H) \
2990 static inline void do_tb_##SUFF(void *vd, void *vt0, void *vt1, \
2991 void *vm, uintptr_t oprsz, bool is_tbx) \
2992 { \
2993 TYPE *d = vd, *tbl0 = vt0, *tbl1 = vt1, *indexes = vm; \
2994 uintptr_t i, nelem = oprsz / sizeof(TYPE); \
2995 for (i = 0; i < nelem; ++i) { \
2996 TYPE index = indexes[H1(i)], val = 0; \
2997 if (index < nelem) { \
2998 val = tbl0[H(index)]; \
2999 } else { \
3000 index -= nelem; \
3001 if (tbl1 && index < nelem) { \
3002 val = tbl1[H(index)]; \
3003 } else if (is_tbx) { \
3004 continue; \
3005 } \
3006 } \
3007 d[H(i)] = val; \
3008 } \
3009 } \
3010 void HELPER(sve_tbl_##SUFF)(void *vd, void *vn, void *vm, uint32_t desc) \
3011 { \
3012 do_tbl1(vd, vn, vm, desc, false, do_tb_##SUFF); \
3013 } \
3014 void HELPER(sve2_tbl_##SUFF)(void *vd, void *vn0, void *vn1, \
3015 void *vm, uint32_t desc) \
3016 { \
3017 do_tbl2(vd, vn0, vn1, vm, desc, false, do_tb_##SUFF); \
3018 } \
3019 void HELPER(sve2_tbx_##SUFF)(void *vd, void *vn, void *vm, uint32_t desc) \
3020 { \
3021 do_tbl1(vd, vn, vm, desc, true, do_tb_##SUFF); \
3022 }
3023
3024 DO_TB(b, uint8_t, H1)
3025 DO_TB(h, uint16_t, H2)
3026 DO_TB(s, uint32_t, H4)
3027 DO_TB(d, uint64_t, H8)
3028
3029 #undef DO_TB
3030
3031 #define DO_UNPK(NAME, TYPED, TYPES, HD, HS) \
3032 void HELPER(NAME)(void *vd, void *vn, uint32_t desc) \
3033 { \
3034 intptr_t i, opr_sz = simd_oprsz(desc); \
3035 TYPED *d = vd; \
3036 TYPES *n = vn; \
3037 ARMVectorReg tmp; \
3038 if (unlikely(vn - vd < opr_sz)) { \
3039 n = memcpy(&tmp, n, opr_sz / 2); \
3040 } \
3041 for (i = 0; i < opr_sz / sizeof(TYPED); i++) { \
3042 d[HD(i)] = n[HS(i)]; \
3043 } \
3044 }
3045
3046 DO_UNPK(sve_sunpk_h, int16_t, int8_t, H2, H1)
3047 DO_UNPK(sve_sunpk_s, int32_t, int16_t, H4, H2)
3048 DO_UNPK(sve_sunpk_d, int64_t, int32_t, H8, H4)
3049
3050 DO_UNPK(sve_uunpk_h, uint16_t, uint8_t, H2, H1)
3051 DO_UNPK(sve_uunpk_s, uint32_t, uint16_t, H4, H2)
3052 DO_UNPK(sve_uunpk_d, uint64_t, uint32_t, H8, H4)
3053
3054 #undef DO_UNPK
3055
3056 /* Mask of bits included in the even numbered predicates of width esz.
3057 * We also use this for expand_bits/compress_bits, and so extend the
3058 * same pattern out to 16-bit units.
3059 */
3060 static const uint64_t even_bit_esz_masks[5] = {
3061 0x5555555555555555ull,
3062 0x3333333333333333ull,
3063 0x0f0f0f0f0f0f0f0full,
3064 0x00ff00ff00ff00ffull,
3065 0x0000ffff0000ffffull,
3066 };
3067
3068 /* Zero-extend units of 2**N bits to units of 2**(N+1) bits.
3069 * For N==0, this corresponds to the operation that in qemu/bitops.h
3070 * we call half_shuffle64; this algorithm is from Hacker's Delight,
3071 * section 7-2 Shuffling Bits.
3072 */
expand_bits(uint64_t x,int n)3073 static uint64_t expand_bits(uint64_t x, int n)
3074 {
3075 int i;
3076
3077 x &= 0xffffffffu;
3078 for (i = 4; i >= n; i--) {
3079 int sh = 1 << i;
3080 x = ((x << sh) | x) & even_bit_esz_masks[i];
3081 }
3082 return x;
3083 }
3084
3085 /* Compress units of 2**(N+1) bits to units of 2**N bits.
3086 * For N==0, this corresponds to the operation that in qemu/bitops.h
3087 * we call half_unshuffle64; this algorithm is from Hacker's Delight,
3088 * section 7-2 Shuffling Bits, where it is called an inverse half shuffle.
3089 */
compress_bits(uint64_t x,int n)3090 static uint64_t compress_bits(uint64_t x, int n)
3091 {
3092 int i;
3093
3094 for (i = n; i <= 4; i++) {
3095 int sh = 1 << i;
3096 x &= even_bit_esz_masks[i];
3097 x = (x >> sh) | x;
3098 }
3099 return x & 0xffffffffu;
3100 }
3101
HELPER(sve_zip_p)3102 void HELPER(sve_zip_p)(void *vd, void *vn, void *vm, uint32_t pred_desc)
3103 {
3104 intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
3105 int esz = FIELD_EX32(pred_desc, PREDDESC, ESZ);
3106 intptr_t high = FIELD_EX32(pred_desc, PREDDESC, DATA);
3107 int esize = 1 << esz;
3108 uint64_t *d = vd;
3109 intptr_t i;
3110
3111 if (oprsz <= 8) {
3112 uint64_t nn = *(uint64_t *)vn;
3113 uint64_t mm = *(uint64_t *)vm;
3114 int half = 4 * oprsz;
3115
3116 nn = extract64(nn, high * half, half);
3117 mm = extract64(mm, high * half, half);
3118 nn = expand_bits(nn, esz);
3119 mm = expand_bits(mm, esz);
3120 d[0] = nn | (mm << esize);
3121 } else {
3122 ARMPredicateReg tmp;
3123
3124 /* We produce output faster than we consume input.
3125 Therefore we must be mindful of possible overlap. */
3126 if (vd == vn) {
3127 vn = memcpy(&tmp, vn, oprsz);
3128 if (vd == vm) {
3129 vm = vn;
3130 }
3131 } else if (vd == vm) {
3132 vm = memcpy(&tmp, vm, oprsz);
3133 }
3134 if (high) {
3135 high = oprsz >> 1;
3136 }
3137
3138 if ((oprsz & 7) == 0) {
3139 uint32_t *n = vn, *m = vm;
3140 high >>= 2;
3141
3142 for (i = 0; i < oprsz / 8; i++) {
3143 uint64_t nn = n[H4(high + i)];
3144 uint64_t mm = m[H4(high + i)];
3145
3146 nn = expand_bits(nn, esz);
3147 mm = expand_bits(mm, esz);
3148 d[i] = nn | (mm << esize);
3149 }
3150 } else {
3151 uint8_t *n = vn, *m = vm;
3152 uint16_t *d16 = vd;
3153
3154 for (i = 0; i < oprsz / 2; i++) {
3155 uint16_t nn = n[H1(high + i)];
3156 uint16_t mm = m[H1(high + i)];
3157
3158 nn = expand_bits(nn, esz);
3159 mm = expand_bits(mm, esz);
3160 d16[H2(i)] = nn | (mm << esize);
3161 }
3162 }
3163 }
3164 }
3165
HELPER(sve_uzp_p)3166 void HELPER(sve_uzp_p)(void *vd, void *vn, void *vm, uint32_t pred_desc)
3167 {
3168 intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
3169 int esz = FIELD_EX32(pred_desc, PREDDESC, ESZ);
3170 int odd = FIELD_EX32(pred_desc, PREDDESC, DATA) << esz;
3171 uint64_t *d = vd, *n = vn, *m = vm;
3172 uint64_t l, h;
3173 intptr_t i;
3174
3175 if (oprsz <= 8) {
3176 l = compress_bits(n[0] >> odd, esz);
3177 h = compress_bits(m[0] >> odd, esz);
3178 d[0] = l | (h << (4 * oprsz));
3179 } else {
3180 ARMPredicateReg tmp_m;
3181 intptr_t oprsz_16 = oprsz / 16;
3182
3183 if ((vm - vd) < (uintptr_t)oprsz) {
3184 m = memcpy(&tmp_m, vm, oprsz);
3185 }
3186
3187 for (i = 0; i < oprsz_16; i++) {
3188 l = n[2 * i + 0];
3189 h = n[2 * i + 1];
3190 l = compress_bits(l >> odd, esz);
3191 h = compress_bits(h >> odd, esz);
3192 d[i] = l | (h << 32);
3193 }
3194
3195 /*
3196 * For VL which is not a multiple of 512, the results from M do not
3197 * align nicely with the uint64_t for D. Put the aligned results
3198 * from M into TMP_M and then copy it into place afterward.
3199 */
3200 if (oprsz & 15) {
3201 int final_shift = (oprsz & 15) * 2;
3202
3203 l = n[2 * i + 0];
3204 h = n[2 * i + 1];
3205 l = compress_bits(l >> odd, esz);
3206 h = compress_bits(h >> odd, esz);
3207 d[i] = l | (h << final_shift);
3208
3209 for (i = 0; i < oprsz_16; i++) {
3210 l = m[2 * i + 0];
3211 h = m[2 * i + 1];
3212 l = compress_bits(l >> odd, esz);
3213 h = compress_bits(h >> odd, esz);
3214 tmp_m.p[i] = l | (h << 32);
3215 }
3216 l = m[2 * i + 0];
3217 h = m[2 * i + 1];
3218 l = compress_bits(l >> odd, esz);
3219 h = compress_bits(h >> odd, esz);
3220 tmp_m.p[i] = l | (h << final_shift);
3221
3222 swap_memmove(vd + oprsz / 2, &tmp_m, oprsz / 2);
3223 } else {
3224 for (i = 0; i < oprsz_16; i++) {
3225 l = m[2 * i + 0];
3226 h = m[2 * i + 1];
3227 l = compress_bits(l >> odd, esz);
3228 h = compress_bits(h >> odd, esz);
3229 d[oprsz_16 + i] = l | (h << 32);
3230 }
3231 }
3232 }
3233 }
3234
HELPER(sve_trn_p)3235 void HELPER(sve_trn_p)(void *vd, void *vn, void *vm, uint32_t pred_desc)
3236 {
3237 intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
3238 int esz = FIELD_EX32(pred_desc, PREDDESC, ESZ);
3239 int odd = FIELD_EX32(pred_desc, PREDDESC, DATA);
3240 uint64_t *d = vd, *n = vn, *m = vm;
3241 uint64_t mask;
3242 int shr, shl;
3243 intptr_t i;
3244
3245 shl = 1 << esz;
3246 shr = 0;
3247 mask = even_bit_esz_masks[esz];
3248 if (odd) {
3249 mask <<= shl;
3250 shr = shl;
3251 shl = 0;
3252 }
3253
3254 for (i = 0; i < DIV_ROUND_UP(oprsz, 8); i++) {
3255 uint64_t nn = (n[i] & mask) >> shr;
3256 uint64_t mm = (m[i] & mask) << shl;
3257 d[i] = nn + mm;
3258 }
3259 }
3260
3261 /* Reverse units of 2**N bits. */
reverse_bits_64(uint64_t x,int n)3262 static uint64_t reverse_bits_64(uint64_t x, int n)
3263 {
3264 int i, sh;
3265
3266 x = bswap64(x);
3267 for (i = 2, sh = 4; i >= n; i--, sh >>= 1) {
3268 uint64_t mask = even_bit_esz_masks[i];
3269 x = ((x & mask) << sh) | ((x >> sh) & mask);
3270 }
3271 return x;
3272 }
3273
reverse_bits_8(uint8_t x,int n)3274 static uint8_t reverse_bits_8(uint8_t x, int n)
3275 {
3276 static const uint8_t mask[3] = { 0x55, 0x33, 0x0f };
3277 int i, sh;
3278
3279 for (i = 2, sh = 4; i >= n; i--, sh >>= 1) {
3280 x = ((x & mask[i]) << sh) | ((x >> sh) & mask[i]);
3281 }
3282 return x;
3283 }
3284
HELPER(sve_rev_p)3285 void HELPER(sve_rev_p)(void *vd, void *vn, uint32_t pred_desc)
3286 {
3287 intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
3288 int esz = FIELD_EX32(pred_desc, PREDDESC, ESZ);
3289 intptr_t i, oprsz_2 = oprsz / 2;
3290
3291 if (oprsz <= 8) {
3292 uint64_t l = *(uint64_t *)vn;
3293 l = reverse_bits_64(l << (64 - 8 * oprsz), esz);
3294 *(uint64_t *)vd = l;
3295 } else if ((oprsz & 15) == 0) {
3296 for (i = 0; i < oprsz_2; i += 8) {
3297 intptr_t ih = oprsz - 8 - i;
3298 uint64_t l = reverse_bits_64(*(uint64_t *)(vn + i), esz);
3299 uint64_t h = reverse_bits_64(*(uint64_t *)(vn + ih), esz);
3300 *(uint64_t *)(vd + i) = h;
3301 *(uint64_t *)(vd + ih) = l;
3302 }
3303 } else {
3304 for (i = 0; i < oprsz_2; i += 1) {
3305 intptr_t il = H1(i);
3306 intptr_t ih = H1(oprsz - 1 - i);
3307 uint8_t l = reverse_bits_8(*(uint8_t *)(vn + il), esz);
3308 uint8_t h = reverse_bits_8(*(uint8_t *)(vn + ih), esz);
3309 *(uint8_t *)(vd + il) = h;
3310 *(uint8_t *)(vd + ih) = l;
3311 }
3312 }
3313 }
3314
HELPER(sve_punpk_p)3315 void HELPER(sve_punpk_p)(void *vd, void *vn, uint32_t pred_desc)
3316 {
3317 intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
3318 intptr_t high = FIELD_EX32(pred_desc, PREDDESC, DATA);
3319 uint64_t *d = vd;
3320 intptr_t i;
3321
3322 if (oprsz <= 8) {
3323 uint64_t nn = *(uint64_t *)vn;
3324 int half = 4 * oprsz;
3325
3326 nn = extract64(nn, high * half, half);
3327 nn = expand_bits(nn, 0);
3328 d[0] = nn;
3329 } else {
3330 ARMPredicateReg tmp_n;
3331
3332 /* We produce output faster than we consume input.
3333 Therefore we must be mindful of possible overlap. */
3334 if ((vn - vd) < (uintptr_t)oprsz) {
3335 vn = memcpy(&tmp_n, vn, oprsz);
3336 }
3337 if (high) {
3338 high = oprsz >> 1;
3339 }
3340
3341 if ((oprsz & 7) == 0) {
3342 uint32_t *n = vn;
3343 high >>= 2;
3344
3345 for (i = 0; i < oprsz / 8; i++) {
3346 uint64_t nn = n[H4(high + i)];
3347 d[i] = expand_bits(nn, 0);
3348 }
3349 } else {
3350 uint16_t *d16 = vd;
3351 uint8_t *n = vn;
3352
3353 for (i = 0; i < oprsz / 2; i++) {
3354 uint16_t nn = n[H1(high + i)];
3355 d16[H2(i)] = expand_bits(nn, 0);
3356 }
3357 }
3358 }
3359 }
3360
3361 #define DO_ZIP(NAME, TYPE, H) \
3362 void HELPER(NAME)(void *vd, void *vn, void *vm, uint32_t desc) \
3363 { \
3364 intptr_t oprsz = simd_oprsz(desc); \
3365 intptr_t odd_ofs = simd_data(desc); \
3366 intptr_t i, oprsz_2 = oprsz / 2; \
3367 ARMVectorReg tmp_n, tmp_m; \
3368 /* We produce output faster than we consume input. \
3369 Therefore we must be mindful of possible overlap. */ \
3370 if (unlikely((vn - vd) < (uintptr_t)oprsz)) { \
3371 vn = memcpy(&tmp_n, vn, oprsz); \
3372 } \
3373 if (unlikely((vm - vd) < (uintptr_t)oprsz)) { \
3374 vm = memcpy(&tmp_m, vm, oprsz); \
3375 } \
3376 for (i = 0; i < oprsz_2; i += sizeof(TYPE)) { \
3377 *(TYPE *)(vd + H(2 * i + 0)) = *(TYPE *)(vn + odd_ofs + H(i)); \
3378 *(TYPE *)(vd + H(2 * i + sizeof(TYPE))) = \
3379 *(TYPE *)(vm + odd_ofs + H(i)); \
3380 } \
3381 if (sizeof(TYPE) == 16 && unlikely(oprsz & 16)) { \
3382 memset(vd + oprsz - 16, 0, 16); \
3383 } \
3384 }
3385
DO_ZIP(sve_zip_b,uint8_t,H1)3386 DO_ZIP(sve_zip_b, uint8_t, H1)
3387 DO_ZIP(sve_zip_h, uint16_t, H1_2)
3388 DO_ZIP(sve_zip_s, uint32_t, H1_4)
3389 DO_ZIP(sve_zip_d, uint64_t, H1_8)
3390 DO_ZIP(sve2_zip_q, Int128, )
3391
3392 #define DO_UZP(NAME, TYPE, H) \
3393 void HELPER(NAME)(void *vd, void *vn, void *vm, uint32_t desc) \
3394 { \
3395 intptr_t oprsz = simd_oprsz(desc); \
3396 intptr_t odd_ofs = simd_data(desc); \
3397 intptr_t i, p; \
3398 ARMVectorReg tmp_m; \
3399 if (unlikely((vm - vd) < (uintptr_t)oprsz)) { \
3400 vm = memcpy(&tmp_m, vm, oprsz); \
3401 } \
3402 i = 0, p = odd_ofs; \
3403 do { \
3404 *(TYPE *)(vd + H(i)) = *(TYPE *)(vn + H(p)); \
3405 i += sizeof(TYPE), p += 2 * sizeof(TYPE); \
3406 } while (p < oprsz); \
3407 p -= oprsz; \
3408 do { \
3409 *(TYPE *)(vd + H(i)) = *(TYPE *)(vm + H(p)); \
3410 i += sizeof(TYPE), p += 2 * sizeof(TYPE); \
3411 } while (p < oprsz); \
3412 tcg_debug_assert(i == oprsz); \
3413 }
3414
3415 DO_UZP(sve_uzp_b, uint8_t, H1)
3416 DO_UZP(sve_uzp_h, uint16_t, H1_2)
3417 DO_UZP(sve_uzp_s, uint32_t, H1_4)
3418 DO_UZP(sve_uzp_d, uint64_t, H1_8)
3419 DO_UZP(sve2_uzp_q, Int128, )
3420
3421 #define DO_TRN(NAME, TYPE, H) \
3422 void HELPER(NAME)(void *vd, void *vn, void *vm, uint32_t desc) \
3423 { \
3424 intptr_t oprsz = simd_oprsz(desc); \
3425 intptr_t odd_ofs = simd_data(desc); \
3426 intptr_t i; \
3427 for (i = 0; i < oprsz; i += 2 * sizeof(TYPE)) { \
3428 TYPE ae = *(TYPE *)(vn + H(i + odd_ofs)); \
3429 TYPE be = *(TYPE *)(vm + H(i + odd_ofs)); \
3430 *(TYPE *)(vd + H(i + 0)) = ae; \
3431 *(TYPE *)(vd + H(i + sizeof(TYPE))) = be; \
3432 } \
3433 if (sizeof(TYPE) == 16 && unlikely(oprsz & 16)) { \
3434 memset(vd + oprsz - 16, 0, 16); \
3435 } \
3436 }
3437
3438 DO_TRN(sve_trn_b, uint8_t, H1)
3439 DO_TRN(sve_trn_h, uint16_t, H1_2)
3440 DO_TRN(sve_trn_s, uint32_t, H1_4)
3441 DO_TRN(sve_trn_d, uint64_t, H1_8)
3442 DO_TRN(sve2_trn_q, Int128, )
3443
3444 #undef DO_ZIP
3445 #undef DO_UZP
3446 #undef DO_TRN
3447
3448 void HELPER(sve_compact_s)(void *vd, void *vn, void *vg, uint32_t desc)
3449 {
3450 intptr_t i, j, opr_sz = simd_oprsz(desc) / 4;
3451 uint32_t *d = vd, *n = vn;
3452 uint8_t *pg = vg;
3453
3454 for (i = j = 0; i < opr_sz; i++) {
3455 if (pg[H1(i / 2)] & (i & 1 ? 0x10 : 0x01)) {
3456 d[H4(j)] = n[H4(i)];
3457 j++;
3458 }
3459 }
3460 for (; j < opr_sz; j++) {
3461 d[H4(j)] = 0;
3462 }
3463 }
3464
HELPER(sve_compact_d)3465 void HELPER(sve_compact_d)(void *vd, void *vn, void *vg, uint32_t desc)
3466 {
3467 intptr_t i, j, opr_sz = simd_oprsz(desc) / 8;
3468 uint64_t *d = vd, *n = vn;
3469 uint8_t *pg = vg;
3470
3471 for (i = j = 0; i < opr_sz; i++) {
3472 if (pg[H1(i)] & 1) {
3473 d[j] = n[i];
3474 j++;
3475 }
3476 }
3477 for (; j < opr_sz; j++) {
3478 d[j] = 0;
3479 }
3480 }
3481
3482 /* Similar to the ARM LastActiveElement pseudocode function, except the
3483 * result is multiplied by the element size. This includes the not found
3484 * indication; e.g. not found for esz=3 is -8.
3485 */
HELPER(sve_last_active_element)3486 int32_t HELPER(sve_last_active_element)(void *vg, uint32_t pred_desc)
3487 {
3488 intptr_t words = DIV_ROUND_UP(FIELD_EX32(pred_desc, PREDDESC, OPRSZ), 8);
3489 intptr_t esz = FIELD_EX32(pred_desc, PREDDESC, ESZ);
3490
3491 return last_active_element(vg, words, esz);
3492 }
3493
HELPER(sve_splice)3494 void HELPER(sve_splice)(void *vd, void *vn, void *vm, void *vg, uint32_t desc)
3495 {
3496 intptr_t opr_sz = simd_oprsz(desc) / 8;
3497 int esz = simd_data(desc);
3498 uint64_t pg, first_g, last_g, len, mask = pred_esz_masks[esz];
3499 intptr_t i, first_i, last_i;
3500 ARMVectorReg tmp;
3501
3502 first_i = last_i = 0;
3503 first_g = last_g = 0;
3504
3505 /* Find the extent of the active elements within VG. */
3506 for (i = QEMU_ALIGN_UP(opr_sz, 8) - 8; i >= 0; i -= 8) {
3507 pg = *(uint64_t *)(vg + i) & mask;
3508 if (pg) {
3509 if (last_g == 0) {
3510 last_g = pg;
3511 last_i = i;
3512 }
3513 first_g = pg;
3514 first_i = i;
3515 }
3516 }
3517
3518 len = 0;
3519 if (first_g != 0) {
3520 first_i = first_i * 8 + ctz64(first_g);
3521 last_i = last_i * 8 + 63 - clz64(last_g);
3522 len = last_i - first_i + (1 << esz);
3523 if (vd == vm) {
3524 vm = memcpy(&tmp, vm, opr_sz * 8);
3525 }
3526 swap_memmove(vd, vn + first_i, len);
3527 }
3528 swap_memmove(vd + len, vm, opr_sz * 8 - len);
3529 }
3530
HELPER(sve_sel_zpzz_b)3531 void HELPER(sve_sel_zpzz_b)(void *vd, void *vn, void *vm,
3532 void *vg, uint32_t desc)
3533 {
3534 intptr_t i, opr_sz = simd_oprsz(desc) / 8;
3535 uint64_t *d = vd, *n = vn, *m = vm;
3536 uint8_t *pg = vg;
3537
3538 for (i = 0; i < opr_sz; i += 1) {
3539 uint64_t nn = n[i], mm = m[i];
3540 uint64_t pp = expand_pred_b(pg[H1(i)]);
3541 d[i] = (nn & pp) | (mm & ~pp);
3542 }
3543 }
3544
HELPER(sve_sel_zpzz_h)3545 void HELPER(sve_sel_zpzz_h)(void *vd, void *vn, void *vm,
3546 void *vg, uint32_t desc)
3547 {
3548 intptr_t i, opr_sz = simd_oprsz(desc) / 8;
3549 uint64_t *d = vd, *n = vn, *m = vm;
3550 uint8_t *pg = vg;
3551
3552 for (i = 0; i < opr_sz; i += 1) {
3553 uint64_t nn = n[i], mm = m[i];
3554 uint64_t pp = expand_pred_h(pg[H1(i)]);
3555 d[i] = (nn & pp) | (mm & ~pp);
3556 }
3557 }
3558
HELPER(sve_sel_zpzz_s)3559 void HELPER(sve_sel_zpzz_s)(void *vd, void *vn, void *vm,
3560 void *vg, uint32_t desc)
3561 {
3562 intptr_t i, opr_sz = simd_oprsz(desc) / 8;
3563 uint64_t *d = vd, *n = vn, *m = vm;
3564 uint8_t *pg = vg;
3565
3566 for (i = 0; i < opr_sz; i += 1) {
3567 uint64_t nn = n[i], mm = m[i];
3568 uint64_t pp = expand_pred_s(pg[H1(i)]);
3569 d[i] = (nn & pp) | (mm & ~pp);
3570 }
3571 }
3572
HELPER(sve_sel_zpzz_d)3573 void HELPER(sve_sel_zpzz_d)(void *vd, void *vn, void *vm,
3574 void *vg, uint32_t desc)
3575 {
3576 intptr_t i, opr_sz = simd_oprsz(desc) / 8;
3577 uint64_t *d = vd, *n = vn, *m = vm;
3578 uint8_t *pg = vg;
3579
3580 for (i = 0; i < opr_sz; i += 1) {
3581 uint64_t nn = n[i], mm = m[i];
3582 d[i] = (pg[H1(i)] & 1 ? nn : mm);
3583 }
3584 }
3585
HELPER(sve_sel_zpzz_q)3586 void HELPER(sve_sel_zpzz_q)(void *vd, void *vn, void *vm,
3587 void *vg, uint32_t desc)
3588 {
3589 intptr_t i, opr_sz = simd_oprsz(desc) / 16;
3590 Int128 *d = vd, *n = vn, *m = vm;
3591 uint16_t *pg = vg;
3592
3593 for (i = 0; i < opr_sz; i += 1) {
3594 d[i] = (pg[H2(i)] & 1 ? n : m)[i];
3595 }
3596 }
3597
3598 /* Two operand comparison controlled by a predicate.
3599 * ??? It is very tempting to want to be able to expand this inline
3600 * with x86 instructions, e.g.
3601 *
3602 * vcmpeqw zm, zn, %ymm0
3603 * vpmovmskb %ymm0, %eax
3604 * and $0x5555, %eax
3605 * and pg, %eax
3606 *
3607 * or even aarch64, e.g.
3608 *
3609 * // mask = 4000 1000 0400 0100 0040 0010 0004 0001
3610 * cmeq v0.8h, zn, zm
3611 * and v0.8h, v0.8h, mask
3612 * addv h0, v0.8h
3613 * and v0.8b, pg
3614 *
3615 * However, coming up with an abstraction that allows vector inputs and
3616 * a scalar output, and also handles the byte-ordering of sub-uint64_t
3617 * scalar outputs, is tricky.
3618 */
3619 #define DO_CMP_PPZZ(NAME, TYPE, OP, H, MASK) \
3620 uint32_t HELPER(NAME)(void *vd, void *vn, void *vm, void *vg, uint32_t desc) \
3621 { \
3622 intptr_t opr_sz = simd_oprsz(desc); \
3623 uint32_t flags = PREDTEST_INIT; \
3624 intptr_t i = opr_sz; \
3625 do { \
3626 uint64_t out = 0, pg; \
3627 do { \
3628 i -= sizeof(TYPE), out <<= sizeof(TYPE); \
3629 TYPE nn = *(TYPE *)(vn + H(i)); \
3630 TYPE mm = *(TYPE *)(vm + H(i)); \
3631 out |= nn OP mm; \
3632 } while (i & 63); \
3633 pg = *(uint64_t *)(vg + (i >> 3)) & MASK; \
3634 out &= pg; \
3635 *(uint64_t *)(vd + (i >> 3)) = out; \
3636 flags = iter_predtest_bwd(out, pg, flags); \
3637 } while (i > 0); \
3638 return flags; \
3639 }
3640
3641 #define DO_CMP_PPZZ_B(NAME, TYPE, OP) \
3642 DO_CMP_PPZZ(NAME, TYPE, OP, H1, 0xffffffffffffffffull)
3643 #define DO_CMP_PPZZ_H(NAME, TYPE, OP) \
3644 DO_CMP_PPZZ(NAME, TYPE, OP, H1_2, 0x5555555555555555ull)
3645 #define DO_CMP_PPZZ_S(NAME, TYPE, OP) \
3646 DO_CMP_PPZZ(NAME, TYPE, OP, H1_4, 0x1111111111111111ull)
3647 #define DO_CMP_PPZZ_D(NAME, TYPE, OP) \
3648 DO_CMP_PPZZ(NAME, TYPE, OP, H1_8, 0x0101010101010101ull)
3649
3650 DO_CMP_PPZZ_B(sve_cmpeq_ppzz_b, uint8_t, ==)
3651 DO_CMP_PPZZ_H(sve_cmpeq_ppzz_h, uint16_t, ==)
3652 DO_CMP_PPZZ_S(sve_cmpeq_ppzz_s, uint32_t, ==)
3653 DO_CMP_PPZZ_D(sve_cmpeq_ppzz_d, uint64_t, ==)
3654
3655 DO_CMP_PPZZ_B(sve_cmpne_ppzz_b, uint8_t, !=)
3656 DO_CMP_PPZZ_H(sve_cmpne_ppzz_h, uint16_t, !=)
3657 DO_CMP_PPZZ_S(sve_cmpne_ppzz_s, uint32_t, !=)
3658 DO_CMP_PPZZ_D(sve_cmpne_ppzz_d, uint64_t, !=)
3659
3660 DO_CMP_PPZZ_B(sve_cmpgt_ppzz_b, int8_t, >)
3661 DO_CMP_PPZZ_H(sve_cmpgt_ppzz_h, int16_t, >)
3662 DO_CMP_PPZZ_S(sve_cmpgt_ppzz_s, int32_t, >)
3663 DO_CMP_PPZZ_D(sve_cmpgt_ppzz_d, int64_t, >)
3664
3665 DO_CMP_PPZZ_B(sve_cmpge_ppzz_b, int8_t, >=)
3666 DO_CMP_PPZZ_H(sve_cmpge_ppzz_h, int16_t, >=)
3667 DO_CMP_PPZZ_S(sve_cmpge_ppzz_s, int32_t, >=)
3668 DO_CMP_PPZZ_D(sve_cmpge_ppzz_d, int64_t, >=)
3669
3670 DO_CMP_PPZZ_B(sve_cmphi_ppzz_b, uint8_t, >)
3671 DO_CMP_PPZZ_H(sve_cmphi_ppzz_h, uint16_t, >)
3672 DO_CMP_PPZZ_S(sve_cmphi_ppzz_s, uint32_t, >)
3673 DO_CMP_PPZZ_D(sve_cmphi_ppzz_d, uint64_t, >)
3674
3675 DO_CMP_PPZZ_B(sve_cmphs_ppzz_b, uint8_t, >=)
3676 DO_CMP_PPZZ_H(sve_cmphs_ppzz_h, uint16_t, >=)
3677 DO_CMP_PPZZ_S(sve_cmphs_ppzz_s, uint32_t, >=)
3678 DO_CMP_PPZZ_D(sve_cmphs_ppzz_d, uint64_t, >=)
3679
3680 #undef DO_CMP_PPZZ_B
3681 #undef DO_CMP_PPZZ_H
3682 #undef DO_CMP_PPZZ_S
3683 #undef DO_CMP_PPZZ_D
3684 #undef DO_CMP_PPZZ
3685
3686 /* Similar, but the second source is "wide". */
3687 #define DO_CMP_PPZW(NAME, TYPE, TYPEW, OP, H, MASK) \
3688 uint32_t HELPER(NAME)(void *vd, void *vn, void *vm, void *vg, uint32_t desc) \
3689 { \
3690 intptr_t opr_sz = simd_oprsz(desc); \
3691 uint32_t flags = PREDTEST_INIT; \
3692 intptr_t i = opr_sz; \
3693 do { \
3694 uint64_t out = 0, pg; \
3695 do { \
3696 TYPEW mm = *(TYPEW *)(vm + i - 8); \
3697 do { \
3698 i -= sizeof(TYPE), out <<= sizeof(TYPE); \
3699 TYPE nn = *(TYPE *)(vn + H(i)); \
3700 out |= nn OP mm; \
3701 } while (i & 7); \
3702 } while (i & 63); \
3703 pg = *(uint64_t *)(vg + (i >> 3)) & MASK; \
3704 out &= pg; \
3705 *(uint64_t *)(vd + (i >> 3)) = out; \
3706 flags = iter_predtest_bwd(out, pg, flags); \
3707 } while (i > 0); \
3708 return flags; \
3709 }
3710
3711 #define DO_CMP_PPZW_B(NAME, TYPE, TYPEW, OP) \
3712 DO_CMP_PPZW(NAME, TYPE, TYPEW, OP, H1, 0xffffffffffffffffull)
3713 #define DO_CMP_PPZW_H(NAME, TYPE, TYPEW, OP) \
3714 DO_CMP_PPZW(NAME, TYPE, TYPEW, OP, H1_2, 0x5555555555555555ull)
3715 #define DO_CMP_PPZW_S(NAME, TYPE, TYPEW, OP) \
3716 DO_CMP_PPZW(NAME, TYPE, TYPEW, OP, H1_4, 0x1111111111111111ull)
3717
3718 DO_CMP_PPZW_B(sve_cmpeq_ppzw_b, int8_t, uint64_t, ==)
3719 DO_CMP_PPZW_H(sve_cmpeq_ppzw_h, int16_t, uint64_t, ==)
3720 DO_CMP_PPZW_S(sve_cmpeq_ppzw_s, int32_t, uint64_t, ==)
3721
3722 DO_CMP_PPZW_B(sve_cmpne_ppzw_b, int8_t, uint64_t, !=)
3723 DO_CMP_PPZW_H(sve_cmpne_ppzw_h, int16_t, uint64_t, !=)
3724 DO_CMP_PPZW_S(sve_cmpne_ppzw_s, int32_t, uint64_t, !=)
3725
3726 DO_CMP_PPZW_B(sve_cmpgt_ppzw_b, int8_t, int64_t, >)
3727 DO_CMP_PPZW_H(sve_cmpgt_ppzw_h, int16_t, int64_t, >)
3728 DO_CMP_PPZW_S(sve_cmpgt_ppzw_s, int32_t, int64_t, >)
3729
3730 DO_CMP_PPZW_B(sve_cmpge_ppzw_b, int8_t, int64_t, >=)
3731 DO_CMP_PPZW_H(sve_cmpge_ppzw_h, int16_t, int64_t, >=)
3732 DO_CMP_PPZW_S(sve_cmpge_ppzw_s, int32_t, int64_t, >=)
3733
3734 DO_CMP_PPZW_B(sve_cmphi_ppzw_b, uint8_t, uint64_t, >)
3735 DO_CMP_PPZW_H(sve_cmphi_ppzw_h, uint16_t, uint64_t, >)
3736 DO_CMP_PPZW_S(sve_cmphi_ppzw_s, uint32_t, uint64_t, >)
3737
3738 DO_CMP_PPZW_B(sve_cmphs_ppzw_b, uint8_t, uint64_t, >=)
3739 DO_CMP_PPZW_H(sve_cmphs_ppzw_h, uint16_t, uint64_t, >=)
3740 DO_CMP_PPZW_S(sve_cmphs_ppzw_s, uint32_t, uint64_t, >=)
3741
3742 DO_CMP_PPZW_B(sve_cmplt_ppzw_b, int8_t, int64_t, <)
3743 DO_CMP_PPZW_H(sve_cmplt_ppzw_h, int16_t, int64_t, <)
3744 DO_CMP_PPZW_S(sve_cmplt_ppzw_s, int32_t, int64_t, <)
3745
3746 DO_CMP_PPZW_B(sve_cmple_ppzw_b, int8_t, int64_t, <=)
3747 DO_CMP_PPZW_H(sve_cmple_ppzw_h, int16_t, int64_t, <=)
3748 DO_CMP_PPZW_S(sve_cmple_ppzw_s, int32_t, int64_t, <=)
3749
3750 DO_CMP_PPZW_B(sve_cmplo_ppzw_b, uint8_t, uint64_t, <)
3751 DO_CMP_PPZW_H(sve_cmplo_ppzw_h, uint16_t, uint64_t, <)
3752 DO_CMP_PPZW_S(sve_cmplo_ppzw_s, uint32_t, uint64_t, <)
3753
3754 DO_CMP_PPZW_B(sve_cmpls_ppzw_b, uint8_t, uint64_t, <=)
3755 DO_CMP_PPZW_H(sve_cmpls_ppzw_h, uint16_t, uint64_t, <=)
3756 DO_CMP_PPZW_S(sve_cmpls_ppzw_s, uint32_t, uint64_t, <=)
3757
3758 #undef DO_CMP_PPZW_B
3759 #undef DO_CMP_PPZW_H
3760 #undef DO_CMP_PPZW_S
3761 #undef DO_CMP_PPZW
3762
3763 /* Similar, but the second source is immediate. */
3764 #define DO_CMP_PPZI(NAME, TYPE, OP, H, MASK) \
3765 uint32_t HELPER(NAME)(void *vd, void *vn, void *vg, uint32_t desc) \
3766 { \
3767 intptr_t opr_sz = simd_oprsz(desc); \
3768 uint32_t flags = PREDTEST_INIT; \
3769 TYPE mm = simd_data(desc); \
3770 intptr_t i = opr_sz; \
3771 do { \
3772 uint64_t out = 0, pg; \
3773 do { \
3774 i -= sizeof(TYPE), out <<= sizeof(TYPE); \
3775 TYPE nn = *(TYPE *)(vn + H(i)); \
3776 out |= nn OP mm; \
3777 } while (i & 63); \
3778 pg = *(uint64_t *)(vg + (i >> 3)) & MASK; \
3779 out &= pg; \
3780 *(uint64_t *)(vd + (i >> 3)) = out; \
3781 flags = iter_predtest_bwd(out, pg, flags); \
3782 } while (i > 0); \
3783 return flags; \
3784 }
3785
3786 #define DO_CMP_PPZI_B(NAME, TYPE, OP) \
3787 DO_CMP_PPZI(NAME, TYPE, OP, H1, 0xffffffffffffffffull)
3788 #define DO_CMP_PPZI_H(NAME, TYPE, OP) \
3789 DO_CMP_PPZI(NAME, TYPE, OP, H1_2, 0x5555555555555555ull)
3790 #define DO_CMP_PPZI_S(NAME, TYPE, OP) \
3791 DO_CMP_PPZI(NAME, TYPE, OP, H1_4, 0x1111111111111111ull)
3792 #define DO_CMP_PPZI_D(NAME, TYPE, OP) \
3793 DO_CMP_PPZI(NAME, TYPE, OP, H1_8, 0x0101010101010101ull)
3794
3795 DO_CMP_PPZI_B(sve_cmpeq_ppzi_b, uint8_t, ==)
3796 DO_CMP_PPZI_H(sve_cmpeq_ppzi_h, uint16_t, ==)
3797 DO_CMP_PPZI_S(sve_cmpeq_ppzi_s, uint32_t, ==)
3798 DO_CMP_PPZI_D(sve_cmpeq_ppzi_d, uint64_t, ==)
3799
3800 DO_CMP_PPZI_B(sve_cmpne_ppzi_b, uint8_t, !=)
3801 DO_CMP_PPZI_H(sve_cmpne_ppzi_h, uint16_t, !=)
3802 DO_CMP_PPZI_S(sve_cmpne_ppzi_s, uint32_t, !=)
3803 DO_CMP_PPZI_D(sve_cmpne_ppzi_d, uint64_t, !=)
3804
3805 DO_CMP_PPZI_B(sve_cmpgt_ppzi_b, int8_t, >)
3806 DO_CMP_PPZI_H(sve_cmpgt_ppzi_h, int16_t, >)
3807 DO_CMP_PPZI_S(sve_cmpgt_ppzi_s, int32_t, >)
3808 DO_CMP_PPZI_D(sve_cmpgt_ppzi_d, int64_t, >)
3809
3810 DO_CMP_PPZI_B(sve_cmpge_ppzi_b, int8_t, >=)
3811 DO_CMP_PPZI_H(sve_cmpge_ppzi_h, int16_t, >=)
3812 DO_CMP_PPZI_S(sve_cmpge_ppzi_s, int32_t, >=)
3813 DO_CMP_PPZI_D(sve_cmpge_ppzi_d, int64_t, >=)
3814
3815 DO_CMP_PPZI_B(sve_cmphi_ppzi_b, uint8_t, >)
3816 DO_CMP_PPZI_H(sve_cmphi_ppzi_h, uint16_t, >)
3817 DO_CMP_PPZI_S(sve_cmphi_ppzi_s, uint32_t, >)
3818 DO_CMP_PPZI_D(sve_cmphi_ppzi_d, uint64_t, >)
3819
3820 DO_CMP_PPZI_B(sve_cmphs_ppzi_b, uint8_t, >=)
3821 DO_CMP_PPZI_H(sve_cmphs_ppzi_h, uint16_t, >=)
3822 DO_CMP_PPZI_S(sve_cmphs_ppzi_s, uint32_t, >=)
3823 DO_CMP_PPZI_D(sve_cmphs_ppzi_d, uint64_t, >=)
3824
3825 DO_CMP_PPZI_B(sve_cmplt_ppzi_b, int8_t, <)
3826 DO_CMP_PPZI_H(sve_cmplt_ppzi_h, int16_t, <)
3827 DO_CMP_PPZI_S(sve_cmplt_ppzi_s, int32_t, <)
3828 DO_CMP_PPZI_D(sve_cmplt_ppzi_d, int64_t, <)
3829
3830 DO_CMP_PPZI_B(sve_cmple_ppzi_b, int8_t, <=)
3831 DO_CMP_PPZI_H(sve_cmple_ppzi_h, int16_t, <=)
3832 DO_CMP_PPZI_S(sve_cmple_ppzi_s, int32_t, <=)
3833 DO_CMP_PPZI_D(sve_cmple_ppzi_d, int64_t, <=)
3834
3835 DO_CMP_PPZI_B(sve_cmplo_ppzi_b, uint8_t, <)
3836 DO_CMP_PPZI_H(sve_cmplo_ppzi_h, uint16_t, <)
3837 DO_CMP_PPZI_S(sve_cmplo_ppzi_s, uint32_t, <)
3838 DO_CMP_PPZI_D(sve_cmplo_ppzi_d, uint64_t, <)
3839
3840 DO_CMP_PPZI_B(sve_cmpls_ppzi_b, uint8_t, <=)
3841 DO_CMP_PPZI_H(sve_cmpls_ppzi_h, uint16_t, <=)
3842 DO_CMP_PPZI_S(sve_cmpls_ppzi_s, uint32_t, <=)
3843 DO_CMP_PPZI_D(sve_cmpls_ppzi_d, uint64_t, <=)
3844
3845 #undef DO_CMP_PPZI_B
3846 #undef DO_CMP_PPZI_H
3847 #undef DO_CMP_PPZI_S
3848 #undef DO_CMP_PPZI_D
3849 #undef DO_CMP_PPZI
3850
3851 /* Similar to the ARM LastActive pseudocode function. */
last_active_pred(void * vd,void * vg,intptr_t oprsz)3852 static bool last_active_pred(void *vd, void *vg, intptr_t oprsz)
3853 {
3854 intptr_t i;
3855
3856 for (i = QEMU_ALIGN_UP(oprsz, 8) - 8; i >= 0; i -= 8) {
3857 uint64_t pg = *(uint64_t *)(vg + i);
3858 if (pg) {
3859 return (pow2floor(pg) & *(uint64_t *)(vd + i)) != 0;
3860 }
3861 }
3862 return 0;
3863 }
3864
3865 /* Compute a mask into RETB that is true for all G, up to and including
3866 * (if after) or excluding (if !after) the first G & N.
3867 * Return true if BRK found.
3868 */
compute_brk(uint64_t * retb,uint64_t n,uint64_t g,bool brk,bool after)3869 static bool compute_brk(uint64_t *retb, uint64_t n, uint64_t g,
3870 bool brk, bool after)
3871 {
3872 uint64_t b;
3873
3874 if (brk) {
3875 b = 0;
3876 } else if ((g & n) == 0) {
3877 /* For all G, no N are set; break not found. */
3878 b = g;
3879 } else {
3880 /* Break somewhere in N. Locate it. */
3881 b = g & n; /* guard true, pred true */
3882 b = b & -b; /* first such */
3883 if (after) {
3884 b = b | (b - 1); /* break after same */
3885 } else {
3886 b = b - 1; /* break before same */
3887 }
3888 brk = true;
3889 }
3890
3891 *retb = b;
3892 return brk;
3893 }
3894
3895 /* Compute a zeroing BRK. */
compute_brk_z(uint64_t * d,uint64_t * n,uint64_t * g,intptr_t oprsz,bool after)3896 static void compute_brk_z(uint64_t *d, uint64_t *n, uint64_t *g,
3897 intptr_t oprsz, bool after)
3898 {
3899 bool brk = false;
3900 intptr_t i;
3901
3902 for (i = 0; i < DIV_ROUND_UP(oprsz, 8); ++i) {
3903 uint64_t this_b, this_g = g[i];
3904
3905 brk = compute_brk(&this_b, n[i], this_g, brk, after);
3906 d[i] = this_b & this_g;
3907 }
3908 }
3909
3910 /* Likewise, but also compute flags. */
compute_brks_z(uint64_t * d,uint64_t * n,uint64_t * g,intptr_t oprsz,bool after)3911 static uint32_t compute_brks_z(uint64_t *d, uint64_t *n, uint64_t *g,
3912 intptr_t oprsz, bool after)
3913 {
3914 uint32_t flags = PREDTEST_INIT;
3915 bool brk = false;
3916 intptr_t i;
3917
3918 for (i = 0; i < DIV_ROUND_UP(oprsz, 8); ++i) {
3919 uint64_t this_b, this_d, this_g = g[i];
3920
3921 brk = compute_brk(&this_b, n[i], this_g, brk, after);
3922 d[i] = this_d = this_b & this_g;
3923 flags = iter_predtest_fwd(this_d, this_g, flags);
3924 }
3925 return flags;
3926 }
3927
3928 /* Compute a merging BRK. */
compute_brk_m(uint64_t * d,uint64_t * n,uint64_t * g,intptr_t oprsz,bool after)3929 static void compute_brk_m(uint64_t *d, uint64_t *n, uint64_t *g,
3930 intptr_t oprsz, bool after)
3931 {
3932 bool brk = false;
3933 intptr_t i;
3934
3935 for (i = 0; i < DIV_ROUND_UP(oprsz, 8); ++i) {
3936 uint64_t this_b, this_g = g[i];
3937
3938 brk = compute_brk(&this_b, n[i], this_g, brk, after);
3939 d[i] = (this_b & this_g) | (d[i] & ~this_g);
3940 }
3941 }
3942
3943 /* Likewise, but also compute flags. */
compute_brks_m(uint64_t * d,uint64_t * n,uint64_t * g,intptr_t oprsz,bool after)3944 static uint32_t compute_brks_m(uint64_t *d, uint64_t *n, uint64_t *g,
3945 intptr_t oprsz, bool after)
3946 {
3947 uint32_t flags = PREDTEST_INIT;
3948 bool brk = false;
3949 intptr_t i;
3950
3951 for (i = 0; i < oprsz / 8; ++i) {
3952 uint64_t this_b, this_d = d[i], this_g = g[i];
3953
3954 brk = compute_brk(&this_b, n[i], this_g, brk, after);
3955 d[i] = this_d = (this_b & this_g) | (this_d & ~this_g);
3956 flags = iter_predtest_fwd(this_d, this_g, flags);
3957 }
3958 return flags;
3959 }
3960
do_zero(ARMPredicateReg * d,intptr_t oprsz)3961 static uint32_t do_zero(ARMPredicateReg *d, intptr_t oprsz)
3962 {
3963 /* It is quicker to zero the whole predicate than loop on OPRSZ.
3964 * The compiler should turn this into 4 64-bit integer stores.
3965 */
3966 memset(d, 0, sizeof(ARMPredicateReg));
3967 return PREDTEST_INIT;
3968 }
3969
HELPER(sve_brkpa)3970 void HELPER(sve_brkpa)(void *vd, void *vn, void *vm, void *vg,
3971 uint32_t pred_desc)
3972 {
3973 intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
3974 if (last_active_pred(vn, vg, oprsz)) {
3975 compute_brk_z(vd, vm, vg, oprsz, true);
3976 } else {
3977 do_zero(vd, oprsz);
3978 }
3979 }
3980
HELPER(sve_brkpas)3981 uint32_t HELPER(sve_brkpas)(void *vd, void *vn, void *vm, void *vg,
3982 uint32_t pred_desc)
3983 {
3984 intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
3985 if (last_active_pred(vn, vg, oprsz)) {
3986 return compute_brks_z(vd, vm, vg, oprsz, true);
3987 } else {
3988 return do_zero(vd, oprsz);
3989 }
3990 }
3991
HELPER(sve_brkpb)3992 void HELPER(sve_brkpb)(void *vd, void *vn, void *vm, void *vg,
3993 uint32_t pred_desc)
3994 {
3995 intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
3996 if (last_active_pred(vn, vg, oprsz)) {
3997 compute_brk_z(vd, vm, vg, oprsz, false);
3998 } else {
3999 do_zero(vd, oprsz);
4000 }
4001 }
4002
HELPER(sve_brkpbs)4003 uint32_t HELPER(sve_brkpbs)(void *vd, void *vn, void *vm, void *vg,
4004 uint32_t pred_desc)
4005 {
4006 intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
4007 if (last_active_pred(vn, vg, oprsz)) {
4008 return compute_brks_z(vd, vm, vg, oprsz, false);
4009 } else {
4010 return do_zero(vd, oprsz);
4011 }
4012 }
4013
HELPER(sve_brka_z)4014 void HELPER(sve_brka_z)(void *vd, void *vn, void *vg, uint32_t pred_desc)
4015 {
4016 intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
4017 compute_brk_z(vd, vn, vg, oprsz, true);
4018 }
4019
HELPER(sve_brkas_z)4020 uint32_t HELPER(sve_brkas_z)(void *vd, void *vn, void *vg, uint32_t pred_desc)
4021 {
4022 intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
4023 return compute_brks_z(vd, vn, vg, oprsz, true);
4024 }
4025
HELPER(sve_brkb_z)4026 void HELPER(sve_brkb_z)(void *vd, void *vn, void *vg, uint32_t pred_desc)
4027 {
4028 intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
4029 compute_brk_z(vd, vn, vg, oprsz, false);
4030 }
4031
HELPER(sve_brkbs_z)4032 uint32_t HELPER(sve_brkbs_z)(void *vd, void *vn, void *vg, uint32_t pred_desc)
4033 {
4034 intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
4035 return compute_brks_z(vd, vn, vg, oprsz, false);
4036 }
4037
HELPER(sve_brka_m)4038 void HELPER(sve_brka_m)(void *vd, void *vn, void *vg, uint32_t pred_desc)
4039 {
4040 intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
4041 compute_brk_m(vd, vn, vg, oprsz, true);
4042 }
4043
HELPER(sve_brkas_m)4044 uint32_t HELPER(sve_brkas_m)(void *vd, void *vn, void *vg, uint32_t pred_desc)
4045 {
4046 intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
4047 return compute_brks_m(vd, vn, vg, oprsz, true);
4048 }
4049
HELPER(sve_brkb_m)4050 void HELPER(sve_brkb_m)(void *vd, void *vn, void *vg, uint32_t pred_desc)
4051 {
4052 intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
4053 compute_brk_m(vd, vn, vg, oprsz, false);
4054 }
4055
HELPER(sve_brkbs_m)4056 uint32_t HELPER(sve_brkbs_m)(void *vd, void *vn, void *vg, uint32_t pred_desc)
4057 {
4058 intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
4059 return compute_brks_m(vd, vn, vg, oprsz, false);
4060 }
4061
HELPER(sve_brkn)4062 void HELPER(sve_brkn)(void *vd, void *vn, void *vg, uint32_t pred_desc)
4063 {
4064 intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
4065 if (!last_active_pred(vn, vg, oprsz)) {
4066 do_zero(vd, oprsz);
4067 }
4068 }
4069
4070 /* As if PredTest(Ones(PL), D, esz). */
predtest_ones(ARMPredicateReg * d,intptr_t oprsz,uint64_t esz_mask)4071 static uint32_t predtest_ones(ARMPredicateReg *d, intptr_t oprsz,
4072 uint64_t esz_mask)
4073 {
4074 uint32_t flags = PREDTEST_INIT;
4075 intptr_t i;
4076
4077 for (i = 0; i < oprsz / 8; i++) {
4078 flags = iter_predtest_fwd(d->p[i], esz_mask, flags);
4079 }
4080 if (oprsz & 7) {
4081 uint64_t mask = ~(-1ULL << (8 * (oprsz & 7)));
4082 flags = iter_predtest_fwd(d->p[i], esz_mask & mask, flags);
4083 }
4084 return flags;
4085 }
4086
HELPER(sve_brkns)4087 uint32_t HELPER(sve_brkns)(void *vd, void *vn, void *vg, uint32_t pred_desc)
4088 {
4089 intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
4090 if (last_active_pred(vn, vg, oprsz)) {
4091 return predtest_ones(vd, oprsz, -1);
4092 } else {
4093 return do_zero(vd, oprsz);
4094 }
4095 }
4096
HELPER(sve_cntp)4097 uint64_t HELPER(sve_cntp)(void *vn, void *vg, uint32_t pred_desc)
4098 {
4099 intptr_t words = DIV_ROUND_UP(FIELD_EX32(pred_desc, PREDDESC, OPRSZ), 8);
4100 intptr_t esz = FIELD_EX32(pred_desc, PREDDESC, ESZ);
4101 uint64_t *n = vn, *g = vg, sum = 0, mask = pred_esz_masks[esz];
4102 intptr_t i;
4103
4104 for (i = 0; i < words; ++i) {
4105 uint64_t t = n[i] & g[i] & mask;
4106 sum += ctpop64(t);
4107 }
4108 return sum;
4109 }
4110
HELPER(sve_whilel)4111 uint32_t HELPER(sve_whilel)(void *vd, uint32_t count, uint32_t pred_desc)
4112 {
4113 intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
4114 intptr_t esz = FIELD_EX32(pred_desc, PREDDESC, ESZ);
4115 uint64_t esz_mask = pred_esz_masks[esz];
4116 ARMPredicateReg *d = vd;
4117 uint32_t flags;
4118 intptr_t i;
4119
4120 /* Begin with a zero predicate register. */
4121 flags = do_zero(d, oprsz);
4122 if (count == 0) {
4123 return flags;
4124 }
4125
4126 /* Set all of the requested bits. */
4127 for (i = 0; i < count / 64; ++i) {
4128 d->p[i] = esz_mask;
4129 }
4130 if (count & 63) {
4131 d->p[i] = MAKE_64BIT_MASK(0, count & 63) & esz_mask;
4132 }
4133
4134 return predtest_ones(d, oprsz, esz_mask);
4135 }
4136
HELPER(sve_whileg)4137 uint32_t HELPER(sve_whileg)(void *vd, uint32_t count, uint32_t pred_desc)
4138 {
4139 intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
4140 intptr_t esz = FIELD_EX32(pred_desc, PREDDESC, ESZ);
4141 uint64_t esz_mask = pred_esz_masks[esz];
4142 ARMPredicateReg *d = vd;
4143 intptr_t i, invcount, oprbits;
4144 uint64_t bits;
4145
4146 if (count == 0) {
4147 return do_zero(d, oprsz);
4148 }
4149
4150 oprbits = oprsz * 8;
4151 tcg_debug_assert(count <= oprbits);
4152
4153 bits = esz_mask;
4154 if (oprbits & 63) {
4155 bits &= MAKE_64BIT_MASK(0, oprbits & 63);
4156 }
4157
4158 invcount = oprbits - count;
4159 for (i = (oprsz - 1) / 8; i > invcount / 64; --i) {
4160 d->p[i] = bits;
4161 bits = esz_mask;
4162 }
4163
4164 d->p[i] = bits & MAKE_64BIT_MASK(invcount & 63, 64);
4165
4166 while (--i >= 0) {
4167 d->p[i] = 0;
4168 }
4169
4170 return predtest_ones(d, oprsz, esz_mask);
4171 }
4172
4173 /* Recursive reduction on a function;
4174 * C.f. the ARM ARM function ReducePredicated.
4175 *
4176 * While it would be possible to write this without the DATA temporary,
4177 * it is much simpler to process the predicate register this way.
4178 * The recursion is bounded to depth 7 (128 fp16 elements), so there's
4179 * little to gain with a more complex non-recursive form.
4180 */
4181 #define DO_REDUCE(NAME, TYPE, H, FUNC, IDENT) \
4182 static TYPE NAME##_reduce(TYPE *data, float_status *status, uintptr_t n) \
4183 { \
4184 if (n == 1) { \
4185 return *data; \
4186 } else { \
4187 uintptr_t half = n / 2; \
4188 TYPE lo = NAME##_reduce(data, status, half); \
4189 TYPE hi = NAME##_reduce(data + half, status, half); \
4190 return TYPE##_##FUNC(lo, hi, status); \
4191 } \
4192 } \
4193 uint64_t HELPER(NAME)(void *vn, void *vg, void *vs, uint32_t desc) \
4194 { \
4195 uintptr_t i, oprsz = simd_oprsz(desc), maxsz = simd_data(desc); \
4196 TYPE data[sizeof(ARMVectorReg) / sizeof(TYPE)]; \
4197 for (i = 0; i < oprsz; ) { \
4198 uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); \
4199 do { \
4200 TYPE nn = *(TYPE *)(vn + H(i)); \
4201 *(TYPE *)((void *)data + i) = (pg & 1 ? nn : IDENT); \
4202 i += sizeof(TYPE), pg >>= sizeof(TYPE); \
4203 } while (i & 15); \
4204 } \
4205 for (; i < maxsz; i += sizeof(TYPE)) { \
4206 *(TYPE *)((void *)data + i) = IDENT; \
4207 } \
4208 return NAME##_reduce(data, vs, maxsz / sizeof(TYPE)); \
4209 }
4210
DO_REDUCE(sve_faddv_h,float16,H1_2,add,float16_zero)4211 DO_REDUCE(sve_faddv_h, float16, H1_2, add, float16_zero)
4212 DO_REDUCE(sve_faddv_s, float32, H1_4, add, float32_zero)
4213 DO_REDUCE(sve_faddv_d, float64, H1_8, add, float64_zero)
4214
4215 /* Identity is floatN_default_nan, without the function call. */
4216 DO_REDUCE(sve_fminnmv_h, float16, H1_2, minnum, 0x7E00)
4217 DO_REDUCE(sve_fminnmv_s, float32, H1_4, minnum, 0x7FC00000)
4218 DO_REDUCE(sve_fminnmv_d, float64, H1_8, minnum, 0x7FF8000000000000ULL)
4219
4220 DO_REDUCE(sve_fmaxnmv_h, float16, H1_2, maxnum, 0x7E00)
4221 DO_REDUCE(sve_fmaxnmv_s, float32, H1_4, maxnum, 0x7FC00000)
4222 DO_REDUCE(sve_fmaxnmv_d, float64, H1_8, maxnum, 0x7FF8000000000000ULL)
4223
4224 DO_REDUCE(sve_fminv_h, float16, H1_2, min, float16_infinity)
4225 DO_REDUCE(sve_fminv_s, float32, H1_4, min, float32_infinity)
4226 DO_REDUCE(sve_fminv_d, float64, H1_8, min, float64_infinity)
4227
4228 DO_REDUCE(sve_fmaxv_h, float16, H1_2, max, float16_chs(float16_infinity))
4229 DO_REDUCE(sve_fmaxv_s, float32, H1_4, max, float32_chs(float32_infinity))
4230 DO_REDUCE(sve_fmaxv_d, float64, H1_8, max, float64_chs(float64_infinity))
4231
4232 #undef DO_REDUCE
4233
4234 uint64_t HELPER(sve_fadda_h)(uint64_t nn, void *vm, void *vg,
4235 void *status, uint32_t desc)
4236 {
4237 intptr_t i = 0, opr_sz = simd_oprsz(desc);
4238 float16 result = nn;
4239
4240 do {
4241 uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3));
4242 do {
4243 if (pg & 1) {
4244 float16 mm = *(float16 *)(vm + H1_2(i));
4245 result = float16_add(result, mm, status);
4246 }
4247 i += sizeof(float16), pg >>= sizeof(float16);
4248 } while (i & 15);
4249 } while (i < opr_sz);
4250
4251 return result;
4252 }
4253
HELPER(sve_fadda_s)4254 uint64_t HELPER(sve_fadda_s)(uint64_t nn, void *vm, void *vg,
4255 void *status, uint32_t desc)
4256 {
4257 intptr_t i = 0, opr_sz = simd_oprsz(desc);
4258 float32 result = nn;
4259
4260 do {
4261 uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3));
4262 do {
4263 if (pg & 1) {
4264 float32 mm = *(float32 *)(vm + H1_2(i));
4265 result = float32_add(result, mm, status);
4266 }
4267 i += sizeof(float32), pg >>= sizeof(float32);
4268 } while (i & 15);
4269 } while (i < opr_sz);
4270
4271 return result;
4272 }
4273
HELPER(sve_fadda_d)4274 uint64_t HELPER(sve_fadda_d)(uint64_t nn, void *vm, void *vg,
4275 void *status, uint32_t desc)
4276 {
4277 intptr_t i = 0, opr_sz = simd_oprsz(desc) / 8;
4278 uint64_t *m = vm;
4279 uint8_t *pg = vg;
4280
4281 for (i = 0; i < opr_sz; i++) {
4282 if (pg[H1(i)] & 1) {
4283 nn = float64_add(nn, m[i], status);
4284 }
4285 }
4286
4287 return nn;
4288 }
4289
4290 /* Fully general three-operand expander, controlled by a predicate,
4291 * With the extra float_status parameter.
4292 */
4293 #define DO_ZPZZ_FP(NAME, TYPE, H, OP) \
4294 void HELPER(NAME)(void *vd, void *vn, void *vm, void *vg, \
4295 void *status, uint32_t desc) \
4296 { \
4297 intptr_t i = simd_oprsz(desc); \
4298 uint64_t *g = vg; \
4299 do { \
4300 uint64_t pg = g[(i - 1) >> 6]; \
4301 do { \
4302 i -= sizeof(TYPE); \
4303 if (likely((pg >> (i & 63)) & 1)) { \
4304 TYPE nn = *(TYPE *)(vn + H(i)); \
4305 TYPE mm = *(TYPE *)(vm + H(i)); \
4306 *(TYPE *)(vd + H(i)) = OP(nn, mm, status); \
4307 } \
4308 } while (i & 63); \
4309 } while (i != 0); \
4310 }
4311
DO_ZPZZ_FP(sve_fadd_h,uint16_t,H1_2,float16_add)4312 DO_ZPZZ_FP(sve_fadd_h, uint16_t, H1_2, float16_add)
4313 DO_ZPZZ_FP(sve_fadd_s, uint32_t, H1_4, float32_add)
4314 DO_ZPZZ_FP(sve_fadd_d, uint64_t, H1_8, float64_add)
4315
4316 DO_ZPZZ_FP(sve_fsub_h, uint16_t, H1_2, float16_sub)
4317 DO_ZPZZ_FP(sve_fsub_s, uint32_t, H1_4, float32_sub)
4318 DO_ZPZZ_FP(sve_fsub_d, uint64_t, H1_8, float64_sub)
4319
4320 DO_ZPZZ_FP(sve_fmul_h, uint16_t, H1_2, float16_mul)
4321 DO_ZPZZ_FP(sve_fmul_s, uint32_t, H1_4, float32_mul)
4322 DO_ZPZZ_FP(sve_fmul_d, uint64_t, H1_8, float64_mul)
4323
4324 DO_ZPZZ_FP(sve_fdiv_h, uint16_t, H1_2, float16_div)
4325 DO_ZPZZ_FP(sve_fdiv_s, uint32_t, H1_4, float32_div)
4326 DO_ZPZZ_FP(sve_fdiv_d, uint64_t, H1_8, float64_div)
4327
4328 DO_ZPZZ_FP(sve_fmin_h, uint16_t, H1_2, float16_min)
4329 DO_ZPZZ_FP(sve_fmin_s, uint32_t, H1_4, float32_min)
4330 DO_ZPZZ_FP(sve_fmin_d, uint64_t, H1_8, float64_min)
4331
4332 DO_ZPZZ_FP(sve_fmax_h, uint16_t, H1_2, float16_max)
4333 DO_ZPZZ_FP(sve_fmax_s, uint32_t, H1_4, float32_max)
4334 DO_ZPZZ_FP(sve_fmax_d, uint64_t, H1_8, float64_max)
4335
4336 DO_ZPZZ_FP(sve_fminnum_h, uint16_t, H1_2, float16_minnum)
4337 DO_ZPZZ_FP(sve_fminnum_s, uint32_t, H1_4, float32_minnum)
4338 DO_ZPZZ_FP(sve_fminnum_d, uint64_t, H1_8, float64_minnum)
4339
4340 DO_ZPZZ_FP(sve_fmaxnum_h, uint16_t, H1_2, float16_maxnum)
4341 DO_ZPZZ_FP(sve_fmaxnum_s, uint32_t, H1_4, float32_maxnum)
4342 DO_ZPZZ_FP(sve_fmaxnum_d, uint64_t, H1_8, float64_maxnum)
4343
4344 static inline float16 abd_h(float16 a, float16 b, float_status *s)
4345 {
4346 return float16_abs(float16_sub(a, b, s));
4347 }
4348
abd_s(float32 a,float32 b,float_status * s)4349 static inline float32 abd_s(float32 a, float32 b, float_status *s)
4350 {
4351 return float32_abs(float32_sub(a, b, s));
4352 }
4353
abd_d(float64 a,float64 b,float_status * s)4354 static inline float64 abd_d(float64 a, float64 b, float_status *s)
4355 {
4356 return float64_abs(float64_sub(a, b, s));
4357 }
4358
DO_ZPZZ_FP(sve_fabd_h,uint16_t,H1_2,abd_h)4359 DO_ZPZZ_FP(sve_fabd_h, uint16_t, H1_2, abd_h)
4360 DO_ZPZZ_FP(sve_fabd_s, uint32_t, H1_4, abd_s)
4361 DO_ZPZZ_FP(sve_fabd_d, uint64_t, H1_8, abd_d)
4362
4363 static inline float64 scalbn_d(float64 a, int64_t b, float_status *s)
4364 {
4365 int b_int = MIN(MAX(b, INT_MIN), INT_MAX);
4366 return float64_scalbn(a, b_int, s);
4367 }
4368
DO_ZPZZ_FP(sve_fscalbn_h,int16_t,H1_2,float16_scalbn)4369 DO_ZPZZ_FP(sve_fscalbn_h, int16_t, H1_2, float16_scalbn)
4370 DO_ZPZZ_FP(sve_fscalbn_s, int32_t, H1_4, float32_scalbn)
4371 DO_ZPZZ_FP(sve_fscalbn_d, int64_t, H1_8, scalbn_d)
4372
4373 DO_ZPZZ_FP(sve_fmulx_h, uint16_t, H1_2, helper_advsimd_mulxh)
4374 DO_ZPZZ_FP(sve_fmulx_s, uint32_t, H1_4, helper_vfp_mulxs)
4375 DO_ZPZZ_FP(sve_fmulx_d, uint64_t, H1_8, helper_vfp_mulxd)
4376
4377 #undef DO_ZPZZ_FP
4378
4379 /* Three-operand expander, with one scalar operand, controlled by
4380 * a predicate, with the extra float_status parameter.
4381 */
4382 #define DO_ZPZS_FP(NAME, TYPE, H, OP) \
4383 void HELPER(NAME)(void *vd, void *vn, void *vg, uint64_t scalar, \
4384 void *status, uint32_t desc) \
4385 { \
4386 intptr_t i = simd_oprsz(desc); \
4387 uint64_t *g = vg; \
4388 TYPE mm = scalar; \
4389 do { \
4390 uint64_t pg = g[(i - 1) >> 6]; \
4391 do { \
4392 i -= sizeof(TYPE); \
4393 if (likely((pg >> (i & 63)) & 1)) { \
4394 TYPE nn = *(TYPE *)(vn + H(i)); \
4395 *(TYPE *)(vd + H(i)) = OP(nn, mm, status); \
4396 } \
4397 } while (i & 63); \
4398 } while (i != 0); \
4399 }
4400
4401 DO_ZPZS_FP(sve_fadds_h, float16, H1_2, float16_add)
4402 DO_ZPZS_FP(sve_fadds_s, float32, H1_4, float32_add)
4403 DO_ZPZS_FP(sve_fadds_d, float64, H1_8, float64_add)
4404
4405 DO_ZPZS_FP(sve_fsubs_h, float16, H1_2, float16_sub)
4406 DO_ZPZS_FP(sve_fsubs_s, float32, H1_4, float32_sub)
4407 DO_ZPZS_FP(sve_fsubs_d, float64, H1_8, float64_sub)
4408
4409 DO_ZPZS_FP(sve_fmuls_h, float16, H1_2, float16_mul)
4410 DO_ZPZS_FP(sve_fmuls_s, float32, H1_4, float32_mul)
4411 DO_ZPZS_FP(sve_fmuls_d, float64, H1_8, float64_mul)
4412
4413 static inline float16 subr_h(float16 a, float16 b, float_status *s)
4414 {
4415 return float16_sub(b, a, s);
4416 }
4417
subr_s(float32 a,float32 b,float_status * s)4418 static inline float32 subr_s(float32 a, float32 b, float_status *s)
4419 {
4420 return float32_sub(b, a, s);
4421 }
4422
subr_d(float64 a,float64 b,float_status * s)4423 static inline float64 subr_d(float64 a, float64 b, float_status *s)
4424 {
4425 return float64_sub(b, a, s);
4426 }
4427
DO_ZPZS_FP(sve_fsubrs_h,float16,H1_2,subr_h)4428 DO_ZPZS_FP(sve_fsubrs_h, float16, H1_2, subr_h)
4429 DO_ZPZS_FP(sve_fsubrs_s, float32, H1_4, subr_s)
4430 DO_ZPZS_FP(sve_fsubrs_d, float64, H1_8, subr_d)
4431
4432 DO_ZPZS_FP(sve_fmaxnms_h, float16, H1_2, float16_maxnum)
4433 DO_ZPZS_FP(sve_fmaxnms_s, float32, H1_4, float32_maxnum)
4434 DO_ZPZS_FP(sve_fmaxnms_d, float64, H1_8, float64_maxnum)
4435
4436 DO_ZPZS_FP(sve_fminnms_h, float16, H1_2, float16_minnum)
4437 DO_ZPZS_FP(sve_fminnms_s, float32, H1_4, float32_minnum)
4438 DO_ZPZS_FP(sve_fminnms_d, float64, H1_8, float64_minnum)
4439
4440 DO_ZPZS_FP(sve_fmaxs_h, float16, H1_2, float16_max)
4441 DO_ZPZS_FP(sve_fmaxs_s, float32, H1_4, float32_max)
4442 DO_ZPZS_FP(sve_fmaxs_d, float64, H1_8, float64_max)
4443
4444 DO_ZPZS_FP(sve_fmins_h, float16, H1_2, float16_min)
4445 DO_ZPZS_FP(sve_fmins_s, float32, H1_4, float32_min)
4446 DO_ZPZS_FP(sve_fmins_d, float64, H1_8, float64_min)
4447
4448 /* Fully general two-operand expander, controlled by a predicate,
4449 * With the extra float_status parameter.
4450 */
4451 #define DO_ZPZ_FP(NAME, TYPE, H, OP) \
4452 void HELPER(NAME)(void *vd, void *vn, void *vg, void *status, uint32_t desc) \
4453 { \
4454 intptr_t i = simd_oprsz(desc); \
4455 uint64_t *g = vg; \
4456 do { \
4457 uint64_t pg = g[(i - 1) >> 6]; \
4458 do { \
4459 i -= sizeof(TYPE); \
4460 if (likely((pg >> (i & 63)) & 1)) { \
4461 TYPE nn = *(TYPE *)(vn + H(i)); \
4462 *(TYPE *)(vd + H(i)) = OP(nn, status); \
4463 } \
4464 } while (i & 63); \
4465 } while (i != 0); \
4466 }
4467
4468 /* SVE fp16 conversions always use IEEE mode. Like AdvSIMD, they ignore
4469 * FZ16. When converting from fp16, this affects flushing input denormals;
4470 * when converting to fp16, this affects flushing output denormals.
4471 */
4472 static inline float32 sve_f16_to_f32(float16 f, float_status *fpst)
4473 {
4474 bool save = get_flush_inputs_to_zero(fpst);
4475 float32 ret;
4476
4477 set_flush_inputs_to_zero(false, fpst);
4478 ret = float16_to_float32(f, true, fpst);
4479 set_flush_inputs_to_zero(save, fpst);
4480 return ret;
4481 }
4482
sve_f16_to_f64(float16 f,float_status * fpst)4483 static inline float64 sve_f16_to_f64(float16 f, float_status *fpst)
4484 {
4485 bool save = get_flush_inputs_to_zero(fpst);
4486 float64 ret;
4487
4488 set_flush_inputs_to_zero(false, fpst);
4489 ret = float16_to_float64(f, true, fpst);
4490 set_flush_inputs_to_zero(save, fpst);
4491 return ret;
4492 }
4493
sve_f32_to_f16(float32 f,float_status * fpst)4494 static inline float16 sve_f32_to_f16(float32 f, float_status *fpst)
4495 {
4496 bool save = get_flush_to_zero(fpst);
4497 float16 ret;
4498
4499 set_flush_to_zero(false, fpst);
4500 ret = float32_to_float16(f, true, fpst);
4501 set_flush_to_zero(save, fpst);
4502 return ret;
4503 }
4504
sve_f64_to_f16(float64 f,float_status * fpst)4505 static inline float16 sve_f64_to_f16(float64 f, float_status *fpst)
4506 {
4507 bool save = get_flush_to_zero(fpst);
4508 float16 ret;
4509
4510 set_flush_to_zero(false, fpst);
4511 ret = float64_to_float16(f, true, fpst);
4512 set_flush_to_zero(save, fpst);
4513 return ret;
4514 }
4515
vfp_float16_to_int16_rtz(float16 f,float_status * s)4516 static inline int16_t vfp_float16_to_int16_rtz(float16 f, float_status *s)
4517 {
4518 if (float16_is_any_nan(f)) {
4519 float_raise(float_flag_invalid, s);
4520 return 0;
4521 }
4522 return float16_to_int16_round_to_zero(f, s);
4523 }
4524
vfp_float16_to_int64_rtz(float16 f,float_status * s)4525 static inline int64_t vfp_float16_to_int64_rtz(float16 f, float_status *s)
4526 {
4527 if (float16_is_any_nan(f)) {
4528 float_raise(float_flag_invalid, s);
4529 return 0;
4530 }
4531 return float16_to_int64_round_to_zero(f, s);
4532 }
4533
vfp_float32_to_int64_rtz(float32 f,float_status * s)4534 static inline int64_t vfp_float32_to_int64_rtz(float32 f, float_status *s)
4535 {
4536 if (float32_is_any_nan(f)) {
4537 float_raise(float_flag_invalid, s);
4538 return 0;
4539 }
4540 return float32_to_int64_round_to_zero(f, s);
4541 }
4542
vfp_float64_to_int64_rtz(float64 f,float_status * s)4543 static inline int64_t vfp_float64_to_int64_rtz(float64 f, float_status *s)
4544 {
4545 if (float64_is_any_nan(f)) {
4546 float_raise(float_flag_invalid, s);
4547 return 0;
4548 }
4549 return float64_to_int64_round_to_zero(f, s);
4550 }
4551
vfp_float16_to_uint16_rtz(float16 f,float_status * s)4552 static inline uint16_t vfp_float16_to_uint16_rtz(float16 f, float_status *s)
4553 {
4554 if (float16_is_any_nan(f)) {
4555 float_raise(float_flag_invalid, s);
4556 return 0;
4557 }
4558 return float16_to_uint16_round_to_zero(f, s);
4559 }
4560
vfp_float16_to_uint64_rtz(float16 f,float_status * s)4561 static inline uint64_t vfp_float16_to_uint64_rtz(float16 f, float_status *s)
4562 {
4563 if (float16_is_any_nan(f)) {
4564 float_raise(float_flag_invalid, s);
4565 return 0;
4566 }
4567 return float16_to_uint64_round_to_zero(f, s);
4568 }
4569
vfp_float32_to_uint64_rtz(float32 f,float_status * s)4570 static inline uint64_t vfp_float32_to_uint64_rtz(float32 f, float_status *s)
4571 {
4572 if (float32_is_any_nan(f)) {
4573 float_raise(float_flag_invalid, s);
4574 return 0;
4575 }
4576 return float32_to_uint64_round_to_zero(f, s);
4577 }
4578
vfp_float64_to_uint64_rtz(float64 f,float_status * s)4579 static inline uint64_t vfp_float64_to_uint64_rtz(float64 f, float_status *s)
4580 {
4581 if (float64_is_any_nan(f)) {
4582 float_raise(float_flag_invalid, s);
4583 return 0;
4584 }
4585 return float64_to_uint64_round_to_zero(f, s);
4586 }
4587
DO_ZPZ_FP(sve_fcvt_sh,uint32_t,H1_4,sve_f32_to_f16)4588 DO_ZPZ_FP(sve_fcvt_sh, uint32_t, H1_4, sve_f32_to_f16)
4589 DO_ZPZ_FP(sve_fcvt_hs, uint32_t, H1_4, sve_f16_to_f32)
4590 DO_ZPZ_FP(sve_bfcvt, uint32_t, H1_4, float32_to_bfloat16)
4591 DO_ZPZ_FP(sve_fcvt_dh, uint64_t, H1_8, sve_f64_to_f16)
4592 DO_ZPZ_FP(sve_fcvt_hd, uint64_t, H1_8, sve_f16_to_f64)
4593 DO_ZPZ_FP(sve_fcvt_ds, uint64_t, H1_8, float64_to_float32)
4594 DO_ZPZ_FP(sve_fcvt_sd, uint64_t, H1_8, float32_to_float64)
4595
4596 DO_ZPZ_FP(sve_fcvtzs_hh, uint16_t, H1_2, vfp_float16_to_int16_rtz)
4597 DO_ZPZ_FP(sve_fcvtzs_hs, uint32_t, H1_4, helper_vfp_tosizh)
4598 DO_ZPZ_FP(sve_fcvtzs_ss, uint32_t, H1_4, helper_vfp_tosizs)
4599 DO_ZPZ_FP(sve_fcvtzs_hd, uint64_t, H1_8, vfp_float16_to_int64_rtz)
4600 DO_ZPZ_FP(sve_fcvtzs_sd, uint64_t, H1_8, vfp_float32_to_int64_rtz)
4601 DO_ZPZ_FP(sve_fcvtzs_ds, uint64_t, H1_8, helper_vfp_tosizd)
4602 DO_ZPZ_FP(sve_fcvtzs_dd, uint64_t, H1_8, vfp_float64_to_int64_rtz)
4603
4604 DO_ZPZ_FP(sve_fcvtzu_hh, uint16_t, H1_2, vfp_float16_to_uint16_rtz)
4605 DO_ZPZ_FP(sve_fcvtzu_hs, uint32_t, H1_4, helper_vfp_touizh)
4606 DO_ZPZ_FP(sve_fcvtzu_ss, uint32_t, H1_4, helper_vfp_touizs)
4607 DO_ZPZ_FP(sve_fcvtzu_hd, uint64_t, H1_8, vfp_float16_to_uint64_rtz)
4608 DO_ZPZ_FP(sve_fcvtzu_sd, uint64_t, H1_8, vfp_float32_to_uint64_rtz)
4609 DO_ZPZ_FP(sve_fcvtzu_ds, uint64_t, H1_8, helper_vfp_touizd)
4610 DO_ZPZ_FP(sve_fcvtzu_dd, uint64_t, H1_8, vfp_float64_to_uint64_rtz)
4611
4612 DO_ZPZ_FP(sve_frint_h, uint16_t, H1_2, helper_advsimd_rinth)
4613 DO_ZPZ_FP(sve_frint_s, uint32_t, H1_4, helper_rints)
4614 DO_ZPZ_FP(sve_frint_d, uint64_t, H1_8, helper_rintd)
4615
4616 DO_ZPZ_FP(sve_frintx_h, uint16_t, H1_2, float16_round_to_int)
4617 DO_ZPZ_FP(sve_frintx_s, uint32_t, H1_4, float32_round_to_int)
4618 DO_ZPZ_FP(sve_frintx_d, uint64_t, H1_8, float64_round_to_int)
4619
4620 DO_ZPZ_FP(sve_frecpx_h, uint16_t, H1_2, helper_frecpx_f16)
4621 DO_ZPZ_FP(sve_frecpx_s, uint32_t, H1_4, helper_frecpx_f32)
4622 DO_ZPZ_FP(sve_frecpx_d, uint64_t, H1_8, helper_frecpx_f64)
4623
4624 DO_ZPZ_FP(sve_fsqrt_h, uint16_t, H1_2, float16_sqrt)
4625 DO_ZPZ_FP(sve_fsqrt_s, uint32_t, H1_4, float32_sqrt)
4626 DO_ZPZ_FP(sve_fsqrt_d, uint64_t, H1_8, float64_sqrt)
4627
4628 DO_ZPZ_FP(sve_scvt_hh, uint16_t, H1_2, int16_to_float16)
4629 DO_ZPZ_FP(sve_scvt_sh, uint32_t, H1_4, int32_to_float16)
4630 DO_ZPZ_FP(sve_scvt_ss, uint32_t, H1_4, int32_to_float32)
4631 DO_ZPZ_FP(sve_scvt_sd, uint64_t, H1_8, int32_to_float64)
4632 DO_ZPZ_FP(sve_scvt_dh, uint64_t, H1_8, int64_to_float16)
4633 DO_ZPZ_FP(sve_scvt_ds, uint64_t, H1_8, int64_to_float32)
4634 DO_ZPZ_FP(sve_scvt_dd, uint64_t, H1_8, int64_to_float64)
4635
4636 DO_ZPZ_FP(sve_ucvt_hh, uint16_t, H1_2, uint16_to_float16)
4637 DO_ZPZ_FP(sve_ucvt_sh, uint32_t, H1_4, uint32_to_float16)
4638 DO_ZPZ_FP(sve_ucvt_ss, uint32_t, H1_4, uint32_to_float32)
4639 DO_ZPZ_FP(sve_ucvt_sd, uint64_t, H1_8, uint32_to_float64)
4640 DO_ZPZ_FP(sve_ucvt_dh, uint64_t, H1_8, uint64_to_float16)
4641 DO_ZPZ_FP(sve_ucvt_ds, uint64_t, H1_8, uint64_to_float32)
4642 DO_ZPZ_FP(sve_ucvt_dd, uint64_t, H1_8, uint64_to_float64)
4643
4644 static int16_t do_float16_logb_as_int(float16 a, float_status *s)
4645 {
4646 /* Extract frac to the top of the uint32_t. */
4647 uint32_t frac = (uint32_t)a << (16 + 6);
4648 int16_t exp = extract32(a, 10, 5);
4649
4650 if (unlikely(exp == 0)) {
4651 if (frac != 0) {
4652 if (!get_flush_inputs_to_zero(s)) {
4653 /* denormal: bias - fractional_zeros */
4654 return -15 - clz32(frac);
4655 }
4656 /* flush to zero */
4657 float_raise(float_flag_input_denormal, s);
4658 }
4659 } else if (unlikely(exp == 0x1f)) {
4660 if (frac == 0) {
4661 return INT16_MAX; /* infinity */
4662 }
4663 } else {
4664 /* normal: exp - bias */
4665 return exp - 15;
4666 }
4667 /* nan or zero */
4668 float_raise(float_flag_invalid, s);
4669 return INT16_MIN;
4670 }
4671
do_float32_logb_as_int(float32 a,float_status * s)4672 static int32_t do_float32_logb_as_int(float32 a, float_status *s)
4673 {
4674 /* Extract frac to the top of the uint32_t. */
4675 uint32_t frac = a << 9;
4676 int32_t exp = extract32(a, 23, 8);
4677
4678 if (unlikely(exp == 0)) {
4679 if (frac != 0) {
4680 if (!get_flush_inputs_to_zero(s)) {
4681 /* denormal: bias - fractional_zeros */
4682 return -127 - clz32(frac);
4683 }
4684 /* flush to zero */
4685 float_raise(float_flag_input_denormal, s);
4686 }
4687 } else if (unlikely(exp == 0xff)) {
4688 if (frac == 0) {
4689 return INT32_MAX; /* infinity */
4690 }
4691 } else {
4692 /* normal: exp - bias */
4693 return exp - 127;
4694 }
4695 /* nan or zero */
4696 float_raise(float_flag_invalid, s);
4697 return INT32_MIN;
4698 }
4699
do_float64_logb_as_int(float64 a,float_status * s)4700 static int64_t do_float64_logb_as_int(float64 a, float_status *s)
4701 {
4702 /* Extract frac to the top of the uint64_t. */
4703 uint64_t frac = a << 12;
4704 int64_t exp = extract64(a, 52, 11);
4705
4706 if (unlikely(exp == 0)) {
4707 if (frac != 0) {
4708 if (!get_flush_inputs_to_zero(s)) {
4709 /* denormal: bias - fractional_zeros */
4710 return -1023 - clz64(frac);
4711 }
4712 /* flush to zero */
4713 float_raise(float_flag_input_denormal, s);
4714 }
4715 } else if (unlikely(exp == 0x7ff)) {
4716 if (frac == 0) {
4717 return INT64_MAX; /* infinity */
4718 }
4719 } else {
4720 /* normal: exp - bias */
4721 return exp - 1023;
4722 }
4723 /* nan or zero */
4724 float_raise(float_flag_invalid, s);
4725 return INT64_MIN;
4726 }
4727
DO_ZPZ_FP(flogb_h,float16,H1_2,do_float16_logb_as_int)4728 DO_ZPZ_FP(flogb_h, float16, H1_2, do_float16_logb_as_int)
4729 DO_ZPZ_FP(flogb_s, float32, H1_4, do_float32_logb_as_int)
4730 DO_ZPZ_FP(flogb_d, float64, H1_8, do_float64_logb_as_int)
4731
4732 #undef DO_ZPZ_FP
4733
4734 static void do_fmla_zpzzz_h(void *vd, void *vn, void *vm, void *va, void *vg,
4735 float_status *status, uint32_t desc,
4736 uint16_t neg1, uint16_t neg3)
4737 {
4738 intptr_t i = simd_oprsz(desc);
4739 uint64_t *g = vg;
4740
4741 do {
4742 uint64_t pg = g[(i - 1) >> 6];
4743 do {
4744 i -= 2;
4745 if (likely((pg >> (i & 63)) & 1)) {
4746 float16 e1, e2, e3, r;
4747
4748 e1 = *(uint16_t *)(vn + H1_2(i)) ^ neg1;
4749 e2 = *(uint16_t *)(vm + H1_2(i));
4750 e3 = *(uint16_t *)(va + H1_2(i)) ^ neg3;
4751 r = float16_muladd(e1, e2, e3, 0, status);
4752 *(uint16_t *)(vd + H1_2(i)) = r;
4753 }
4754 } while (i & 63);
4755 } while (i != 0);
4756 }
4757
HELPER(sve_fmla_zpzzz_h)4758 void HELPER(sve_fmla_zpzzz_h)(void *vd, void *vn, void *vm, void *va,
4759 void *vg, void *status, uint32_t desc)
4760 {
4761 do_fmla_zpzzz_h(vd, vn, vm, va, vg, status, desc, 0, 0);
4762 }
4763
HELPER(sve_fmls_zpzzz_h)4764 void HELPER(sve_fmls_zpzzz_h)(void *vd, void *vn, void *vm, void *va,
4765 void *vg, void *status, uint32_t desc)
4766 {
4767 do_fmla_zpzzz_h(vd, vn, vm, va, vg, status, desc, 0x8000, 0);
4768 }
4769
HELPER(sve_fnmla_zpzzz_h)4770 void HELPER(sve_fnmla_zpzzz_h)(void *vd, void *vn, void *vm, void *va,
4771 void *vg, void *status, uint32_t desc)
4772 {
4773 do_fmla_zpzzz_h(vd, vn, vm, va, vg, status, desc, 0x8000, 0x8000);
4774 }
4775
HELPER(sve_fnmls_zpzzz_h)4776 void HELPER(sve_fnmls_zpzzz_h)(void *vd, void *vn, void *vm, void *va,
4777 void *vg, void *status, uint32_t desc)
4778 {
4779 do_fmla_zpzzz_h(vd, vn, vm, va, vg, status, desc, 0, 0x8000);
4780 }
4781
do_fmla_zpzzz_s(void * vd,void * vn,void * vm,void * va,void * vg,float_status * status,uint32_t desc,uint32_t neg1,uint32_t neg3)4782 static void do_fmla_zpzzz_s(void *vd, void *vn, void *vm, void *va, void *vg,
4783 float_status *status, uint32_t desc,
4784 uint32_t neg1, uint32_t neg3)
4785 {
4786 intptr_t i = simd_oprsz(desc);
4787 uint64_t *g = vg;
4788
4789 do {
4790 uint64_t pg = g[(i - 1) >> 6];
4791 do {
4792 i -= 4;
4793 if (likely((pg >> (i & 63)) & 1)) {
4794 float32 e1, e2, e3, r;
4795
4796 e1 = *(uint32_t *)(vn + H1_4(i)) ^ neg1;
4797 e2 = *(uint32_t *)(vm + H1_4(i));
4798 e3 = *(uint32_t *)(va + H1_4(i)) ^ neg3;
4799 r = float32_muladd(e1, e2, e3, 0, status);
4800 *(uint32_t *)(vd + H1_4(i)) = r;
4801 }
4802 } while (i & 63);
4803 } while (i != 0);
4804 }
4805
HELPER(sve_fmla_zpzzz_s)4806 void HELPER(sve_fmla_zpzzz_s)(void *vd, void *vn, void *vm, void *va,
4807 void *vg, void *status, uint32_t desc)
4808 {
4809 do_fmla_zpzzz_s(vd, vn, vm, va, vg, status, desc, 0, 0);
4810 }
4811
HELPER(sve_fmls_zpzzz_s)4812 void HELPER(sve_fmls_zpzzz_s)(void *vd, void *vn, void *vm, void *va,
4813 void *vg, void *status, uint32_t desc)
4814 {
4815 do_fmla_zpzzz_s(vd, vn, vm, va, vg, status, desc, 0x80000000, 0);
4816 }
4817
HELPER(sve_fnmla_zpzzz_s)4818 void HELPER(sve_fnmla_zpzzz_s)(void *vd, void *vn, void *vm, void *va,
4819 void *vg, void *status, uint32_t desc)
4820 {
4821 do_fmla_zpzzz_s(vd, vn, vm, va, vg, status, desc, 0x80000000, 0x80000000);
4822 }
4823
HELPER(sve_fnmls_zpzzz_s)4824 void HELPER(sve_fnmls_zpzzz_s)(void *vd, void *vn, void *vm, void *va,
4825 void *vg, void *status, uint32_t desc)
4826 {
4827 do_fmla_zpzzz_s(vd, vn, vm, va, vg, status, desc, 0, 0x80000000);
4828 }
4829
do_fmla_zpzzz_d(void * vd,void * vn,void * vm,void * va,void * vg,float_status * status,uint32_t desc,uint64_t neg1,uint64_t neg3)4830 static void do_fmla_zpzzz_d(void *vd, void *vn, void *vm, void *va, void *vg,
4831 float_status *status, uint32_t desc,
4832 uint64_t neg1, uint64_t neg3)
4833 {
4834 intptr_t i = simd_oprsz(desc);
4835 uint64_t *g = vg;
4836
4837 do {
4838 uint64_t pg = g[(i - 1) >> 6];
4839 do {
4840 i -= 8;
4841 if (likely((pg >> (i & 63)) & 1)) {
4842 float64 e1, e2, e3, r;
4843
4844 e1 = *(uint64_t *)(vn + i) ^ neg1;
4845 e2 = *(uint64_t *)(vm + i);
4846 e3 = *(uint64_t *)(va + i) ^ neg3;
4847 r = float64_muladd(e1, e2, e3, 0, status);
4848 *(uint64_t *)(vd + i) = r;
4849 }
4850 } while (i & 63);
4851 } while (i != 0);
4852 }
4853
HELPER(sve_fmla_zpzzz_d)4854 void HELPER(sve_fmla_zpzzz_d)(void *vd, void *vn, void *vm, void *va,
4855 void *vg, void *status, uint32_t desc)
4856 {
4857 do_fmla_zpzzz_d(vd, vn, vm, va, vg, status, desc, 0, 0);
4858 }
4859
HELPER(sve_fmls_zpzzz_d)4860 void HELPER(sve_fmls_zpzzz_d)(void *vd, void *vn, void *vm, void *va,
4861 void *vg, void *status, uint32_t desc)
4862 {
4863 do_fmla_zpzzz_d(vd, vn, vm, va, vg, status, desc, INT64_MIN, 0);
4864 }
4865
HELPER(sve_fnmla_zpzzz_d)4866 void HELPER(sve_fnmla_zpzzz_d)(void *vd, void *vn, void *vm, void *va,
4867 void *vg, void *status, uint32_t desc)
4868 {
4869 do_fmla_zpzzz_d(vd, vn, vm, va, vg, status, desc, INT64_MIN, INT64_MIN);
4870 }
4871
HELPER(sve_fnmls_zpzzz_d)4872 void HELPER(sve_fnmls_zpzzz_d)(void *vd, void *vn, void *vm, void *va,
4873 void *vg, void *status, uint32_t desc)
4874 {
4875 do_fmla_zpzzz_d(vd, vn, vm, va, vg, status, desc, 0, INT64_MIN);
4876 }
4877
4878 /* Two operand floating-point comparison controlled by a predicate.
4879 * Unlike the integer version, we are not allowed to optimistically
4880 * compare operands, since the comparison may have side effects wrt
4881 * the FPSR.
4882 */
4883 #define DO_FPCMP_PPZZ(NAME, TYPE, H, OP) \
4884 void HELPER(NAME)(void *vd, void *vn, void *vm, void *vg, \
4885 void *status, uint32_t desc) \
4886 { \
4887 intptr_t i = simd_oprsz(desc), j = (i - 1) >> 6; \
4888 uint64_t *d = vd, *g = vg; \
4889 do { \
4890 uint64_t out = 0, pg = g[j]; \
4891 do { \
4892 i -= sizeof(TYPE), out <<= sizeof(TYPE); \
4893 if (likely((pg >> (i & 63)) & 1)) { \
4894 TYPE nn = *(TYPE *)(vn + H(i)); \
4895 TYPE mm = *(TYPE *)(vm + H(i)); \
4896 out |= OP(TYPE, nn, mm, status); \
4897 } \
4898 } while (i & 63); \
4899 d[j--] = out; \
4900 } while (i > 0); \
4901 }
4902
4903 #define DO_FPCMP_PPZZ_H(NAME, OP) \
4904 DO_FPCMP_PPZZ(NAME##_h, float16, H1_2, OP)
4905 #define DO_FPCMP_PPZZ_S(NAME, OP) \
4906 DO_FPCMP_PPZZ(NAME##_s, float32, H1_4, OP)
4907 #define DO_FPCMP_PPZZ_D(NAME, OP) \
4908 DO_FPCMP_PPZZ(NAME##_d, float64, H1_8, OP)
4909
4910 #define DO_FPCMP_PPZZ_ALL(NAME, OP) \
4911 DO_FPCMP_PPZZ_H(NAME, OP) \
4912 DO_FPCMP_PPZZ_S(NAME, OP) \
4913 DO_FPCMP_PPZZ_D(NAME, OP)
4914
4915 #define DO_FCMGE(TYPE, X, Y, ST) TYPE##_compare(Y, X, ST) <= 0
4916 #define DO_FCMGT(TYPE, X, Y, ST) TYPE##_compare(Y, X, ST) < 0
4917 #define DO_FCMLE(TYPE, X, Y, ST) TYPE##_compare(X, Y, ST) <= 0
4918 #define DO_FCMLT(TYPE, X, Y, ST) TYPE##_compare(X, Y, ST) < 0
4919 #define DO_FCMEQ(TYPE, X, Y, ST) TYPE##_compare_quiet(X, Y, ST) == 0
4920 #define DO_FCMNE(TYPE, X, Y, ST) TYPE##_compare_quiet(X, Y, ST) != 0
4921 #define DO_FCMUO(TYPE, X, Y, ST) \
4922 TYPE##_compare_quiet(X, Y, ST) == float_relation_unordered
4923 #define DO_FACGE(TYPE, X, Y, ST) \
4924 TYPE##_compare(TYPE##_abs(Y), TYPE##_abs(X), ST) <= 0
4925 #define DO_FACGT(TYPE, X, Y, ST) \
4926 TYPE##_compare(TYPE##_abs(Y), TYPE##_abs(X), ST) < 0
4927
DO_FPCMP_PPZZ_ALL(sve_fcmge,DO_FCMGE)4928 DO_FPCMP_PPZZ_ALL(sve_fcmge, DO_FCMGE)
4929 DO_FPCMP_PPZZ_ALL(sve_fcmgt, DO_FCMGT)
4930 DO_FPCMP_PPZZ_ALL(sve_fcmeq, DO_FCMEQ)
4931 DO_FPCMP_PPZZ_ALL(sve_fcmne, DO_FCMNE)
4932 DO_FPCMP_PPZZ_ALL(sve_fcmuo, DO_FCMUO)
4933 DO_FPCMP_PPZZ_ALL(sve_facge, DO_FACGE)
4934 DO_FPCMP_PPZZ_ALL(sve_facgt, DO_FACGT)
4935
4936 #undef DO_FPCMP_PPZZ_ALL
4937 #undef DO_FPCMP_PPZZ_D
4938 #undef DO_FPCMP_PPZZ_S
4939 #undef DO_FPCMP_PPZZ_H
4940 #undef DO_FPCMP_PPZZ
4941
4942 /* One operand floating-point comparison against zero, controlled
4943 * by a predicate.
4944 */
4945 #define DO_FPCMP_PPZ0(NAME, TYPE, H, OP) \
4946 void HELPER(NAME)(void *vd, void *vn, void *vg, \
4947 void *status, uint32_t desc) \
4948 { \
4949 intptr_t i = simd_oprsz(desc), j = (i - 1) >> 6; \
4950 uint64_t *d = vd, *g = vg; \
4951 do { \
4952 uint64_t out = 0, pg = g[j]; \
4953 do { \
4954 i -= sizeof(TYPE), out <<= sizeof(TYPE); \
4955 if ((pg >> (i & 63)) & 1) { \
4956 TYPE nn = *(TYPE *)(vn + H(i)); \
4957 out |= OP(TYPE, nn, 0, status); \
4958 } \
4959 } while (i & 63); \
4960 d[j--] = out; \
4961 } while (i > 0); \
4962 }
4963
4964 #define DO_FPCMP_PPZ0_H(NAME, OP) \
4965 DO_FPCMP_PPZ0(NAME##_h, float16, H1_2, OP)
4966 #define DO_FPCMP_PPZ0_S(NAME, OP) \
4967 DO_FPCMP_PPZ0(NAME##_s, float32, H1_4, OP)
4968 #define DO_FPCMP_PPZ0_D(NAME, OP) \
4969 DO_FPCMP_PPZ0(NAME##_d, float64, H1_8, OP)
4970
4971 #define DO_FPCMP_PPZ0_ALL(NAME, OP) \
4972 DO_FPCMP_PPZ0_H(NAME, OP) \
4973 DO_FPCMP_PPZ0_S(NAME, OP) \
4974 DO_FPCMP_PPZ0_D(NAME, OP)
4975
4976 DO_FPCMP_PPZ0_ALL(sve_fcmge0, DO_FCMGE)
4977 DO_FPCMP_PPZ0_ALL(sve_fcmgt0, DO_FCMGT)
4978 DO_FPCMP_PPZ0_ALL(sve_fcmle0, DO_FCMLE)
4979 DO_FPCMP_PPZ0_ALL(sve_fcmlt0, DO_FCMLT)
4980 DO_FPCMP_PPZ0_ALL(sve_fcmeq0, DO_FCMEQ)
4981 DO_FPCMP_PPZ0_ALL(sve_fcmne0, DO_FCMNE)
4982
4983 /* FP Trig Multiply-Add. */
4984
4985 void HELPER(sve_ftmad_h)(void *vd, void *vn, void *vm, void *vs, uint32_t desc)
4986 {
4987 static const float16 coeff[16] = {
4988 0x3c00, 0xb155, 0x2030, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
4989 0x3c00, 0xb800, 0x293a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
4990 };
4991 intptr_t i, opr_sz = simd_oprsz(desc) / sizeof(float16);
4992 intptr_t x = simd_data(desc);
4993 float16 *d = vd, *n = vn, *m = vm;
4994 for (i = 0; i < opr_sz; i++) {
4995 float16 mm = m[i];
4996 intptr_t xx = x;
4997 if (float16_is_neg(mm)) {
4998 mm = float16_abs(mm);
4999 xx += 8;
5000 }
5001 d[i] = float16_muladd(n[i], mm, coeff[xx], 0, vs);
5002 }
5003 }
5004
HELPER(sve_ftmad_s)5005 void HELPER(sve_ftmad_s)(void *vd, void *vn, void *vm, void *vs, uint32_t desc)
5006 {
5007 static const float32 coeff[16] = {
5008 0x3f800000, 0xbe2aaaab, 0x3c088886, 0xb95008b9,
5009 0x36369d6d, 0x00000000, 0x00000000, 0x00000000,
5010 0x3f800000, 0xbf000000, 0x3d2aaaa6, 0xbab60705,
5011 0x37cd37cc, 0x00000000, 0x00000000, 0x00000000,
5012 };
5013 intptr_t i, opr_sz = simd_oprsz(desc) / sizeof(float32);
5014 intptr_t x = simd_data(desc);
5015 float32 *d = vd, *n = vn, *m = vm;
5016 for (i = 0; i < opr_sz; i++) {
5017 float32 mm = m[i];
5018 intptr_t xx = x;
5019 if (float32_is_neg(mm)) {
5020 mm = float32_abs(mm);
5021 xx += 8;
5022 }
5023 d[i] = float32_muladd(n[i], mm, coeff[xx], 0, vs);
5024 }
5025 }
5026
HELPER(sve_ftmad_d)5027 void HELPER(sve_ftmad_d)(void *vd, void *vn, void *vm, void *vs, uint32_t desc)
5028 {
5029 static const float64 coeff[16] = {
5030 0x3ff0000000000000ull, 0xbfc5555555555543ull,
5031 0x3f8111111110f30cull, 0xbf2a01a019b92fc6ull,
5032 0x3ec71de351f3d22bull, 0xbe5ae5e2b60f7b91ull,
5033 0x3de5d8408868552full, 0x0000000000000000ull,
5034 0x3ff0000000000000ull, 0xbfe0000000000000ull,
5035 0x3fa5555555555536ull, 0xbf56c16c16c13a0bull,
5036 0x3efa01a019b1e8d8ull, 0xbe927e4f7282f468ull,
5037 0x3e21ee96d2641b13ull, 0xbda8f76380fbb401ull,
5038 };
5039 intptr_t i, opr_sz = simd_oprsz(desc) / sizeof(float64);
5040 intptr_t x = simd_data(desc);
5041 float64 *d = vd, *n = vn, *m = vm;
5042 for (i = 0; i < opr_sz; i++) {
5043 float64 mm = m[i];
5044 intptr_t xx = x;
5045 if (float64_is_neg(mm)) {
5046 mm = float64_abs(mm);
5047 xx += 8;
5048 }
5049 d[i] = float64_muladd(n[i], mm, coeff[xx], 0, vs);
5050 }
5051 }
5052
5053 /*
5054 * FP Complex Add
5055 */
5056
HELPER(sve_fcadd_h)5057 void HELPER(sve_fcadd_h)(void *vd, void *vn, void *vm, void *vg,
5058 void *vs, uint32_t desc)
5059 {
5060 intptr_t j, i = simd_oprsz(desc);
5061 uint64_t *g = vg;
5062 float16 neg_imag = float16_set_sign(0, simd_data(desc));
5063 float16 neg_real = float16_chs(neg_imag);
5064
5065 do {
5066 uint64_t pg = g[(i - 1) >> 6];
5067 do {
5068 float16 e0, e1, e2, e3;
5069
5070 /* I holds the real index; J holds the imag index. */
5071 j = i - sizeof(float16);
5072 i -= 2 * sizeof(float16);
5073
5074 e0 = *(float16 *)(vn + H1_2(i));
5075 e1 = *(float16 *)(vm + H1_2(j)) ^ neg_real;
5076 e2 = *(float16 *)(vn + H1_2(j));
5077 e3 = *(float16 *)(vm + H1_2(i)) ^ neg_imag;
5078
5079 if (likely((pg >> (i & 63)) & 1)) {
5080 *(float16 *)(vd + H1_2(i)) = float16_add(e0, e1, vs);
5081 }
5082 if (likely((pg >> (j & 63)) & 1)) {
5083 *(float16 *)(vd + H1_2(j)) = float16_add(e2, e3, vs);
5084 }
5085 } while (i & 63);
5086 } while (i != 0);
5087 }
5088
HELPER(sve_fcadd_s)5089 void HELPER(sve_fcadd_s)(void *vd, void *vn, void *vm, void *vg,
5090 void *vs, uint32_t desc)
5091 {
5092 intptr_t j, i = simd_oprsz(desc);
5093 uint64_t *g = vg;
5094 float32 neg_imag = float32_set_sign(0, simd_data(desc));
5095 float32 neg_real = float32_chs(neg_imag);
5096
5097 do {
5098 uint64_t pg = g[(i - 1) >> 6];
5099 do {
5100 float32 e0, e1, e2, e3;
5101
5102 /* I holds the real index; J holds the imag index. */
5103 j = i - sizeof(float32);
5104 i -= 2 * sizeof(float32);
5105
5106 e0 = *(float32 *)(vn + H1_2(i));
5107 e1 = *(float32 *)(vm + H1_2(j)) ^ neg_real;
5108 e2 = *(float32 *)(vn + H1_2(j));
5109 e3 = *(float32 *)(vm + H1_2(i)) ^ neg_imag;
5110
5111 if (likely((pg >> (i & 63)) & 1)) {
5112 *(float32 *)(vd + H1_2(i)) = float32_add(e0, e1, vs);
5113 }
5114 if (likely((pg >> (j & 63)) & 1)) {
5115 *(float32 *)(vd + H1_2(j)) = float32_add(e2, e3, vs);
5116 }
5117 } while (i & 63);
5118 } while (i != 0);
5119 }
5120
HELPER(sve_fcadd_d)5121 void HELPER(sve_fcadd_d)(void *vd, void *vn, void *vm, void *vg,
5122 void *vs, uint32_t desc)
5123 {
5124 intptr_t j, i = simd_oprsz(desc);
5125 uint64_t *g = vg;
5126 float64 neg_imag = float64_set_sign(0, simd_data(desc));
5127 float64 neg_real = float64_chs(neg_imag);
5128
5129 do {
5130 uint64_t pg = g[(i - 1) >> 6];
5131 do {
5132 float64 e0, e1, e2, e3;
5133
5134 /* I holds the real index; J holds the imag index. */
5135 j = i - sizeof(float64);
5136 i -= 2 * sizeof(float64);
5137
5138 e0 = *(float64 *)(vn + H1_2(i));
5139 e1 = *(float64 *)(vm + H1_2(j)) ^ neg_real;
5140 e2 = *(float64 *)(vn + H1_2(j));
5141 e3 = *(float64 *)(vm + H1_2(i)) ^ neg_imag;
5142
5143 if (likely((pg >> (i & 63)) & 1)) {
5144 *(float64 *)(vd + H1_2(i)) = float64_add(e0, e1, vs);
5145 }
5146 if (likely((pg >> (j & 63)) & 1)) {
5147 *(float64 *)(vd + H1_2(j)) = float64_add(e2, e3, vs);
5148 }
5149 } while (i & 63);
5150 } while (i != 0);
5151 }
5152
5153 /*
5154 * FP Complex Multiply
5155 */
5156
HELPER(sve_fcmla_zpzzz_h)5157 void HELPER(sve_fcmla_zpzzz_h)(void *vd, void *vn, void *vm, void *va,
5158 void *vg, void *status, uint32_t desc)
5159 {
5160 intptr_t j, i = simd_oprsz(desc);
5161 unsigned rot = simd_data(desc);
5162 bool flip = rot & 1;
5163 float16 neg_imag, neg_real;
5164 uint64_t *g = vg;
5165
5166 neg_imag = float16_set_sign(0, (rot & 2) != 0);
5167 neg_real = float16_set_sign(0, rot == 1 || rot == 2);
5168
5169 do {
5170 uint64_t pg = g[(i - 1) >> 6];
5171 do {
5172 float16 e1, e2, e3, e4, nr, ni, mr, mi, d;
5173
5174 /* I holds the real index; J holds the imag index. */
5175 j = i - sizeof(float16);
5176 i -= 2 * sizeof(float16);
5177
5178 nr = *(float16 *)(vn + H1_2(i));
5179 ni = *(float16 *)(vn + H1_2(j));
5180 mr = *(float16 *)(vm + H1_2(i));
5181 mi = *(float16 *)(vm + H1_2(j));
5182
5183 e2 = (flip ? ni : nr);
5184 e1 = (flip ? mi : mr) ^ neg_real;
5185 e4 = e2;
5186 e3 = (flip ? mr : mi) ^ neg_imag;
5187
5188 if (likely((pg >> (i & 63)) & 1)) {
5189 d = *(float16 *)(va + H1_2(i));
5190 d = float16_muladd(e2, e1, d, 0, status);
5191 *(float16 *)(vd + H1_2(i)) = d;
5192 }
5193 if (likely((pg >> (j & 63)) & 1)) {
5194 d = *(float16 *)(va + H1_2(j));
5195 d = float16_muladd(e4, e3, d, 0, status);
5196 *(float16 *)(vd + H1_2(j)) = d;
5197 }
5198 } while (i & 63);
5199 } while (i != 0);
5200 }
5201
HELPER(sve_fcmla_zpzzz_s)5202 void HELPER(sve_fcmla_zpzzz_s)(void *vd, void *vn, void *vm, void *va,
5203 void *vg, void *status, uint32_t desc)
5204 {
5205 intptr_t j, i = simd_oprsz(desc);
5206 unsigned rot = simd_data(desc);
5207 bool flip = rot & 1;
5208 float32 neg_imag, neg_real;
5209 uint64_t *g = vg;
5210
5211 neg_imag = float32_set_sign(0, (rot & 2) != 0);
5212 neg_real = float32_set_sign(0, rot == 1 || rot == 2);
5213
5214 do {
5215 uint64_t pg = g[(i - 1) >> 6];
5216 do {
5217 float32 e1, e2, e3, e4, nr, ni, mr, mi, d;
5218
5219 /* I holds the real index; J holds the imag index. */
5220 j = i - sizeof(float32);
5221 i -= 2 * sizeof(float32);
5222
5223 nr = *(float32 *)(vn + H1_2(i));
5224 ni = *(float32 *)(vn + H1_2(j));
5225 mr = *(float32 *)(vm + H1_2(i));
5226 mi = *(float32 *)(vm + H1_2(j));
5227
5228 e2 = (flip ? ni : nr);
5229 e1 = (flip ? mi : mr) ^ neg_real;
5230 e4 = e2;
5231 e3 = (flip ? mr : mi) ^ neg_imag;
5232
5233 if (likely((pg >> (i & 63)) & 1)) {
5234 d = *(float32 *)(va + H1_2(i));
5235 d = float32_muladd(e2, e1, d, 0, status);
5236 *(float32 *)(vd + H1_2(i)) = d;
5237 }
5238 if (likely((pg >> (j & 63)) & 1)) {
5239 d = *(float32 *)(va + H1_2(j));
5240 d = float32_muladd(e4, e3, d, 0, status);
5241 *(float32 *)(vd + H1_2(j)) = d;
5242 }
5243 } while (i & 63);
5244 } while (i != 0);
5245 }
5246
HELPER(sve_fcmla_zpzzz_d)5247 void HELPER(sve_fcmla_zpzzz_d)(void *vd, void *vn, void *vm, void *va,
5248 void *vg, void *status, uint32_t desc)
5249 {
5250 intptr_t j, i = simd_oprsz(desc);
5251 unsigned rot = simd_data(desc);
5252 bool flip = rot & 1;
5253 float64 neg_imag, neg_real;
5254 uint64_t *g = vg;
5255
5256 neg_imag = float64_set_sign(0, (rot & 2) != 0);
5257 neg_real = float64_set_sign(0, rot == 1 || rot == 2);
5258
5259 do {
5260 uint64_t pg = g[(i - 1) >> 6];
5261 do {
5262 float64 e1, e2, e3, e4, nr, ni, mr, mi, d;
5263
5264 /* I holds the real index; J holds the imag index. */
5265 j = i - sizeof(float64);
5266 i -= 2 * sizeof(float64);
5267
5268 nr = *(float64 *)(vn + H1_2(i));
5269 ni = *(float64 *)(vn + H1_2(j));
5270 mr = *(float64 *)(vm + H1_2(i));
5271 mi = *(float64 *)(vm + H1_2(j));
5272
5273 e2 = (flip ? ni : nr);
5274 e1 = (flip ? mi : mr) ^ neg_real;
5275 e4 = e2;
5276 e3 = (flip ? mr : mi) ^ neg_imag;
5277
5278 if (likely((pg >> (i & 63)) & 1)) {
5279 d = *(float64 *)(va + H1_2(i));
5280 d = float64_muladd(e2, e1, d, 0, status);
5281 *(float64 *)(vd + H1_2(i)) = d;
5282 }
5283 if (likely((pg >> (j & 63)) & 1)) {
5284 d = *(float64 *)(va + H1_2(j));
5285 d = float64_muladd(e4, e3, d, 0, status);
5286 *(float64 *)(vd + H1_2(j)) = d;
5287 }
5288 } while (i & 63);
5289 } while (i != 0);
5290 }
5291
5292 /*
5293 * Load contiguous data, protected by a governing predicate.
5294 */
5295
5296 /*
5297 * Skip through a sequence of inactive elements in the guarding predicate @vg,
5298 * beginning at @reg_off bounded by @reg_max. Return the offset of the active
5299 * element >= @reg_off, or @reg_max if there were no active elements at all.
5300 */
find_next_active(uint64_t * vg,intptr_t reg_off,intptr_t reg_max,int esz)5301 static intptr_t find_next_active(uint64_t *vg, intptr_t reg_off,
5302 intptr_t reg_max, int esz)
5303 {
5304 uint64_t pg_mask = pred_esz_masks[esz];
5305 uint64_t pg = (vg[reg_off >> 6] & pg_mask) >> (reg_off & 63);
5306
5307 /* In normal usage, the first element is active. */
5308 if (likely(pg & 1)) {
5309 return reg_off;
5310 }
5311
5312 if (pg == 0) {
5313 reg_off &= -64;
5314 do {
5315 reg_off += 64;
5316 if (unlikely(reg_off >= reg_max)) {
5317 /* The entire predicate was false. */
5318 return reg_max;
5319 }
5320 pg = vg[reg_off >> 6] & pg_mask;
5321 } while (pg == 0);
5322 }
5323 reg_off += ctz64(pg);
5324
5325 /* We should never see an out of range predicate bit set. */
5326 tcg_debug_assert(reg_off < reg_max);
5327 return reg_off;
5328 }
5329
5330 /*
5331 * Resolve the guest virtual address to info->host and info->flags.
5332 * If @nofault, return false if the page is invalid, otherwise
5333 * exit via page fault exception.
5334 */
5335
sve_probe_page(SVEHostPage * info,bool nofault,CPUARMState * env,target_ulong addr,int mem_off,MMUAccessType access_type,int mmu_idx,uintptr_t retaddr)5336 bool sve_probe_page(SVEHostPage *info, bool nofault, CPUARMState *env,
5337 target_ulong addr, int mem_off, MMUAccessType access_type,
5338 int mmu_idx, uintptr_t retaddr)
5339 {
5340 int flags;
5341
5342 addr += mem_off;
5343
5344 /*
5345 * User-only currently always issues with TBI. See the comment
5346 * above useronly_clean_ptr. Usually we clean this top byte away
5347 * during translation, but we can't do that for e.g. vector + imm
5348 * addressing modes.
5349 *
5350 * We currently always enable TBI for user-only, and do not provide
5351 * a way to turn it off. So clean the pointer unconditionally here,
5352 * rather than look it up here, or pass it down from above.
5353 */
5354 addr = useronly_clean_ptr(addr);
5355
5356 #ifdef CONFIG_USER_ONLY
5357 flags = probe_access_flags(env, addr, 0, access_type, mmu_idx, nofault,
5358 &info->host, retaddr);
5359 #else
5360 CPUTLBEntryFull *full;
5361 flags = probe_access_full(env, addr, 0, access_type, mmu_idx, nofault,
5362 &info->host, &full, retaddr);
5363 #endif
5364 info->flags = flags;
5365
5366 if (flags & TLB_INVALID_MASK) {
5367 g_assert(nofault);
5368 return false;
5369 }
5370
5371 #ifdef CONFIG_USER_ONLY
5372 memset(&info->attrs, 0, sizeof(info->attrs));
5373 /* Require both ANON and MTE; see allocation_tag_mem(). */
5374 info->tagged = (flags & PAGE_ANON) && (flags & PAGE_MTE);
5375 #else
5376 info->attrs = full->attrs;
5377 info->tagged = full->extra.arm.pte_attrs == 0xf0;
5378 #endif
5379
5380 /* Ensure that info->host[] is relative to addr, not addr + mem_off. */
5381 info->host -= mem_off;
5382 return true;
5383 }
5384
5385 /*
5386 * Find first active element on each page, and a loose bound for the
5387 * final element on each page. Identify any single element that spans
5388 * the page boundary. Return true if there are any active elements.
5389 */
sve_cont_ldst_elements(SVEContLdSt * info,target_ulong addr,uint64_t * vg,intptr_t reg_max,int esz,int msize)5390 bool sve_cont_ldst_elements(SVEContLdSt *info, target_ulong addr, uint64_t *vg,
5391 intptr_t reg_max, int esz, int msize)
5392 {
5393 const int esize = 1 << esz;
5394 const uint64_t pg_mask = pred_esz_masks[esz];
5395 intptr_t reg_off_first = -1, reg_off_last = -1, reg_off_split;
5396 intptr_t mem_off_last, mem_off_split;
5397 intptr_t page_split, elt_split;
5398 intptr_t i;
5399
5400 /* Set all of the element indices to -1, and the TLB data to 0. */
5401 memset(info, -1, offsetof(SVEContLdSt, page));
5402 memset(info->page, 0, sizeof(info->page));
5403
5404 /* Gross scan over the entire predicate to find bounds. */
5405 i = 0;
5406 do {
5407 uint64_t pg = vg[i] & pg_mask;
5408 if (pg) {
5409 reg_off_last = i * 64 + 63 - clz64(pg);
5410 if (reg_off_first < 0) {
5411 reg_off_first = i * 64 + ctz64(pg);
5412 }
5413 }
5414 } while (++i * 64 < reg_max);
5415
5416 if (unlikely(reg_off_first < 0)) {
5417 /* No active elements, no pages touched. */
5418 return false;
5419 }
5420 tcg_debug_assert(reg_off_last >= 0 && reg_off_last < reg_max);
5421
5422 info->reg_off_first[0] = reg_off_first;
5423 info->mem_off_first[0] = (reg_off_first >> esz) * msize;
5424 mem_off_last = (reg_off_last >> esz) * msize;
5425
5426 page_split = -(addr | TARGET_PAGE_MASK);
5427 if (likely(mem_off_last + msize <= page_split)) {
5428 /* The entire operation fits within a single page. */
5429 info->reg_off_last[0] = reg_off_last;
5430 return true;
5431 }
5432
5433 info->page_split = page_split;
5434 elt_split = page_split / msize;
5435 reg_off_split = elt_split << esz;
5436 mem_off_split = elt_split * msize;
5437
5438 /*
5439 * This is the last full element on the first page, but it is not
5440 * necessarily active. If there is no full element, i.e. the first
5441 * active element is the one that's split, this value remains -1.
5442 * It is useful as iteration bounds.
5443 */
5444 if (elt_split != 0) {
5445 info->reg_off_last[0] = reg_off_split - esize;
5446 }
5447
5448 /* Determine if an unaligned element spans the pages. */
5449 if (page_split % msize != 0) {
5450 /* It is helpful to know if the split element is active. */
5451 if ((vg[reg_off_split >> 6] >> (reg_off_split & 63)) & 1) {
5452 info->reg_off_split = reg_off_split;
5453 info->mem_off_split = mem_off_split;
5454
5455 if (reg_off_split == reg_off_last) {
5456 /* The page crossing element is last. */
5457 return true;
5458 }
5459 }
5460 reg_off_split += esize;
5461 mem_off_split += msize;
5462 }
5463
5464 /*
5465 * We do want the first active element on the second page, because
5466 * this may affect the address reported in an exception.
5467 */
5468 reg_off_split = find_next_active(vg, reg_off_split, reg_max, esz);
5469 tcg_debug_assert(reg_off_split <= reg_off_last);
5470 info->reg_off_first[1] = reg_off_split;
5471 info->mem_off_first[1] = (reg_off_split >> esz) * msize;
5472 info->reg_off_last[1] = reg_off_last;
5473 return true;
5474 }
5475
5476 /*
5477 * Resolve the guest virtual addresses to info->page[].
5478 * Control the generation of page faults with @fault. Return false if
5479 * there is no work to do, which can only happen with @fault == FAULT_NO.
5480 */
sve_cont_ldst_pages(SVEContLdSt * info,SVEContFault fault,CPUARMState * env,target_ulong addr,MMUAccessType access_type,uintptr_t retaddr)5481 bool sve_cont_ldst_pages(SVEContLdSt *info, SVEContFault fault,
5482 CPUARMState *env, target_ulong addr,
5483 MMUAccessType access_type, uintptr_t retaddr)
5484 {
5485 int mmu_idx = arm_env_mmu_index(env);
5486 int mem_off = info->mem_off_first[0];
5487 bool nofault = fault == FAULT_NO;
5488 bool have_work = true;
5489
5490 if (!sve_probe_page(&info->page[0], nofault, env, addr, mem_off,
5491 access_type, mmu_idx, retaddr)) {
5492 /* No work to be done. */
5493 return false;
5494 }
5495
5496 if (likely(info->page_split < 0)) {
5497 /* The entire operation was on the one page. */
5498 return true;
5499 }
5500
5501 /*
5502 * If the second page is invalid, then we want the fault address to be
5503 * the first byte on that page which is accessed.
5504 */
5505 if (info->mem_off_split >= 0) {
5506 /*
5507 * There is an element split across the pages. The fault address
5508 * should be the first byte of the second page.
5509 */
5510 mem_off = info->page_split;
5511 /*
5512 * If the split element is also the first active element
5513 * of the vector, then: For first-fault we should continue
5514 * to generate faults for the second page. For no-fault,
5515 * we have work only if the second page is valid.
5516 */
5517 if (info->mem_off_first[0] < info->mem_off_split) {
5518 nofault = FAULT_FIRST;
5519 have_work = false;
5520 }
5521 } else {
5522 /*
5523 * There is no element split across the pages. The fault address
5524 * should be the first active element on the second page.
5525 */
5526 mem_off = info->mem_off_first[1];
5527 /*
5528 * There must have been one active element on the first page,
5529 * so we're out of first-fault territory.
5530 */
5531 nofault = fault != FAULT_ALL;
5532 }
5533
5534 have_work |= sve_probe_page(&info->page[1], nofault, env, addr, mem_off,
5535 access_type, mmu_idx, retaddr);
5536 return have_work;
5537 }
5538
5539 #ifndef CONFIG_USER_ONLY
sve_cont_ldst_watchpoints(SVEContLdSt * info,CPUARMState * env,uint64_t * vg,target_ulong addr,int esize,int msize,int wp_access,uintptr_t retaddr)5540 void sve_cont_ldst_watchpoints(SVEContLdSt *info, CPUARMState *env,
5541 uint64_t *vg, target_ulong addr,
5542 int esize, int msize, int wp_access,
5543 uintptr_t retaddr)
5544 {
5545 intptr_t mem_off, reg_off, reg_last;
5546 int flags0 = info->page[0].flags;
5547 int flags1 = info->page[1].flags;
5548
5549 if (likely(!((flags0 | flags1) & TLB_WATCHPOINT))) {
5550 return;
5551 }
5552
5553 /* Indicate that watchpoints are handled. */
5554 info->page[0].flags = flags0 & ~TLB_WATCHPOINT;
5555 info->page[1].flags = flags1 & ~TLB_WATCHPOINT;
5556
5557 if (flags0 & TLB_WATCHPOINT) {
5558 mem_off = info->mem_off_first[0];
5559 reg_off = info->reg_off_first[0];
5560 reg_last = info->reg_off_last[0];
5561
5562 while (reg_off <= reg_last) {
5563 uint64_t pg = vg[reg_off >> 6];
5564 do {
5565 if ((pg >> (reg_off & 63)) & 1) {
5566 cpu_check_watchpoint(env_cpu(env), addr + mem_off,
5567 msize, info->page[0].attrs,
5568 wp_access, retaddr);
5569 }
5570 reg_off += esize;
5571 mem_off += msize;
5572 } while (reg_off <= reg_last && (reg_off & 63));
5573 }
5574 }
5575
5576 mem_off = info->mem_off_split;
5577 if (mem_off >= 0) {
5578 cpu_check_watchpoint(env_cpu(env), addr + mem_off, msize,
5579 info->page[0].attrs, wp_access, retaddr);
5580 }
5581
5582 mem_off = info->mem_off_first[1];
5583 if ((flags1 & TLB_WATCHPOINT) && mem_off >= 0) {
5584 reg_off = info->reg_off_first[1];
5585 reg_last = info->reg_off_last[1];
5586
5587 do {
5588 uint64_t pg = vg[reg_off >> 6];
5589 do {
5590 if ((pg >> (reg_off & 63)) & 1) {
5591 cpu_check_watchpoint(env_cpu(env), addr + mem_off,
5592 msize, info->page[1].attrs,
5593 wp_access, retaddr);
5594 }
5595 reg_off += esize;
5596 mem_off += msize;
5597 } while (reg_off & 63);
5598 } while (reg_off <= reg_last);
5599 }
5600 }
5601 #endif
5602
sve_cont_ldst_mte_check(SVEContLdSt * info,CPUARMState * env,uint64_t * vg,target_ulong addr,int esize,int msize,uint32_t mtedesc,uintptr_t ra)5603 void sve_cont_ldst_mte_check(SVEContLdSt *info, CPUARMState *env,
5604 uint64_t *vg, target_ulong addr, int esize,
5605 int msize, uint32_t mtedesc, uintptr_t ra)
5606 {
5607 intptr_t mem_off, reg_off, reg_last;
5608
5609 /* Process the page only if MemAttr == Tagged. */
5610 if (info->page[0].tagged) {
5611 mem_off = info->mem_off_first[0];
5612 reg_off = info->reg_off_first[0];
5613 reg_last = info->reg_off_split;
5614 if (reg_last < 0) {
5615 reg_last = info->reg_off_last[0];
5616 }
5617
5618 do {
5619 uint64_t pg = vg[reg_off >> 6];
5620 do {
5621 if ((pg >> (reg_off & 63)) & 1) {
5622 mte_check(env, mtedesc, addr, ra);
5623 }
5624 reg_off += esize;
5625 mem_off += msize;
5626 } while (reg_off <= reg_last && (reg_off & 63));
5627 } while (reg_off <= reg_last);
5628 }
5629
5630 mem_off = info->mem_off_first[1];
5631 if (mem_off >= 0 && info->page[1].tagged) {
5632 reg_off = info->reg_off_first[1];
5633 reg_last = info->reg_off_last[1];
5634
5635 do {
5636 uint64_t pg = vg[reg_off >> 6];
5637 do {
5638 if ((pg >> (reg_off & 63)) & 1) {
5639 mte_check(env, mtedesc, addr, ra);
5640 }
5641 reg_off += esize;
5642 mem_off += msize;
5643 } while (reg_off & 63);
5644 } while (reg_off <= reg_last);
5645 }
5646 }
5647
5648 /*
5649 * Common helper for all contiguous 1,2,3,4-register predicated stores.
5650 */
5651 static inline QEMU_ALWAYS_INLINE
sve_ldN_r(CPUARMState * env,uint64_t * vg,const target_ulong addr,uint32_t desc,const uintptr_t retaddr,const int esz,const int msz,const int N,uint32_t mtedesc,sve_ldst1_host_fn * host_fn,sve_ldst1_tlb_fn * tlb_fn)5652 void sve_ldN_r(CPUARMState *env, uint64_t *vg, const target_ulong addr,
5653 uint32_t desc, const uintptr_t retaddr,
5654 const int esz, const int msz, const int N, uint32_t mtedesc,
5655 sve_ldst1_host_fn *host_fn,
5656 sve_ldst1_tlb_fn *tlb_fn)
5657 {
5658 const unsigned rd = simd_data(desc);
5659 const intptr_t reg_max = simd_oprsz(desc);
5660 intptr_t reg_off, reg_last, mem_off;
5661 SVEContLdSt info;
5662 void *host;
5663 int flags, i;
5664
5665 /* Find the active elements. */
5666 if (!sve_cont_ldst_elements(&info, addr, vg, reg_max, esz, N << msz)) {
5667 /* The entire predicate was false; no load occurs. */
5668 for (i = 0; i < N; ++i) {
5669 memset(&env->vfp.zregs[(rd + i) & 31], 0, reg_max);
5670 }
5671 return;
5672 }
5673
5674 /* Probe the page(s). Exit with exception for any invalid page. */
5675 sve_cont_ldst_pages(&info, FAULT_ALL, env, addr, MMU_DATA_LOAD, retaddr);
5676
5677 /* Handle watchpoints for all active elements. */
5678 sve_cont_ldst_watchpoints(&info, env, vg, addr, 1 << esz, N << msz,
5679 BP_MEM_READ, retaddr);
5680
5681 /*
5682 * Handle mte checks for all active elements.
5683 * Since TBI must be set for MTE, !mtedesc => !mte_active.
5684 */
5685 if (mtedesc) {
5686 sve_cont_ldst_mte_check(&info, env, vg, addr, 1 << esz, N << msz,
5687 mtedesc, retaddr);
5688 }
5689
5690 flags = info.page[0].flags | info.page[1].flags;
5691 if (unlikely(flags != 0)) {
5692 /*
5693 * At least one page includes MMIO.
5694 * Any bus operation can fail with cpu_transaction_failed,
5695 * which for ARM will raise SyncExternal. Perform the load
5696 * into scratch memory to preserve register state until the end.
5697 */
5698 ARMVectorReg scratch[4] = { };
5699
5700 mem_off = info.mem_off_first[0];
5701 reg_off = info.reg_off_first[0];
5702 reg_last = info.reg_off_last[1];
5703 if (reg_last < 0) {
5704 reg_last = info.reg_off_split;
5705 if (reg_last < 0) {
5706 reg_last = info.reg_off_last[0];
5707 }
5708 }
5709
5710 do {
5711 uint64_t pg = vg[reg_off >> 6];
5712 do {
5713 if ((pg >> (reg_off & 63)) & 1) {
5714 for (i = 0; i < N; ++i) {
5715 tlb_fn(env, &scratch[i], reg_off,
5716 addr + mem_off + (i << msz), retaddr);
5717 }
5718 }
5719 reg_off += 1 << esz;
5720 mem_off += N << msz;
5721 } while (reg_off & 63);
5722 } while (reg_off <= reg_last);
5723
5724 for (i = 0; i < N; ++i) {
5725 memcpy(&env->vfp.zregs[(rd + i) & 31], &scratch[i], reg_max);
5726 }
5727 return;
5728 }
5729
5730 /* The entire operation is in RAM, on valid pages. */
5731
5732 for (i = 0; i < N; ++i) {
5733 memset(&env->vfp.zregs[(rd + i) & 31], 0, reg_max);
5734 }
5735
5736 mem_off = info.mem_off_first[0];
5737 reg_off = info.reg_off_first[0];
5738 reg_last = info.reg_off_last[0];
5739 host = info.page[0].host;
5740
5741 set_helper_retaddr(retaddr);
5742
5743 while (reg_off <= reg_last) {
5744 uint64_t pg = vg[reg_off >> 6];
5745 do {
5746 if ((pg >> (reg_off & 63)) & 1) {
5747 for (i = 0; i < N; ++i) {
5748 host_fn(&env->vfp.zregs[(rd + i) & 31], reg_off,
5749 host + mem_off + (i << msz));
5750 }
5751 }
5752 reg_off += 1 << esz;
5753 mem_off += N << msz;
5754 } while (reg_off <= reg_last && (reg_off & 63));
5755 }
5756
5757 clear_helper_retaddr();
5758
5759 /*
5760 * Use the slow path to manage the cross-page misalignment.
5761 * But we know this is RAM and cannot trap.
5762 */
5763 mem_off = info.mem_off_split;
5764 if (unlikely(mem_off >= 0)) {
5765 reg_off = info.reg_off_split;
5766 for (i = 0; i < N; ++i) {
5767 tlb_fn(env, &env->vfp.zregs[(rd + i) & 31], reg_off,
5768 addr + mem_off + (i << msz), retaddr);
5769 }
5770 }
5771
5772 mem_off = info.mem_off_first[1];
5773 if (unlikely(mem_off >= 0)) {
5774 reg_off = info.reg_off_first[1];
5775 reg_last = info.reg_off_last[1];
5776 host = info.page[1].host;
5777
5778 set_helper_retaddr(retaddr);
5779
5780 do {
5781 uint64_t pg = vg[reg_off >> 6];
5782 do {
5783 if ((pg >> (reg_off & 63)) & 1) {
5784 for (i = 0; i < N; ++i) {
5785 host_fn(&env->vfp.zregs[(rd + i) & 31], reg_off,
5786 host + mem_off + (i << msz));
5787 }
5788 }
5789 reg_off += 1 << esz;
5790 mem_off += N << msz;
5791 } while (reg_off & 63);
5792 } while (reg_off <= reg_last);
5793
5794 clear_helper_retaddr();
5795 }
5796 }
5797
5798 static inline QEMU_ALWAYS_INLINE
sve_ldN_r_mte(CPUARMState * env,uint64_t * vg,target_ulong addr,uint32_t desc,const uintptr_t ra,const int esz,const int msz,const int N,sve_ldst1_host_fn * host_fn,sve_ldst1_tlb_fn * tlb_fn)5799 void sve_ldN_r_mte(CPUARMState *env, uint64_t *vg, target_ulong addr,
5800 uint32_t desc, const uintptr_t ra,
5801 const int esz, const int msz, const int N,
5802 sve_ldst1_host_fn *host_fn,
5803 sve_ldst1_tlb_fn *tlb_fn)
5804 {
5805 uint32_t mtedesc = desc >> (SIMD_DATA_SHIFT + SVE_MTEDESC_SHIFT);
5806 int bit55 = extract64(addr, 55, 1);
5807
5808 /* Remove mtedesc from the normal sve descriptor. */
5809 desc = extract32(desc, 0, SIMD_DATA_SHIFT + SVE_MTEDESC_SHIFT);
5810
5811 /* Perform gross MTE suppression early. */
5812 if (!tbi_check(mtedesc, bit55) ||
5813 tcma_check(mtedesc, bit55, allocation_tag_from_addr(addr))) {
5814 mtedesc = 0;
5815 }
5816
5817 sve_ldN_r(env, vg, addr, desc, ra, esz, msz, N, mtedesc, host_fn, tlb_fn);
5818 }
5819
5820 #define DO_LD1_1(NAME, ESZ) \
5821 void HELPER(sve_##NAME##_r)(CPUARMState *env, void *vg, \
5822 target_ulong addr, uint32_t desc) \
5823 { \
5824 sve_ldN_r(env, vg, addr, desc, GETPC(), ESZ, MO_8, 1, 0, \
5825 sve_##NAME##_host, sve_##NAME##_tlb); \
5826 } \
5827 void HELPER(sve_##NAME##_r_mte)(CPUARMState *env, void *vg, \
5828 target_ulong addr, uint32_t desc) \
5829 { \
5830 sve_ldN_r_mte(env, vg, addr, desc, GETPC(), ESZ, MO_8, 1, \
5831 sve_##NAME##_host, sve_##NAME##_tlb); \
5832 }
5833
5834 #define DO_LD1_2(NAME, ESZ, MSZ) \
5835 void HELPER(sve_##NAME##_le_r)(CPUARMState *env, void *vg, \
5836 target_ulong addr, uint32_t desc) \
5837 { \
5838 sve_ldN_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, 1, 0, \
5839 sve_##NAME##_le_host, sve_##NAME##_le_tlb); \
5840 } \
5841 void HELPER(sve_##NAME##_be_r)(CPUARMState *env, void *vg, \
5842 target_ulong addr, uint32_t desc) \
5843 { \
5844 sve_ldN_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, 1, 0, \
5845 sve_##NAME##_be_host, sve_##NAME##_be_tlb); \
5846 } \
5847 void HELPER(sve_##NAME##_le_r_mte)(CPUARMState *env, void *vg, \
5848 target_ulong addr, uint32_t desc) \
5849 { \
5850 sve_ldN_r_mte(env, vg, addr, desc, GETPC(), ESZ, MSZ, 1, \
5851 sve_##NAME##_le_host, sve_##NAME##_le_tlb); \
5852 } \
5853 void HELPER(sve_##NAME##_be_r_mte)(CPUARMState *env, void *vg, \
5854 target_ulong addr, uint32_t desc) \
5855 { \
5856 sve_ldN_r_mte(env, vg, addr, desc, GETPC(), ESZ, MSZ, 1, \
5857 sve_##NAME##_be_host, sve_##NAME##_be_tlb); \
5858 }
5859
DO_LD1_1(ld1bb,MO_8)5860 DO_LD1_1(ld1bb, MO_8)
5861 DO_LD1_1(ld1bhu, MO_16)
5862 DO_LD1_1(ld1bhs, MO_16)
5863 DO_LD1_1(ld1bsu, MO_32)
5864 DO_LD1_1(ld1bss, MO_32)
5865 DO_LD1_1(ld1bdu, MO_64)
5866 DO_LD1_1(ld1bds, MO_64)
5867
5868 DO_LD1_2(ld1hh, MO_16, MO_16)
5869 DO_LD1_2(ld1hsu, MO_32, MO_16)
5870 DO_LD1_2(ld1hss, MO_32, MO_16)
5871 DO_LD1_2(ld1hdu, MO_64, MO_16)
5872 DO_LD1_2(ld1hds, MO_64, MO_16)
5873
5874 DO_LD1_2(ld1ss, MO_32, MO_32)
5875 DO_LD1_2(ld1sdu, MO_64, MO_32)
5876 DO_LD1_2(ld1sds, MO_64, MO_32)
5877
5878 DO_LD1_2(ld1dd, MO_64, MO_64)
5879
5880 #undef DO_LD1_1
5881 #undef DO_LD1_2
5882
5883 #define DO_LDN_1(N) \
5884 void HELPER(sve_ld##N##bb_r)(CPUARMState *env, void *vg, \
5885 target_ulong addr, uint32_t desc) \
5886 { \
5887 sve_ldN_r(env, vg, addr, desc, GETPC(), MO_8, MO_8, N, 0, \
5888 sve_ld1bb_host, sve_ld1bb_tlb); \
5889 } \
5890 void HELPER(sve_ld##N##bb_r_mte)(CPUARMState *env, void *vg, \
5891 target_ulong addr, uint32_t desc) \
5892 { \
5893 sve_ldN_r_mte(env, vg, addr, desc, GETPC(), MO_8, MO_8, N, \
5894 sve_ld1bb_host, sve_ld1bb_tlb); \
5895 }
5896
5897 #define DO_LDN_2(N, SUFF, ESZ) \
5898 void HELPER(sve_ld##N##SUFF##_le_r)(CPUARMState *env, void *vg, \
5899 target_ulong addr, uint32_t desc) \
5900 { \
5901 sve_ldN_r(env, vg, addr, desc, GETPC(), ESZ, ESZ, N, 0, \
5902 sve_ld1##SUFF##_le_host, sve_ld1##SUFF##_le_tlb); \
5903 } \
5904 void HELPER(sve_ld##N##SUFF##_be_r)(CPUARMState *env, void *vg, \
5905 target_ulong addr, uint32_t desc) \
5906 { \
5907 sve_ldN_r(env, vg, addr, desc, GETPC(), ESZ, ESZ, N, 0, \
5908 sve_ld1##SUFF##_be_host, sve_ld1##SUFF##_be_tlb); \
5909 } \
5910 void HELPER(sve_ld##N##SUFF##_le_r_mte)(CPUARMState *env, void *vg, \
5911 target_ulong addr, uint32_t desc) \
5912 { \
5913 sve_ldN_r_mte(env, vg, addr, desc, GETPC(), ESZ, ESZ, N, \
5914 sve_ld1##SUFF##_le_host, sve_ld1##SUFF##_le_tlb); \
5915 } \
5916 void HELPER(sve_ld##N##SUFF##_be_r_mte)(CPUARMState *env, void *vg, \
5917 target_ulong addr, uint32_t desc) \
5918 { \
5919 sve_ldN_r_mte(env, vg, addr, desc, GETPC(), ESZ, ESZ, N, \
5920 sve_ld1##SUFF##_be_host, sve_ld1##SUFF##_be_tlb); \
5921 }
5922
5923 DO_LDN_1(2)
5924 DO_LDN_1(3)
5925 DO_LDN_1(4)
5926
5927 DO_LDN_2(2, hh, MO_16)
5928 DO_LDN_2(3, hh, MO_16)
5929 DO_LDN_2(4, hh, MO_16)
5930
5931 DO_LDN_2(2, ss, MO_32)
5932 DO_LDN_2(3, ss, MO_32)
5933 DO_LDN_2(4, ss, MO_32)
5934
5935 DO_LDN_2(2, dd, MO_64)
5936 DO_LDN_2(3, dd, MO_64)
5937 DO_LDN_2(4, dd, MO_64)
5938
5939 #undef DO_LDN_1
5940 #undef DO_LDN_2
5941
5942 /*
5943 * Load contiguous data, first-fault and no-fault.
5944 *
5945 * For user-only, we control the race between page_check_range and
5946 * another thread's munmap by using set/clear_helper_retaddr. Any
5947 * SEGV that occurs between those markers is assumed to be because
5948 * the guest page vanished. Keep that block as small as possible
5949 * so that unrelated QEMU bugs are not blamed on the guest.
5950 */
5951
5952 /* Fault on byte I. All bits in FFR from I are cleared. The vector
5953 * result from I is CONSTRAINED UNPREDICTABLE; we choose the MERGE
5954 * option, which leaves subsequent data unchanged.
5955 */
5956 static void record_fault(CPUARMState *env, uintptr_t i, uintptr_t oprsz)
5957 {
5958 uint64_t *ffr = env->vfp.pregs[FFR_PRED_NUM].p;
5959
5960 if (i & 63) {
5961 ffr[i / 64] &= MAKE_64BIT_MASK(0, i & 63);
5962 i = ROUND_UP(i, 64);
5963 }
5964 for (; i < oprsz; i += 64) {
5965 ffr[i / 64] = 0;
5966 }
5967 }
5968
5969 /*
5970 * Common helper for all contiguous no-fault and first-fault loads.
5971 */
5972 static inline QEMU_ALWAYS_INLINE
sve_ldnfff1_r(CPUARMState * env,void * vg,const target_ulong addr,uint32_t desc,const uintptr_t retaddr,uint32_t mtedesc,const int esz,const int msz,const SVEContFault fault,sve_ldst1_host_fn * host_fn,sve_ldst1_tlb_fn * tlb_fn)5973 void sve_ldnfff1_r(CPUARMState *env, void *vg, const target_ulong addr,
5974 uint32_t desc, const uintptr_t retaddr, uint32_t mtedesc,
5975 const int esz, const int msz, const SVEContFault fault,
5976 sve_ldst1_host_fn *host_fn,
5977 sve_ldst1_tlb_fn *tlb_fn)
5978 {
5979 const unsigned rd = simd_data(desc);
5980 void *vd = &env->vfp.zregs[rd];
5981 const intptr_t reg_max = simd_oprsz(desc);
5982 intptr_t reg_off, mem_off, reg_last;
5983 SVEContLdSt info;
5984 int flags;
5985 void *host;
5986
5987 /* Find the active elements. */
5988 if (!sve_cont_ldst_elements(&info, addr, vg, reg_max, esz, 1 << msz)) {
5989 /* The entire predicate was false; no load occurs. */
5990 memset(vd, 0, reg_max);
5991 return;
5992 }
5993 reg_off = info.reg_off_first[0];
5994
5995 /* Probe the page(s). */
5996 if (!sve_cont_ldst_pages(&info, fault, env, addr, MMU_DATA_LOAD, retaddr)) {
5997 /* Fault on first element. */
5998 tcg_debug_assert(fault == FAULT_NO);
5999 memset(vd, 0, reg_max);
6000 goto do_fault;
6001 }
6002
6003 mem_off = info.mem_off_first[0];
6004 flags = info.page[0].flags;
6005
6006 /*
6007 * Disable MTE checking if the Tagged bit is not set. Since TBI must
6008 * be set within MTEDESC for MTE, !mtedesc => !mte_active.
6009 */
6010 if (!info.page[0].tagged) {
6011 mtedesc = 0;
6012 }
6013
6014 if (fault == FAULT_FIRST) {
6015 /* Trapping mte check for the first-fault element. */
6016 if (mtedesc) {
6017 mte_check(env, mtedesc, addr + mem_off, retaddr);
6018 }
6019
6020 /*
6021 * Special handling of the first active element,
6022 * if it crosses a page boundary or is MMIO.
6023 */
6024 bool is_split = mem_off == info.mem_off_split;
6025 if (unlikely(flags != 0) || unlikely(is_split)) {
6026 /*
6027 * Use the slow path for cross-page handling.
6028 * Might trap for MMIO or watchpoints.
6029 */
6030 tlb_fn(env, vd, reg_off, addr + mem_off, retaddr);
6031
6032 /* After any fault, zero the other elements. */
6033 swap_memzero(vd, reg_off);
6034 reg_off += 1 << esz;
6035 mem_off += 1 << msz;
6036 swap_memzero(vd + reg_off, reg_max - reg_off);
6037
6038 if (is_split) {
6039 goto second_page;
6040 }
6041 } else {
6042 memset(vd, 0, reg_max);
6043 }
6044 } else {
6045 memset(vd, 0, reg_max);
6046 if (unlikely(mem_off == info.mem_off_split)) {
6047 /* The first active element crosses a page boundary. */
6048 flags |= info.page[1].flags;
6049 if (unlikely(flags & TLB_MMIO)) {
6050 /* Some page is MMIO, see below. */
6051 goto do_fault;
6052 }
6053 if (unlikely(flags & TLB_WATCHPOINT) &&
6054 (cpu_watchpoint_address_matches
6055 (env_cpu(env), addr + mem_off, 1 << msz)
6056 & BP_MEM_READ)) {
6057 /* Watchpoint hit, see below. */
6058 goto do_fault;
6059 }
6060 if (mtedesc && !mte_probe(env, mtedesc, addr + mem_off)) {
6061 goto do_fault;
6062 }
6063 /*
6064 * Use the slow path for cross-page handling.
6065 * This is RAM, without a watchpoint, and will not trap.
6066 */
6067 tlb_fn(env, vd, reg_off, addr + mem_off, retaddr);
6068 goto second_page;
6069 }
6070 }
6071
6072 /*
6073 * From this point on, all memory operations are MemSingleNF.
6074 *
6075 * Per the MemSingleNF pseudocode, a no-fault load from Device memory
6076 * must not actually hit the bus -- it returns (UNKNOWN, FAULT) instead.
6077 *
6078 * Unfortuately we do not have access to the memory attributes from the
6079 * PTE to tell Device memory from Normal memory. So we make a mostly
6080 * correct check, and indicate (UNKNOWN, FAULT) for any MMIO.
6081 * This gives the right answer for the common cases of "Normal memory,
6082 * backed by host RAM" and "Device memory, backed by MMIO".
6083 * The architecture allows us to suppress an NF load and return
6084 * (UNKNOWN, FAULT) for any reason, so our behaviour for the corner
6085 * case of "Normal memory, backed by MMIO" is permitted. The case we
6086 * get wrong is "Device memory, backed by host RAM", for which we
6087 * should return (UNKNOWN, FAULT) for but do not.
6088 *
6089 * Similarly, CPU_BP breakpoints would raise exceptions, and so
6090 * return (UNKNOWN, FAULT). For simplicity, we consider gdb and
6091 * architectural breakpoints the same.
6092 */
6093 if (unlikely(flags & TLB_MMIO)) {
6094 goto do_fault;
6095 }
6096
6097 reg_last = info.reg_off_last[0];
6098 host = info.page[0].host;
6099
6100 set_helper_retaddr(retaddr);
6101
6102 do {
6103 uint64_t pg = *(uint64_t *)(vg + (reg_off >> 3));
6104 do {
6105 if ((pg >> (reg_off & 63)) & 1) {
6106 if (unlikely(flags & TLB_WATCHPOINT) &&
6107 (cpu_watchpoint_address_matches
6108 (env_cpu(env), addr + mem_off, 1 << msz)
6109 & BP_MEM_READ)) {
6110 clear_helper_retaddr();
6111 goto do_fault;
6112 }
6113 if (mtedesc && !mte_probe(env, mtedesc, addr + mem_off)) {
6114 clear_helper_retaddr();
6115 goto do_fault;
6116 }
6117 host_fn(vd, reg_off, host + mem_off);
6118 }
6119 reg_off += 1 << esz;
6120 mem_off += 1 << msz;
6121 } while (reg_off <= reg_last && (reg_off & 63));
6122 } while (reg_off <= reg_last);
6123
6124 clear_helper_retaddr();
6125
6126 /*
6127 * MemSingleNF is allowed to fail for any reason. We have special
6128 * code above to handle the first element crossing a page boundary.
6129 * As an implementation choice, decline to handle a cross-page element
6130 * in any other position.
6131 */
6132 reg_off = info.reg_off_split;
6133 if (reg_off >= 0) {
6134 goto do_fault;
6135 }
6136
6137 second_page:
6138 reg_off = info.reg_off_first[1];
6139 if (likely(reg_off < 0)) {
6140 /* No active elements on the second page. All done. */
6141 return;
6142 }
6143
6144 /*
6145 * MemSingleNF is allowed to fail for any reason. As an implementation
6146 * choice, decline to handle elements on the second page. This should
6147 * be low frequency as the guest walks through memory -- the next
6148 * iteration of the guest's loop should be aligned on the page boundary,
6149 * and then all following iterations will stay aligned.
6150 */
6151
6152 do_fault:
6153 record_fault(env, reg_off, reg_max);
6154 }
6155
6156 static inline QEMU_ALWAYS_INLINE
sve_ldnfff1_r_mte(CPUARMState * env,void * vg,target_ulong addr,uint32_t desc,const uintptr_t retaddr,const int esz,const int msz,const SVEContFault fault,sve_ldst1_host_fn * host_fn,sve_ldst1_tlb_fn * tlb_fn)6157 void sve_ldnfff1_r_mte(CPUARMState *env, void *vg, target_ulong addr,
6158 uint32_t desc, const uintptr_t retaddr,
6159 const int esz, const int msz, const SVEContFault fault,
6160 sve_ldst1_host_fn *host_fn,
6161 sve_ldst1_tlb_fn *tlb_fn)
6162 {
6163 uint32_t mtedesc = desc >> (SIMD_DATA_SHIFT + SVE_MTEDESC_SHIFT);
6164 int bit55 = extract64(addr, 55, 1);
6165
6166 /* Remove mtedesc from the normal sve descriptor. */
6167 desc = extract32(desc, 0, SIMD_DATA_SHIFT + SVE_MTEDESC_SHIFT);
6168
6169 /* Perform gross MTE suppression early. */
6170 if (!tbi_check(mtedesc, bit55) ||
6171 tcma_check(mtedesc, bit55, allocation_tag_from_addr(addr))) {
6172 mtedesc = 0;
6173 }
6174
6175 sve_ldnfff1_r(env, vg, addr, desc, retaddr, mtedesc,
6176 esz, msz, fault, host_fn, tlb_fn);
6177 }
6178
6179 #define DO_LDFF1_LDNF1_1(PART, ESZ) \
6180 void HELPER(sve_ldff1##PART##_r)(CPUARMState *env, void *vg, \
6181 target_ulong addr, uint32_t desc) \
6182 { \
6183 sve_ldnfff1_r(env, vg, addr, desc, GETPC(), 0, ESZ, MO_8, FAULT_FIRST, \
6184 sve_ld1##PART##_host, sve_ld1##PART##_tlb); \
6185 } \
6186 void HELPER(sve_ldnf1##PART##_r)(CPUARMState *env, void *vg, \
6187 target_ulong addr, uint32_t desc) \
6188 { \
6189 sve_ldnfff1_r(env, vg, addr, desc, GETPC(), 0, ESZ, MO_8, FAULT_NO, \
6190 sve_ld1##PART##_host, sve_ld1##PART##_tlb); \
6191 } \
6192 void HELPER(sve_ldff1##PART##_r_mte)(CPUARMState *env, void *vg, \
6193 target_ulong addr, uint32_t desc) \
6194 { \
6195 sve_ldnfff1_r_mte(env, vg, addr, desc, GETPC(), ESZ, MO_8, FAULT_FIRST, \
6196 sve_ld1##PART##_host, sve_ld1##PART##_tlb); \
6197 } \
6198 void HELPER(sve_ldnf1##PART##_r_mte)(CPUARMState *env, void *vg, \
6199 target_ulong addr, uint32_t desc) \
6200 { \
6201 sve_ldnfff1_r_mte(env, vg, addr, desc, GETPC(), ESZ, MO_8, FAULT_NO, \
6202 sve_ld1##PART##_host, sve_ld1##PART##_tlb); \
6203 }
6204
6205 #define DO_LDFF1_LDNF1_2(PART, ESZ, MSZ) \
6206 void HELPER(sve_ldff1##PART##_le_r)(CPUARMState *env, void *vg, \
6207 target_ulong addr, uint32_t desc) \
6208 { \
6209 sve_ldnfff1_r(env, vg, addr, desc, GETPC(), 0, ESZ, MSZ, FAULT_FIRST, \
6210 sve_ld1##PART##_le_host, sve_ld1##PART##_le_tlb); \
6211 } \
6212 void HELPER(sve_ldnf1##PART##_le_r)(CPUARMState *env, void *vg, \
6213 target_ulong addr, uint32_t desc) \
6214 { \
6215 sve_ldnfff1_r(env, vg, addr, desc, GETPC(), 0, ESZ, MSZ, FAULT_NO, \
6216 sve_ld1##PART##_le_host, sve_ld1##PART##_le_tlb); \
6217 } \
6218 void HELPER(sve_ldff1##PART##_be_r)(CPUARMState *env, void *vg, \
6219 target_ulong addr, uint32_t desc) \
6220 { \
6221 sve_ldnfff1_r(env, vg, addr, desc, GETPC(), 0, ESZ, MSZ, FAULT_FIRST, \
6222 sve_ld1##PART##_be_host, sve_ld1##PART##_be_tlb); \
6223 } \
6224 void HELPER(sve_ldnf1##PART##_be_r)(CPUARMState *env, void *vg, \
6225 target_ulong addr, uint32_t desc) \
6226 { \
6227 sve_ldnfff1_r(env, vg, addr, desc, GETPC(), 0, ESZ, MSZ, FAULT_NO, \
6228 sve_ld1##PART##_be_host, sve_ld1##PART##_be_tlb); \
6229 } \
6230 void HELPER(sve_ldff1##PART##_le_r_mte)(CPUARMState *env, void *vg, \
6231 target_ulong addr, uint32_t desc) \
6232 { \
6233 sve_ldnfff1_r_mte(env, vg, addr, desc, GETPC(), ESZ, MSZ, FAULT_FIRST, \
6234 sve_ld1##PART##_le_host, sve_ld1##PART##_le_tlb); \
6235 } \
6236 void HELPER(sve_ldnf1##PART##_le_r_mte)(CPUARMState *env, void *vg, \
6237 target_ulong addr, uint32_t desc) \
6238 { \
6239 sve_ldnfff1_r_mte(env, vg, addr, desc, GETPC(), ESZ, MSZ, FAULT_NO, \
6240 sve_ld1##PART##_le_host, sve_ld1##PART##_le_tlb); \
6241 } \
6242 void HELPER(sve_ldff1##PART##_be_r_mte)(CPUARMState *env, void *vg, \
6243 target_ulong addr, uint32_t desc) \
6244 { \
6245 sve_ldnfff1_r_mte(env, vg, addr, desc, GETPC(), ESZ, MSZ, FAULT_FIRST, \
6246 sve_ld1##PART##_be_host, sve_ld1##PART##_be_tlb); \
6247 } \
6248 void HELPER(sve_ldnf1##PART##_be_r_mte)(CPUARMState *env, void *vg, \
6249 target_ulong addr, uint32_t desc) \
6250 { \
6251 sve_ldnfff1_r_mte(env, vg, addr, desc, GETPC(), ESZ, MSZ, FAULT_NO, \
6252 sve_ld1##PART##_be_host, sve_ld1##PART##_be_tlb); \
6253 }
6254
DO_LDFF1_LDNF1_1(bb,MO_8)6255 DO_LDFF1_LDNF1_1(bb, MO_8)
6256 DO_LDFF1_LDNF1_1(bhu, MO_16)
6257 DO_LDFF1_LDNF1_1(bhs, MO_16)
6258 DO_LDFF1_LDNF1_1(bsu, MO_32)
6259 DO_LDFF1_LDNF1_1(bss, MO_32)
6260 DO_LDFF1_LDNF1_1(bdu, MO_64)
6261 DO_LDFF1_LDNF1_1(bds, MO_64)
6262
6263 DO_LDFF1_LDNF1_2(hh, MO_16, MO_16)
6264 DO_LDFF1_LDNF1_2(hsu, MO_32, MO_16)
6265 DO_LDFF1_LDNF1_2(hss, MO_32, MO_16)
6266 DO_LDFF1_LDNF1_2(hdu, MO_64, MO_16)
6267 DO_LDFF1_LDNF1_2(hds, MO_64, MO_16)
6268
6269 DO_LDFF1_LDNF1_2(ss, MO_32, MO_32)
6270 DO_LDFF1_LDNF1_2(sdu, MO_64, MO_32)
6271 DO_LDFF1_LDNF1_2(sds, MO_64, MO_32)
6272
6273 DO_LDFF1_LDNF1_2(dd, MO_64, MO_64)
6274
6275 #undef DO_LDFF1_LDNF1_1
6276 #undef DO_LDFF1_LDNF1_2
6277
6278 /*
6279 * Common helper for all contiguous 1,2,3,4-register predicated stores.
6280 */
6281
6282 static inline QEMU_ALWAYS_INLINE
6283 void sve_stN_r(CPUARMState *env, uint64_t *vg, target_ulong addr,
6284 uint32_t desc, const uintptr_t retaddr,
6285 const int esz, const int msz, const int N, uint32_t mtedesc,
6286 sve_ldst1_host_fn *host_fn,
6287 sve_ldst1_tlb_fn *tlb_fn)
6288 {
6289 const unsigned rd = simd_data(desc);
6290 const intptr_t reg_max = simd_oprsz(desc);
6291 intptr_t reg_off, reg_last, mem_off;
6292 SVEContLdSt info;
6293 void *host;
6294 int i, flags;
6295
6296 /* Find the active elements. */
6297 if (!sve_cont_ldst_elements(&info, addr, vg, reg_max, esz, N << msz)) {
6298 /* The entire predicate was false; no store occurs. */
6299 return;
6300 }
6301
6302 /* Probe the page(s). Exit with exception for any invalid page. */
6303 sve_cont_ldst_pages(&info, FAULT_ALL, env, addr, MMU_DATA_STORE, retaddr);
6304
6305 /* Handle watchpoints for all active elements. */
6306 sve_cont_ldst_watchpoints(&info, env, vg, addr, 1 << esz, N << msz,
6307 BP_MEM_WRITE, retaddr);
6308
6309 /*
6310 * Handle mte checks for all active elements.
6311 * Since TBI must be set for MTE, !mtedesc => !mte_active.
6312 */
6313 if (mtedesc) {
6314 sve_cont_ldst_mte_check(&info, env, vg, addr, 1 << esz, N << msz,
6315 mtedesc, retaddr);
6316 }
6317
6318 flags = info.page[0].flags | info.page[1].flags;
6319 if (unlikely(flags != 0)) {
6320 #ifdef CONFIG_USER_ONLY
6321 g_assert_not_reached();
6322 #else
6323 /*
6324 * At least one page includes MMIO.
6325 * Any bus operation can fail with cpu_transaction_failed,
6326 * which for ARM will raise SyncExternal. We cannot avoid
6327 * this fault and will leave with the store incomplete.
6328 */
6329 mem_off = info.mem_off_first[0];
6330 reg_off = info.reg_off_first[0];
6331 reg_last = info.reg_off_last[1];
6332 if (reg_last < 0) {
6333 reg_last = info.reg_off_split;
6334 if (reg_last < 0) {
6335 reg_last = info.reg_off_last[0];
6336 }
6337 }
6338
6339 do {
6340 uint64_t pg = vg[reg_off >> 6];
6341 do {
6342 if ((pg >> (reg_off & 63)) & 1) {
6343 for (i = 0; i < N; ++i) {
6344 tlb_fn(env, &env->vfp.zregs[(rd + i) & 31], reg_off,
6345 addr + mem_off + (i << msz), retaddr);
6346 }
6347 }
6348 reg_off += 1 << esz;
6349 mem_off += N << msz;
6350 } while (reg_off & 63);
6351 } while (reg_off <= reg_last);
6352 return;
6353 #endif
6354 }
6355
6356 mem_off = info.mem_off_first[0];
6357 reg_off = info.reg_off_first[0];
6358 reg_last = info.reg_off_last[0];
6359 host = info.page[0].host;
6360
6361 set_helper_retaddr(retaddr);
6362
6363 while (reg_off <= reg_last) {
6364 uint64_t pg = vg[reg_off >> 6];
6365 do {
6366 if ((pg >> (reg_off & 63)) & 1) {
6367 for (i = 0; i < N; ++i) {
6368 host_fn(&env->vfp.zregs[(rd + i) & 31], reg_off,
6369 host + mem_off + (i << msz));
6370 }
6371 }
6372 reg_off += 1 << esz;
6373 mem_off += N << msz;
6374 } while (reg_off <= reg_last && (reg_off & 63));
6375 }
6376
6377 clear_helper_retaddr();
6378
6379 /*
6380 * Use the slow path to manage the cross-page misalignment.
6381 * But we know this is RAM and cannot trap.
6382 */
6383 mem_off = info.mem_off_split;
6384 if (unlikely(mem_off >= 0)) {
6385 reg_off = info.reg_off_split;
6386 for (i = 0; i < N; ++i) {
6387 tlb_fn(env, &env->vfp.zregs[(rd + i) & 31], reg_off,
6388 addr + mem_off + (i << msz), retaddr);
6389 }
6390 }
6391
6392 mem_off = info.mem_off_first[1];
6393 if (unlikely(mem_off >= 0)) {
6394 reg_off = info.reg_off_first[1];
6395 reg_last = info.reg_off_last[1];
6396 host = info.page[1].host;
6397
6398 set_helper_retaddr(retaddr);
6399
6400 do {
6401 uint64_t pg = vg[reg_off >> 6];
6402 do {
6403 if ((pg >> (reg_off & 63)) & 1) {
6404 for (i = 0; i < N; ++i) {
6405 host_fn(&env->vfp.zregs[(rd + i) & 31], reg_off,
6406 host + mem_off + (i << msz));
6407 }
6408 }
6409 reg_off += 1 << esz;
6410 mem_off += N << msz;
6411 } while (reg_off & 63);
6412 } while (reg_off <= reg_last);
6413
6414 clear_helper_retaddr();
6415 }
6416 }
6417
6418 static inline QEMU_ALWAYS_INLINE
sve_stN_r_mte(CPUARMState * env,uint64_t * vg,target_ulong addr,uint32_t desc,const uintptr_t ra,const int esz,const int msz,const int N,sve_ldst1_host_fn * host_fn,sve_ldst1_tlb_fn * tlb_fn)6419 void sve_stN_r_mte(CPUARMState *env, uint64_t *vg, target_ulong addr,
6420 uint32_t desc, const uintptr_t ra,
6421 const int esz, const int msz, const int N,
6422 sve_ldst1_host_fn *host_fn,
6423 sve_ldst1_tlb_fn *tlb_fn)
6424 {
6425 uint32_t mtedesc = desc >> (SIMD_DATA_SHIFT + SVE_MTEDESC_SHIFT);
6426 int bit55 = extract64(addr, 55, 1);
6427
6428 /* Remove mtedesc from the normal sve descriptor. */
6429 desc = extract32(desc, 0, SIMD_DATA_SHIFT + SVE_MTEDESC_SHIFT);
6430
6431 /* Perform gross MTE suppression early. */
6432 if (!tbi_check(mtedesc, bit55) ||
6433 tcma_check(mtedesc, bit55, allocation_tag_from_addr(addr))) {
6434 mtedesc = 0;
6435 }
6436
6437 sve_stN_r(env, vg, addr, desc, ra, esz, msz, N, mtedesc, host_fn, tlb_fn);
6438 }
6439
6440 #define DO_STN_1(N, NAME, ESZ) \
6441 void HELPER(sve_st##N##NAME##_r)(CPUARMState *env, void *vg, \
6442 target_ulong addr, uint32_t desc) \
6443 { \
6444 sve_stN_r(env, vg, addr, desc, GETPC(), ESZ, MO_8, N, 0, \
6445 sve_st1##NAME##_host, sve_st1##NAME##_tlb); \
6446 } \
6447 void HELPER(sve_st##N##NAME##_r_mte)(CPUARMState *env, void *vg, \
6448 target_ulong addr, uint32_t desc) \
6449 { \
6450 sve_stN_r_mte(env, vg, addr, desc, GETPC(), ESZ, MO_8, N, \
6451 sve_st1##NAME##_host, sve_st1##NAME##_tlb); \
6452 }
6453
6454 #define DO_STN_2(N, NAME, ESZ, MSZ) \
6455 void HELPER(sve_st##N##NAME##_le_r)(CPUARMState *env, void *vg, \
6456 target_ulong addr, uint32_t desc) \
6457 { \
6458 sve_stN_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, N, 0, \
6459 sve_st1##NAME##_le_host, sve_st1##NAME##_le_tlb); \
6460 } \
6461 void HELPER(sve_st##N##NAME##_be_r)(CPUARMState *env, void *vg, \
6462 target_ulong addr, uint32_t desc) \
6463 { \
6464 sve_stN_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, N, 0, \
6465 sve_st1##NAME##_be_host, sve_st1##NAME##_be_tlb); \
6466 } \
6467 void HELPER(sve_st##N##NAME##_le_r_mte)(CPUARMState *env, void *vg, \
6468 target_ulong addr, uint32_t desc) \
6469 { \
6470 sve_stN_r_mte(env, vg, addr, desc, GETPC(), ESZ, MSZ, N, \
6471 sve_st1##NAME##_le_host, sve_st1##NAME##_le_tlb); \
6472 } \
6473 void HELPER(sve_st##N##NAME##_be_r_mte)(CPUARMState *env, void *vg, \
6474 target_ulong addr, uint32_t desc) \
6475 { \
6476 sve_stN_r_mte(env, vg, addr, desc, GETPC(), ESZ, MSZ, N, \
6477 sve_st1##NAME##_be_host, sve_st1##NAME##_be_tlb); \
6478 }
6479
6480 DO_STN_1(1, bb, MO_8)
6481 DO_STN_1(1, bh, MO_16)
6482 DO_STN_1(1, bs, MO_32)
6483 DO_STN_1(1, bd, MO_64)
6484 DO_STN_1(2, bb, MO_8)
6485 DO_STN_1(3, bb, MO_8)
6486 DO_STN_1(4, bb, MO_8)
6487
6488 DO_STN_2(1, hh, MO_16, MO_16)
6489 DO_STN_2(1, hs, MO_32, MO_16)
6490 DO_STN_2(1, hd, MO_64, MO_16)
6491 DO_STN_2(2, hh, MO_16, MO_16)
6492 DO_STN_2(3, hh, MO_16, MO_16)
6493 DO_STN_2(4, hh, MO_16, MO_16)
6494
6495 DO_STN_2(1, ss, MO_32, MO_32)
6496 DO_STN_2(1, sd, MO_64, MO_32)
6497 DO_STN_2(2, ss, MO_32, MO_32)
6498 DO_STN_2(3, ss, MO_32, MO_32)
6499 DO_STN_2(4, ss, MO_32, MO_32)
6500
6501 DO_STN_2(1, dd, MO_64, MO_64)
6502 DO_STN_2(2, dd, MO_64, MO_64)
6503 DO_STN_2(3, dd, MO_64, MO_64)
6504 DO_STN_2(4, dd, MO_64, MO_64)
6505
6506 #undef DO_STN_1
6507 #undef DO_STN_2
6508
6509 /*
6510 * Loads with a vector index.
6511 */
6512
6513 /*
6514 * Load the element at @reg + @reg_ofs, sign or zero-extend as needed.
6515 */
6516 typedef target_ulong zreg_off_fn(void *reg, intptr_t reg_ofs);
6517
off_zsu_s(void * reg,intptr_t reg_ofs)6518 static target_ulong off_zsu_s(void *reg, intptr_t reg_ofs)
6519 {
6520 return *(uint32_t *)(reg + H1_4(reg_ofs));
6521 }
6522
off_zss_s(void * reg,intptr_t reg_ofs)6523 static target_ulong off_zss_s(void *reg, intptr_t reg_ofs)
6524 {
6525 return *(int32_t *)(reg + H1_4(reg_ofs));
6526 }
6527
off_zsu_d(void * reg,intptr_t reg_ofs)6528 static target_ulong off_zsu_d(void *reg, intptr_t reg_ofs)
6529 {
6530 return (uint32_t)*(uint64_t *)(reg + reg_ofs);
6531 }
6532
off_zss_d(void * reg,intptr_t reg_ofs)6533 static target_ulong off_zss_d(void *reg, intptr_t reg_ofs)
6534 {
6535 return (int32_t)*(uint64_t *)(reg + reg_ofs);
6536 }
6537
off_zd_d(void * reg,intptr_t reg_ofs)6538 static target_ulong off_zd_d(void *reg, intptr_t reg_ofs)
6539 {
6540 return *(uint64_t *)(reg + reg_ofs);
6541 }
6542
6543 static inline QEMU_ALWAYS_INLINE
sve_ld1_z(CPUARMState * env,void * vd,uint64_t * vg,void * vm,target_ulong base,uint32_t desc,uintptr_t retaddr,uint32_t mtedesc,int esize,int msize,zreg_off_fn * off_fn,sve_ldst1_host_fn * host_fn,sve_ldst1_tlb_fn * tlb_fn)6544 void sve_ld1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm,
6545 target_ulong base, uint32_t desc, uintptr_t retaddr,
6546 uint32_t mtedesc, int esize, int msize,
6547 zreg_off_fn *off_fn,
6548 sve_ldst1_host_fn *host_fn,
6549 sve_ldst1_tlb_fn *tlb_fn)
6550 {
6551 const int mmu_idx = arm_env_mmu_index(env);
6552 const intptr_t reg_max = simd_oprsz(desc);
6553 const int scale = simd_data(desc);
6554 ARMVectorReg scratch;
6555 intptr_t reg_off;
6556 SVEHostPage info, info2;
6557
6558 memset(&scratch, 0, reg_max);
6559 reg_off = 0;
6560 do {
6561 uint64_t pg = vg[reg_off >> 6];
6562 do {
6563 if (likely(pg & 1)) {
6564 target_ulong addr = base + (off_fn(vm, reg_off) << scale);
6565 target_ulong in_page = -(addr | TARGET_PAGE_MASK);
6566
6567 sve_probe_page(&info, false, env, addr, 0, MMU_DATA_LOAD,
6568 mmu_idx, retaddr);
6569
6570 if (likely(in_page >= msize)) {
6571 if (unlikely(info.flags & TLB_WATCHPOINT)) {
6572 cpu_check_watchpoint(env_cpu(env), addr, msize,
6573 info.attrs, BP_MEM_READ, retaddr);
6574 }
6575 if (mtedesc && info.tagged) {
6576 mte_check(env, mtedesc, addr, retaddr);
6577 }
6578 if (unlikely(info.flags & TLB_MMIO)) {
6579 tlb_fn(env, &scratch, reg_off, addr, retaddr);
6580 } else {
6581 set_helper_retaddr(retaddr);
6582 host_fn(&scratch, reg_off, info.host);
6583 clear_helper_retaddr();
6584 }
6585 } else {
6586 /* Element crosses the page boundary. */
6587 sve_probe_page(&info2, false, env, addr + in_page, 0,
6588 MMU_DATA_LOAD, mmu_idx, retaddr);
6589 if (unlikely((info.flags | info2.flags) & TLB_WATCHPOINT)) {
6590 cpu_check_watchpoint(env_cpu(env), addr,
6591 msize, info.attrs,
6592 BP_MEM_READ, retaddr);
6593 }
6594 if (mtedesc && info.tagged) {
6595 mte_check(env, mtedesc, addr, retaddr);
6596 }
6597 tlb_fn(env, &scratch, reg_off, addr, retaddr);
6598 }
6599 }
6600 reg_off += esize;
6601 pg >>= esize;
6602 } while (reg_off & 63);
6603 } while (reg_off < reg_max);
6604
6605 /* Wait until all exceptions have been raised to write back. */
6606 memcpy(vd, &scratch, reg_max);
6607 }
6608
6609 static inline QEMU_ALWAYS_INLINE
sve_ld1_z_mte(CPUARMState * env,void * vd,uint64_t * vg,void * vm,target_ulong base,uint32_t desc,uintptr_t retaddr,int esize,int msize,zreg_off_fn * off_fn,sve_ldst1_host_fn * host_fn,sve_ldst1_tlb_fn * tlb_fn)6610 void sve_ld1_z_mte(CPUARMState *env, void *vd, uint64_t *vg, void *vm,
6611 target_ulong base, uint32_t desc, uintptr_t retaddr,
6612 int esize, int msize, zreg_off_fn *off_fn,
6613 sve_ldst1_host_fn *host_fn,
6614 sve_ldst1_tlb_fn *tlb_fn)
6615 {
6616 uint32_t mtedesc = desc >> (SIMD_DATA_SHIFT + SVE_MTEDESC_SHIFT);
6617 /* Remove mtedesc from the normal sve descriptor. */
6618 desc = extract32(desc, 0, SIMD_DATA_SHIFT + SVE_MTEDESC_SHIFT);
6619
6620 /*
6621 * ??? TODO: For the 32-bit offset extractions, base + ofs cannot
6622 * offset base entirely over the address space hole to change the
6623 * pointer tag, or change the bit55 selector. So we could here
6624 * examine TBI + TCMA like we do for sve_ldN_r_mte().
6625 */
6626 sve_ld1_z(env, vd, vg, vm, base, desc, retaddr, mtedesc,
6627 esize, msize, off_fn, host_fn, tlb_fn);
6628 }
6629
6630 #define DO_LD1_ZPZ_S(MEM, OFS, MSZ) \
6631 void HELPER(sve_ld##MEM##_##OFS)(CPUARMState *env, void *vd, void *vg, \
6632 void *vm, target_ulong base, uint32_t desc) \
6633 { \
6634 sve_ld1_z(env, vd, vg, vm, base, desc, GETPC(), 0, 4, 1 << MSZ, \
6635 off_##OFS##_s, sve_ld1##MEM##_host, sve_ld1##MEM##_tlb); \
6636 } \
6637 void HELPER(sve_ld##MEM##_##OFS##_mte)(CPUARMState *env, void *vd, void *vg, \
6638 void *vm, target_ulong base, uint32_t desc) \
6639 { \
6640 sve_ld1_z_mte(env, vd, vg, vm, base, desc, GETPC(), 4, 1 << MSZ, \
6641 off_##OFS##_s, sve_ld1##MEM##_host, sve_ld1##MEM##_tlb); \
6642 }
6643
6644 #define DO_LD1_ZPZ_D(MEM, OFS, MSZ) \
6645 void HELPER(sve_ld##MEM##_##OFS)(CPUARMState *env, void *vd, void *vg, \
6646 void *vm, target_ulong base, uint32_t desc) \
6647 { \
6648 sve_ld1_z(env, vd, vg, vm, base, desc, GETPC(), 0, 8, 1 << MSZ, \
6649 off_##OFS##_d, sve_ld1##MEM##_host, sve_ld1##MEM##_tlb); \
6650 } \
6651 void HELPER(sve_ld##MEM##_##OFS##_mte)(CPUARMState *env, void *vd, void *vg, \
6652 void *vm, target_ulong base, uint32_t desc) \
6653 { \
6654 sve_ld1_z_mte(env, vd, vg, vm, base, desc, GETPC(), 8, 1 << MSZ, \
6655 off_##OFS##_d, sve_ld1##MEM##_host, sve_ld1##MEM##_tlb); \
6656 }
6657
DO_LD1_ZPZ_S(bsu,zsu,MO_8)6658 DO_LD1_ZPZ_S(bsu, zsu, MO_8)
6659 DO_LD1_ZPZ_S(bsu, zss, MO_8)
6660 DO_LD1_ZPZ_D(bdu, zsu, MO_8)
6661 DO_LD1_ZPZ_D(bdu, zss, MO_8)
6662 DO_LD1_ZPZ_D(bdu, zd, MO_8)
6663
6664 DO_LD1_ZPZ_S(bss, zsu, MO_8)
6665 DO_LD1_ZPZ_S(bss, zss, MO_8)
6666 DO_LD1_ZPZ_D(bds, zsu, MO_8)
6667 DO_LD1_ZPZ_D(bds, zss, MO_8)
6668 DO_LD1_ZPZ_D(bds, zd, MO_8)
6669
6670 DO_LD1_ZPZ_S(hsu_le, zsu, MO_16)
6671 DO_LD1_ZPZ_S(hsu_le, zss, MO_16)
6672 DO_LD1_ZPZ_D(hdu_le, zsu, MO_16)
6673 DO_LD1_ZPZ_D(hdu_le, zss, MO_16)
6674 DO_LD1_ZPZ_D(hdu_le, zd, MO_16)
6675
6676 DO_LD1_ZPZ_S(hsu_be, zsu, MO_16)
6677 DO_LD1_ZPZ_S(hsu_be, zss, MO_16)
6678 DO_LD1_ZPZ_D(hdu_be, zsu, MO_16)
6679 DO_LD1_ZPZ_D(hdu_be, zss, MO_16)
6680 DO_LD1_ZPZ_D(hdu_be, zd, MO_16)
6681
6682 DO_LD1_ZPZ_S(hss_le, zsu, MO_16)
6683 DO_LD1_ZPZ_S(hss_le, zss, MO_16)
6684 DO_LD1_ZPZ_D(hds_le, zsu, MO_16)
6685 DO_LD1_ZPZ_D(hds_le, zss, MO_16)
6686 DO_LD1_ZPZ_D(hds_le, zd, MO_16)
6687
6688 DO_LD1_ZPZ_S(hss_be, zsu, MO_16)
6689 DO_LD1_ZPZ_S(hss_be, zss, MO_16)
6690 DO_LD1_ZPZ_D(hds_be, zsu, MO_16)
6691 DO_LD1_ZPZ_D(hds_be, zss, MO_16)
6692 DO_LD1_ZPZ_D(hds_be, zd, MO_16)
6693
6694 DO_LD1_ZPZ_S(ss_le, zsu, MO_32)
6695 DO_LD1_ZPZ_S(ss_le, zss, MO_32)
6696 DO_LD1_ZPZ_D(sdu_le, zsu, MO_32)
6697 DO_LD1_ZPZ_D(sdu_le, zss, MO_32)
6698 DO_LD1_ZPZ_D(sdu_le, zd, MO_32)
6699
6700 DO_LD1_ZPZ_S(ss_be, zsu, MO_32)
6701 DO_LD1_ZPZ_S(ss_be, zss, MO_32)
6702 DO_LD1_ZPZ_D(sdu_be, zsu, MO_32)
6703 DO_LD1_ZPZ_D(sdu_be, zss, MO_32)
6704 DO_LD1_ZPZ_D(sdu_be, zd, MO_32)
6705
6706 DO_LD1_ZPZ_D(sds_le, zsu, MO_32)
6707 DO_LD1_ZPZ_D(sds_le, zss, MO_32)
6708 DO_LD1_ZPZ_D(sds_le, zd, MO_32)
6709
6710 DO_LD1_ZPZ_D(sds_be, zsu, MO_32)
6711 DO_LD1_ZPZ_D(sds_be, zss, MO_32)
6712 DO_LD1_ZPZ_D(sds_be, zd, MO_32)
6713
6714 DO_LD1_ZPZ_D(dd_le, zsu, MO_64)
6715 DO_LD1_ZPZ_D(dd_le, zss, MO_64)
6716 DO_LD1_ZPZ_D(dd_le, zd, MO_64)
6717
6718 DO_LD1_ZPZ_D(dd_be, zsu, MO_64)
6719 DO_LD1_ZPZ_D(dd_be, zss, MO_64)
6720 DO_LD1_ZPZ_D(dd_be, zd, MO_64)
6721
6722 #undef DO_LD1_ZPZ_S
6723 #undef DO_LD1_ZPZ_D
6724
6725 /* First fault loads with a vector index. */
6726
6727 /*
6728 * Common helpers for all gather first-faulting loads.
6729 */
6730
6731 static inline QEMU_ALWAYS_INLINE
6732 void sve_ldff1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm,
6733 target_ulong base, uint32_t desc, uintptr_t retaddr,
6734 uint32_t mtedesc, const int esz, const int msz,
6735 zreg_off_fn *off_fn,
6736 sve_ldst1_host_fn *host_fn,
6737 sve_ldst1_tlb_fn *tlb_fn)
6738 {
6739 const int mmu_idx = arm_env_mmu_index(env);
6740 const intptr_t reg_max = simd_oprsz(desc);
6741 const int scale = simd_data(desc);
6742 const int esize = 1 << esz;
6743 const int msize = 1 << msz;
6744 intptr_t reg_off;
6745 SVEHostPage info;
6746 target_ulong addr, in_page;
6747 ARMVectorReg scratch;
6748
6749 /* Skip to the first true predicate. */
6750 reg_off = find_next_active(vg, 0, reg_max, esz);
6751 if (unlikely(reg_off >= reg_max)) {
6752 /* The entire predicate was false; no load occurs. */
6753 memset(vd, 0, reg_max);
6754 return;
6755 }
6756
6757 /* Protect against overlap between vd and vm. */
6758 if (unlikely(vd == vm)) {
6759 vm = memcpy(&scratch, vm, reg_max);
6760 }
6761
6762 /*
6763 * Probe the first element, allowing faults.
6764 */
6765 addr = base + (off_fn(vm, reg_off) << scale);
6766 if (mtedesc) {
6767 mte_check(env, mtedesc, addr, retaddr);
6768 }
6769 tlb_fn(env, vd, reg_off, addr, retaddr);
6770
6771 /* After any fault, zero the other elements. */
6772 swap_memzero(vd, reg_off);
6773 reg_off += esize;
6774 swap_memzero(vd + reg_off, reg_max - reg_off);
6775
6776 /*
6777 * Probe the remaining elements, not allowing faults.
6778 */
6779 while (reg_off < reg_max) {
6780 uint64_t pg = vg[reg_off >> 6];
6781 do {
6782 if (likely((pg >> (reg_off & 63)) & 1)) {
6783 addr = base + (off_fn(vm, reg_off) << scale);
6784 in_page = -(addr | TARGET_PAGE_MASK);
6785
6786 if (unlikely(in_page < msize)) {
6787 /* Stop if the element crosses a page boundary. */
6788 goto fault;
6789 }
6790
6791 sve_probe_page(&info, true, env, addr, 0, MMU_DATA_LOAD,
6792 mmu_idx, retaddr);
6793 if (unlikely(info.flags & (TLB_INVALID_MASK | TLB_MMIO))) {
6794 goto fault;
6795 }
6796 if (unlikely(info.flags & TLB_WATCHPOINT) &&
6797 (cpu_watchpoint_address_matches
6798 (env_cpu(env), addr, msize) & BP_MEM_READ)) {
6799 goto fault;
6800 }
6801 if (mtedesc && info.tagged && !mte_probe(env, mtedesc, addr)) {
6802 goto fault;
6803 }
6804
6805 set_helper_retaddr(retaddr);
6806 host_fn(vd, reg_off, info.host);
6807 clear_helper_retaddr();
6808 }
6809 reg_off += esize;
6810 } while (reg_off & 63);
6811 }
6812 return;
6813
6814 fault:
6815 record_fault(env, reg_off, reg_max);
6816 }
6817
6818 static inline QEMU_ALWAYS_INLINE
sve_ldff1_z_mte(CPUARMState * env,void * vd,uint64_t * vg,void * vm,target_ulong base,uint32_t desc,uintptr_t retaddr,const int esz,const int msz,zreg_off_fn * off_fn,sve_ldst1_host_fn * host_fn,sve_ldst1_tlb_fn * tlb_fn)6819 void sve_ldff1_z_mte(CPUARMState *env, void *vd, uint64_t *vg, void *vm,
6820 target_ulong base, uint32_t desc, uintptr_t retaddr,
6821 const int esz, const int msz,
6822 zreg_off_fn *off_fn,
6823 sve_ldst1_host_fn *host_fn,
6824 sve_ldst1_tlb_fn *tlb_fn)
6825 {
6826 uint32_t mtedesc = desc >> (SIMD_DATA_SHIFT + SVE_MTEDESC_SHIFT);
6827 /* Remove mtedesc from the normal sve descriptor. */
6828 desc = extract32(desc, 0, SIMD_DATA_SHIFT + SVE_MTEDESC_SHIFT);
6829
6830 /*
6831 * ??? TODO: For the 32-bit offset extractions, base + ofs cannot
6832 * offset base entirely over the address space hole to change the
6833 * pointer tag, or change the bit55 selector. So we could here
6834 * examine TBI + TCMA like we do for sve_ldN_r_mte().
6835 */
6836 sve_ldff1_z(env, vd, vg, vm, base, desc, retaddr, mtedesc,
6837 esz, msz, off_fn, host_fn, tlb_fn);
6838 }
6839
6840 #define DO_LDFF1_ZPZ_S(MEM, OFS, MSZ) \
6841 void HELPER(sve_ldff##MEM##_##OFS) \
6842 (CPUARMState *env, void *vd, void *vg, \
6843 void *vm, target_ulong base, uint32_t desc) \
6844 { \
6845 sve_ldff1_z(env, vd, vg, vm, base, desc, GETPC(), 0, MO_32, MSZ, \
6846 off_##OFS##_s, sve_ld1##MEM##_host, sve_ld1##MEM##_tlb); \
6847 } \
6848 void HELPER(sve_ldff##MEM##_##OFS##_mte) \
6849 (CPUARMState *env, void *vd, void *vg, \
6850 void *vm, target_ulong base, uint32_t desc) \
6851 { \
6852 sve_ldff1_z_mte(env, vd, vg, vm, base, desc, GETPC(), MO_32, MSZ, \
6853 off_##OFS##_s, sve_ld1##MEM##_host, sve_ld1##MEM##_tlb); \
6854 }
6855
6856 #define DO_LDFF1_ZPZ_D(MEM, OFS, MSZ) \
6857 void HELPER(sve_ldff##MEM##_##OFS) \
6858 (CPUARMState *env, void *vd, void *vg, \
6859 void *vm, target_ulong base, uint32_t desc) \
6860 { \
6861 sve_ldff1_z(env, vd, vg, vm, base, desc, GETPC(), 0, MO_64, MSZ, \
6862 off_##OFS##_d, sve_ld1##MEM##_host, sve_ld1##MEM##_tlb); \
6863 } \
6864 void HELPER(sve_ldff##MEM##_##OFS##_mte) \
6865 (CPUARMState *env, void *vd, void *vg, \
6866 void *vm, target_ulong base, uint32_t desc) \
6867 { \
6868 sve_ldff1_z_mte(env, vd, vg, vm, base, desc, GETPC(), MO_64, MSZ, \
6869 off_##OFS##_d, sve_ld1##MEM##_host, sve_ld1##MEM##_tlb); \
6870 }
6871
DO_LDFF1_ZPZ_S(bsu,zsu,MO_8)6872 DO_LDFF1_ZPZ_S(bsu, zsu, MO_8)
6873 DO_LDFF1_ZPZ_S(bsu, zss, MO_8)
6874 DO_LDFF1_ZPZ_D(bdu, zsu, MO_8)
6875 DO_LDFF1_ZPZ_D(bdu, zss, MO_8)
6876 DO_LDFF1_ZPZ_D(bdu, zd, MO_8)
6877
6878 DO_LDFF1_ZPZ_S(bss, zsu, MO_8)
6879 DO_LDFF1_ZPZ_S(bss, zss, MO_8)
6880 DO_LDFF1_ZPZ_D(bds, zsu, MO_8)
6881 DO_LDFF1_ZPZ_D(bds, zss, MO_8)
6882 DO_LDFF1_ZPZ_D(bds, zd, MO_8)
6883
6884 DO_LDFF1_ZPZ_S(hsu_le, zsu, MO_16)
6885 DO_LDFF1_ZPZ_S(hsu_le, zss, MO_16)
6886 DO_LDFF1_ZPZ_D(hdu_le, zsu, MO_16)
6887 DO_LDFF1_ZPZ_D(hdu_le, zss, MO_16)
6888 DO_LDFF1_ZPZ_D(hdu_le, zd, MO_16)
6889
6890 DO_LDFF1_ZPZ_S(hsu_be, zsu, MO_16)
6891 DO_LDFF1_ZPZ_S(hsu_be, zss, MO_16)
6892 DO_LDFF1_ZPZ_D(hdu_be, zsu, MO_16)
6893 DO_LDFF1_ZPZ_D(hdu_be, zss, MO_16)
6894 DO_LDFF1_ZPZ_D(hdu_be, zd, MO_16)
6895
6896 DO_LDFF1_ZPZ_S(hss_le, zsu, MO_16)
6897 DO_LDFF1_ZPZ_S(hss_le, zss, MO_16)
6898 DO_LDFF1_ZPZ_D(hds_le, zsu, MO_16)
6899 DO_LDFF1_ZPZ_D(hds_le, zss, MO_16)
6900 DO_LDFF1_ZPZ_D(hds_le, zd, MO_16)
6901
6902 DO_LDFF1_ZPZ_S(hss_be, zsu, MO_16)
6903 DO_LDFF1_ZPZ_S(hss_be, zss, MO_16)
6904 DO_LDFF1_ZPZ_D(hds_be, zsu, MO_16)
6905 DO_LDFF1_ZPZ_D(hds_be, zss, MO_16)
6906 DO_LDFF1_ZPZ_D(hds_be, zd, MO_16)
6907
6908 DO_LDFF1_ZPZ_S(ss_le, zsu, MO_32)
6909 DO_LDFF1_ZPZ_S(ss_le, zss, MO_32)
6910 DO_LDFF1_ZPZ_D(sdu_le, zsu, MO_32)
6911 DO_LDFF1_ZPZ_D(sdu_le, zss, MO_32)
6912 DO_LDFF1_ZPZ_D(sdu_le, zd, MO_32)
6913
6914 DO_LDFF1_ZPZ_S(ss_be, zsu, MO_32)
6915 DO_LDFF1_ZPZ_S(ss_be, zss, MO_32)
6916 DO_LDFF1_ZPZ_D(sdu_be, zsu, MO_32)
6917 DO_LDFF1_ZPZ_D(sdu_be, zss, MO_32)
6918 DO_LDFF1_ZPZ_D(sdu_be, zd, MO_32)
6919
6920 DO_LDFF1_ZPZ_D(sds_le, zsu, MO_32)
6921 DO_LDFF1_ZPZ_D(sds_le, zss, MO_32)
6922 DO_LDFF1_ZPZ_D(sds_le, zd, MO_32)
6923
6924 DO_LDFF1_ZPZ_D(sds_be, zsu, MO_32)
6925 DO_LDFF1_ZPZ_D(sds_be, zss, MO_32)
6926 DO_LDFF1_ZPZ_D(sds_be, zd, MO_32)
6927
6928 DO_LDFF1_ZPZ_D(dd_le, zsu, MO_64)
6929 DO_LDFF1_ZPZ_D(dd_le, zss, MO_64)
6930 DO_LDFF1_ZPZ_D(dd_le, zd, MO_64)
6931
6932 DO_LDFF1_ZPZ_D(dd_be, zsu, MO_64)
6933 DO_LDFF1_ZPZ_D(dd_be, zss, MO_64)
6934 DO_LDFF1_ZPZ_D(dd_be, zd, MO_64)
6935
6936 /* Stores with a vector index. */
6937
6938 static inline QEMU_ALWAYS_INLINE
6939 void sve_st1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm,
6940 target_ulong base, uint32_t desc, uintptr_t retaddr,
6941 uint32_t mtedesc, int esize, int msize,
6942 zreg_off_fn *off_fn,
6943 sve_ldst1_host_fn *host_fn,
6944 sve_ldst1_tlb_fn *tlb_fn)
6945 {
6946 const int mmu_idx = arm_env_mmu_index(env);
6947 const intptr_t reg_max = simd_oprsz(desc);
6948 const int scale = simd_data(desc);
6949 void *host[ARM_MAX_VQ * 4];
6950 intptr_t reg_off, i;
6951 SVEHostPage info, info2;
6952
6953 /*
6954 * Probe all of the elements for host addresses and flags.
6955 */
6956 i = reg_off = 0;
6957 do {
6958 uint64_t pg = vg[reg_off >> 6];
6959 do {
6960 target_ulong addr = base + (off_fn(vm, reg_off) << scale);
6961 target_ulong in_page = -(addr | TARGET_PAGE_MASK);
6962
6963 host[i] = NULL;
6964 if (likely((pg >> (reg_off & 63)) & 1)) {
6965 if (likely(in_page >= msize)) {
6966 sve_probe_page(&info, false, env, addr, 0, MMU_DATA_STORE,
6967 mmu_idx, retaddr);
6968 if (!(info.flags & TLB_MMIO)) {
6969 host[i] = info.host;
6970 }
6971 } else {
6972 /*
6973 * Element crosses the page boundary.
6974 * Probe both pages, but do not record the host address,
6975 * so that we use the slow path.
6976 */
6977 sve_probe_page(&info, false, env, addr, 0,
6978 MMU_DATA_STORE, mmu_idx, retaddr);
6979 sve_probe_page(&info2, false, env, addr + in_page, 0,
6980 MMU_DATA_STORE, mmu_idx, retaddr);
6981 info.flags |= info2.flags;
6982 }
6983
6984 if (unlikely(info.flags & TLB_WATCHPOINT)) {
6985 cpu_check_watchpoint(env_cpu(env), addr, msize,
6986 info.attrs, BP_MEM_WRITE, retaddr);
6987 }
6988
6989 if (mtedesc && info.tagged) {
6990 mte_check(env, mtedesc, addr, retaddr);
6991 }
6992 }
6993 i += 1;
6994 reg_off += esize;
6995 } while (reg_off & 63);
6996 } while (reg_off < reg_max);
6997
6998 /*
6999 * Now that we have recognized all exceptions except SyncExternal
7000 * (from TLB_MMIO), which we cannot avoid, perform all of the stores.
7001 *
7002 * Note for the common case of an element in RAM, not crossing a page
7003 * boundary, we have stored the host address in host[]. This doubles
7004 * as a first-level check against the predicate, since only enabled
7005 * elements have non-null host addresses.
7006 */
7007 i = reg_off = 0;
7008 do {
7009 void *h = host[i];
7010 if (likely(h != NULL)) {
7011 set_helper_retaddr(retaddr);
7012 host_fn(vd, reg_off, h);
7013 clear_helper_retaddr();
7014 } else if ((vg[reg_off >> 6] >> (reg_off & 63)) & 1) {
7015 target_ulong addr = base + (off_fn(vm, reg_off) << scale);
7016 tlb_fn(env, vd, reg_off, addr, retaddr);
7017 }
7018 i += 1;
7019 reg_off += esize;
7020 } while (reg_off < reg_max);
7021 }
7022
7023 static inline QEMU_ALWAYS_INLINE
sve_st1_z_mte(CPUARMState * env,void * vd,uint64_t * vg,void * vm,target_ulong base,uint32_t desc,uintptr_t retaddr,int esize,int msize,zreg_off_fn * off_fn,sve_ldst1_host_fn * host_fn,sve_ldst1_tlb_fn * tlb_fn)7024 void sve_st1_z_mte(CPUARMState *env, void *vd, uint64_t *vg, void *vm,
7025 target_ulong base, uint32_t desc, uintptr_t retaddr,
7026 int esize, int msize, zreg_off_fn *off_fn,
7027 sve_ldst1_host_fn *host_fn,
7028 sve_ldst1_tlb_fn *tlb_fn)
7029 {
7030 uint32_t mtedesc = desc >> (SIMD_DATA_SHIFT + SVE_MTEDESC_SHIFT);
7031 /* Remove mtedesc from the normal sve descriptor. */
7032 desc = extract32(desc, 0, SIMD_DATA_SHIFT + SVE_MTEDESC_SHIFT);
7033
7034 /*
7035 * ??? TODO: For the 32-bit offset extractions, base + ofs cannot
7036 * offset base entirely over the address space hole to change the
7037 * pointer tag, or change the bit55 selector. So we could here
7038 * examine TBI + TCMA like we do for sve_ldN_r_mte().
7039 */
7040 sve_st1_z(env, vd, vg, vm, base, desc, retaddr, mtedesc,
7041 esize, msize, off_fn, host_fn, tlb_fn);
7042 }
7043
7044 #define DO_ST1_ZPZ_S(MEM, OFS, MSZ) \
7045 void HELPER(sve_st##MEM##_##OFS)(CPUARMState *env, void *vd, void *vg, \
7046 void *vm, target_ulong base, uint32_t desc) \
7047 { \
7048 sve_st1_z(env, vd, vg, vm, base, desc, GETPC(), 0, 4, 1 << MSZ, \
7049 off_##OFS##_s, sve_st1##MEM##_host, sve_st1##MEM##_tlb); \
7050 } \
7051 void HELPER(sve_st##MEM##_##OFS##_mte)(CPUARMState *env, void *vd, void *vg, \
7052 void *vm, target_ulong base, uint32_t desc) \
7053 { \
7054 sve_st1_z_mte(env, vd, vg, vm, base, desc, GETPC(), 4, 1 << MSZ, \
7055 off_##OFS##_s, sve_st1##MEM##_host, sve_st1##MEM##_tlb); \
7056 }
7057
7058 #define DO_ST1_ZPZ_D(MEM, OFS, MSZ) \
7059 void HELPER(sve_st##MEM##_##OFS)(CPUARMState *env, void *vd, void *vg, \
7060 void *vm, target_ulong base, uint32_t desc) \
7061 { \
7062 sve_st1_z(env, vd, vg, vm, base, desc, GETPC(), 0, 8, 1 << MSZ, \
7063 off_##OFS##_d, sve_st1##MEM##_host, sve_st1##MEM##_tlb); \
7064 } \
7065 void HELPER(sve_st##MEM##_##OFS##_mte)(CPUARMState *env, void *vd, void *vg, \
7066 void *vm, target_ulong base, uint32_t desc) \
7067 { \
7068 sve_st1_z_mte(env, vd, vg, vm, base, desc, GETPC(), 8, 1 << MSZ, \
7069 off_##OFS##_d, sve_st1##MEM##_host, sve_st1##MEM##_tlb); \
7070 }
7071
DO_ST1_ZPZ_S(bs,zsu,MO_8)7072 DO_ST1_ZPZ_S(bs, zsu, MO_8)
7073 DO_ST1_ZPZ_S(hs_le, zsu, MO_16)
7074 DO_ST1_ZPZ_S(hs_be, zsu, MO_16)
7075 DO_ST1_ZPZ_S(ss_le, zsu, MO_32)
7076 DO_ST1_ZPZ_S(ss_be, zsu, MO_32)
7077
7078 DO_ST1_ZPZ_S(bs, zss, MO_8)
7079 DO_ST1_ZPZ_S(hs_le, zss, MO_16)
7080 DO_ST1_ZPZ_S(hs_be, zss, MO_16)
7081 DO_ST1_ZPZ_S(ss_le, zss, MO_32)
7082 DO_ST1_ZPZ_S(ss_be, zss, MO_32)
7083
7084 DO_ST1_ZPZ_D(bd, zsu, MO_8)
7085 DO_ST1_ZPZ_D(hd_le, zsu, MO_16)
7086 DO_ST1_ZPZ_D(hd_be, zsu, MO_16)
7087 DO_ST1_ZPZ_D(sd_le, zsu, MO_32)
7088 DO_ST1_ZPZ_D(sd_be, zsu, MO_32)
7089 DO_ST1_ZPZ_D(dd_le, zsu, MO_64)
7090 DO_ST1_ZPZ_D(dd_be, zsu, MO_64)
7091
7092 DO_ST1_ZPZ_D(bd, zss, MO_8)
7093 DO_ST1_ZPZ_D(hd_le, zss, MO_16)
7094 DO_ST1_ZPZ_D(hd_be, zss, MO_16)
7095 DO_ST1_ZPZ_D(sd_le, zss, MO_32)
7096 DO_ST1_ZPZ_D(sd_be, zss, MO_32)
7097 DO_ST1_ZPZ_D(dd_le, zss, MO_64)
7098 DO_ST1_ZPZ_D(dd_be, zss, MO_64)
7099
7100 DO_ST1_ZPZ_D(bd, zd, MO_8)
7101 DO_ST1_ZPZ_D(hd_le, zd, MO_16)
7102 DO_ST1_ZPZ_D(hd_be, zd, MO_16)
7103 DO_ST1_ZPZ_D(sd_le, zd, MO_32)
7104 DO_ST1_ZPZ_D(sd_be, zd, MO_32)
7105 DO_ST1_ZPZ_D(dd_le, zd, MO_64)
7106 DO_ST1_ZPZ_D(dd_be, zd, MO_64)
7107
7108 #undef DO_ST1_ZPZ_S
7109 #undef DO_ST1_ZPZ_D
7110
7111 void HELPER(sve2_eor3)(void *vd, void *vn, void *vm, void *vk, uint32_t desc)
7112 {
7113 intptr_t i, opr_sz = simd_oprsz(desc) / 8;
7114 uint64_t *d = vd, *n = vn, *m = vm, *k = vk;
7115
7116 for (i = 0; i < opr_sz; ++i) {
7117 d[i] = n[i] ^ m[i] ^ k[i];
7118 }
7119 }
7120
HELPER(sve2_bcax)7121 void HELPER(sve2_bcax)(void *vd, void *vn, void *vm, void *vk, uint32_t desc)
7122 {
7123 intptr_t i, opr_sz = simd_oprsz(desc) / 8;
7124 uint64_t *d = vd, *n = vn, *m = vm, *k = vk;
7125
7126 for (i = 0; i < opr_sz; ++i) {
7127 d[i] = n[i] ^ (m[i] & ~k[i]);
7128 }
7129 }
7130
HELPER(sve2_bsl1n)7131 void HELPER(sve2_bsl1n)(void *vd, void *vn, void *vm, void *vk, uint32_t desc)
7132 {
7133 intptr_t i, opr_sz = simd_oprsz(desc) / 8;
7134 uint64_t *d = vd, *n = vn, *m = vm, *k = vk;
7135
7136 for (i = 0; i < opr_sz; ++i) {
7137 d[i] = (~n[i] & k[i]) | (m[i] & ~k[i]);
7138 }
7139 }
7140
HELPER(sve2_bsl2n)7141 void HELPER(sve2_bsl2n)(void *vd, void *vn, void *vm, void *vk, uint32_t desc)
7142 {
7143 intptr_t i, opr_sz = simd_oprsz(desc) / 8;
7144 uint64_t *d = vd, *n = vn, *m = vm, *k = vk;
7145
7146 for (i = 0; i < opr_sz; ++i) {
7147 d[i] = (n[i] & k[i]) | (~m[i] & ~k[i]);
7148 }
7149 }
7150
HELPER(sve2_nbsl)7151 void HELPER(sve2_nbsl)(void *vd, void *vn, void *vm, void *vk, uint32_t desc)
7152 {
7153 intptr_t i, opr_sz = simd_oprsz(desc) / 8;
7154 uint64_t *d = vd, *n = vn, *m = vm, *k = vk;
7155
7156 for (i = 0; i < opr_sz; ++i) {
7157 d[i] = ~((n[i] & k[i]) | (m[i] & ~k[i]));
7158 }
7159 }
7160
7161 /*
7162 * Returns true if m0 or m1 contains the low uint8_t/uint16_t in n.
7163 * See hasless(v,1) from
7164 * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
7165 */
do_match2(uint64_t n,uint64_t m0,uint64_t m1,int esz)7166 static inline bool do_match2(uint64_t n, uint64_t m0, uint64_t m1, int esz)
7167 {
7168 int bits = 8 << esz;
7169 uint64_t ones = dup_const(esz, 1);
7170 uint64_t signs = ones << (bits - 1);
7171 uint64_t cmp0, cmp1;
7172
7173 cmp1 = dup_const(esz, n);
7174 cmp0 = cmp1 ^ m0;
7175 cmp1 = cmp1 ^ m1;
7176 cmp0 = (cmp0 - ones) & ~cmp0;
7177 cmp1 = (cmp1 - ones) & ~cmp1;
7178 return (cmp0 | cmp1) & signs;
7179 }
7180
do_match(void * vd,void * vn,void * vm,void * vg,uint32_t desc,int esz,bool nmatch)7181 static inline uint32_t do_match(void *vd, void *vn, void *vm, void *vg,
7182 uint32_t desc, int esz, bool nmatch)
7183 {
7184 uint16_t esz_mask = pred_esz_masks[esz];
7185 intptr_t opr_sz = simd_oprsz(desc);
7186 uint32_t flags = PREDTEST_INIT;
7187 intptr_t i, j, k;
7188
7189 for (i = 0; i < opr_sz; i += 16) {
7190 uint64_t m0 = *(uint64_t *)(vm + i);
7191 uint64_t m1 = *(uint64_t *)(vm + i + 8);
7192 uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)) & esz_mask;
7193 uint16_t out = 0;
7194
7195 for (j = 0; j < 16; j += 8) {
7196 uint64_t n = *(uint64_t *)(vn + i + j);
7197
7198 for (k = 0; k < 8; k += 1 << esz) {
7199 if (pg & (1 << (j + k))) {
7200 bool o = do_match2(n >> (k * 8), m0, m1, esz);
7201 out |= (o ^ nmatch) << (j + k);
7202 }
7203 }
7204 }
7205 *(uint16_t *)(vd + H1_2(i >> 3)) = out;
7206 flags = iter_predtest_fwd(out, pg, flags);
7207 }
7208 return flags;
7209 }
7210
7211 #define DO_PPZZ_MATCH(NAME, ESZ, INV) \
7212 uint32_t HELPER(NAME)(void *vd, void *vn, void *vm, void *vg, uint32_t desc) \
7213 { \
7214 return do_match(vd, vn, vm, vg, desc, ESZ, INV); \
7215 }
7216
DO_PPZZ_MATCH(sve2_match_ppzz_b,MO_8,false)7217 DO_PPZZ_MATCH(sve2_match_ppzz_b, MO_8, false)
7218 DO_PPZZ_MATCH(sve2_match_ppzz_h, MO_16, false)
7219
7220 DO_PPZZ_MATCH(sve2_nmatch_ppzz_b, MO_8, true)
7221 DO_PPZZ_MATCH(sve2_nmatch_ppzz_h, MO_16, true)
7222
7223 #undef DO_PPZZ_MATCH
7224
7225 void HELPER(sve2_histcnt_s)(void *vd, void *vn, void *vm, void *vg,
7226 uint32_t desc)
7227 {
7228 ARMVectorReg scratch;
7229 intptr_t i, j;
7230 intptr_t opr_sz = simd_oprsz(desc);
7231 uint32_t *d = vd, *n = vn, *m = vm;
7232 uint8_t *pg = vg;
7233
7234 if (d == n) {
7235 n = memcpy(&scratch, n, opr_sz);
7236 if (d == m) {
7237 m = n;
7238 }
7239 } else if (d == m) {
7240 m = memcpy(&scratch, m, opr_sz);
7241 }
7242
7243 for (i = 0; i < opr_sz; i += 4) {
7244 uint64_t count = 0;
7245 uint8_t pred;
7246
7247 pred = pg[H1(i >> 3)] >> (i & 7);
7248 if (pred & 1) {
7249 uint32_t nn = n[H4(i >> 2)];
7250
7251 for (j = 0; j <= i; j += 4) {
7252 pred = pg[H1(j >> 3)] >> (j & 7);
7253 if ((pred & 1) && nn == m[H4(j >> 2)]) {
7254 ++count;
7255 }
7256 }
7257 }
7258 d[H4(i >> 2)] = count;
7259 }
7260 }
7261
HELPER(sve2_histcnt_d)7262 void HELPER(sve2_histcnt_d)(void *vd, void *vn, void *vm, void *vg,
7263 uint32_t desc)
7264 {
7265 ARMVectorReg scratch;
7266 intptr_t i, j;
7267 intptr_t opr_sz = simd_oprsz(desc);
7268 uint64_t *d = vd, *n = vn, *m = vm;
7269 uint8_t *pg = vg;
7270
7271 if (d == n) {
7272 n = memcpy(&scratch, n, opr_sz);
7273 if (d == m) {
7274 m = n;
7275 }
7276 } else if (d == m) {
7277 m = memcpy(&scratch, m, opr_sz);
7278 }
7279
7280 for (i = 0; i < opr_sz / 8; ++i) {
7281 uint64_t count = 0;
7282 if (pg[H1(i)] & 1) {
7283 uint64_t nn = n[i];
7284 for (j = 0; j <= i; ++j) {
7285 if ((pg[H1(j)] & 1) && nn == m[j]) {
7286 ++count;
7287 }
7288 }
7289 }
7290 d[i] = count;
7291 }
7292 }
7293
7294 /*
7295 * Returns the number of bytes in m0 and m1 that match n.
7296 * Unlike do_match2 we don't just need true/false, we need an exact count.
7297 * This requires two extra logical operations.
7298 */
do_histseg_cnt(uint8_t n,uint64_t m0,uint64_t m1)7299 static inline uint64_t do_histseg_cnt(uint8_t n, uint64_t m0, uint64_t m1)
7300 {
7301 const uint64_t mask = dup_const(MO_8, 0x7f);
7302 uint64_t cmp0, cmp1;
7303
7304 cmp1 = dup_const(MO_8, n);
7305 cmp0 = cmp1 ^ m0;
7306 cmp1 = cmp1 ^ m1;
7307
7308 /*
7309 * 1: clear msb of each byte to avoid carry to next byte (& mask)
7310 * 2: carry in to msb if byte != 0 (+ mask)
7311 * 3: set msb if cmp has msb set (| cmp)
7312 * 4: set ~msb to ignore them (| mask)
7313 * We now have 0xff for byte != 0 or 0x7f for byte == 0.
7314 * 5: invert, resulting in 0x80 if and only if byte == 0.
7315 */
7316 cmp0 = ~(((cmp0 & mask) + mask) | cmp0 | mask);
7317 cmp1 = ~(((cmp1 & mask) + mask) | cmp1 | mask);
7318
7319 /*
7320 * Combine the two compares in a way that the bits do
7321 * not overlap, and so preserves the count of set bits.
7322 * If the host has an efficient instruction for ctpop,
7323 * then ctpop(x) + ctpop(y) has the same number of
7324 * operations as ctpop(x | (y >> 1)). If the host does
7325 * not have an efficient ctpop, then we only want to
7326 * use it once.
7327 */
7328 return ctpop64(cmp0 | (cmp1 >> 1));
7329 }
7330
HELPER(sve2_histseg)7331 void HELPER(sve2_histseg)(void *vd, void *vn, void *vm, uint32_t desc)
7332 {
7333 intptr_t i, j;
7334 intptr_t opr_sz = simd_oprsz(desc);
7335
7336 for (i = 0; i < opr_sz; i += 16) {
7337 uint64_t n0 = *(uint64_t *)(vn + i);
7338 uint64_t m0 = *(uint64_t *)(vm + i);
7339 uint64_t n1 = *(uint64_t *)(vn + i + 8);
7340 uint64_t m1 = *(uint64_t *)(vm + i + 8);
7341 uint64_t out0 = 0;
7342 uint64_t out1 = 0;
7343
7344 for (j = 0; j < 64; j += 8) {
7345 uint64_t cnt0 = do_histseg_cnt(n0 >> j, m0, m1);
7346 uint64_t cnt1 = do_histseg_cnt(n1 >> j, m0, m1);
7347 out0 |= cnt0 << j;
7348 out1 |= cnt1 << j;
7349 }
7350
7351 *(uint64_t *)(vd + i) = out0;
7352 *(uint64_t *)(vd + i + 8) = out1;
7353 }
7354 }
7355
HELPER(sve2_xar_b)7356 void HELPER(sve2_xar_b)(void *vd, void *vn, void *vm, uint32_t desc)
7357 {
7358 intptr_t i, opr_sz = simd_oprsz(desc) / 8;
7359 int shr = simd_data(desc);
7360 int shl = 8 - shr;
7361 uint64_t mask = dup_const(MO_8, 0xff >> shr);
7362 uint64_t *d = vd, *n = vn, *m = vm;
7363
7364 for (i = 0; i < opr_sz; ++i) {
7365 uint64_t t = n[i] ^ m[i];
7366 d[i] = ((t >> shr) & mask) | ((t << shl) & ~mask);
7367 }
7368 }
7369
HELPER(sve2_xar_h)7370 void HELPER(sve2_xar_h)(void *vd, void *vn, void *vm, uint32_t desc)
7371 {
7372 intptr_t i, opr_sz = simd_oprsz(desc) / 8;
7373 int shr = simd_data(desc);
7374 int shl = 16 - shr;
7375 uint64_t mask = dup_const(MO_16, 0xffff >> shr);
7376 uint64_t *d = vd, *n = vn, *m = vm;
7377
7378 for (i = 0; i < opr_sz; ++i) {
7379 uint64_t t = n[i] ^ m[i];
7380 d[i] = ((t >> shr) & mask) | ((t << shl) & ~mask);
7381 }
7382 }
7383
HELPER(sve2_xar_s)7384 void HELPER(sve2_xar_s)(void *vd, void *vn, void *vm, uint32_t desc)
7385 {
7386 intptr_t i, opr_sz = simd_oprsz(desc) / 4;
7387 int shr = simd_data(desc);
7388 uint32_t *d = vd, *n = vn, *m = vm;
7389
7390 for (i = 0; i < opr_sz; ++i) {
7391 d[i] = ror32(n[i] ^ m[i], shr);
7392 }
7393 }
7394
HELPER(fmmla_s)7395 void HELPER(fmmla_s)(void *vd, void *vn, void *vm, void *va,
7396 void *status, uint32_t desc)
7397 {
7398 intptr_t s, opr_sz = simd_oprsz(desc) / (sizeof(float32) * 4);
7399
7400 for (s = 0; s < opr_sz; ++s) {
7401 float32 *n = vn + s * sizeof(float32) * 4;
7402 float32 *m = vm + s * sizeof(float32) * 4;
7403 float32 *a = va + s * sizeof(float32) * 4;
7404 float32 *d = vd + s * sizeof(float32) * 4;
7405 float32 n00 = n[H4(0)], n01 = n[H4(1)];
7406 float32 n10 = n[H4(2)], n11 = n[H4(3)];
7407 float32 m00 = m[H4(0)], m01 = m[H4(1)];
7408 float32 m10 = m[H4(2)], m11 = m[H4(3)];
7409 float32 p0, p1;
7410
7411 /* i = 0, j = 0 */
7412 p0 = float32_mul(n00, m00, status);
7413 p1 = float32_mul(n01, m01, status);
7414 d[H4(0)] = float32_add(a[H4(0)], float32_add(p0, p1, status), status);
7415
7416 /* i = 0, j = 1 */
7417 p0 = float32_mul(n00, m10, status);
7418 p1 = float32_mul(n01, m11, status);
7419 d[H4(1)] = float32_add(a[H4(1)], float32_add(p0, p1, status), status);
7420
7421 /* i = 1, j = 0 */
7422 p0 = float32_mul(n10, m00, status);
7423 p1 = float32_mul(n11, m01, status);
7424 d[H4(2)] = float32_add(a[H4(2)], float32_add(p0, p1, status), status);
7425
7426 /* i = 1, j = 1 */
7427 p0 = float32_mul(n10, m10, status);
7428 p1 = float32_mul(n11, m11, status);
7429 d[H4(3)] = float32_add(a[H4(3)], float32_add(p0, p1, status), status);
7430 }
7431 }
7432
HELPER(fmmla_d)7433 void HELPER(fmmla_d)(void *vd, void *vn, void *vm, void *va,
7434 void *status, uint32_t desc)
7435 {
7436 intptr_t s, opr_sz = simd_oprsz(desc) / (sizeof(float64) * 4);
7437
7438 for (s = 0; s < opr_sz; ++s) {
7439 float64 *n = vn + s * sizeof(float64) * 4;
7440 float64 *m = vm + s * sizeof(float64) * 4;
7441 float64 *a = va + s * sizeof(float64) * 4;
7442 float64 *d = vd + s * sizeof(float64) * 4;
7443 float64 n00 = n[0], n01 = n[1], n10 = n[2], n11 = n[3];
7444 float64 m00 = m[0], m01 = m[1], m10 = m[2], m11 = m[3];
7445 float64 p0, p1;
7446
7447 /* i = 0, j = 0 */
7448 p0 = float64_mul(n00, m00, status);
7449 p1 = float64_mul(n01, m01, status);
7450 d[0] = float64_add(a[0], float64_add(p0, p1, status), status);
7451
7452 /* i = 0, j = 1 */
7453 p0 = float64_mul(n00, m10, status);
7454 p1 = float64_mul(n01, m11, status);
7455 d[1] = float64_add(a[1], float64_add(p0, p1, status), status);
7456
7457 /* i = 1, j = 0 */
7458 p0 = float64_mul(n10, m00, status);
7459 p1 = float64_mul(n11, m01, status);
7460 d[2] = float64_add(a[2], float64_add(p0, p1, status), status);
7461
7462 /* i = 1, j = 1 */
7463 p0 = float64_mul(n10, m10, status);
7464 p1 = float64_mul(n11, m11, status);
7465 d[3] = float64_add(a[3], float64_add(p0, p1, status), status);
7466 }
7467 }
7468
7469 #define DO_FCVTNT(NAME, TYPEW, TYPEN, HW, HN, OP) \
7470 void HELPER(NAME)(void *vd, void *vn, void *vg, void *status, uint32_t desc) \
7471 { \
7472 intptr_t i = simd_oprsz(desc); \
7473 uint64_t *g = vg; \
7474 do { \
7475 uint64_t pg = g[(i - 1) >> 6]; \
7476 do { \
7477 i -= sizeof(TYPEW); \
7478 if (likely((pg >> (i & 63)) & 1)) { \
7479 TYPEW nn = *(TYPEW *)(vn + HW(i)); \
7480 *(TYPEN *)(vd + HN(i + sizeof(TYPEN))) = OP(nn, status); \
7481 } \
7482 } while (i & 63); \
7483 } while (i != 0); \
7484 }
7485
7486 DO_FCVTNT(sve_bfcvtnt, uint32_t, uint16_t, H1_4, H1_2, float32_to_bfloat16)
7487 DO_FCVTNT(sve2_fcvtnt_sh, uint32_t, uint16_t, H1_4, H1_2, sve_f32_to_f16)
7488 DO_FCVTNT(sve2_fcvtnt_ds, uint64_t, uint32_t, H1_8, H1_4, float64_to_float32)
7489
7490 #define DO_FCVTLT(NAME, TYPEW, TYPEN, HW, HN, OP) \
7491 void HELPER(NAME)(void *vd, void *vn, void *vg, void *status, uint32_t desc) \
7492 { \
7493 intptr_t i = simd_oprsz(desc); \
7494 uint64_t *g = vg; \
7495 do { \
7496 uint64_t pg = g[(i - 1) >> 6]; \
7497 do { \
7498 i -= sizeof(TYPEW); \
7499 if (likely((pg >> (i & 63)) & 1)) { \
7500 TYPEN nn = *(TYPEN *)(vn + HN(i + sizeof(TYPEN))); \
7501 *(TYPEW *)(vd + HW(i)) = OP(nn, status); \
7502 } \
7503 } while (i & 63); \
7504 } while (i != 0); \
7505 }
7506
7507 DO_FCVTLT(sve2_fcvtlt_hs, uint32_t, uint16_t, H1_4, H1_2, sve_f16_to_f32)
7508 DO_FCVTLT(sve2_fcvtlt_sd, uint64_t, uint32_t, H1_8, H1_4, float32_to_float64)
7509
7510 #undef DO_FCVTLT
7511 #undef DO_FCVTNT
7512