1/*
2 * QEMU TCG support -- s390x vector instruction translation functions
3 *
4 * Copyright (C) 2019 Red Hat Inc
5 *
6 * Authors:
7 * David Hildenbrand <david@redhat.com>
8 *
9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 * See the COPYING file in the top-level directory.
11 */
12
13/*
14 * For most instructions that use the same element size for reads and
15 * writes, we can use real gvec vector expansion, which potantially uses
16 * real host vector instructions. As they only work up to 64 bit elements,
17 * 128 bit elements (vector is a single element) have to be handled
18 * differently. Operations that are too complicated to encode via TCG ops
19 * are handled via gvec ool (out-of-line) handlers.
20 *
21 * As soon as instructions use different element sizes for reads and writes
22 * or access elements "out of their element scope" we expand them manually
23 * in fancy loops, as gvec expansion does not deal with actual element
24 * numbers and does also not support access to other elements.
25 *
26 * 128 bit elements:
27 * As we only have i32/i64, such elements have to be loaded into two
28 * i64 values and can then be processed e.g. by tcg_gen_add2_i64.
29 *
30 * Sizes:
31 * On s390x, the operand size (oprsz) and the maximum size (maxsz) are
32 * always 16 (128 bit). What gvec code calls "vece", s390x calls "es",
33 * a.k.a. "element size". These values nicely map to MO_8 ... MO_64. Only
34 * 128 bit element size has to be treated in a special way (MO_64 + 1).
35 * We will use ES_* instead of MO_* for this reason in this file.
36 *
37 * CC handling:
38 * As gvec ool-helpers can currently not return values (besides via
39 * pointers like vectors or cpu_env), whenever we have to set the CC and
40 * can't conclude the value from the result vector, we will directly
41 * set it in "env->cc_op" and mark it as static via set_cc_static()".
42 * Whenever this is done, the helper writes globals (cc_op).
43 */
44
45#define NUM_VEC_ELEMENT_BYTES(es) (1 << (es))
46#define NUM_VEC_ELEMENTS(es) (16 / NUM_VEC_ELEMENT_BYTES(es))
47#define NUM_VEC_ELEMENT_BITS(es) (NUM_VEC_ELEMENT_BYTES(es) * BITS_PER_BYTE)
48
49#define ES_8 MO_8
50#define ES_16 MO_16
51#define ES_32 MO_32
52#define ES_64 MO_64
53#define ES_128 4
54
55/* Floating-Point Format */
56#define FPF_SHORT 2
57#define FPF_LONG 3
58#define FPF_EXT 4
59
60static inline bool valid_vec_element(uint8_t enr, MemOp es)
61{
62 return !(enr & ~(NUM_VEC_ELEMENTS(es) - 1));
63}
64
65static void read_vec_element_i64(TCGv_i64 dst, uint8_t reg, uint8_t enr,
66 MemOp memop)
67{
68 const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE);
69
70 switch (memop) {
71 case ES_8:
72 tcg_gen_ld8u_i64(dst, cpu_env, offs);
73 break;
74 case ES_16:
75 tcg_gen_ld16u_i64(dst, cpu_env, offs);
76 break;
77 case ES_32:
78 tcg_gen_ld32u_i64(dst, cpu_env, offs);
79 break;
80 case ES_8 | MO_SIGN:
81 tcg_gen_ld8s_i64(dst, cpu_env, offs);
82 break;
83 case ES_16 | MO_SIGN:
84 tcg_gen_ld16s_i64(dst, cpu_env, offs);
85 break;
86 case ES_32 | MO_SIGN:
87 tcg_gen_ld32s_i64(dst, cpu_env, offs);
88 break;
89 case ES_64:
90 case ES_64 | MO_SIGN:
91 tcg_gen_ld_i64(dst, cpu_env, offs);
92 break;
93 default:
94 g_assert_not_reached();
95 }
96}
97
98static void read_vec_element_i32(TCGv_i32 dst, uint8_t reg, uint8_t enr,
99 MemOp memop)
100{
101 const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE);
102
103 switch (memop) {
104 case ES_8:
105 tcg_gen_ld8u_i32(dst, cpu_env, offs);
106 break;
107 case ES_16:
108 tcg_gen_ld16u_i32(dst, cpu_env, offs);
109 break;
110 case ES_8 | MO_SIGN:
111 tcg_gen_ld8s_i32(dst, cpu_env, offs);
112 break;
113 case ES_16 | MO_SIGN:
114 tcg_gen_ld16s_i32(dst, cpu_env, offs);
115 break;
116 case ES_32:
117 case ES_32 | MO_SIGN:
118 tcg_gen_ld_i32(dst, cpu_env, offs);
119 break;
120 default:
121 g_assert_not_reached();
122 }
123}
124
125static void write_vec_element_i64(TCGv_i64 src, int reg, uint8_t enr,
126 MemOp memop)
127{
128 const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE);
129
130 switch (memop) {
131 case ES_8:
132 tcg_gen_st8_i64(src, cpu_env, offs);
133 break;
134 case ES_16:
135 tcg_gen_st16_i64(src, cpu_env, offs);
136 break;
137 case ES_32:
138 tcg_gen_st32_i64(src, cpu_env, offs);
139 break;
140 case ES_64:
141 tcg_gen_st_i64(src, cpu_env, offs);
142 break;
143 default:
144 g_assert_not_reached();
145 }
146}
147
148static void write_vec_element_i32(TCGv_i32 src, int reg, uint8_t enr,
149 MemOp memop)
150{
151 const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE);
152
153 switch (memop) {
154 case ES_8:
155 tcg_gen_st8_i32(src, cpu_env, offs);
156 break;
157 case ES_16:
158 tcg_gen_st16_i32(src, cpu_env, offs);
159 break;
160 case ES_32:
161 tcg_gen_st_i32(src, cpu_env, offs);
162 break;
163 default:
164 g_assert_not_reached();
165 }
166}
167
168static void get_vec_element_ptr_i64(TCGv_ptr ptr, uint8_t reg, TCGv_i64 enr,
169 uint8_t es)
170{
171 TCGv_i64 tmp = tcg_temp_new_i64();
172
173 /* mask off invalid parts from the element nr */
174 tcg_gen_andi_i64(tmp, enr, NUM_VEC_ELEMENTS(es) - 1);
175
176 /* convert it to an element offset relative to cpu_env (vec_reg_offset() */
177 tcg_gen_shli_i64(tmp, tmp, es);
178#ifndef HOST_WORDS_BIGENDIAN
179 tcg_gen_xori_i64(tmp, tmp, 8 - NUM_VEC_ELEMENT_BYTES(es));
180#endif
181 tcg_gen_addi_i64(tmp, tmp, vec_full_reg_offset(reg));
182
183 /* generate the final ptr by adding cpu_env */
184 tcg_gen_trunc_i64_ptr(ptr, tmp);
185 tcg_gen_add_ptr(ptr, ptr, cpu_env);
186
187 tcg_temp_free_i64(tmp);
188}
189
190#define gen_gvec_2(v1, v2, gen) \
191 tcg_gen_gvec_2(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
192 16, 16, gen)
193#define gen_gvec_2s(v1, v2, c, gen) \
194 tcg_gen_gvec_2s(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
195 16, 16, c, gen)
196#define gen_gvec_2_ool(v1, v2, data, fn) \
197 tcg_gen_gvec_2_ool(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
198 16, 16, data, fn)
199#define gen_gvec_2i_ool(v1, v2, c, data, fn) \
200 tcg_gen_gvec_2i_ool(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
201 c, 16, 16, data, fn)
202#define gen_gvec_2_ptr(v1, v2, ptr, data, fn) \
203 tcg_gen_gvec_2_ptr(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
204 ptr, 16, 16, data, fn)
205#define gen_gvec_3(v1, v2, v3, gen) \
206 tcg_gen_gvec_3(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
207 vec_full_reg_offset(v3), 16, 16, gen)
208#define gen_gvec_3_ool(v1, v2, v3, data, fn) \
209 tcg_gen_gvec_3_ool(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
210 vec_full_reg_offset(v3), 16, 16, data, fn)
211#define gen_gvec_3_ptr(v1, v2, v3, ptr, data, fn) \
212 tcg_gen_gvec_3_ptr(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
213 vec_full_reg_offset(v3), ptr, 16, 16, data, fn)
214#define gen_gvec_3i(v1, v2, v3, c, gen) \
215 tcg_gen_gvec_3i(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
216 vec_full_reg_offset(v3), 16, 16, c, gen)
217#define gen_gvec_4(v1, v2, v3, v4, gen) \
218 tcg_gen_gvec_4(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
219 vec_full_reg_offset(v3), vec_full_reg_offset(v4), \
220 16, 16, gen)
221#define gen_gvec_4_ool(v1, v2, v3, v4, data, fn) \
222 tcg_gen_gvec_4_ool(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
223 vec_full_reg_offset(v3), vec_full_reg_offset(v4), \
224 16, 16, data, fn)
225#define gen_gvec_4_ptr(v1, v2, v3, v4, ptr, data, fn) \
226 tcg_gen_gvec_4_ptr(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
227 vec_full_reg_offset(v3), vec_full_reg_offset(v4), \
228 ptr, 16, 16, data, fn)
229#define gen_gvec_dup_i64(es, v1, c) \
230 tcg_gen_gvec_dup_i64(es, vec_full_reg_offset(v1), 16, 16, c)
231#define gen_gvec_mov(v1, v2) \
232 tcg_gen_gvec_mov(0, vec_full_reg_offset(v1), vec_full_reg_offset(v2), 16, \
233 16)
234#define gen_gvec_dup64i(v1, c) \
235 tcg_gen_gvec_dup64i(vec_full_reg_offset(v1), 16, 16, c)
236#define gen_gvec_fn_2(fn, es, v1, v2) \
237 tcg_gen_gvec_##fn(es, vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
238 16, 16)
239#define gen_gvec_fn_2i(fn, es, v1, v2, c) \
240 tcg_gen_gvec_##fn(es, vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
241 c, 16, 16)
242#define gen_gvec_fn_2s(fn, es, v1, v2, s) \
243 tcg_gen_gvec_##fn(es, vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
244 s, 16, 16)
245#define gen_gvec_fn_3(fn, es, v1, v2, v3) \
246 tcg_gen_gvec_##fn(es, vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
247 vec_full_reg_offset(v3), 16, 16)
248#define gen_gvec_fn_4(fn, es, v1, v2, v3, v4) \
249 tcg_gen_gvec_##fn(es, vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
250 vec_full_reg_offset(v3), vec_full_reg_offset(v4), 16, 16)
251
252/*
253 * Helper to carry out a 128 bit vector computation using 2 i64 values per
254 * vector.
255 */
256typedef void (*gen_gvec128_3_i64_fn)(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al,
257 TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh);
258static void gen_gvec128_3_i64(gen_gvec128_3_i64_fn fn, uint8_t d, uint8_t a,
259 uint8_t b)
260{
261 TCGv_i64 dh = tcg_temp_new_i64();
262 TCGv_i64 dl = tcg_temp_new_i64();
263 TCGv_i64 ah = tcg_temp_new_i64();
264 TCGv_i64 al = tcg_temp_new_i64();
265 TCGv_i64 bh = tcg_temp_new_i64();
266 TCGv_i64 bl = tcg_temp_new_i64();
267
268 read_vec_element_i64(ah, a, 0, ES_64);
269 read_vec_element_i64(al, a, 1, ES_64);
270 read_vec_element_i64(bh, b, 0, ES_64);
271 read_vec_element_i64(bl, b, 1, ES_64);
272 fn(dl, dh, al, ah, bl, bh);
273 write_vec_element_i64(dh, d, 0, ES_64);
274 write_vec_element_i64(dl, d, 1, ES_64);
275
276 tcg_temp_free_i64(dh);
277 tcg_temp_free_i64(dl);
278 tcg_temp_free_i64(ah);
279 tcg_temp_free_i64(al);
280 tcg_temp_free_i64(bh);
281 tcg_temp_free_i64(bl);
282}
283
284typedef void (*gen_gvec128_4_i64_fn)(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al,
285 TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh,
286 TCGv_i64 cl, TCGv_i64 ch);
287static void gen_gvec128_4_i64(gen_gvec128_4_i64_fn fn, uint8_t d, uint8_t a,
288 uint8_t b, uint8_t c)
289{
290 TCGv_i64 dh = tcg_temp_new_i64();
291 TCGv_i64 dl = tcg_temp_new_i64();
292 TCGv_i64 ah = tcg_temp_new_i64();
293 TCGv_i64 al = tcg_temp_new_i64();
294 TCGv_i64 bh = tcg_temp_new_i64();
295 TCGv_i64 bl = tcg_temp_new_i64();
296 TCGv_i64 ch = tcg_temp_new_i64();
297 TCGv_i64 cl = tcg_temp_new_i64();
298
299 read_vec_element_i64(ah, a, 0, ES_64);
300 read_vec_element_i64(al, a, 1, ES_64);
301 read_vec_element_i64(bh, b, 0, ES_64);
302 read_vec_element_i64(bl, b, 1, ES_64);
303 read_vec_element_i64(ch, c, 0, ES_64);
304 read_vec_element_i64(cl, c, 1, ES_64);
305 fn(dl, dh, al, ah, bl, bh, cl, ch);
306 write_vec_element_i64(dh, d, 0, ES_64);
307 write_vec_element_i64(dl, d, 1, ES_64);
308
309 tcg_temp_free_i64(dh);
310 tcg_temp_free_i64(dl);
311 tcg_temp_free_i64(ah);
312 tcg_temp_free_i64(al);
313 tcg_temp_free_i64(bh);
314 tcg_temp_free_i64(bl);
315 tcg_temp_free_i64(ch);
316 tcg_temp_free_i64(cl);
317}
318
319static void gen_gvec_dupi(uint8_t es, uint8_t reg, uint64_t c)
320{
321 switch (es) {
322 case ES_8:
323 tcg_gen_gvec_dup8i(vec_full_reg_offset(reg), 16, 16, c);
324 break;
325 case ES_16:
326 tcg_gen_gvec_dup16i(vec_full_reg_offset(reg), 16, 16, c);
327 break;
328 case ES_32:
329 tcg_gen_gvec_dup32i(vec_full_reg_offset(reg), 16, 16, c);
330 break;
331 case ES_64:
332 gen_gvec_dup64i(reg, c);
333 break;
334 default:
335 g_assert_not_reached();
336 }
337}
338
339static void zero_vec(uint8_t reg)
340{
341 tcg_gen_gvec_dup8i(vec_full_reg_offset(reg), 16, 16, 0);
342}
343
344static void gen_addi2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
345 uint64_t b)
346{
347 TCGv_i64 bl = tcg_const_i64(b);
348 TCGv_i64 bh = tcg_const_i64(0);
349
350 tcg_gen_add2_i64(dl, dh, al, ah, bl, bh);
351 tcg_temp_free_i64(bl);
352 tcg_temp_free_i64(bh);
353}
354
355static DisasJumpType op_vge(DisasContext *s, DisasOps *o)
356{
357 const uint8_t es = s->insn->data;
358 const uint8_t enr = get_field(s->fields, m3);
359 TCGv_i64 tmp;
360
361 if (!valid_vec_element(enr, es)) {
362 gen_program_exception(s, PGM_SPECIFICATION);
363 return DISAS_NORETURN;
364 }
365
366 tmp = tcg_temp_new_i64();
367 read_vec_element_i64(tmp, get_field(s->fields, v2), enr, es);
368 tcg_gen_add_i64(o->addr1, o->addr1, tmp);
369 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 0);
370
371 tcg_gen_qemu_ld_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
372 write_vec_element_i64(tmp, get_field(s->fields, v1), enr, es);
373 tcg_temp_free_i64(tmp);
374 return DISAS_NEXT;
375}
376
377static uint64_t generate_byte_mask(uint8_t mask)
378{
379 uint64_t r = 0;
380 int i;
381
382 for (i = 0; i < 8; i++) {
383 if ((mask >> i) & 1) {
384 r |= 0xffull << (i * 8);
385 }
386 }
387 return r;
388}
389
390static DisasJumpType op_vgbm(DisasContext *s, DisasOps *o)
391{
392 const uint16_t i2 = get_field(s->fields, i2);
393
394 if (i2 == (i2 & 0xff) * 0x0101) {
395 /*
396 * Masks for both 64 bit elements of the vector are the same.
397 * Trust tcg to produce a good constant loading.
398 */
399 gen_gvec_dup64i(get_field(s->fields, v1),
400 generate_byte_mask(i2 & 0xff));
401 } else {
402 TCGv_i64 t = tcg_temp_new_i64();
403
404 tcg_gen_movi_i64(t, generate_byte_mask(i2 >> 8));
405 write_vec_element_i64(t, get_field(s->fields, v1), 0, ES_64);
406 tcg_gen_movi_i64(t, generate_byte_mask(i2));
407 write_vec_element_i64(t, get_field(s->fields, v1), 1, ES_64);
408 tcg_temp_free_i64(t);
409 }
410 return DISAS_NEXT;
411}
412
413static DisasJumpType op_vgm(DisasContext *s, DisasOps *o)
414{
415 const uint8_t es = get_field(s->fields, m4);
416 const uint8_t bits = NUM_VEC_ELEMENT_BITS(es);
417 const uint8_t i2 = get_field(s->fields, i2) & (bits - 1);
418 const uint8_t i3 = get_field(s->fields, i3) & (bits - 1);
419 uint64_t mask = 0;
420 int i;
421
422 if (es > ES_64) {
423 gen_program_exception(s, PGM_SPECIFICATION);
424 return DISAS_NORETURN;
425 }
426
427 /* generate the mask - take care of wrapping */
428 for (i = i2; ; i = (i + 1) % bits) {
429 mask |= 1ull << (bits - i - 1);
430 if (i == i3) {
431 break;
432 }
433 }
434
435 gen_gvec_dupi(es, get_field(s->fields, v1), mask);
436 return DISAS_NEXT;
437}
438
439static DisasJumpType op_vl(DisasContext *s, DisasOps *o)
440{
441 TCGv_i64 t0 = tcg_temp_new_i64();
442 TCGv_i64 t1 = tcg_temp_new_i64();
443
444 tcg_gen_qemu_ld_i64(t0, o->addr1, get_mem_index(s), MO_TEQ);
445 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
446 tcg_gen_qemu_ld_i64(t1, o->addr1, get_mem_index(s), MO_TEQ);
447 write_vec_element_i64(t0, get_field(s->fields, v1), 0, ES_64);
448 write_vec_element_i64(t1, get_field(s->fields, v1), 1, ES_64);
449 tcg_temp_free(t0);
450 tcg_temp_free(t1);
451 return DISAS_NEXT;
452}
453
454static DisasJumpType op_vlr(DisasContext *s, DisasOps *o)
455{
456 gen_gvec_mov(get_field(s->fields, v1), get_field(s->fields, v2));
457 return DISAS_NEXT;
458}
459
460static DisasJumpType op_vlrep(DisasContext *s, DisasOps *o)
461{
462 const uint8_t es = get_field(s->fields, m3);
463 TCGv_i64 tmp;
464
465 if (es > ES_64) {
466 gen_program_exception(s, PGM_SPECIFICATION);
467 return DISAS_NORETURN;
468 }
469
470 tmp = tcg_temp_new_i64();
471 tcg_gen_qemu_ld_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
472 gen_gvec_dup_i64(es, get_field(s->fields, v1), tmp);
473 tcg_temp_free_i64(tmp);
474 return DISAS_NEXT;
475}
476
477static DisasJumpType op_vle(DisasContext *s, DisasOps *o)
478{
479 const uint8_t es = s->insn->data;
480 const uint8_t enr = get_field(s->fields, m3);
481 TCGv_i64 tmp;
482
483 if (!valid_vec_element(enr, es)) {
484 gen_program_exception(s, PGM_SPECIFICATION);
485 return DISAS_NORETURN;
486 }
487
488 tmp = tcg_temp_new_i64();
489 tcg_gen_qemu_ld_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
490 write_vec_element_i64(tmp, get_field(s->fields, v1), enr, es);
491 tcg_temp_free_i64(tmp);
492 return DISAS_NEXT;
493}
494
495static DisasJumpType op_vlei(DisasContext *s, DisasOps *o)
496{
497 const uint8_t es = s->insn->data;
498 const uint8_t enr = get_field(s->fields, m3);
499 TCGv_i64 tmp;
500
501 if (!valid_vec_element(enr, es)) {
502 gen_program_exception(s, PGM_SPECIFICATION);
503 return DISAS_NORETURN;
504 }
505
506 tmp = tcg_const_i64((int16_t)get_field(s->fields, i2));
507 write_vec_element_i64(tmp, get_field(s->fields, v1), enr, es);
508 tcg_temp_free_i64(tmp);
509 return DISAS_NEXT;
510}
511
512static DisasJumpType op_vlgv(DisasContext *s, DisasOps *o)
513{
514 const uint8_t es = get_field(s->fields, m4);
515 TCGv_ptr ptr;
516
517 if (es > ES_64) {
518 gen_program_exception(s, PGM_SPECIFICATION);
519 return DISAS_NORETURN;
520 }
521
522 /* fast path if we don't need the register content */
523 if (!get_field(s->fields, b2)) {
524 uint8_t enr = get_field(s->fields, d2) & (NUM_VEC_ELEMENTS(es) - 1);
525
526 read_vec_element_i64(o->out, get_field(s->fields, v3), enr, es);
527 return DISAS_NEXT;
528 }
529
530 ptr = tcg_temp_new_ptr();
531 get_vec_element_ptr_i64(ptr, get_field(s->fields, v3), o->addr1, es);
532 switch (es) {
533 case ES_8:
534 tcg_gen_ld8u_i64(o->out, ptr, 0);
535 break;
536 case ES_16:
537 tcg_gen_ld16u_i64(o->out, ptr, 0);
538 break;
539 case ES_32:
540 tcg_gen_ld32u_i64(o->out, ptr, 0);
541 break;
542 case ES_64:
543 tcg_gen_ld_i64(o->out, ptr, 0);
544 break;
545 default:
546 g_assert_not_reached();
547 }
548 tcg_temp_free_ptr(ptr);
549
550 return DISAS_NEXT;
551}
552
553static DisasJumpType op_vllez(DisasContext *s, DisasOps *o)
554{
555 uint8_t es = get_field(s->fields, m3);
556 uint8_t enr;
557 TCGv_i64 t;
558
559 switch (es) {
560 /* rightmost sub-element of leftmost doubleword */
561 case ES_8:
562 enr = 7;
563 break;
564 case ES_16:
565 enr = 3;
566 break;
567 case ES_32:
568 enr = 1;
569 break;
570 case ES_64:
571 enr = 0;
572 break;
573 /* leftmost sub-element of leftmost doubleword */
574 case 6:
575 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
576 es = ES_32;
577 enr = 0;
578 break;
579 }
580 /* fallthrough */
581 default:
582 gen_program_exception(s, PGM_SPECIFICATION);
583 return DISAS_NORETURN;
584 }
585
586 t = tcg_temp_new_i64();
587 tcg_gen_qemu_ld_i64(t, o->addr1, get_mem_index(s), MO_TE | es);
588 zero_vec(get_field(s->fields, v1));
589 write_vec_element_i64(t, get_field(s->fields, v1), enr, es);
590 tcg_temp_free_i64(t);
591 return DISAS_NEXT;
592}
593
594static DisasJumpType op_vlm(DisasContext *s, DisasOps *o)
595{
596 const uint8_t v3 = get_field(s->fields, v3);
597 uint8_t v1 = get_field(s->fields, v1);
598 TCGv_i64 t0, t1;
599
600 if (v3 < v1 || (v3 - v1 + 1) > 16) {
601 gen_program_exception(s, PGM_SPECIFICATION);
602 return DISAS_NORETURN;
603 }
604
605 /*
606 * Check for possible access exceptions by trying to load the last
607 * element. The first element will be checked first next.
608 */
609 t0 = tcg_temp_new_i64();
610 t1 = tcg_temp_new_i64();
611 gen_addi_and_wrap_i64(s, t0, o->addr1, (v3 - v1) * 16 + 8);
612 tcg_gen_qemu_ld_i64(t0, t0, get_mem_index(s), MO_TEQ);
613
614 for (;; v1++) {
615 tcg_gen_qemu_ld_i64(t1, o->addr1, get_mem_index(s), MO_TEQ);
616 write_vec_element_i64(t1, v1, 0, ES_64);
617 if (v1 == v3) {
618 break;
619 }
620 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
621 tcg_gen_qemu_ld_i64(t1, o->addr1, get_mem_index(s), MO_TEQ);
622 write_vec_element_i64(t1, v1, 1, ES_64);
623 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
624 }
625
626 /* Store the last element, loaded first */
627 write_vec_element_i64(t0, v1, 1, ES_64);
628
629 tcg_temp_free_i64(t0);
630 tcg_temp_free_i64(t1);
631 return DISAS_NEXT;
632}
633
634static DisasJumpType op_vlbb(DisasContext *s, DisasOps *o)
635{
636 const int64_t block_size = (1ull << (get_field(s->fields, m3) + 6));
637 const int v1_offs = vec_full_reg_offset(get_field(s->fields, v1));
638 TCGv_ptr a0;
639 TCGv_i64 bytes;
640
641 if (get_field(s->fields, m3) > 6) {
642 gen_program_exception(s, PGM_SPECIFICATION);
643 return DISAS_NORETURN;
644 }
645
646 bytes = tcg_temp_new_i64();
647 a0 = tcg_temp_new_ptr();
648 /* calculate the number of bytes until the next block boundary */
649 tcg_gen_ori_i64(bytes, o->addr1, -block_size);
650 tcg_gen_neg_i64(bytes, bytes);
651
652 tcg_gen_addi_ptr(a0, cpu_env, v1_offs);
653 gen_helper_vll(cpu_env, a0, o->addr1, bytes);
654 tcg_temp_free_i64(bytes);
655 tcg_temp_free_ptr(a0);
656 return DISAS_NEXT;
657}
658
659static DisasJumpType op_vlvg(DisasContext *s, DisasOps *o)
660{
661 const uint8_t es = get_field(s->fields, m4);
662 TCGv_ptr ptr;
663
664 if (es > ES_64) {
665 gen_program_exception(s, PGM_SPECIFICATION);
666 return DISAS_NORETURN;
667 }
668
669 /* fast path if we don't need the register content */
670 if (!get_field(s->fields, b2)) {
671 uint8_t enr = get_field(s->fields, d2) & (NUM_VEC_ELEMENTS(es) - 1);
672
673 write_vec_element_i64(o->in2, get_field(s->fields, v1), enr, es);
674 return DISAS_NEXT;
675 }
676
677 ptr = tcg_temp_new_ptr();
678 get_vec_element_ptr_i64(ptr, get_field(s->fields, v1), o->addr1, es);
679 switch (es) {
680 case ES_8:
681 tcg_gen_st8_i64(o->in2, ptr, 0);
682 break;
683 case ES_16:
684 tcg_gen_st16_i64(o->in2, ptr, 0);
685 break;
686 case ES_32:
687 tcg_gen_st32_i64(o->in2, ptr, 0);
688 break;
689 case ES_64:
690 tcg_gen_st_i64(o->in2, ptr, 0);
691 break;
692 default:
693 g_assert_not_reached();
694 }
695 tcg_temp_free_ptr(ptr);
696
697 return DISAS_NEXT;
698}
699
700static DisasJumpType op_vlvgp(DisasContext *s, DisasOps *o)
701{
702 write_vec_element_i64(o->in1, get_field(s->fields, v1), 0, ES_64);
703 write_vec_element_i64(o->in2, get_field(s->fields, v1), 1, ES_64);
704 return DISAS_NEXT;
705}
706
707static DisasJumpType op_vll(DisasContext *s, DisasOps *o)
708{
709 const int v1_offs = vec_full_reg_offset(get_field(s->fields, v1));
710 TCGv_ptr a0 = tcg_temp_new_ptr();
711
712 /* convert highest index into an actual length */
713 tcg_gen_addi_i64(o->in2, o->in2, 1);
714 tcg_gen_addi_ptr(a0, cpu_env, v1_offs);
715 gen_helper_vll(cpu_env, a0, o->addr1, o->in2);
716 tcg_temp_free_ptr(a0);
717 return DISAS_NEXT;
718}
719
720static DisasJumpType op_vmr(DisasContext *s, DisasOps *o)
721{
722 const uint8_t v1 = get_field(s->fields, v1);
723 const uint8_t v2 = get_field(s->fields, v2);
724 const uint8_t v3 = get_field(s->fields, v3);
725 const uint8_t es = get_field(s->fields, m4);
726 int dst_idx, src_idx;
727 TCGv_i64 tmp;
728
729 if (es > ES_64) {
730 gen_program_exception(s, PGM_SPECIFICATION);
731 return DISAS_NORETURN;
732 }
733
734 tmp = tcg_temp_new_i64();
735 if (s->fields->op2 == 0x61) {
736 /* iterate backwards to avoid overwriting data we might need later */
737 for (dst_idx = NUM_VEC_ELEMENTS(es) - 1; dst_idx >= 0; dst_idx--) {
738 src_idx = dst_idx / 2;
739 if (dst_idx % 2 == 0) {
740 read_vec_element_i64(tmp, v2, src_idx, es);
741 } else {
742 read_vec_element_i64(tmp, v3, src_idx, es);
743 }
744 write_vec_element_i64(tmp, v1, dst_idx, es);
745 }
746 } else {
747 /* iterate forward to avoid overwriting data we might need later */
748 for (dst_idx = 0; dst_idx < NUM_VEC_ELEMENTS(es); dst_idx++) {
749 src_idx = (dst_idx + NUM_VEC_ELEMENTS(es)) / 2;
750 if (dst_idx % 2 == 0) {
751 read_vec_element_i64(tmp, v2, src_idx, es);
752 } else {
753 read_vec_element_i64(tmp, v3, src_idx, es);
754 }
755 write_vec_element_i64(tmp, v1, dst_idx, es);
756 }
757 }
758 tcg_temp_free_i64(tmp);
759 return DISAS_NEXT;
760}
761
762static DisasJumpType op_vpk(DisasContext *s, DisasOps *o)
763{
764 const uint8_t v1 = get_field(s->fields, v1);
765 const uint8_t v2 = get_field(s->fields, v2);
766 const uint8_t v3 = get_field(s->fields, v3);
767 const uint8_t es = get_field(s->fields, m4);
768 static gen_helper_gvec_3 * const vpk[3] = {
769 gen_helper_gvec_vpk16,
770 gen_helper_gvec_vpk32,
771 gen_helper_gvec_vpk64,
772 };
773 static gen_helper_gvec_3 * const vpks[3] = {
774 gen_helper_gvec_vpks16,
775 gen_helper_gvec_vpks32,
776 gen_helper_gvec_vpks64,
777 };
778 static gen_helper_gvec_3_ptr * const vpks_cc[3] = {
779 gen_helper_gvec_vpks_cc16,
780 gen_helper_gvec_vpks_cc32,
781 gen_helper_gvec_vpks_cc64,
782 };
783 static gen_helper_gvec_3 * const vpkls[3] = {
784 gen_helper_gvec_vpkls16,
785 gen_helper_gvec_vpkls32,
786 gen_helper_gvec_vpkls64,
787 };
788 static gen_helper_gvec_3_ptr * const vpkls_cc[3] = {
789 gen_helper_gvec_vpkls_cc16,
790 gen_helper_gvec_vpkls_cc32,
791 gen_helper_gvec_vpkls_cc64,
792 };
793
794 if (es == ES_8 || es > ES_64) {
795 gen_program_exception(s, PGM_SPECIFICATION);
796 return DISAS_NORETURN;
797 }
798
799 switch (s->fields->op2) {
800 case 0x97:
801 if (get_field(s->fields, m5) & 0x1) {
802 gen_gvec_3_ptr(v1, v2, v3, cpu_env, 0, vpks_cc[es - 1]);
803 set_cc_static(s);
804 } else {
805 gen_gvec_3_ool(v1, v2, v3, 0, vpks[es - 1]);
806 }
807 break;
808 case 0x95:
809 if (get_field(s->fields, m5) & 0x1) {
810 gen_gvec_3_ptr(v1, v2, v3, cpu_env, 0, vpkls_cc[es - 1]);
811 set_cc_static(s);
812 } else {
813 gen_gvec_3_ool(v1, v2, v3, 0, vpkls[es - 1]);
814 }
815 break;
816 case 0x94:
817 /* If sources and destination dont't overlap -> fast path */
818 if (v1 != v2 && v1 != v3) {
819 const uint8_t src_es = get_field(s->fields, m4);
820 const uint8_t dst_es = src_es - 1;
821 TCGv_i64 tmp = tcg_temp_new_i64();
822 int dst_idx, src_idx;
823
824 for (dst_idx = 0; dst_idx < NUM_VEC_ELEMENTS(dst_es); dst_idx++) {
825 src_idx = dst_idx;
826 if (src_idx < NUM_VEC_ELEMENTS(src_es)) {
827 read_vec_element_i64(tmp, v2, src_idx, src_es);
828 } else {
829 src_idx -= NUM_VEC_ELEMENTS(src_es);
830 read_vec_element_i64(tmp, v3, src_idx, src_es);
831 }
832 write_vec_element_i64(tmp, v1, dst_idx, dst_es);
833 }
834 tcg_temp_free_i64(tmp);
835 } else {
836 gen_gvec_3_ool(v1, v2, v3, 0, vpk[es - 1]);
837 }
838 break;
839 default:
840 g_assert_not_reached();
841 }
842 return DISAS_NEXT;
843}
844
845static DisasJumpType op_vperm(DisasContext *s, DisasOps *o)
846{
847 gen_gvec_4_ool(get_field(s->fields, v1), get_field(s->fields, v2),
848 get_field(s->fields, v3), get_field(s->fields, v4),
849 0, gen_helper_gvec_vperm);
850 return DISAS_NEXT;
851}
852
853static DisasJumpType op_vpdi(DisasContext *s, DisasOps *o)
854{
855 const uint8_t i2 = extract32(get_field(s->fields, m4), 2, 1);
856 const uint8_t i3 = extract32(get_field(s->fields, m4), 0, 1);
857 TCGv_i64 t0 = tcg_temp_new_i64();
858 TCGv_i64 t1 = tcg_temp_new_i64();
859
860 read_vec_element_i64(t0, get_field(s->fields, v2), i2, ES_64);
861 read_vec_element_i64(t1, get_field(s->fields, v3), i3, ES_64);
862 write_vec_element_i64(t0, get_field(s->fields, v1), 0, ES_64);
863 write_vec_element_i64(t1, get_field(s->fields, v1), 1, ES_64);
864 tcg_temp_free_i64(t0);
865 tcg_temp_free_i64(t1);
866 return DISAS_NEXT;
867}
868
869static DisasJumpType op_vrep(DisasContext *s, DisasOps *o)
870{
871 const uint8_t enr = get_field(s->fields, i2);
872 const uint8_t es = get_field(s->fields, m4);
873
874 if (es > ES_64 || !valid_vec_element(enr, es)) {
875 gen_program_exception(s, PGM_SPECIFICATION);
876 return DISAS_NORETURN;
877 }
878
879 tcg_gen_gvec_dup_mem(es, vec_full_reg_offset(get_field(s->fields, v1)),
880 vec_reg_offset(get_field(s->fields, v3), enr, es),
881 16, 16);
882 return DISAS_NEXT;
883}
884
885static DisasJumpType op_vrepi(DisasContext *s, DisasOps *o)
886{
887 const int64_t data = (int16_t)get_field(s->fields, i2);
888 const uint8_t es = get_field(s->fields, m3);
889
890 if (es > ES_64) {
891 gen_program_exception(s, PGM_SPECIFICATION);
892 return DISAS_NORETURN;
893 }
894
895 gen_gvec_dupi(es, get_field(s->fields, v1), data);
896 return DISAS_NEXT;
897}
898
899static DisasJumpType op_vsce(DisasContext *s, DisasOps *o)
900{
901 const uint8_t es = s->insn->data;
902 const uint8_t enr = get_field(s->fields, m3);
903 TCGv_i64 tmp;
904
905 if (!valid_vec_element(enr, es)) {
906 gen_program_exception(s, PGM_SPECIFICATION);
907 return DISAS_NORETURN;
908 }
909
910 tmp = tcg_temp_new_i64();
911 read_vec_element_i64(tmp, get_field(s->fields, v2), enr, es);
912 tcg_gen_add_i64(o->addr1, o->addr1, tmp);
913 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 0);
914
915 read_vec_element_i64(tmp, get_field(s->fields, v1), enr, es);
916 tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
917 tcg_temp_free_i64(tmp);
918 return DISAS_NEXT;
919}
920
921static DisasJumpType op_vsel(DisasContext *s, DisasOps *o)
922{
923 gen_gvec_fn_4(bitsel, ES_8, get_field(s->fields, v1),
924 get_field(s->fields, v4), get_field(s->fields, v2),
925 get_field(s->fields, v3));
926 return DISAS_NEXT;
927}
928
929static DisasJumpType op_vseg(DisasContext *s, DisasOps *o)
930{
931 const uint8_t es = get_field(s->fields, m3);
932 int idx1, idx2;
933 TCGv_i64 tmp;
934
935 switch (es) {
936 case ES_8:
937 idx1 = 7;
938 idx2 = 15;
939 break;
940 case ES_16:
941 idx1 = 3;
942 idx2 = 7;
943 break;
944 case ES_32:
945 idx1 = 1;
946 idx2 = 3;
947 break;
948 default:
949 gen_program_exception(s, PGM_SPECIFICATION);
950 return DISAS_NORETURN;
951 }
952
953 tmp = tcg_temp_new_i64();
954 read_vec_element_i64(tmp, get_field(s->fields, v2), idx1, es | MO_SIGN);
955 write_vec_element_i64(tmp, get_field(s->fields, v1), 0, ES_64);
956 read_vec_element_i64(tmp, get_field(s->fields, v2), idx2, es | MO_SIGN);
957 write_vec_element_i64(tmp, get_field(s->fields, v1), 1, ES_64);
958 tcg_temp_free_i64(tmp);
959 return DISAS_NEXT;
960}
961
962static DisasJumpType op_vst(DisasContext *s, DisasOps *o)
963{
964 TCGv_i64 tmp = tcg_const_i64(16);
965
966 /* Probe write access before actually modifying memory */
967 gen_helper_probe_write_access(cpu_env, o->addr1, tmp);
968
969 read_vec_element_i64(tmp, get_field(s->fields, v1), 0, ES_64);
970 tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEQ);
971 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
972 read_vec_element_i64(tmp, get_field(s->fields, v1), 1, ES_64);
973 tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEQ);
974 tcg_temp_free_i64(tmp);
975 return DISAS_NEXT;
976}
977
978static DisasJumpType op_vste(DisasContext *s, DisasOps *o)
979{
980 const uint8_t es = s->insn->data;
981 const uint8_t enr = get_field(s->fields, m3);
982 TCGv_i64 tmp;
983
984 if (!valid_vec_element(enr, es)) {
985 gen_program_exception(s, PGM_SPECIFICATION);
986 return DISAS_NORETURN;
987 }
988
989 tmp = tcg_temp_new_i64();
990 read_vec_element_i64(tmp, get_field(s->fields, v1), enr, es);
991 tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
992 tcg_temp_free_i64(tmp);
993 return DISAS_NEXT;
994}
995
996static DisasJumpType op_vstm(DisasContext *s, DisasOps *o)
997{
998 const uint8_t v3 = get_field(s->fields, v3);
999 uint8_t v1 = get_field(s->fields, v1);
1000 TCGv_i64 tmp;
1001
1002 while (v3 < v1 || (v3 - v1 + 1) > 16) {
1003 gen_program_exception(s, PGM_SPECIFICATION);
1004 return DISAS_NORETURN;
1005 }
1006
1007 /* Probe write access before actually modifying memory */
1008 tmp = tcg_const_i64((v3 - v1 + 1) * 16);
1009 gen_helper_probe_write_access(cpu_env, o->addr1, tmp);
1010
1011 for (;; v1++) {
1012 read_vec_element_i64(tmp, v1, 0, ES_64);
1013 tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEQ);
1014 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
1015 read_vec_element_i64(tmp, v1, 1, ES_64);
1016 tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEQ);
1017 if (v1 == v3) {
1018 break;
1019 }
1020 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
1021 }
1022 tcg_temp_free_i64(tmp);
1023 return DISAS_NEXT;
1024}
1025
1026static DisasJumpType op_vstl(DisasContext *s, DisasOps *o)
1027{
1028 const int v1_offs = vec_full_reg_offset(get_field(s->fields, v1));
1029 TCGv_ptr a0 = tcg_temp_new_ptr();
1030
1031 /* convert highest index into an actual length */
1032 tcg_gen_addi_i64(o->in2, o->in2, 1);
1033 tcg_gen_addi_ptr(a0, cpu_env, v1_offs);
1034 gen_helper_vstl(cpu_env, a0, o->addr1, o->in2);
1035 tcg_temp_free_ptr(a0);
1036 return DISAS_NEXT;
1037}
1038
1039static DisasJumpType op_vup(DisasContext *s, DisasOps *o)
1040{
1041 const bool logical = s->fields->op2 == 0xd4 || s->fields->op2 == 0xd5;
1042 const uint8_t v1 = get_field(s->fields, v1);
1043 const uint8_t v2 = get_field(s->fields, v2);
1044 const uint8_t src_es = get_field(s->fields, m3);
1045 const uint8_t dst_es = src_es + 1;
1046 int dst_idx, src_idx;
1047 TCGv_i64 tmp;
1048
1049 if (src_es > ES_32) {
1050 gen_program_exception(s, PGM_SPECIFICATION);
1051 return DISAS_NORETURN;
1052 }
1053
1054 tmp = tcg_temp_new_i64();
1055 if (s->fields->op2 == 0xd7 || s->fields->op2 == 0xd5) {
1056 /* iterate backwards to avoid overwriting data we might need later */
1057 for (dst_idx = NUM_VEC_ELEMENTS(dst_es) - 1; dst_idx >= 0; dst_idx--) {
1058 src_idx = dst_idx;
1059 read_vec_element_i64(tmp, v2, src_idx,
1060 src_es | (logical ? 0 : MO_SIGN));
1061 write_vec_element_i64(tmp, v1, dst_idx, dst_es);
1062 }
1063
1064 } else {
1065 /* iterate forward to avoid overwriting data we might need later */
1066 for (dst_idx = 0; dst_idx < NUM_VEC_ELEMENTS(dst_es); dst_idx++) {
1067 src_idx = dst_idx + NUM_VEC_ELEMENTS(src_es) / 2;
1068 read_vec_element_i64(tmp, v2, src_idx,
1069 src_es | (logical ? 0 : MO_SIGN));
1070 write_vec_element_i64(tmp, v1, dst_idx, dst_es);
1071 }
1072 }
1073 tcg_temp_free_i64(tmp);
1074 return DISAS_NEXT;
1075}
1076
1077static DisasJumpType op_va(DisasContext *s, DisasOps *o)
1078{
1079 const uint8_t es = get_field(s->fields, m4);
1080
1081 if (es > ES_128) {
1082 gen_program_exception(s, PGM_SPECIFICATION);
1083 return DISAS_NORETURN;
1084 } else if (es == ES_128) {
1085 gen_gvec128_3_i64(tcg_gen_add2_i64, get_field(s->fields, v1),
1086 get_field(s->fields, v2), get_field(s->fields, v3));
1087 return DISAS_NEXT;
1088 }
1089 gen_gvec_fn_3(add, es, get_field(s->fields, v1), get_field(s->fields, v2),
1090 get_field(s->fields, v3));
1091 return DISAS_NEXT;
1092}
1093
1094static void gen_acc(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b, uint8_t es)
1095{
1096 const uint8_t msb_bit_nr = NUM_VEC_ELEMENT_BITS(es) - 1;
1097 TCGv_i64 msb_mask = tcg_const_i64(dup_const(es, 1ull << msb_bit_nr));
1098 TCGv_i64 t1 = tcg_temp_new_i64();
1099 TCGv_i64 t2 = tcg_temp_new_i64();
1100 TCGv_i64 t3 = tcg_temp_new_i64();
1101
1102 /* Calculate the carry into the MSB, ignoring the old MSBs */
1103 tcg_gen_andc_i64(t1, a, msb_mask);
1104 tcg_gen_andc_i64(t2, b, msb_mask);
1105 tcg_gen_add_i64(t1, t1, t2);
1106 /* Calculate the MSB without any carry into it */
1107 tcg_gen_xor_i64(t3, a, b);
1108 /* Calculate the carry out of the MSB in the MSB bit position */
1109 tcg_gen_and_i64(d, a, b);
1110 tcg_gen_and_i64(t1, t1, t3);
1111 tcg_gen_or_i64(d, d, t1);
1112 /* Isolate and shift the carry into position */
1113 tcg_gen_and_i64(d, d, msb_mask);
1114 tcg_gen_shri_i64(d, d, msb_bit_nr);
1115
1116 tcg_temp_free_i64(t1);
1117 tcg_temp_free_i64(t2);
1118 tcg_temp_free_i64(t3);
1119}
1120
1121static void gen_acc8_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
1122{
1123 gen_acc(d, a, b, ES_8);
1124}
1125
1126static void gen_acc16_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
1127{
1128 gen_acc(d, a, b, ES_16);
1129}
1130
1131static void gen_acc_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
1132{
1133 TCGv_i32 t = tcg_temp_new_i32();
1134
1135 tcg_gen_add_i32(t, a, b);
1136 tcg_gen_setcond_i32(TCG_COND_LTU, d, t, b);
1137 tcg_temp_free_i32(t);
1138}
1139
1140static void gen_acc_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
1141{
1142 TCGv_i64 t = tcg_temp_new_i64();
1143
1144 tcg_gen_add_i64(t, a, b);
1145 tcg_gen_setcond_i64(TCG_COND_LTU, d, t, b);
1146 tcg_temp_free_i64(t);
1147}
1148
1149static void gen_acc2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al,
1150 TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh)
1151{
1152 TCGv_i64 th = tcg_temp_new_i64();
1153 TCGv_i64 tl = tcg_temp_new_i64();
1154 TCGv_i64 zero = tcg_const_i64(0);
1155
1156 tcg_gen_add2_i64(tl, th, al, zero, bl, zero);
1157 tcg_gen_add2_i64(tl, th, th, zero, ah, zero);
1158 tcg_gen_add2_i64(tl, dl, tl, th, bh, zero);
1159 tcg_gen_mov_i64(dh, zero);
1160
1161 tcg_temp_free_i64(th);
1162 tcg_temp_free_i64(tl);
1163 tcg_temp_free_i64(zero);
1164}
1165
1166static DisasJumpType op_vacc(DisasContext *s, DisasOps *o)
1167{
1168 const uint8_t es = get_field(s->fields, m4);
1169 static const GVecGen3 g[4] = {
1170 { .fni8 = gen_acc8_i64, },
1171 { .fni8 = gen_acc16_i64, },
1172 { .fni4 = gen_acc_i32, },
1173 { .fni8 = gen_acc_i64, },
1174 };
1175
1176 if (es > ES_128) {
1177 gen_program_exception(s, PGM_SPECIFICATION);
1178 return DISAS_NORETURN;
1179 } else if (es == ES_128) {
1180 gen_gvec128_3_i64(gen_acc2_i64, get_field(s->fields, v1),
1181 get_field(s->fields, v2), get_field(s->fields, v3));
1182 return DISAS_NEXT;
1183 }
1184 gen_gvec_3(get_field(s->fields, v1), get_field(s->fields, v2),
1185 get_field(s->fields, v3), &g[es]);
1186 return DISAS_NEXT;
1187}
1188
1189static void gen_ac2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
1190 TCGv_i64 bl, TCGv_i64 bh, TCGv_i64 cl, TCGv_i64 ch)
1191{
1192 TCGv_i64 tl = tcg_temp_new_i64();
1193 TCGv_i64 th = tcg_const_i64(0);
1194
1195 /* extract the carry only */
1196 tcg_gen_extract_i64(tl, cl, 0, 1);
1197 tcg_gen_add2_i64(dl, dh, al, ah, bl, bh);
1198 tcg_gen_add2_i64(dl, dh, dl, dh, tl, th);
1199
1200 tcg_temp_free_i64(tl);
1201 tcg_temp_free_i64(th);
1202}
1203
1204static DisasJumpType op_vac(DisasContext *s, DisasOps *o)
1205{
1206 if (get_field(s->fields, m5) != ES_128) {
1207 gen_program_exception(s, PGM_SPECIFICATION);
1208 return DISAS_NORETURN;
1209 }
1210
1211 gen_gvec128_4_i64(gen_ac2_i64, get_field(s->fields, v1),
1212 get_field(s->fields, v2), get_field(s->fields, v3),
1213 get_field(s->fields, v4));
1214 return DISAS_NEXT;
1215}
1216
1217static void gen_accc2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
1218 TCGv_i64 bl, TCGv_i64 bh, TCGv_i64 cl, TCGv_i64 ch)
1219{
1220 TCGv_i64 tl = tcg_temp_new_i64();
1221 TCGv_i64 th = tcg_temp_new_i64();
1222 TCGv_i64 zero = tcg_const_i64(0);
1223
1224 tcg_gen_andi_i64(tl, cl, 1);
1225 tcg_gen_add2_i64(tl, th, tl, zero, al, zero);
1226 tcg_gen_add2_i64(tl, th, tl, th, bl, zero);
1227 tcg_gen_add2_i64(tl, th, th, zero, ah, zero);
1228 tcg_gen_add2_i64(tl, dl, tl, th, bh, zero);
1229 tcg_gen_mov_i64(dh, zero);
1230
1231 tcg_temp_free_i64(tl);
1232 tcg_temp_free_i64(th);
1233 tcg_temp_free_i64(zero);
1234}
1235
1236static DisasJumpType op_vaccc(DisasContext *s, DisasOps *o)
1237{
1238 if (get_field(s->fields, m5) != ES_128) {
1239 gen_program_exception(s, PGM_SPECIFICATION);
1240 return DISAS_NORETURN;
1241 }
1242
1243 gen_gvec128_4_i64(gen_accc2_i64, get_field(s->fields, v1),
1244 get_field(s->fields, v2), get_field(s->fields, v3),
1245 get_field(s->fields, v4));
1246 return DISAS_NEXT;
1247}
1248
1249static DisasJumpType op_vn(DisasContext *s, DisasOps *o)
1250{
1251 gen_gvec_fn_3(and, ES_8, get_field(s->fields, v1), get_field(s->fields, v2),
1252 get_field(s->fields, v3));
1253 return DISAS_NEXT;
1254}
1255
1256static DisasJumpType op_vnc(DisasContext *s, DisasOps *o)
1257{
1258 gen_gvec_fn_3(andc, ES_8, get_field(s->fields, v1),
1259 get_field(s->fields, v2), get_field(s->fields, v3));
1260 return DISAS_NEXT;
1261}
1262
1263static void gen_avg_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
1264{
1265 TCGv_i64 t0 = tcg_temp_new_i64();
1266 TCGv_i64 t1 = tcg_temp_new_i64();
1267
1268 tcg_gen_ext_i32_i64(t0, a);
1269 tcg_gen_ext_i32_i64(t1, b);
1270 tcg_gen_add_i64(t0, t0, t1);
1271 tcg_gen_addi_i64(t0, t0, 1);
1272 tcg_gen_shri_i64(t0, t0, 1);
1273 tcg_gen_extrl_i64_i32(d, t0);
1274
1275 tcg_temp_free(t0);
1276 tcg_temp_free(t1);
1277}
1278
1279static void gen_avg_i64(TCGv_i64 dl, TCGv_i64 al, TCGv_i64 bl)
1280{
1281 TCGv_i64 dh = tcg_temp_new_i64();
1282 TCGv_i64 ah = tcg_temp_new_i64();
1283 TCGv_i64 bh = tcg_temp_new_i64();
1284
1285 /* extending the sign by one bit is sufficient */
1286 tcg_gen_extract_i64(ah, al, 63, 1);
1287 tcg_gen_extract_i64(bh, bl, 63, 1);
1288 tcg_gen_add2_i64(dl, dh, al, ah, bl, bh);
1289 gen_addi2_i64(dl, dh, dl, dh, 1);
1290 tcg_gen_extract2_i64(dl, dl, dh, 1);
1291
1292 tcg_temp_free_i64(dh);
1293 tcg_temp_free_i64(ah);
1294 tcg_temp_free_i64(bh);
1295}
1296
1297static DisasJumpType op_vavg(DisasContext *s, DisasOps *o)
1298{
1299 const uint8_t es = get_field(s->fields, m4);
1300 static const GVecGen3 g[4] = {
1301 { .fno = gen_helper_gvec_vavg8, },
1302 { .fno = gen_helper_gvec_vavg16, },
1303 { .fni4 = gen_avg_i32, },
1304 { .fni8 = gen_avg_i64, },
1305 };
1306
1307 if (es > ES_64) {
1308 gen_program_exception(s, PGM_SPECIFICATION);
1309 return DISAS_NORETURN;
1310 }
1311 gen_gvec_3(get_field(s->fields, v1), get_field(s->fields, v2),
1312 get_field(s->fields, v3), &g[es]);
1313 return DISAS_NEXT;
1314}
1315
1316static void gen_avgl_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
1317{
1318 TCGv_i64 t0 = tcg_temp_new_i64();
1319 TCGv_i64 t1 = tcg_temp_new_i64();
1320
1321 tcg_gen_extu_i32_i64(t0, a);
1322 tcg_gen_extu_i32_i64(t1, b);
1323 tcg_gen_add_i64(t0, t0, t1);
1324 tcg_gen_addi_i64(t0, t0, 1);
1325 tcg_gen_shri_i64(t0, t0, 1);
1326 tcg_gen_extrl_i64_i32(d, t0);
1327
1328 tcg_temp_free(t0);
1329 tcg_temp_free(t1);
1330}
1331
1332static void gen_avgl_i64(TCGv_i64 dl, TCGv_i64 al, TCGv_i64 bl)
1333{
1334 TCGv_i64 dh = tcg_temp_new_i64();
1335 TCGv_i64 zero = tcg_const_i64(0);
1336
1337 tcg_gen_add2_i64(dl, dh, al, zero, bl, zero);
1338 gen_addi2_i64(dl, dh, dl, dh, 1);
1339 tcg_gen_extract2_i64(dl, dl, dh, 1);
1340
1341 tcg_temp_free_i64(dh);
1342 tcg_temp_free_i64(zero);
1343}
1344
1345static DisasJumpType op_vavgl(DisasContext *s, DisasOps *o)
1346{
1347 const uint8_t es = get_field(s->fields, m4);
1348 static const GVecGen3 g[4] = {
1349 { .fno = gen_helper_gvec_vavgl8, },
1350 { .fno = gen_helper_gvec_vavgl16, },
1351 { .fni4 = gen_avgl_i32, },
1352 { .fni8 = gen_avgl_i64, },
1353 };
1354
1355 if (es > ES_64) {
1356 gen_program_exception(s, PGM_SPECIFICATION);
1357 return DISAS_NORETURN;
1358 }
1359 gen_gvec_3(get_field(s->fields, v1), get_field(s->fields, v2),
1360 get_field(s->fields, v3), &g[es]);
1361 return DISAS_NEXT;
1362}
1363
1364static DisasJumpType op_vcksm(DisasContext *s, DisasOps *o)
1365{
1366 TCGv_i32 tmp = tcg_temp_new_i32();
1367 TCGv_i32 sum = tcg_temp_new_i32();
1368 int i;
1369
1370 read_vec_element_i32(sum, get_field(s->fields, v3), 1, ES_32);
1371 for (i = 0; i < 4; i++) {
1372 read_vec_element_i32(tmp, get_field(s->fields, v2), i, ES_32);
1373 tcg_gen_add2_i32(tmp, sum, sum, sum, tmp, tmp);
1374 }
1375 zero_vec(get_field(s->fields, v1));
1376 write_vec_element_i32(sum, get_field(s->fields, v1), 1, ES_32);
1377
1378 tcg_temp_free_i32(tmp);
1379 tcg_temp_free_i32(sum);
1380 return DISAS_NEXT;
1381}
1382
1383static DisasJumpType op_vec(DisasContext *s, DisasOps *o)
1384{
1385 uint8_t es = get_field(s->fields, m3);
1386 const uint8_t enr = NUM_VEC_ELEMENTS(es) / 2 - 1;
1387
1388 if (es > ES_64) {
1389 gen_program_exception(s, PGM_SPECIFICATION);
1390 return DISAS_NORETURN;
1391 }
1392 if (s->fields->op2 == 0xdb) {
1393 es |= MO_SIGN;
1394 }
1395
1396 o->in1 = tcg_temp_new_i64();
1397 o->in2 = tcg_temp_new_i64();
1398 read_vec_element_i64(o->in1, get_field(s->fields, v1), enr, es);
1399 read_vec_element_i64(o->in2, get_field(s->fields, v2), enr, es);
1400 return DISAS_NEXT;
1401}
1402
1403static DisasJumpType op_vc(DisasContext *s, DisasOps *o)
1404{
1405 const uint8_t es = get_field(s->fields, m4);
1406 TCGCond cond = s->insn->data;
1407
1408 if (es > ES_64) {
1409 gen_program_exception(s, PGM_SPECIFICATION);
1410 return DISAS_NORETURN;
1411 }
1412
1413 tcg_gen_gvec_cmp(cond, es,
1414 vec_full_reg_offset(get_field(s->fields, v1)),
1415 vec_full_reg_offset(get_field(s->fields, v2)),
1416 vec_full_reg_offset(get_field(s->fields, v3)), 16, 16);
1417 if (get_field(s->fields, m5) & 0x1) {
1418 TCGv_i64 low = tcg_temp_new_i64();
1419 TCGv_i64 high = tcg_temp_new_i64();
1420
1421 read_vec_element_i64(high, get_field(s->fields, v1), 0, ES_64);
1422 read_vec_element_i64(low, get_field(s->fields, v1), 1, ES_64);
1423 gen_op_update2_cc_i64(s, CC_OP_VC, low, high);
1424
1425 tcg_temp_free_i64(low);
1426 tcg_temp_free_i64(high);
1427 }
1428 return DISAS_NEXT;
1429}
1430
1431static void gen_clz_i32(TCGv_i32 d, TCGv_i32 a)
1432{
1433 tcg_gen_clzi_i32(d, a, 32);
1434}
1435
1436static void gen_clz_i64(TCGv_i64 d, TCGv_i64 a)
1437{
1438 tcg_gen_clzi_i64(d, a, 64);
1439}
1440
1441static DisasJumpType op_vclz(DisasContext *s, DisasOps *o)
1442{
1443 const uint8_t es = get_field(s->fields, m3);
1444 static const GVecGen2 g[4] = {
1445 { .fno = gen_helper_gvec_vclz8, },
1446 { .fno = gen_helper_gvec_vclz16, },
1447 { .fni4 = gen_clz_i32, },
1448 { .fni8 = gen_clz_i64, },
1449 };
1450
1451 if (es > ES_64) {
1452 gen_program_exception(s, PGM_SPECIFICATION);
1453 return DISAS_NORETURN;
1454 }
1455 gen_gvec_2(get_field(s->fields, v1), get_field(s->fields, v2), &g[es]);
1456 return DISAS_NEXT;
1457}
1458
1459static void gen_ctz_i32(TCGv_i32 d, TCGv_i32 a)
1460{
1461 tcg_gen_ctzi_i32(d, a, 32);
1462}
1463
1464static void gen_ctz_i64(TCGv_i64 d, TCGv_i64 a)
1465{
1466 tcg_gen_ctzi_i64(d, a, 64);
1467}
1468
1469static DisasJumpType op_vctz(DisasContext *s, DisasOps *o)
1470{
1471 const uint8_t es = get_field(s->fields, m3);
1472 static const GVecGen2 g[4] = {
1473 { .fno = gen_helper_gvec_vctz8, },
1474 { .fno = gen_helper_gvec_vctz16, },
1475 { .fni4 = gen_ctz_i32, },
1476 { .fni8 = gen_ctz_i64, },
1477 };
1478
1479 if (es > ES_64) {
1480 gen_program_exception(s, PGM_SPECIFICATION);
1481 return DISAS_NORETURN;
1482 }
1483 gen_gvec_2(get_field(s->fields, v1), get_field(s->fields, v2), &g[es]);
1484 return DISAS_NEXT;
1485}
1486
1487static DisasJumpType op_vx(DisasContext *s, DisasOps *o)
1488{
1489 gen_gvec_fn_3(xor, ES_8, get_field(s->fields, v1), get_field(s->fields, v2),
1490 get_field(s->fields, v3));
1491 return DISAS_NEXT;
1492}
1493
1494static DisasJumpType op_vgfm(DisasContext *s, DisasOps *o)
1495{
1496 const uint8_t es = get_field(s->fields, m4);
1497 static const GVecGen3 g[4] = {
1498 { .fno = gen_helper_gvec_vgfm8, },
1499 { .fno = gen_helper_gvec_vgfm16, },
1500 { .fno = gen_helper_gvec_vgfm32, },
1501 { .fno = gen_helper_gvec_vgfm64, },
1502 };
1503
1504 if (es > ES_64) {
1505 gen_program_exception(s, PGM_SPECIFICATION);
1506 return DISAS_NORETURN;
1507 }
1508 gen_gvec_3(get_field(s->fields, v1), get_field(s->fields, v2),
1509 get_field(s->fields, v3), &g[es]);
1510 return DISAS_NEXT;
1511}
1512
1513static DisasJumpType op_vgfma(DisasContext *s, DisasOps *o)
1514{
1515 const uint8_t es = get_field(s->fields, m5);
1516 static const GVecGen4 g[4] = {
1517 { .fno = gen_helper_gvec_vgfma8, },
1518 { .fno = gen_helper_gvec_vgfma16, },
1519 { .fno = gen_helper_gvec_vgfma32, },
1520 { .fno = gen_helper_gvec_vgfma64, },
1521 };
1522
1523 if (es > ES_64) {
1524 gen_program_exception(s, PGM_SPECIFICATION);
1525 return DISAS_NORETURN;
1526 }
1527 gen_gvec_4(get_field(s->fields, v1), get_field(s->fields, v2),
1528 get_field(s->fields, v3), get_field(s->fields, v4), &g[es]);
1529 return DISAS_NEXT;
1530}
1531
1532static DisasJumpType op_vlc(DisasContext *s, DisasOps *o)
1533{
1534 const uint8_t es = get_field(s->fields, m3);
1535
1536 if (es > ES_64) {
1537 gen_program_exception(s, PGM_SPECIFICATION);
1538 return DISAS_NORETURN;
1539 }
1540
1541 gen_gvec_fn_2(neg, es, get_field(s->fields, v1), get_field(s->fields, v2));
1542 return DISAS_NEXT;
1543}
1544
1545static DisasJumpType op_vlp(DisasContext *s, DisasOps *o)
1546{
1547 const uint8_t es = get_field(s->fields, m3);
1548
1549 if (es > ES_64) {
1550 gen_program_exception(s, PGM_SPECIFICATION);
1551 return DISAS_NORETURN;
1552 }
1553
1554 gen_gvec_fn_2(abs, es, get_field(s->fields, v1), get_field(s->fields, v2));
1555 return DISAS_NEXT;
1556}
1557
1558static DisasJumpType op_vmx(DisasContext *s, DisasOps *o)
1559{
1560 const uint8_t v1 = get_field(s->fields, v1);
1561 const uint8_t v2 = get_field(s->fields, v2);
1562 const uint8_t v3 = get_field(s->fields, v3);
1563 const uint8_t es = get_field(s->fields, m4);
1564
1565 if (es > ES_64) {
1566 gen_program_exception(s, PGM_SPECIFICATION);
1567 return DISAS_NORETURN;
1568 }
1569
1570 switch (s->fields->op2) {
1571 case 0xff:
1572 gen_gvec_fn_3(smax, es, v1, v2, v3);
1573 break;
1574 case 0xfd:
1575 gen_gvec_fn_3(umax, es, v1, v2, v3);
1576 break;
1577 case 0xfe:
1578 gen_gvec_fn_3(smin, es, v1, v2, v3);
1579 break;
1580 case 0xfc:
1581 gen_gvec_fn_3(umin, es, v1, v2, v3);
1582 break;
1583 default:
1584 g_assert_not_reached();
1585 }
1586 return DISAS_NEXT;
1587}
1588
1589static void gen_mal_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b, TCGv_i32 c)
1590{
1591 TCGv_i32 t0 = tcg_temp_new_i32();
1592
1593 tcg_gen_mul_i32(t0, a, b);
1594 tcg_gen_add_i32(d, t0, c);
1595
1596 tcg_temp_free_i32(t0);
1597}
1598
1599static void gen_mah_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b, TCGv_i32 c)
1600{
1601 TCGv_i64 t0 = tcg_temp_new_i64();
1602 TCGv_i64 t1 = tcg_temp_new_i64();
1603 TCGv_i64 t2 = tcg_temp_new_i64();
1604
1605 tcg_gen_ext_i32_i64(t0, a);
1606 tcg_gen_ext_i32_i64(t1, b);
1607 tcg_gen_ext_i32_i64(t2, c);
1608 tcg_gen_mul_i64(t0, t0, t1);
1609 tcg_gen_add_i64(t0, t0, t2);
1610 tcg_gen_extrh_i64_i32(d, t0);
1611
1612 tcg_temp_free(t0);
1613 tcg_temp_free(t1);
1614 tcg_temp_free(t2);
1615}
1616
1617static void gen_malh_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b, TCGv_i32 c)
1618{
1619 TCGv_i64 t0 = tcg_temp_new_i64();
1620 TCGv_i64 t1 = tcg_temp_new_i64();
1621 TCGv_i64 t2 = tcg_temp_new_i64();
1622
1623 tcg_gen_extu_i32_i64(t0, a);
1624 tcg_gen_extu_i32_i64(t1, b);
1625 tcg_gen_extu_i32_i64(t2, c);
1626 tcg_gen_mul_i64(t0, t0, t1);
1627 tcg_gen_add_i64(t0, t0, t2);
1628 tcg_gen_extrh_i64_i32(d, t0);
1629
1630 tcg_temp_free(t0);
1631 tcg_temp_free(t1);
1632 tcg_temp_free(t2);
1633}
1634
1635static DisasJumpType op_vma(DisasContext *s, DisasOps *o)
1636{
1637 const uint8_t es = get_field(s->fields, m5);
1638 static const GVecGen4 g_vmal[3] = {
1639 { .fno = gen_helper_gvec_vmal8, },
1640 { .fno = gen_helper_gvec_vmal16, },
1641 { .fni4 = gen_mal_i32, },
1642 };
1643 static const GVecGen4 g_vmah[3] = {
1644 { .fno = gen_helper_gvec_vmah8, },
1645 { .fno = gen_helper_gvec_vmah16, },
1646 { .fni4 = gen_mah_i32, },
1647 };
1648 static const GVecGen4 g_vmalh[3] = {
1649 { .fno = gen_helper_gvec_vmalh8, },
1650 { .fno = gen_helper_gvec_vmalh16, },
1651 { .fni4 = gen_malh_i32, },
1652 };
1653 static const GVecGen4 g_vmae[3] = {
1654 { .fno = gen_helper_gvec_vmae8, },
1655 { .fno = gen_helper_gvec_vmae16, },
1656 { .fno = gen_helper_gvec_vmae32, },
1657 };
1658 static const GVecGen4 g_vmale[3] = {
1659 { .fno = gen_helper_gvec_vmale8, },
1660 { .fno = gen_helper_gvec_vmale16, },
1661 { .fno = gen_helper_gvec_vmale32, },
1662 };
1663 static const GVecGen4 g_vmao[3] = {
1664 { .fno = gen_helper_gvec_vmao8, },
1665 { .fno = gen_helper_gvec_vmao16, },
1666 { .fno = gen_helper_gvec_vmao32, },
1667 };
1668 static const GVecGen4 g_vmalo[3] = {
1669 { .fno = gen_helper_gvec_vmalo8, },
1670 { .fno = gen_helper_gvec_vmalo16, },
1671 { .fno = gen_helper_gvec_vmalo32, },
1672 };
1673 const GVecGen4 *fn;
1674
1675 if (es > ES_32) {
1676 gen_program_exception(s, PGM_SPECIFICATION);
1677 return DISAS_NORETURN;
1678 }
1679
1680 switch (s->fields->op2) {
1681 case 0xaa:
1682 fn = &g_vmal[es];
1683 break;
1684 case 0xab:
1685 fn = &g_vmah[es];
1686 break;
1687 case 0xa9:
1688 fn = &g_vmalh[es];
1689 break;
1690 case 0xae:
1691 fn = &g_vmae[es];
1692 break;
1693 case 0xac:
1694 fn = &g_vmale[es];
1695 break;
1696 case 0xaf:
1697 fn = &g_vmao[es];
1698 break;
1699 case 0xad:
1700 fn = &g_vmalo[es];
1701 break;
1702 default:
1703 g_assert_not_reached();
1704 }
1705
1706 gen_gvec_4(get_field(s->fields, v1), get_field(s->fields, v2),
1707 get_field(s->fields, v3), get_field(s->fields, v4), fn);
1708 return DISAS_NEXT;
1709}
1710
1711static void gen_mh_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
1712{
1713 TCGv_i32 t = tcg_temp_new_i32();
1714
1715 tcg_gen_muls2_i32(t, d, a, b);
1716 tcg_temp_free_i32(t);
1717}
1718
1719static void gen_mlh_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
1720{
1721 TCGv_i32 t = tcg_temp_new_i32();
1722
1723 tcg_gen_mulu2_i32(t, d, a, b);
1724 tcg_temp_free_i32(t);
1725}
1726
1727static DisasJumpType op_vm(DisasContext *s, DisasOps *o)
1728{
1729 const uint8_t es = get_field(s->fields, m4);
1730 static const GVecGen3 g_vmh[3] = {
1731 { .fno = gen_helper_gvec_vmh8, },
1732 { .fno = gen_helper_gvec_vmh16, },
1733 { .fni4 = gen_mh_i32, },
1734 };
1735 static const GVecGen3 g_vmlh[3] = {
1736 { .fno = gen_helper_gvec_vmlh8, },
1737 { .fno = gen_helper_gvec_vmlh16, },
1738 { .fni4 = gen_mlh_i32, },
1739 };
1740 static const GVecGen3 g_vme[3] = {
1741 { .fno = gen_helper_gvec_vme8, },
1742 { .fno = gen_helper_gvec_vme16, },
1743 { .fno = gen_helper_gvec_vme32, },
1744 };
1745 static const GVecGen3 g_vmle[3] = {
1746 { .fno = gen_helper_gvec_vmle8, },
1747 { .fno = gen_helper_gvec_vmle16, },
1748 { .fno = gen_helper_gvec_vmle32, },
1749 };
1750 static const GVecGen3 g_vmo[3] = {
1751 { .fno = gen_helper_gvec_vmo8, },
1752 { .fno = gen_helper_gvec_vmo16, },
1753 { .fno = gen_helper_gvec_vmo32, },
1754 };
1755 static const GVecGen3 g_vmlo[3] = {
1756 { .fno = gen_helper_gvec_vmlo8, },
1757 { .fno = gen_helper_gvec_vmlo16, },
1758 { .fno = gen_helper_gvec_vmlo32, },
1759 };
1760 const GVecGen3 *fn;
1761
1762 if (es > ES_32) {
1763 gen_program_exception(s, PGM_SPECIFICATION);
1764 return DISAS_NORETURN;
1765 }
1766
1767 switch (s->fields->op2) {
1768 case 0xa2:
1769 gen_gvec_fn_3(mul, es, get_field(s->fields, v1),
1770 get_field(s->fields, v2), get_field(s->fields, v3));
1771 return DISAS_NEXT;
1772 case 0xa3:
1773 fn = &g_vmh[es];
1774 break;
1775 case 0xa1:
1776 fn = &g_vmlh[es];
1777 break;
1778 case 0xa6:
1779 fn = &g_vme[es];
1780 break;
1781 case 0xa4:
1782 fn = &g_vmle[es];
1783 break;
1784 case 0xa7:
1785 fn = &g_vmo[es];
1786 break;
1787 case 0xa5:
1788 fn = &g_vmlo[es];
1789 break;
1790 default:
1791 g_assert_not_reached();
1792 }
1793
1794 gen_gvec_3(get_field(s->fields, v1), get_field(s->fields, v2),
1795 get_field(s->fields, v3), fn);
1796 return DISAS_NEXT;
1797}
1798
1799static DisasJumpType op_vnn(DisasContext *s, DisasOps *o)
1800{
1801 gen_gvec_fn_3(nand, ES_8, get_field(s->fields, v1),
1802 get_field(s->fields, v2), get_field(s->fields, v3));
1803 return DISAS_NEXT;
1804}
1805
1806static DisasJumpType op_vno(DisasContext *s, DisasOps *o)
1807{
1808 gen_gvec_fn_3(nor, ES_8, get_field(s->fields, v1), get_field(s->fields, v2),
1809 get_field(s->fields, v3));
1810 return DISAS_NEXT;
1811}
1812
1813static DisasJumpType op_vnx(DisasContext *s, DisasOps *o)
1814{
1815 gen_gvec_fn_3(eqv, ES_8, get_field(s->fields, v1), get_field(s->fields, v2),
1816 get_field(s->fields, v3));
1817 return DISAS_NEXT;
1818}
1819
1820static DisasJumpType op_vo(DisasContext *s, DisasOps *o)
1821{
1822 gen_gvec_fn_3(or, ES_8, get_field(s->fields, v1), get_field(s->fields, v2),
1823 get_field(s->fields, v3));
1824 return DISAS_NEXT;
1825}
1826
1827static DisasJumpType op_voc(DisasContext *s, DisasOps *o)
1828{
1829 gen_gvec_fn_3(orc, ES_8, get_field(s->fields, v1), get_field(s->fields, v2),
1830 get_field(s->fields, v3));
1831 return DISAS_NEXT;
1832}
1833
1834static DisasJumpType op_vpopct(DisasContext *s, DisasOps *o)
1835{
1836 const uint8_t es = get_field(s->fields, m3);
1837 static const GVecGen2 g[4] = {
1838 { .fno = gen_helper_gvec_vpopct8, },
1839 { .fno = gen_helper_gvec_vpopct16, },
1840 { .fni4 = tcg_gen_ctpop_i32, },
1841 { .fni8 = tcg_gen_ctpop_i64, },
1842 };
1843
1844 if (es > ES_64 || (es != ES_8 && !s390_has_feat(S390_FEAT_VECTOR_ENH))) {
1845 gen_program_exception(s, PGM_SPECIFICATION);
1846 return DISAS_NORETURN;
1847 }
1848
1849 gen_gvec_2(get_field(s->fields, v1), get_field(s->fields, v2), &g[es]);
1850 return DISAS_NEXT;
1851}
1852
1853static void gen_rll_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
1854{
1855 TCGv_i32 t0 = tcg_temp_new_i32();
1856
1857 tcg_gen_andi_i32(t0, b, 31);
1858 tcg_gen_rotl_i32(d, a, t0);
1859 tcg_temp_free_i32(t0);
1860}
1861
1862static void gen_rll_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
1863{
1864 TCGv_i64 t0 = tcg_temp_new_i64();
1865
1866 tcg_gen_andi_i64(t0, b, 63);
1867 tcg_gen_rotl_i64(d, a, t0);
1868 tcg_temp_free_i64(t0);
1869}
1870
1871static DisasJumpType op_verllv(DisasContext *s, DisasOps *o)
1872{
1873 const uint8_t es = get_field(s->fields, m4);
1874 static const GVecGen3 g[4] = {
1875 { .fno = gen_helper_gvec_verllv8, },
1876 { .fno = gen_helper_gvec_verllv16, },
1877 { .fni4 = gen_rll_i32, },
1878 { .fni8 = gen_rll_i64, },
1879 };
1880
1881 if (es > ES_64) {
1882 gen_program_exception(s, PGM_SPECIFICATION);
1883 return DISAS_NORETURN;
1884 }
1885
1886 gen_gvec_3(get_field(s->fields, v1), get_field(s->fields, v2),
1887 get_field(s->fields, v3), &g[es]);
1888 return DISAS_NEXT;
1889}
1890
1891static DisasJumpType op_verll(DisasContext *s, DisasOps *o)
1892{
1893 const uint8_t es = get_field(s->fields, m4);
1894 static const GVecGen2s g[4] = {
1895 { .fno = gen_helper_gvec_verll8, },
1896 { .fno = gen_helper_gvec_verll16, },
1897 { .fni4 = gen_rll_i32, },
1898 { .fni8 = gen_rll_i64, },
1899 };
1900
1901 if (es > ES_64) {
1902 gen_program_exception(s, PGM_SPECIFICATION);
1903 return DISAS_NORETURN;
1904 }
1905 gen_gvec_2s(get_field(s->fields, v1), get_field(s->fields, v3), o->addr1,
1906 &g[es]);
1907 return DISAS_NEXT;
1908}
1909
1910static void gen_rim_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b, int32_t c)
1911{
1912 TCGv_i32 t = tcg_temp_new_i32();
1913
1914 tcg_gen_rotli_i32(t, a, c & 31);
1915 tcg_gen_and_i32(t, t, b);
1916 tcg_gen_andc_i32(d, d, b);
1917 tcg_gen_or_i32(d, d, t);
1918
1919 tcg_temp_free_i32(t);
1920}
1921
1922static void gen_rim_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b, int64_t c)
1923{
1924 TCGv_i64 t = tcg_temp_new_i64();
1925
1926 tcg_gen_rotli_i64(t, a, c & 63);
1927 tcg_gen_and_i64(t, t, b);
1928 tcg_gen_andc_i64(d, d, b);
1929 tcg_gen_or_i64(d, d, t);
1930
1931 tcg_temp_free_i64(t);
1932}
1933
1934static DisasJumpType op_verim(DisasContext *s, DisasOps *o)
1935{
1936 const uint8_t es = get_field(s->fields, m5);
1937 const uint8_t i4 = get_field(s->fields, i4) &
1938 (NUM_VEC_ELEMENT_BITS(es) - 1);
1939 static const GVecGen3i g[4] = {
1940 { .fno = gen_helper_gvec_verim8, },
1941 { .fno = gen_helper_gvec_verim16, },
1942 { .fni4 = gen_rim_i32,
1943 .load_dest = true, },
1944 { .fni8 = gen_rim_i64,
1945 .load_dest = true, },
1946 };
1947
1948 if (es > ES_64) {
1949 gen_program_exception(s, PGM_SPECIFICATION);
1950 return DISAS_NORETURN;
1951 }
1952
1953 gen_gvec_3i(get_field(s->fields, v1), get_field(s->fields, v2),
1954 get_field(s->fields, v3), i4, &g[es]);
1955 return DISAS_NEXT;
1956}
1957
1958static DisasJumpType op_vesv(DisasContext *s, DisasOps *o)
1959{
1960 const uint8_t es = get_field(s->fields, m4);
1961 const uint8_t v1 = get_field(s->fields, v1);
1962 const uint8_t v2 = get_field(s->fields, v2);
1963 const uint8_t v3 = get_field(s->fields, v3);
1964
1965 if (es > ES_64) {
1966 gen_program_exception(s, PGM_SPECIFICATION);
1967 return DISAS_NORETURN;
1968 }
1969
1970 switch (s->fields->op2) {
1971 case 0x70:
1972 gen_gvec_fn_3(shlv, es, v1, v2, v3);
1973 break;
1974 case 0x7a:
1975 gen_gvec_fn_3(sarv, es, v1, v2, v3);
1976 break;
1977 case 0x78:
1978 gen_gvec_fn_3(shrv, es, v1, v2, v3);
1979 break;
1980 default:
1981 g_assert_not_reached();
1982 }
1983 return DISAS_NEXT;
1984}
1985
1986static DisasJumpType op_ves(DisasContext *s, DisasOps *o)
1987{
1988 const uint8_t es = get_field(s->fields, m4);
1989 const uint8_t d2 = get_field(s->fields, d2) &
1990 (NUM_VEC_ELEMENT_BITS(es) - 1);
1991 const uint8_t v1 = get_field(s->fields, v1);
1992 const uint8_t v3 = get_field(s->fields, v3);
1993 TCGv_i32 shift;
1994
1995 if (es > ES_64) {
1996 gen_program_exception(s, PGM_SPECIFICATION);
1997 return DISAS_NORETURN;
1998 }
1999
2000 if (likely(!get_field(s->fields, b2))) {
2001 switch (s->fields->op2) {
2002 case 0x30:
2003 gen_gvec_fn_2i(shli, es, v1, v3, d2);
2004 break;
2005 case 0x3a:
2006 gen_gvec_fn_2i(sari, es, v1, v3, d2);
2007 break;
2008 case 0x38:
2009 gen_gvec_fn_2i(shri, es, v1, v3, d2);
2010 break;
2011 default:
2012 g_assert_not_reached();
2013 }
2014 } else {
2015 shift = tcg_temp_new_i32();
2016 tcg_gen_extrl_i64_i32(shift, o->addr1);
2017 tcg_gen_andi_i32(shift, shift, NUM_VEC_ELEMENT_BITS(es) - 1);
2018 switch (s->fields->op2) {
2019 case 0x30:
2020 gen_gvec_fn_2s(shls, es, v1, v3, shift);
2021 break;
2022 case 0x3a:
2023 gen_gvec_fn_2s(sars, es, v1, v3, shift);
2024 break;
2025 case 0x38:
2026 gen_gvec_fn_2s(shrs, es, v1, v3, shift);
2027 break;
2028 default:
2029 g_assert_not_reached();
2030 }
2031 tcg_temp_free_i32(shift);
2032 }
2033 return DISAS_NEXT;
2034}
2035
2036static DisasJumpType op_vsl(DisasContext *s, DisasOps *o)
2037{
2038 TCGv_i64 shift = tcg_temp_new_i64();
2039
2040 read_vec_element_i64(shift, get_field(s->fields, v3), 7, ES_8);
2041 if (s->fields->op2 == 0x74) {
2042 tcg_gen_andi_i64(shift, shift, 0x7);
2043 } else {
2044 tcg_gen_andi_i64(shift, shift, 0x78);
2045 }
2046
2047 gen_gvec_2i_ool(get_field(s->fields, v1), get_field(s->fields, v2),
2048 shift, 0, gen_helper_gvec_vsl);
2049 tcg_temp_free_i64(shift);
2050 return DISAS_NEXT;
2051}
2052
2053static DisasJumpType op_vsldb(DisasContext *s, DisasOps *o)
2054{
2055 const uint8_t i4 = get_field(s->fields, i4) & 0xf;
2056 const int left_shift = (i4 & 7) * 8;
2057 const int right_shift = 64 - left_shift;
2058 TCGv_i64 t0 = tcg_temp_new_i64();
2059 TCGv_i64 t1 = tcg_temp_new_i64();
2060 TCGv_i64 t2 = tcg_temp_new_i64();
2061
2062 if ((i4 & 8) == 0) {
2063 read_vec_element_i64(t0, get_field(s->fields, v2), 0, ES_64);
2064 read_vec_element_i64(t1, get_field(s->fields, v2), 1, ES_64);
2065 read_vec_element_i64(t2, get_field(s->fields, v3), 0, ES_64);
2066 } else {
2067 read_vec_element_i64(t0, get_field(s->fields, v2), 1, ES_64);
2068 read_vec_element_i64(t1, get_field(s->fields, v3), 0, ES_64);
2069 read_vec_element_i64(t2, get_field(s->fields, v3), 1, ES_64);
2070 }
2071 tcg_gen_extract2_i64(t0, t1, t0, right_shift);
2072 tcg_gen_extract2_i64(t1, t2, t1, right_shift);
2073 write_vec_element_i64(t0, get_field(s->fields, v1), 0, ES_64);
2074 write_vec_element_i64(t1, get_field(s->fields, v1), 1, ES_64);
2075
2076 tcg_temp_free(t0);
2077 tcg_temp_free(t1);
2078 tcg_temp_free(t2);
2079 return DISAS_NEXT;
2080}
2081
2082static DisasJumpType op_vsra(DisasContext *s, DisasOps *o)
2083{
2084 TCGv_i64 shift = tcg_temp_new_i64();
2085
2086 read_vec_element_i64(shift, get_field(s->fields, v3), 7, ES_8);
2087 if (s->fields->op2 == 0x7e) {
2088 tcg_gen_andi_i64(shift, shift, 0x7);
2089 } else {
2090 tcg_gen_andi_i64(shift, shift, 0x78);
2091 }
2092
2093 gen_gvec_2i_ool(get_field(s->fields, v1), get_field(s->fields, v2),
2094 shift, 0, gen_helper_gvec_vsra);
2095 tcg_temp_free_i64(shift);
2096 return DISAS_NEXT;
2097}
2098
2099static DisasJumpType op_vsrl(DisasContext *s, DisasOps *o)
2100{
2101 TCGv_i64 shift = tcg_temp_new_i64();
2102
2103 read_vec_element_i64(shift, get_field(s->fields, v3), 7, ES_8);
2104 if (s->fields->op2 == 0x7c) {
2105 tcg_gen_andi_i64(shift, shift, 0x7);
2106 } else {
2107 tcg_gen_andi_i64(shift, shift, 0x78);
2108 }
2109
2110 gen_gvec_2i_ool(get_field(s->fields, v1), get_field(s->fields, v2),
2111 shift, 0, gen_helper_gvec_vsrl);
2112 tcg_temp_free_i64(shift);
2113 return DISAS_NEXT;
2114}
2115
2116static DisasJumpType op_vs(DisasContext *s, DisasOps *o)
2117{
2118 const uint8_t es = get_field(s->fields, m4);
2119
2120 if (es > ES_128) {
2121 gen_program_exception(s, PGM_SPECIFICATION);
2122 return DISAS_NORETURN;
2123 } else if (es == ES_128) {
2124 gen_gvec128_3_i64(tcg_gen_sub2_i64, get_field(s->fields, v1),
2125 get_field(s->fields, v2), get_field(s->fields, v3));
2126 return DISAS_NEXT;
2127 }
2128 gen_gvec_fn_3(sub, es, get_field(s->fields, v1), get_field(s->fields, v2),
2129 get_field(s->fields, v3));
2130 return DISAS_NEXT;
2131}
2132
2133static void gen_scbi_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
2134{
2135 tcg_gen_setcond_i32(TCG_COND_LTU, d, a, b);
2136}
2137
2138static void gen_scbi_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
2139{
2140 tcg_gen_setcond_i64(TCG_COND_LTU, d, a, b);
2141}
2142
2143static void gen_scbi2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al,
2144 TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh)
2145{
2146 TCGv_i64 th = tcg_temp_new_i64();
2147 TCGv_i64 tl = tcg_temp_new_i64();
2148 TCGv_i64 zero = tcg_const_i64(0);
2149
2150 tcg_gen_sub2_i64(tl, th, al, zero, bl, zero);
2151 tcg_gen_andi_i64(th, th, 1);
2152 tcg_gen_sub2_i64(tl, th, ah, zero, th, zero);
2153 tcg_gen_sub2_i64(tl, th, tl, th, bh, zero);
2154 tcg_gen_andi_i64(dl, th, 1);
2155 tcg_gen_mov_i64(dh, zero);
2156
2157 tcg_temp_free_i64(th);
2158 tcg_temp_free_i64(tl);
2159 tcg_temp_free_i64(zero);
2160}
2161
2162static DisasJumpType op_vscbi(DisasContext *s, DisasOps *o)
2163{
2164 const uint8_t es = get_field(s->fields, m4);
2165 static const GVecGen3 g[4] = {
2166 { .fno = gen_helper_gvec_vscbi8, },
2167 { .fno = gen_helper_gvec_vscbi16, },
2168 { .fni4 = gen_scbi_i32, },
2169 { .fni8 = gen_scbi_i64, },
2170 };
2171
2172 if (es > ES_128) {
2173 gen_program_exception(s, PGM_SPECIFICATION);
2174 return DISAS_NORETURN;
2175 } else if (es == ES_128) {
2176 gen_gvec128_3_i64(gen_scbi2_i64, get_field(s->fields, v1),
2177 get_field(s->fields, v2), get_field(s->fields, v3));
2178 return DISAS_NEXT;
2179 }
2180 gen_gvec_3(get_field(s->fields, v1), get_field(s->fields, v2),
2181 get_field(s->fields, v3), &g[es]);
2182 return DISAS_NEXT;
2183}
2184
2185static void gen_sbi2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
2186 TCGv_i64 bl, TCGv_i64 bh, TCGv_i64 cl, TCGv_i64 ch)
2187{
2188 TCGv_i64 tl = tcg_temp_new_i64();
2189 TCGv_i64 zero = tcg_const_i64(0);
2190
2191 tcg_gen_andi_i64(tl, cl, 1);
2192 tcg_gen_sub2_i64(dl, dh, al, ah, bl, bh);
2193 tcg_gen_sub2_i64(dl, dh, dl, dh, tl, zero);
2194 tcg_temp_free_i64(tl);
2195 tcg_temp_free_i64(zero);
2196}
2197
2198static DisasJumpType op_vsbi(DisasContext *s, DisasOps *o)
2199{
2200 if (get_field(s->fields, m5) != ES_128) {
2201 gen_program_exception(s, PGM_SPECIFICATION);
2202 return DISAS_NORETURN;
2203 }
2204
2205 gen_gvec128_4_i64(gen_sbi2_i64, get_field(s->fields, v1),
2206 get_field(s->fields, v2), get_field(s->fields, v3),
2207 get_field(s->fields, v4));
2208 return DISAS_NEXT;
2209}
2210
2211static void gen_sbcbi2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
2212 TCGv_i64 bl, TCGv_i64 bh, TCGv_i64 cl, TCGv_i64 ch)
2213{
2214 TCGv_i64 th = tcg_temp_new_i64();
2215 TCGv_i64 tl = tcg_temp_new_i64();
2216 TCGv_i64 zero = tcg_const_i64(0);
2217
2218 tcg_gen_andi_i64(tl, cl, 1);
2219 tcg_gen_sub2_i64(tl, th, al, zero, tl, zero);
2220 tcg_gen_sub2_i64(tl, th, tl, th, bl, zero);
2221 tcg_gen_andi_i64(th, th, 1);
2222 tcg_gen_sub2_i64(tl, th, ah, zero, th, zero);
2223 tcg_gen_sub2_i64(tl, th, tl, th, bh, zero);
2224 tcg_gen_andi_i64(dl, th, 1);
2225 tcg_gen_mov_i64(dh, zero);
2226
2227 tcg_temp_free_i64(tl);
2228 tcg_temp_free_i64(th);
2229 tcg_temp_free_i64(zero);
2230}
2231
2232static DisasJumpType op_vsbcbi(DisasContext *s, DisasOps *o)
2233{
2234 if (get_field(s->fields, m5) != ES_128) {
2235 gen_program_exception(s, PGM_SPECIFICATION);
2236 return DISAS_NORETURN;
2237 }
2238
2239 gen_gvec128_4_i64(gen_sbcbi2_i64, get_field(s->fields, v1),
2240 get_field(s->fields, v2), get_field(s->fields, v3),
2241 get_field(s->fields, v4));
2242 return DISAS_NEXT;
2243}
2244
2245static DisasJumpType op_vsumg(DisasContext *s, DisasOps *o)
2246{
2247 const uint8_t es = get_field(s->fields, m4);
2248 TCGv_i64 sum, tmp;
2249 uint8_t dst_idx;
2250
2251 if (es == ES_8 || es > ES_32) {
2252 gen_program_exception(s, PGM_SPECIFICATION);
2253 return DISAS_NORETURN;
2254 }
2255
2256 sum = tcg_temp_new_i64();
2257 tmp = tcg_temp_new_i64();
2258 for (dst_idx = 0; dst_idx < 2; dst_idx++) {
2259 uint8_t idx = dst_idx * NUM_VEC_ELEMENTS(es) / 2;
2260 const uint8_t max_idx = idx + NUM_VEC_ELEMENTS(es) / 2 - 1;
2261
2262 read_vec_element_i64(sum, get_field(s->fields, v3), max_idx, es);
2263 for (; idx <= max_idx; idx++) {
2264 read_vec_element_i64(tmp, get_field(s->fields, v2), idx, es);
2265 tcg_gen_add_i64(sum, sum, tmp);
2266 }
2267 write_vec_element_i64(sum, get_field(s->fields, v1), dst_idx, ES_64);
2268 }
2269 tcg_temp_free_i64(sum);
2270 tcg_temp_free_i64(tmp);
2271 return DISAS_NEXT;
2272}
2273
2274static DisasJumpType op_vsumq(DisasContext *s, DisasOps *o)
2275{
2276 const uint8_t es = get_field(s->fields, m4);
2277 const uint8_t max_idx = NUM_VEC_ELEMENTS(es) - 1;
2278 TCGv_i64 sumh, suml, zero, tmpl;
2279 uint8_t idx;
2280
2281 if (es < ES_32 || es > ES_64) {
2282 gen_program_exception(s, PGM_SPECIFICATION);
2283 return DISAS_NORETURN;
2284 }
2285
2286 sumh = tcg_const_i64(0);
2287 suml = tcg_temp_new_i64();
2288 zero = tcg_const_i64(0);
2289 tmpl = tcg_temp_new_i64();
2290
2291 read_vec_element_i64(suml, get_field(s->fields, v3), max_idx, es);
2292 for (idx = 0; idx <= max_idx; idx++) {
2293 read_vec_element_i64(tmpl, get_field(s->fields, v2), idx, es);
2294 tcg_gen_add2_i64(suml, sumh, suml, sumh, tmpl, zero);
2295 }
2296 write_vec_element_i64(sumh, get_field(s->fields, v1), 0, ES_64);
2297 write_vec_element_i64(suml, get_field(s->fields, v1), 1, ES_64);
2298
2299 tcg_temp_free_i64(sumh);
2300 tcg_temp_free_i64(suml);
2301 tcg_temp_free_i64(zero);
2302 tcg_temp_free_i64(tmpl);
2303 return DISAS_NEXT;
2304}
2305
2306static DisasJumpType op_vsum(DisasContext *s, DisasOps *o)
2307{
2308 const uint8_t es = get_field(s->fields, m4);
2309 TCGv_i32 sum, tmp;
2310 uint8_t dst_idx;
2311
2312 if (es > ES_16) {
2313 gen_program_exception(s, PGM_SPECIFICATION);
2314 return DISAS_NORETURN;
2315 }
2316
2317 sum = tcg_temp_new_i32();
2318 tmp = tcg_temp_new_i32();
2319 for (dst_idx = 0; dst_idx < 4; dst_idx++) {
2320 uint8_t idx = dst_idx * NUM_VEC_ELEMENTS(es) / 4;
2321 const uint8_t max_idx = idx + NUM_VEC_ELEMENTS(es) / 4 - 1;
2322
2323 read_vec_element_i32(sum, get_field(s->fields, v3), max_idx, es);
2324 for (; idx <= max_idx; idx++) {
2325 read_vec_element_i32(tmp, get_field(s->fields, v2), idx, es);
2326 tcg_gen_add_i32(sum, sum, tmp);
2327 }
2328 write_vec_element_i32(sum, get_field(s->fields, v1), dst_idx, ES_32);
2329 }
2330 tcg_temp_free_i32(sum);
2331 tcg_temp_free_i32(tmp);
2332 return DISAS_NEXT;
2333}
2334
2335static DisasJumpType op_vtm(DisasContext *s, DisasOps *o)
2336{
2337 gen_gvec_2_ptr(get_field(s->fields, v1), get_field(s->fields, v2),
2338 cpu_env, 0, gen_helper_gvec_vtm);
2339 set_cc_static(s);
2340 return DISAS_NEXT;
2341}
2342
2343static DisasJumpType op_vfae(DisasContext *s, DisasOps *o)
2344{
2345 const uint8_t es = get_field(s->fields, m4);
2346 const uint8_t m5 = get_field(s->fields, m5);
2347 static gen_helper_gvec_3 * const g[3] = {
2348 gen_helper_gvec_vfae8,
2349 gen_helper_gvec_vfae16,
2350 gen_helper_gvec_vfae32,
2351 };
2352 static gen_helper_gvec_3_ptr * const g_cc[3] = {
2353 gen_helper_gvec_vfae_cc8,
2354 gen_helper_gvec_vfae_cc16,
2355 gen_helper_gvec_vfae_cc32,
2356 };
2357 if (es > ES_32) {
2358 gen_program_exception(s, PGM_SPECIFICATION);
2359 return DISAS_NORETURN;
2360 }
2361
2362 if (extract32(m5, 0, 1)) {
2363 gen_gvec_3_ptr(get_field(s->fields, v1), get_field(s->fields, v2),
2364 get_field(s->fields, v3), cpu_env, m5, g_cc[es]);
2365 set_cc_static(s);
2366 } else {
2367 gen_gvec_3_ool(get_field(s->fields, v1), get_field(s->fields, v2),
2368 get_field(s->fields, v3), m5, g[es]);
2369 }
2370 return DISAS_NEXT;
2371}
2372
2373static DisasJumpType op_vfee(DisasContext *s, DisasOps *o)
2374{
2375 const uint8_t es = get_field(s->fields, m4);
2376 const uint8_t m5 = get_field(s->fields, m5);
2377 static gen_helper_gvec_3 * const g[3] = {
2378 gen_helper_gvec_vfee8,
2379 gen_helper_gvec_vfee16,
2380 gen_helper_gvec_vfee32,
2381 };
2382 static gen_helper_gvec_3_ptr * const g_cc[3] = {
2383 gen_helper_gvec_vfee_cc8,
2384 gen_helper_gvec_vfee_cc16,
2385 gen_helper_gvec_vfee_cc32,
2386 };
2387
2388 if (es > ES_32 || m5 & ~0x3) {
2389 gen_program_exception(s, PGM_SPECIFICATION);
2390 return DISAS_NORETURN;
2391 }
2392
2393 if (extract32(m5, 0, 1)) {
2394 gen_gvec_3_ptr(get_field(s->fields, v1), get_field(s->fields, v2),
2395 get_field(s->fields, v3), cpu_env, m5, g_cc[es]);
2396 set_cc_static(s);
2397 } else {
2398 gen_gvec_3_ool(get_field(s->fields, v1), get_field(s->fields, v2),
2399 get_field(s->fields, v3), m5, g[es]);
2400 }
2401 return DISAS_NEXT;
2402}
2403
2404static DisasJumpType op_vfene(DisasContext *s, DisasOps *o)
2405{
2406 const uint8_t es = get_field(s->fields, m4);
2407 const uint8_t m5 = get_field(s->fields, m5);
2408 static gen_helper_gvec_3 * const g[3] = {
2409 gen_helper_gvec_vfene8,
2410 gen_helper_gvec_vfene16,
2411 gen_helper_gvec_vfene32,
2412 };
2413 static gen_helper_gvec_3_ptr * const g_cc[3] = {
2414 gen_helper_gvec_vfene_cc8,
2415 gen_helper_gvec_vfene_cc16,
2416 gen_helper_gvec_vfene_cc32,
2417 };
2418
2419 if (es > ES_32 || m5 & ~0x3) {
2420 gen_program_exception(s, PGM_SPECIFICATION);
2421 return DISAS_NORETURN;
2422 }
2423
2424 if (extract32(m5, 0, 1)) {
2425 gen_gvec_3_ptr(get_field(s->fields, v1), get_field(s->fields, v2),
2426 get_field(s->fields, v3), cpu_env, m5, g_cc[es]);
2427 set_cc_static(s);
2428 } else {
2429 gen_gvec_3_ool(get_field(s->fields, v1), get_field(s->fields, v2),
2430 get_field(s->fields, v3), m5, g[es]);
2431 }
2432 return DISAS_NEXT;
2433}
2434
2435static DisasJumpType op_vistr(DisasContext *s, DisasOps *o)
2436{
2437 const uint8_t es = get_field(s->fields, m4);
2438 const uint8_t m5 = get_field(s->fields, m5);
2439 static gen_helper_gvec_2 * const g[3] = {
2440 gen_helper_gvec_vistr8,
2441 gen_helper_gvec_vistr16,
2442 gen_helper_gvec_vistr32,
2443 };
2444 static gen_helper_gvec_2_ptr * const g_cc[3] = {
2445 gen_helper_gvec_vistr_cc8,
2446 gen_helper_gvec_vistr_cc16,
2447 gen_helper_gvec_vistr_cc32,
2448 };
2449
2450 if (es > ES_32 || m5 & ~0x1) {
2451 gen_program_exception(s, PGM_SPECIFICATION);
2452 return DISAS_NORETURN;
2453 }
2454
2455 if (extract32(m5, 0, 1)) {
2456 gen_gvec_2_ptr(get_field(s->fields, v1), get_field(s->fields, v2),
2457 cpu_env, 0, g_cc[es]);
2458 set_cc_static(s);
2459 } else {
2460 gen_gvec_2_ool(get_field(s->fields, v1), get_field(s->fields, v2), 0,
2461 g[es]);
2462 }
2463 return DISAS_NEXT;
2464}
2465
2466static DisasJumpType op_vstrc(DisasContext *s, DisasOps *o)
2467{
2468 const uint8_t es = get_field(s->fields, m5);
2469 const uint8_t m6 = get_field(s->fields, m6);
2470 static gen_helper_gvec_4 * const g[3] = {
2471 gen_helper_gvec_vstrc8,
2472 gen_helper_gvec_vstrc16,
2473 gen_helper_gvec_vstrc32,
2474 };
2475 static gen_helper_gvec_4 * const g_rt[3] = {
2476 gen_helper_gvec_vstrc_rt8,
2477 gen_helper_gvec_vstrc_rt16,
2478 gen_helper_gvec_vstrc_rt32,
2479 };
2480 static gen_helper_gvec_4_ptr * const g_cc[3] = {
2481 gen_helper_gvec_vstrc_cc8,
2482 gen_helper_gvec_vstrc_cc16,
2483 gen_helper_gvec_vstrc_cc32,
2484 };
2485 static gen_helper_gvec_4_ptr * const g_cc_rt[3] = {
2486 gen_helper_gvec_vstrc_cc_rt8,
2487 gen_helper_gvec_vstrc_cc_rt16,
2488 gen_helper_gvec_vstrc_cc_rt32,
2489 };
2490
2491 if (es > ES_32) {
2492 gen_program_exception(s, PGM_SPECIFICATION);
2493 return DISAS_NORETURN;
2494 }
2495
2496 if (extract32(m6, 0, 1)) {
2497 if (extract32(m6, 2, 1)) {
2498 gen_gvec_4_ptr(get_field(s->fields, v1), get_field(s->fields, v2),
2499 get_field(s->fields, v3), get_field(s->fields, v4),
2500 cpu_env, m6, g_cc_rt[es]);
2501 } else {
2502 gen_gvec_4_ptr(get_field(s->fields, v1), get_field(s->fields, v2),
2503 get_field(s->fields, v3), get_field(s->fields, v4),
2504 cpu_env, m6, g_cc[es]);
2505 }
2506 set_cc_static(s);
2507 } else {
2508 if (extract32(m6, 2, 1)) {
2509 gen_gvec_4_ool(get_field(s->fields, v1), get_field(s->fields, v2),
2510 get_field(s->fields, v3), get_field(s->fields, v4),
2511 m6, g_rt[es]);
2512 } else {
2513 gen_gvec_4_ool(get_field(s->fields, v1), get_field(s->fields, v2),
2514 get_field(s->fields, v3), get_field(s->fields, v4),
2515 m6, g[es]);
2516 }
2517 }
2518 return DISAS_NEXT;
2519}
2520
2521static DisasJumpType op_vfa(DisasContext *s, DisasOps *o)
2522{
2523 const uint8_t fpf = get_field(s->fields, m4);
2524 const uint8_t m5 = get_field(s->fields, m5);
2525 const bool se = extract32(m5, 3, 1);
2526 gen_helper_gvec_3_ptr *fn;
2527
2528 if (fpf != FPF_LONG || extract32(m5, 0, 3)) {
2529 gen_program_exception(s, PGM_SPECIFICATION);
2530 return DISAS_NORETURN;
2531 }
2532
2533 switch (s->fields->op2) {
2534 case 0xe3:
2535 fn = se ? gen_helper_gvec_vfa64s : gen_helper_gvec_vfa64;
2536 break;
2537 case 0xe5:
2538 fn = se ? gen_helper_gvec_vfd64s : gen_helper_gvec_vfd64;
2539 break;
2540 case 0xe7:
2541 fn = se ? gen_helper_gvec_vfm64s : gen_helper_gvec_vfm64;
2542 break;
2543 case 0xe2:
2544 fn = se ? gen_helper_gvec_vfs64s : gen_helper_gvec_vfs64;
2545 break;
2546 default:
2547 g_assert_not_reached();
2548 }
2549 gen_gvec_3_ptr(get_field(s->fields, v1), get_field(s->fields, v2),
2550 get_field(s->fields, v3), cpu_env, 0, fn);
2551 return DISAS_NEXT;
2552}
2553
2554static DisasJumpType op_wfc(DisasContext *s, DisasOps *o)
2555{
2556 const uint8_t fpf = get_field(s->fields, m3);
2557 const uint8_t m4 = get_field(s->fields, m4);
2558
2559 if (fpf != FPF_LONG || m4) {
2560 gen_program_exception(s, PGM_SPECIFICATION);
2561 return DISAS_NORETURN;
2562 }
2563
2564 if (s->fields->op2 == 0xcb) {
2565 gen_gvec_2_ptr(get_field(s->fields, v1), get_field(s->fields, v2),
2566 cpu_env, 0, gen_helper_gvec_wfc64);
2567 } else {
2568 gen_gvec_2_ptr(get_field(s->fields, v1), get_field(s->fields, v2),
2569 cpu_env, 0, gen_helper_gvec_wfk64);
2570 }
2571 set_cc_static(s);
2572 return DISAS_NEXT;
2573}
2574
2575static DisasJumpType op_vfc(DisasContext *s, DisasOps *o)
2576{
2577 const uint8_t fpf = get_field(s->fields, m4);
2578 const uint8_t m5 = get_field(s->fields, m5);
2579 const uint8_t m6 = get_field(s->fields, m6);
2580 const bool se = extract32(m5, 3, 1);
2581 const bool cs = extract32(m6, 0, 1);
2582 gen_helper_gvec_3_ptr *fn;
2583
2584 if (fpf != FPF_LONG || extract32(m5, 0, 3) || extract32(m6, 1, 3)) {
2585 gen_program_exception(s, PGM_SPECIFICATION);
2586 return DISAS_NORETURN;
2587 }
2588
2589 if (cs) {
2590 switch (s->fields->op2) {
2591 case 0xe8:
2592 fn = se ? gen_helper_gvec_vfce64s_cc : gen_helper_gvec_vfce64_cc;
2593 break;
2594 case 0xeb:
2595 fn = se ? gen_helper_gvec_vfch64s_cc : gen_helper_gvec_vfch64_cc;
2596 break;
2597 case 0xea:
2598 fn = se ? gen_helper_gvec_vfche64s_cc : gen_helper_gvec_vfche64_cc;
2599 break;
2600 default:
2601 g_assert_not_reached();
2602 }
2603 } else {
2604 switch (s->fields->op2) {
2605 case 0xe8:
2606 fn = se ? gen_helper_gvec_vfce64s : gen_helper_gvec_vfce64;
2607 break;
2608 case 0xeb:
2609 fn = se ? gen_helper_gvec_vfch64s : gen_helper_gvec_vfch64;
2610 break;
2611 case 0xea:
2612 fn = se ? gen_helper_gvec_vfche64s : gen_helper_gvec_vfche64;
2613 break;
2614 default:
2615 g_assert_not_reached();
2616 }
2617 }
2618 gen_gvec_3_ptr(get_field(s->fields, v1), get_field(s->fields, v2),
2619 get_field(s->fields, v3), cpu_env, 0, fn);
2620 if (cs) {
2621 set_cc_static(s);
2622 }
2623 return DISAS_NEXT;
2624}
2625
2626static DisasJumpType op_vcdg(DisasContext *s, DisasOps *o)
2627{
2628 const uint8_t fpf = get_field(s->fields, m3);
2629 const uint8_t m4 = get_field(s->fields, m4);
2630 const uint8_t erm = get_field(s->fields, m5);
2631 const bool se = extract32(m4, 3, 1);
2632 gen_helper_gvec_2_ptr *fn;
2633
2634 if (fpf != FPF_LONG || extract32(m4, 0, 2) || erm > 7 || erm == 2) {
2635 gen_program_exception(s, PGM_SPECIFICATION);
2636 return DISAS_NORETURN;
2637 }
2638
2639 switch (s->fields->op2) {
2640 case 0xc3:
2641 fn = se ? gen_helper_gvec_vcdg64s : gen_helper_gvec_vcdg64;
2642 break;
2643 case 0xc1:
2644 fn = se ? gen_helper_gvec_vcdlg64s : gen_helper_gvec_vcdlg64;
2645 break;
2646 case 0xc2:
2647 fn = se ? gen_helper_gvec_vcgd64s : gen_helper_gvec_vcgd64;
2648 break;
2649 case 0xc0:
2650 fn = se ? gen_helper_gvec_vclgd64s : gen_helper_gvec_vclgd64;
2651 break;
2652 case 0xc7:
2653 fn = se ? gen_helper_gvec_vfi64s : gen_helper_gvec_vfi64;
2654 break;
2655 case 0xc5:
2656 fn = se ? gen_helper_gvec_vflr64s : gen_helper_gvec_vflr64;
2657 break;
2658 default:
2659 g_assert_not_reached();
2660 }
2661 gen_gvec_2_ptr(get_field(s->fields, v1), get_field(s->fields, v2), cpu_env,
2662 deposit32(m4, 4, 4, erm), fn);
2663 return DISAS_NEXT;
2664}
2665
2666static DisasJumpType op_vfll(DisasContext *s, DisasOps *o)
2667{
2668 const uint8_t fpf = get_field(s->fields, m3);
2669 const uint8_t m4 = get_field(s->fields, m4);
2670 gen_helper_gvec_2_ptr *fn = gen_helper_gvec_vfll32;
2671
2672 if (fpf != FPF_SHORT || extract32(m4, 0, 3)) {
2673 gen_program_exception(s, PGM_SPECIFICATION);
2674 return DISAS_NORETURN;
2675 }
2676
2677 if (extract32(m4, 3, 1)) {
2678 fn = gen_helper_gvec_vfll32s;
2679 }
2680 gen_gvec_2_ptr(get_field(s->fields, v1), get_field(s->fields, v2), cpu_env,
2681 0, fn);
2682 return DISAS_NEXT;
2683}
2684
2685static DisasJumpType op_vfma(DisasContext *s, DisasOps *o)
2686{
2687 const uint8_t m5 = get_field(s->fields, m5);
2688 const uint8_t fpf = get_field(s->fields, m6);
2689 const bool se = extract32(m5, 3, 1);
2690 gen_helper_gvec_4_ptr *fn;
2691
2692 if (fpf != FPF_LONG || extract32(m5, 0, 3)) {
2693 gen_program_exception(s, PGM_SPECIFICATION);
2694 return DISAS_NORETURN;
2695 }
2696
2697 if (s->fields->op2 == 0x8f) {
2698 fn = se ? gen_helper_gvec_vfma64s : gen_helper_gvec_vfma64;
2699 } else {
2700 fn = se ? gen_helper_gvec_vfms64s : gen_helper_gvec_vfms64;
2701 }
2702 gen_gvec_4_ptr(get_field(s->fields, v1), get_field(s->fields, v2),
2703 get_field(s->fields, v3), get_field(s->fields, v4), cpu_env,
2704 0, fn);
2705 return DISAS_NEXT;
2706}
2707
2708static DisasJumpType op_vfpso(DisasContext *s, DisasOps *o)
2709{
2710 const uint8_t v1 = get_field(s->fields, v1);
2711 const uint8_t v2 = get_field(s->fields, v2);
2712 const uint8_t fpf = get_field(s->fields, m3);
2713 const uint8_t m4 = get_field(s->fields, m4);
2714 const uint8_t m5 = get_field(s->fields, m5);
2715 TCGv_i64 tmp;
2716
2717 if (fpf != FPF_LONG || extract32(m4, 0, 3) || m5 > 2) {
2718 gen_program_exception(s, PGM_SPECIFICATION);
2719 return DISAS_NORETURN;
2720 }
2721
2722 if (extract32(m4, 3, 1)) {
2723 tmp = tcg_temp_new_i64();
2724 read_vec_element_i64(tmp, v2, 0, ES_64);
2725 switch (m5) {
2726 case 0:
2727 /* sign bit is inverted (complement) */
2728 tcg_gen_xori_i64(tmp, tmp, 1ull << 63);
2729 break;
2730 case 1:
2731 /* sign bit is set to one (negative) */
2732 tcg_gen_ori_i64(tmp, tmp, 1ull << 63);
2733 break;
2734 case 2:
2735 /* sign bit is set to zero (positive) */
2736 tcg_gen_andi_i64(tmp, tmp, (1ull << 63) - 1);
2737 break;
2738 }
2739 write_vec_element_i64(tmp, v1, 0, ES_64);
2740 tcg_temp_free_i64(tmp);
2741 } else {
2742 switch (m5) {
2743 case 0:
2744 /* sign bit is inverted (complement) */
2745 gen_gvec_fn_2i(xori, ES_64, v1, v2, 1ull << 63);
2746 break;
2747 case 1:
2748 /* sign bit is set to one (negative) */
2749 gen_gvec_fn_2i(ori, ES_64, v1, v2, 1ull << 63);
2750 break;
2751 case 2:
2752 /* sign bit is set to zero (positive) */
2753 gen_gvec_fn_2i(andi, ES_64, v1, v2, (1ull << 63) - 1);
2754 break;
2755 }
2756 }
2757 return DISAS_NEXT;
2758}
2759
2760static DisasJumpType op_vfsq(DisasContext *s, DisasOps *o)
2761{
2762 const uint8_t fpf = get_field(s->fields, m3);
2763 const uint8_t m4 = get_field(s->fields, m4);
2764 gen_helper_gvec_2_ptr *fn = gen_helper_gvec_vfsq64;
2765
2766 if (fpf != FPF_LONG || extract32(m4, 0, 3)) {
2767 gen_program_exception(s, PGM_SPECIFICATION);
2768 return DISAS_NORETURN;
2769 }
2770
2771 if (extract32(m4, 3, 1)) {
2772 fn = gen_helper_gvec_vfsq64s;
2773 }
2774 gen_gvec_2_ptr(get_field(s->fields, v1), get_field(s->fields, v2), cpu_env,
2775 0, fn);
2776 return DISAS_NEXT;
2777}
2778
2779static DisasJumpType op_vftci(DisasContext *s, DisasOps *o)
2780{
2781 const uint16_t i3 = get_field(s->fields, i3);
2782 const uint8_t fpf = get_field(s->fields, m4);
2783 const uint8_t m5 = get_field(s->fields, m5);
2784 gen_helper_gvec_2_ptr *fn = gen_helper_gvec_vftci64;
2785
2786 if (fpf != FPF_LONG || extract32(m5, 0, 3)) {
2787 gen_program_exception(s, PGM_SPECIFICATION);
2788 return DISAS_NORETURN;
2789 }
2790
2791 if (extract32(m5, 3, 1)) {
2792 fn = gen_helper_gvec_vftci64s;
2793 }
2794 gen_gvec_2_ptr(get_field(s->fields, v1), get_field(s->fields, v2), cpu_env,
2795 i3, fn);
2796 set_cc_static(s);
2797 return DISAS_NEXT;
2798}
2799