2 * QEMU TCG support -- s390x vector instruction translation functions
4 * Copyright (C) 2019 Red Hat Inc
7 * David Hildenbrand <david@redhat.com>
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.
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.
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.
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.
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.
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).
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)
55 /* Floating-Point Format */
60 static inline bool valid_vec_element(uint8_t enr, MemOp es)
62 return !(enr & ~(NUM_VEC_ELEMENTS(es) - 1));
65 static void read_vec_element_i64(TCGv_i64 dst, uint8_t reg, uint8_t enr,
68 const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE);
70 switch ((unsigned)memop) {
72 tcg_gen_ld8u_i64(dst, cpu_env, offs);
75 tcg_gen_ld16u_i64(dst, cpu_env, offs);
78 tcg_gen_ld32u_i64(dst, cpu_env, offs);
81 tcg_gen_ld8s_i64(dst, cpu_env, offs);
84 tcg_gen_ld16s_i64(dst, cpu_env, offs);
87 tcg_gen_ld32s_i64(dst, cpu_env, offs);
91 tcg_gen_ld_i64(dst, cpu_env, offs);
94 g_assert_not_reached();
98 static void read_vec_element_i32(TCGv_i32 dst, uint8_t reg, uint8_t enr,
101 const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE);
105 tcg_gen_ld8u_i32(dst, cpu_env, offs);
108 tcg_gen_ld16u_i32(dst, cpu_env, offs);
111 tcg_gen_ld8s_i32(dst, cpu_env, offs);
113 case ES_16 | MO_SIGN:
114 tcg_gen_ld16s_i32(dst, cpu_env, offs);
117 case ES_32 | MO_SIGN:
118 tcg_gen_ld_i32(dst, cpu_env, offs);
121 g_assert_not_reached();
125 static void write_vec_element_i64(TCGv_i64 src, int reg, uint8_t enr,
128 const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE);
132 tcg_gen_st8_i64(src, cpu_env, offs);
135 tcg_gen_st16_i64(src, cpu_env, offs);
138 tcg_gen_st32_i64(src, cpu_env, offs);
141 tcg_gen_st_i64(src, cpu_env, offs);
144 g_assert_not_reached();
148 static void write_vec_element_i32(TCGv_i32 src, int reg, uint8_t enr,
151 const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE);
155 tcg_gen_st8_i32(src, cpu_env, offs);
158 tcg_gen_st16_i32(src, cpu_env, offs);
161 tcg_gen_st_i32(src, cpu_env, offs);
164 g_assert_not_reached();
168 static void get_vec_element_ptr_i64(TCGv_ptr ptr, uint8_t reg, TCGv_i64 enr,
171 TCGv_i64 tmp = tcg_temp_new_i64();
173 /* mask off invalid parts from the element nr */
174 tcg_gen_andi_i64(tmp, enr, NUM_VEC_ELEMENTS(es) - 1);
176 /* convert it to an element offset relative to cpu_env (vec_reg_offset() */
177 tcg_gen_shli_i64(tmp, tmp, es);
179 tcg_gen_xori_i64(tmp, tmp, 8 - NUM_VEC_ELEMENT_BYTES(es));
181 tcg_gen_addi_i64(tmp, tmp, vec_full_reg_offset(reg));
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);
187 tcg_temp_free_i64(tmp);
190 #define gen_gvec_2(v1, v2, gen) \
191 tcg_gen_gvec_2(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
193 #define gen_gvec_2s(v1, v2, c, gen) \
194 tcg_gen_gvec_2s(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
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), \
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), \
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), \
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), \
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, \
234 #define gen_gvec_dup_imm(es, v1, c) \
235 tcg_gen_gvec_dup_imm(es, 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), \
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), \
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), \
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)
253 * Helper to carry out a 128 bit vector computation using 2 i64 values per
256 typedef 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);
258 static void gen_gvec128_3_i64(gen_gvec128_3_i64_fn fn, uint8_t d, uint8_t a,
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();
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);
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);
284 typedef 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);
287 static void gen_gvec128_4_i64(gen_gvec128_4_i64_fn fn, uint8_t d, uint8_t a,
288 uint8_t b, uint8_t c)
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();
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);
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);
319 static void gen_addi2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
322 TCGv_i64 bl = tcg_const_i64(b);
323 TCGv_i64 bh = tcg_const_i64(0);
325 tcg_gen_add2_i64(dl, dh, al, ah, bl, bh);
326 tcg_temp_free_i64(bl);
327 tcg_temp_free_i64(bh);
330 static DisasJumpType op_vbperm(DisasContext *s, DisasOps *o)
332 gen_gvec_3_ool(get_field(s, v1), get_field(s, v2), get_field(s, v3), 0,
333 gen_helper_gvec_vbperm);
338 static DisasJumpType op_vge(DisasContext *s, DisasOps *o)
340 const uint8_t es = s->insn->data;
341 const uint8_t enr = get_field(s, m3);
344 if (!valid_vec_element(enr, es)) {
345 gen_program_exception(s, PGM_SPECIFICATION);
346 return DISAS_NORETURN;
349 tmp = tcg_temp_new_i64();
350 read_vec_element_i64(tmp, get_field(s, v2), enr, es);
351 tcg_gen_add_i64(o->addr1, o->addr1, tmp);
352 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 0);
354 tcg_gen_qemu_ld_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
355 write_vec_element_i64(tmp, get_field(s, v1), enr, es);
356 tcg_temp_free_i64(tmp);
360 static uint64_t generate_byte_mask(uint8_t mask)
365 for (i = 0; i < 8; i++) {
366 if ((mask >> i) & 1) {
367 r |= 0xffull << (i * 8);
373 static DisasJumpType op_vgbm(DisasContext *s, DisasOps *o)
375 const uint16_t i2 = get_field(s, i2);
377 if (i2 == (i2 & 0xff) * 0x0101) {
379 * Masks for both 64 bit elements of the vector are the same.
380 * Trust tcg to produce a good constant loading.
382 gen_gvec_dup_imm(ES_64, get_field(s, v1),
383 generate_byte_mask(i2 & 0xff));
385 TCGv_i64 t = tcg_temp_new_i64();
387 tcg_gen_movi_i64(t, generate_byte_mask(i2 >> 8));
388 write_vec_element_i64(t, get_field(s, v1), 0, ES_64);
389 tcg_gen_movi_i64(t, generate_byte_mask(i2));
390 write_vec_element_i64(t, get_field(s, v1), 1, ES_64);
391 tcg_temp_free_i64(t);
396 static DisasJumpType op_vgm(DisasContext *s, DisasOps *o)
398 const uint8_t es = get_field(s, m4);
399 const uint8_t bits = NUM_VEC_ELEMENT_BITS(es);
400 const uint8_t i2 = get_field(s, i2) & (bits - 1);
401 const uint8_t i3 = get_field(s, i3) & (bits - 1);
406 gen_program_exception(s, PGM_SPECIFICATION);
407 return DISAS_NORETURN;
410 /* generate the mask - take care of wrapping */
411 for (i = i2; ; i = (i + 1) % bits) {
412 mask |= 1ull << (bits - i - 1);
418 gen_gvec_dup_imm(es, get_field(s, v1), mask);
422 static DisasJumpType op_vl(DisasContext *s, DisasOps *o)
424 TCGv_i64 t0 = tcg_temp_new_i64();
425 TCGv_i64 t1 = tcg_temp_new_i64();
427 tcg_gen_qemu_ld_i64(t0, o->addr1, get_mem_index(s), MO_TEUQ);
428 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
429 tcg_gen_qemu_ld_i64(t1, o->addr1, get_mem_index(s), MO_TEUQ);
430 write_vec_element_i64(t0, get_field(s, v1), 0, ES_64);
431 write_vec_element_i64(t1, get_field(s, v1), 1, ES_64);
437 static DisasJumpType op_vlr(DisasContext *s, DisasOps *o)
439 gen_gvec_mov(get_field(s, v1), get_field(s, v2));
443 static DisasJumpType op_vlrep(DisasContext *s, DisasOps *o)
445 const uint8_t es = get_field(s, m3);
449 gen_program_exception(s, PGM_SPECIFICATION);
450 return DISAS_NORETURN;
453 tmp = tcg_temp_new_i64();
454 tcg_gen_qemu_ld_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
455 gen_gvec_dup_i64(es, get_field(s, v1), tmp);
456 tcg_temp_free_i64(tmp);
460 static DisasJumpType op_vlebr(DisasContext *s, DisasOps *o)
462 const uint8_t es = s->insn->data;
463 const uint8_t enr = get_field(s, m3);
466 if (!valid_vec_element(enr, es)) {
467 gen_program_exception(s, PGM_SPECIFICATION);
468 return DISAS_NORETURN;
471 tmp = tcg_temp_new_i64();
472 tcg_gen_qemu_ld_i64(tmp, o->addr1, get_mem_index(s), MO_LE | es);
473 write_vec_element_i64(tmp, get_field(s, v1), enr, es);
474 tcg_temp_free_i64(tmp);
478 static DisasJumpType op_vlbrrep(DisasContext *s, DisasOps *o)
480 const uint8_t es = get_field(s, m3);
483 if (es < ES_16 || es > ES_64) {
484 gen_program_exception(s, PGM_SPECIFICATION);
485 return DISAS_NORETURN;
488 tmp = tcg_temp_new_i64();
489 tcg_gen_qemu_ld_i64(tmp, o->addr1, get_mem_index(s), MO_LE | es);
490 gen_gvec_dup_i64(es, get_field(s, v1), tmp);
491 tcg_temp_free_i64(tmp);
495 static DisasJumpType op_vllebrz(DisasContext *s, DisasOps *o)
497 const uint8_t m3 = get_field(s, m3);
513 gen_program_exception(s, PGM_SPECIFICATION);
514 return DISAS_NORETURN;
517 tmp = tcg_temp_new_i64();
518 tcg_gen_qemu_ld_i64(tmp, o->addr1, get_mem_index(s), MO_LE | es);
519 tcg_gen_shli_i64(tmp, tmp, lshift);
521 write_vec_element_i64(tmp, get_field(s, v1), 0, ES_64);
522 write_vec_element_i64(tcg_constant_i64(0), get_field(s, v1), 1, ES_64);
523 tcg_temp_free_i64(tmp);
527 static DisasJumpType op_vlbr(DisasContext *s, DisasOps *o)
529 const uint8_t es = get_field(s, m3);
532 if (es < ES_16 || es > ES_128) {
533 gen_program_exception(s, PGM_SPECIFICATION);
534 return DISAS_NORETURN;
537 t0 = tcg_temp_new_i64();
538 t1 = tcg_temp_new_i64();
542 tcg_gen_qemu_ld_i64(t1, o->addr1, get_mem_index(s), MO_LEUQ);
543 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
544 tcg_gen_qemu_ld_i64(t0, o->addr1, get_mem_index(s), MO_LEUQ);
548 /* Begin with byte reversed doublewords... */
549 tcg_gen_qemu_ld_i64(t0, o->addr1, get_mem_index(s), MO_LEUQ);
550 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
551 tcg_gen_qemu_ld_i64(t1, o->addr1, get_mem_index(s), MO_LEUQ);
554 * For 16 and 32-bit elements, the doubleword bswap also reversed
555 * the order of the elements. Perform a larger order swap to put
556 * them back into place. For the 128-bit "element", finish the
557 * bswap by swapping the doublewords.
561 tcg_gen_hswap_i64(t0, t0);
562 tcg_gen_hswap_i64(t1, t1);
565 tcg_gen_wswap_i64(t0, t0);
566 tcg_gen_wswap_i64(t1, t1);
571 g_assert_not_reached();
575 write_vec_element_i64(t0, get_field(s, v1), 0, ES_64);
576 write_vec_element_i64(t1, get_field(s, v1), 1, ES_64);
583 static DisasJumpType op_vle(DisasContext *s, DisasOps *o)
585 const uint8_t es = s->insn->data;
586 const uint8_t enr = get_field(s, m3);
589 if (!valid_vec_element(enr, es)) {
590 gen_program_exception(s, PGM_SPECIFICATION);
591 return DISAS_NORETURN;
594 tmp = tcg_temp_new_i64();
595 tcg_gen_qemu_ld_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
596 write_vec_element_i64(tmp, get_field(s, v1), enr, es);
597 tcg_temp_free_i64(tmp);
601 static DisasJumpType op_vlei(DisasContext *s, DisasOps *o)
603 const uint8_t es = s->insn->data;
604 const uint8_t enr = get_field(s, m3);
607 if (!valid_vec_element(enr, es)) {
608 gen_program_exception(s, PGM_SPECIFICATION);
609 return DISAS_NORETURN;
612 tmp = tcg_const_i64((int16_t)get_field(s, i2));
613 write_vec_element_i64(tmp, get_field(s, v1), enr, es);
614 tcg_temp_free_i64(tmp);
618 static DisasJumpType op_vler(DisasContext *s, DisasOps *o)
620 const uint8_t es = get_field(s, m3);
622 if (es < ES_16 || es > ES_64) {
623 gen_program_exception(s, PGM_SPECIFICATION);
624 return DISAS_NORETURN;
627 TCGv_i64 t0 = tcg_temp_new_i64();
628 TCGv_i64 t1 = tcg_temp_new_i64();
630 /* Begin with the two doublewords swapped... */
631 tcg_gen_qemu_ld_i64(t1, o->addr1, get_mem_index(s), MO_TEUQ);
632 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
633 tcg_gen_qemu_ld_i64(t0, o->addr1, get_mem_index(s), MO_TEUQ);
635 /* ... then swap smaller elements within the doublewords as required. */
638 tcg_gen_hswap_i64(t1, t1);
639 tcg_gen_hswap_i64(t0, t0);
642 tcg_gen_wswap_i64(t1, t1);
643 tcg_gen_wswap_i64(t0, t0);
648 g_assert_not_reached();
651 write_vec_element_i64(t0, get_field(s, v1), 0, ES_64);
652 write_vec_element_i64(t1, get_field(s, v1), 1, ES_64);
658 static DisasJumpType op_vlgv(DisasContext *s, DisasOps *o)
660 const uint8_t es = get_field(s, m4);
664 gen_program_exception(s, PGM_SPECIFICATION);
665 return DISAS_NORETURN;
668 /* fast path if we don't need the register content */
669 if (!get_field(s, b2)) {
670 uint8_t enr = get_field(s, d2) & (NUM_VEC_ELEMENTS(es) - 1);
672 read_vec_element_i64(o->out, get_field(s, v3), enr, es);
676 ptr = tcg_temp_new_ptr();
677 get_vec_element_ptr_i64(ptr, get_field(s, v3), o->addr1, es);
680 tcg_gen_ld8u_i64(o->out, ptr, 0);
683 tcg_gen_ld16u_i64(o->out, ptr, 0);
686 tcg_gen_ld32u_i64(o->out, ptr, 0);
689 tcg_gen_ld_i64(o->out, ptr, 0);
692 g_assert_not_reached();
694 tcg_temp_free_ptr(ptr);
699 static DisasJumpType op_vllez(DisasContext *s, DisasOps *o)
701 uint8_t es = get_field(s, m3);
706 /* rightmost sub-element of leftmost doubleword */
719 /* leftmost sub-element of leftmost doubleword */
721 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
728 gen_program_exception(s, PGM_SPECIFICATION);
729 return DISAS_NORETURN;
732 t = tcg_temp_new_i64();
733 tcg_gen_qemu_ld_i64(t, o->addr1, get_mem_index(s), MO_TE | es);
734 gen_gvec_dup_imm(es, get_field(s, v1), 0);
735 write_vec_element_i64(t, get_field(s, v1), enr, es);
736 tcg_temp_free_i64(t);
740 static DisasJumpType op_vlm(DisasContext *s, DisasOps *o)
742 const uint8_t v3 = get_field(s, v3);
743 uint8_t v1 = get_field(s, v1);
746 if (v3 < v1 || (v3 - v1 + 1) > 16) {
747 gen_program_exception(s, PGM_SPECIFICATION);
748 return DISAS_NORETURN;
752 * Check for possible access exceptions by trying to load the last
753 * element. The first element will be checked first next.
755 t0 = tcg_temp_new_i64();
756 t1 = tcg_temp_new_i64();
757 gen_addi_and_wrap_i64(s, t0, o->addr1, (v3 - v1) * 16 + 8);
758 tcg_gen_qemu_ld_i64(t0, t0, get_mem_index(s), MO_TEUQ);
761 tcg_gen_qemu_ld_i64(t1, o->addr1, get_mem_index(s), MO_TEUQ);
762 write_vec_element_i64(t1, v1, 0, ES_64);
766 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
767 tcg_gen_qemu_ld_i64(t1, o->addr1, get_mem_index(s), MO_TEUQ);
768 write_vec_element_i64(t1, v1, 1, ES_64);
769 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
772 /* Store the last element, loaded first */
773 write_vec_element_i64(t0, v1, 1, ES_64);
775 tcg_temp_free_i64(t0);
776 tcg_temp_free_i64(t1);
780 static DisasJumpType op_vlbb(DisasContext *s, DisasOps *o)
782 const int64_t block_size = (1ull << (get_field(s, m3) + 6));
783 const int v1_offs = vec_full_reg_offset(get_field(s, v1));
787 if (get_field(s, m3) > 6) {
788 gen_program_exception(s, PGM_SPECIFICATION);
789 return DISAS_NORETURN;
792 bytes = tcg_temp_new_i64();
793 a0 = tcg_temp_new_ptr();
794 /* calculate the number of bytes until the next block boundary */
795 tcg_gen_ori_i64(bytes, o->addr1, -block_size);
796 tcg_gen_neg_i64(bytes, bytes);
798 tcg_gen_addi_ptr(a0, cpu_env, v1_offs);
799 gen_helper_vll(cpu_env, a0, o->addr1, bytes);
800 tcg_temp_free_i64(bytes);
801 tcg_temp_free_ptr(a0);
805 static DisasJumpType op_vlvg(DisasContext *s, DisasOps *o)
807 const uint8_t es = get_field(s, m4);
811 gen_program_exception(s, PGM_SPECIFICATION);
812 return DISAS_NORETURN;
815 /* fast path if we don't need the register content */
816 if (!get_field(s, b2)) {
817 uint8_t enr = get_field(s, d2) & (NUM_VEC_ELEMENTS(es) - 1);
819 write_vec_element_i64(o->in2, get_field(s, v1), enr, es);
823 ptr = tcg_temp_new_ptr();
824 get_vec_element_ptr_i64(ptr, get_field(s, v1), o->addr1, es);
827 tcg_gen_st8_i64(o->in2, ptr, 0);
830 tcg_gen_st16_i64(o->in2, ptr, 0);
833 tcg_gen_st32_i64(o->in2, ptr, 0);
836 tcg_gen_st_i64(o->in2, ptr, 0);
839 g_assert_not_reached();
841 tcg_temp_free_ptr(ptr);
846 static DisasJumpType op_vlvgp(DisasContext *s, DisasOps *o)
848 write_vec_element_i64(o->in1, get_field(s, v1), 0, ES_64);
849 write_vec_element_i64(o->in2, get_field(s, v1), 1, ES_64);
853 static DisasJumpType op_vll(DisasContext *s, DisasOps *o)
855 const int v1_offs = vec_full_reg_offset(get_field(s, v1));
856 TCGv_ptr a0 = tcg_temp_new_ptr();
858 /* convert highest index into an actual length */
859 tcg_gen_addi_i64(o->in2, o->in2, 1);
860 tcg_gen_addi_ptr(a0, cpu_env, v1_offs);
861 gen_helper_vll(cpu_env, a0, o->addr1, o->in2);
862 tcg_temp_free_ptr(a0);
866 static DisasJumpType op_vmr(DisasContext *s, DisasOps *o)
868 const uint8_t v1 = get_field(s, v1);
869 const uint8_t v2 = get_field(s, v2);
870 const uint8_t v3 = get_field(s, v3);
871 const uint8_t es = get_field(s, m4);
872 int dst_idx, src_idx;
876 gen_program_exception(s, PGM_SPECIFICATION);
877 return DISAS_NORETURN;
880 tmp = tcg_temp_new_i64();
881 if (s->fields.op2 == 0x61) {
882 /* iterate backwards to avoid overwriting data we might need later */
883 for (dst_idx = NUM_VEC_ELEMENTS(es) - 1; dst_idx >= 0; dst_idx--) {
884 src_idx = dst_idx / 2;
885 if (dst_idx % 2 == 0) {
886 read_vec_element_i64(tmp, v2, src_idx, es);
888 read_vec_element_i64(tmp, v3, src_idx, es);
890 write_vec_element_i64(tmp, v1, dst_idx, es);
893 /* iterate forward to avoid overwriting data we might need later */
894 for (dst_idx = 0; dst_idx < NUM_VEC_ELEMENTS(es); dst_idx++) {
895 src_idx = (dst_idx + NUM_VEC_ELEMENTS(es)) / 2;
896 if (dst_idx % 2 == 0) {
897 read_vec_element_i64(tmp, v2, src_idx, es);
899 read_vec_element_i64(tmp, v3, src_idx, es);
901 write_vec_element_i64(tmp, v1, dst_idx, es);
904 tcg_temp_free_i64(tmp);
908 static DisasJumpType op_vpk(DisasContext *s, DisasOps *o)
910 const uint8_t v1 = get_field(s, v1);
911 const uint8_t v2 = get_field(s, v2);
912 const uint8_t v3 = get_field(s, v3);
913 const uint8_t es = get_field(s, m4);
914 static gen_helper_gvec_3 * const vpk[3] = {
915 gen_helper_gvec_vpk16,
916 gen_helper_gvec_vpk32,
917 gen_helper_gvec_vpk64,
919 static gen_helper_gvec_3 * const vpks[3] = {
920 gen_helper_gvec_vpks16,
921 gen_helper_gvec_vpks32,
922 gen_helper_gvec_vpks64,
924 static gen_helper_gvec_3_ptr * const vpks_cc[3] = {
925 gen_helper_gvec_vpks_cc16,
926 gen_helper_gvec_vpks_cc32,
927 gen_helper_gvec_vpks_cc64,
929 static gen_helper_gvec_3 * const vpkls[3] = {
930 gen_helper_gvec_vpkls16,
931 gen_helper_gvec_vpkls32,
932 gen_helper_gvec_vpkls64,
934 static gen_helper_gvec_3_ptr * const vpkls_cc[3] = {
935 gen_helper_gvec_vpkls_cc16,
936 gen_helper_gvec_vpkls_cc32,
937 gen_helper_gvec_vpkls_cc64,
940 if (es == ES_8 || es > ES_64) {
941 gen_program_exception(s, PGM_SPECIFICATION);
942 return DISAS_NORETURN;
945 switch (s->fields.op2) {
947 if (get_field(s, m5) & 0x1) {
948 gen_gvec_3_ptr(v1, v2, v3, cpu_env, 0, vpks_cc[es - 1]);
951 gen_gvec_3_ool(v1, v2, v3, 0, vpks[es - 1]);
955 if (get_field(s, m5) & 0x1) {
956 gen_gvec_3_ptr(v1, v2, v3, cpu_env, 0, vpkls_cc[es - 1]);
959 gen_gvec_3_ool(v1, v2, v3, 0, vpkls[es - 1]);
963 /* If sources and destination dont't overlap -> fast path */
964 if (v1 != v2 && v1 != v3) {
965 const uint8_t src_es = get_field(s, m4);
966 const uint8_t dst_es = src_es - 1;
967 TCGv_i64 tmp = tcg_temp_new_i64();
968 int dst_idx, src_idx;
970 for (dst_idx = 0; dst_idx < NUM_VEC_ELEMENTS(dst_es); dst_idx++) {
972 if (src_idx < NUM_VEC_ELEMENTS(src_es)) {
973 read_vec_element_i64(tmp, v2, src_idx, src_es);
975 src_idx -= NUM_VEC_ELEMENTS(src_es);
976 read_vec_element_i64(tmp, v3, src_idx, src_es);
978 write_vec_element_i64(tmp, v1, dst_idx, dst_es);
980 tcg_temp_free_i64(tmp);
982 gen_gvec_3_ool(v1, v2, v3, 0, vpk[es - 1]);
986 g_assert_not_reached();
991 static DisasJumpType op_vperm(DisasContext *s, DisasOps *o)
993 gen_gvec_4_ool(get_field(s, v1), get_field(s, v2),
994 get_field(s, v3), get_field(s, v4),
995 0, gen_helper_gvec_vperm);
999 static DisasJumpType op_vpdi(DisasContext *s, DisasOps *o)
1001 const uint8_t i2 = extract32(get_field(s, m4), 2, 1);
1002 const uint8_t i3 = extract32(get_field(s, m4), 0, 1);
1003 TCGv_i64 t0 = tcg_temp_new_i64();
1004 TCGv_i64 t1 = tcg_temp_new_i64();
1006 read_vec_element_i64(t0, get_field(s, v2), i2, ES_64);
1007 read_vec_element_i64(t1, get_field(s, v3), i3, ES_64);
1008 write_vec_element_i64(t0, get_field(s, v1), 0, ES_64);
1009 write_vec_element_i64(t1, get_field(s, v1), 1, ES_64);
1010 tcg_temp_free_i64(t0);
1011 tcg_temp_free_i64(t1);
1015 static DisasJumpType op_vrep(DisasContext *s, DisasOps *o)
1017 const uint8_t enr = get_field(s, i2);
1018 const uint8_t es = get_field(s, m4);
1020 if (es > ES_64 || !valid_vec_element(enr, es)) {
1021 gen_program_exception(s, PGM_SPECIFICATION);
1022 return DISAS_NORETURN;
1025 tcg_gen_gvec_dup_mem(es, vec_full_reg_offset(get_field(s, v1)),
1026 vec_reg_offset(get_field(s, v3), enr, es),
1031 static DisasJumpType op_vrepi(DisasContext *s, DisasOps *o)
1033 const int64_t data = (int16_t)get_field(s, i2);
1034 const uint8_t es = get_field(s, m3);
1037 gen_program_exception(s, PGM_SPECIFICATION);
1038 return DISAS_NORETURN;
1041 gen_gvec_dup_imm(es, get_field(s, v1), data);
1045 static DisasJumpType op_vsce(DisasContext *s, DisasOps *o)
1047 const uint8_t es = s->insn->data;
1048 const uint8_t enr = get_field(s, m3);
1051 if (!valid_vec_element(enr, es)) {
1052 gen_program_exception(s, PGM_SPECIFICATION);
1053 return DISAS_NORETURN;
1056 tmp = tcg_temp_new_i64();
1057 read_vec_element_i64(tmp, get_field(s, v2), enr, es);
1058 tcg_gen_add_i64(o->addr1, o->addr1, tmp);
1059 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 0);
1061 read_vec_element_i64(tmp, get_field(s, v1), enr, es);
1062 tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
1063 tcg_temp_free_i64(tmp);
1067 static DisasJumpType op_vsel(DisasContext *s, DisasOps *o)
1069 gen_gvec_fn_4(bitsel, ES_8, get_field(s, v1),
1070 get_field(s, v4), get_field(s, v2),
1075 static DisasJumpType op_vseg(DisasContext *s, DisasOps *o)
1077 const uint8_t es = get_field(s, m3);
1095 gen_program_exception(s, PGM_SPECIFICATION);
1096 return DISAS_NORETURN;
1099 tmp = tcg_temp_new_i64();
1100 read_vec_element_i64(tmp, get_field(s, v2), idx1, es | MO_SIGN);
1101 write_vec_element_i64(tmp, get_field(s, v1), 0, ES_64);
1102 read_vec_element_i64(tmp, get_field(s, v2), idx2, es | MO_SIGN);
1103 write_vec_element_i64(tmp, get_field(s, v1), 1, ES_64);
1104 tcg_temp_free_i64(tmp);
1108 static DisasJumpType op_vst(DisasContext *s, DisasOps *o)
1110 TCGv_i64 tmp = tcg_const_i64(16);
1112 /* Probe write access before actually modifying memory */
1113 gen_helper_probe_write_access(cpu_env, o->addr1, tmp);
1115 read_vec_element_i64(tmp, get_field(s, v1), 0, ES_64);
1116 tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEUQ);
1117 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
1118 read_vec_element_i64(tmp, get_field(s, v1), 1, ES_64);
1119 tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEUQ);
1120 tcg_temp_free_i64(tmp);
1124 static DisasJumpType op_vstebr(DisasContext *s, DisasOps *o)
1126 const uint8_t es = s->insn->data;
1127 const uint8_t enr = get_field(s, m3);
1130 if (!valid_vec_element(enr, es)) {
1131 gen_program_exception(s, PGM_SPECIFICATION);
1132 return DISAS_NORETURN;
1135 tmp = tcg_temp_new_i64();
1136 read_vec_element_i64(tmp, get_field(s, v1), enr, es);
1137 tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_LE | es);
1138 tcg_temp_free_i64(tmp);
1142 static DisasJumpType op_vstbr(DisasContext *s, DisasOps *o)
1144 const uint8_t es = get_field(s, m3);
1147 if (es < ES_16 || es > ES_128) {
1148 gen_program_exception(s, PGM_SPECIFICATION);
1149 return DISAS_NORETURN;
1152 /* Probe write access before actually modifying memory */
1153 gen_helper_probe_write_access(cpu_env, o->addr1, tcg_constant_i64(16));
1155 t0 = tcg_temp_new_i64();
1156 t1 = tcg_temp_new_i64();
1160 read_vec_element_i64(t1, get_field(s, v1), 0, ES_64);
1161 read_vec_element_i64(t0, get_field(s, v1), 1, ES_64);
1165 read_vec_element_i64(t0, get_field(s, v1), 0, ES_64);
1166 read_vec_element_i64(t1, get_field(s, v1), 1, ES_64);
1169 * For 16 and 32-bit elements, the doubleword bswap below will
1170 * reverse the order of the elements. Perform a larger order
1171 * swap to put them back into place. For the 128-bit "element",
1172 * finish the bswap by swapping the doublewords.
1176 tcg_gen_hswap_i64(t0, t0);
1177 tcg_gen_hswap_i64(t1, t1);
1180 tcg_gen_wswap_i64(t0, t0);
1181 tcg_gen_wswap_i64(t1, t1);
1186 g_assert_not_reached();
1190 tcg_gen_qemu_st_i64(t0, o->addr1, get_mem_index(s), MO_LEUQ);
1191 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
1192 tcg_gen_qemu_st_i64(t1, o->addr1, get_mem_index(s), MO_LEUQ);
1199 static DisasJumpType op_vste(DisasContext *s, DisasOps *o)
1201 const uint8_t es = s->insn->data;
1202 const uint8_t enr = get_field(s, m3);
1205 if (!valid_vec_element(enr, es)) {
1206 gen_program_exception(s, PGM_SPECIFICATION);
1207 return DISAS_NORETURN;
1210 tmp = tcg_temp_new_i64();
1211 read_vec_element_i64(tmp, get_field(s, v1), enr, es);
1212 tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
1213 tcg_temp_free_i64(tmp);
1217 static DisasJumpType op_vster(DisasContext *s, DisasOps *o)
1219 const uint8_t es = get_field(s, m3);
1222 if (es < ES_16 || es > ES_64) {
1223 gen_program_exception(s, PGM_SPECIFICATION);
1224 return DISAS_NORETURN;
1227 /* Probe write access before actually modifying memory */
1228 gen_helper_probe_write_access(cpu_env, o->addr1, tcg_constant_i64(16));
1230 /* Begin with the two doublewords swapped... */
1231 t0 = tcg_temp_new_i64();
1232 t1 = tcg_temp_new_i64();
1233 read_vec_element_i64(t1, get_field(s, v1), 0, ES_64);
1234 read_vec_element_i64(t0, get_field(s, v1), 1, ES_64);
1236 /* ... then swap smaller elements within the doublewords as required. */
1239 tcg_gen_hswap_i64(t1, t1);
1240 tcg_gen_hswap_i64(t0, t0);
1243 tcg_gen_wswap_i64(t1, t1);
1244 tcg_gen_wswap_i64(t0, t0);
1249 g_assert_not_reached();
1252 tcg_gen_qemu_st_i64(t0, o->addr1, get_mem_index(s), MO_TEUQ);
1253 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
1254 tcg_gen_qemu_st_i64(t1, o->addr1, get_mem_index(s), MO_TEUQ);
1261 static DisasJumpType op_vstm(DisasContext *s, DisasOps *o)
1263 const uint8_t v3 = get_field(s, v3);
1264 uint8_t v1 = get_field(s, v1);
1267 while (v3 < v1 || (v3 - v1 + 1) > 16) {
1268 gen_program_exception(s, PGM_SPECIFICATION);
1269 return DISAS_NORETURN;
1272 /* Probe write access before actually modifying memory */
1273 tmp = tcg_const_i64((v3 - v1 + 1) * 16);
1274 gen_helper_probe_write_access(cpu_env, o->addr1, tmp);
1277 read_vec_element_i64(tmp, v1, 0, ES_64);
1278 tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEUQ);
1279 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
1280 read_vec_element_i64(tmp, v1, 1, ES_64);
1281 tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEUQ);
1285 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
1287 tcg_temp_free_i64(tmp);
1291 static DisasJumpType op_vstl(DisasContext *s, DisasOps *o)
1293 const int v1_offs = vec_full_reg_offset(get_field(s, v1));
1294 TCGv_ptr a0 = tcg_temp_new_ptr();
1296 /* convert highest index into an actual length */
1297 tcg_gen_addi_i64(o->in2, o->in2, 1);
1298 tcg_gen_addi_ptr(a0, cpu_env, v1_offs);
1299 gen_helper_vstl(cpu_env, a0, o->addr1, o->in2);
1300 tcg_temp_free_ptr(a0);
1304 static DisasJumpType op_vup(DisasContext *s, DisasOps *o)
1306 const bool logical = s->fields.op2 == 0xd4 || s->fields.op2 == 0xd5;
1307 const uint8_t v1 = get_field(s, v1);
1308 const uint8_t v2 = get_field(s, v2);
1309 const uint8_t src_es = get_field(s, m3);
1310 const uint8_t dst_es = src_es + 1;
1311 int dst_idx, src_idx;
1314 if (src_es > ES_32) {
1315 gen_program_exception(s, PGM_SPECIFICATION);
1316 return DISAS_NORETURN;
1319 tmp = tcg_temp_new_i64();
1320 if (s->fields.op2 == 0xd7 || s->fields.op2 == 0xd5) {
1321 /* iterate backwards to avoid overwriting data we might need later */
1322 for (dst_idx = NUM_VEC_ELEMENTS(dst_es) - 1; dst_idx >= 0; dst_idx--) {
1324 read_vec_element_i64(tmp, v2, src_idx,
1325 src_es | (logical ? 0 : MO_SIGN));
1326 write_vec_element_i64(tmp, v1, dst_idx, dst_es);
1330 /* iterate forward to avoid overwriting data we might need later */
1331 for (dst_idx = 0; dst_idx < NUM_VEC_ELEMENTS(dst_es); dst_idx++) {
1332 src_idx = dst_idx + NUM_VEC_ELEMENTS(src_es) / 2;
1333 read_vec_element_i64(tmp, v2, src_idx,
1334 src_es | (logical ? 0 : MO_SIGN));
1335 write_vec_element_i64(tmp, v1, dst_idx, dst_es);
1338 tcg_temp_free_i64(tmp);
1342 static DisasJumpType op_va(DisasContext *s, DisasOps *o)
1344 const uint8_t es = get_field(s, m4);
1347 gen_program_exception(s, PGM_SPECIFICATION);
1348 return DISAS_NORETURN;
1349 } else if (es == ES_128) {
1350 gen_gvec128_3_i64(tcg_gen_add2_i64, get_field(s, v1),
1351 get_field(s, v2), get_field(s, v3));
1354 gen_gvec_fn_3(add, es, get_field(s, v1), get_field(s, v2),
1359 static void gen_acc(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b, uint8_t es)
1361 const uint8_t msb_bit_nr = NUM_VEC_ELEMENT_BITS(es) - 1;
1362 TCGv_i64 msb_mask = tcg_const_i64(dup_const(es, 1ull << msb_bit_nr));
1363 TCGv_i64 t1 = tcg_temp_new_i64();
1364 TCGv_i64 t2 = tcg_temp_new_i64();
1365 TCGv_i64 t3 = tcg_temp_new_i64();
1367 /* Calculate the carry into the MSB, ignoring the old MSBs */
1368 tcg_gen_andc_i64(t1, a, msb_mask);
1369 tcg_gen_andc_i64(t2, b, msb_mask);
1370 tcg_gen_add_i64(t1, t1, t2);
1371 /* Calculate the MSB without any carry into it */
1372 tcg_gen_xor_i64(t3, a, b);
1373 /* Calculate the carry out of the MSB in the MSB bit position */
1374 tcg_gen_and_i64(d, a, b);
1375 tcg_gen_and_i64(t1, t1, t3);
1376 tcg_gen_or_i64(d, d, t1);
1377 /* Isolate and shift the carry into position */
1378 tcg_gen_and_i64(d, d, msb_mask);
1379 tcg_gen_shri_i64(d, d, msb_bit_nr);
1381 tcg_temp_free_i64(t1);
1382 tcg_temp_free_i64(t2);
1383 tcg_temp_free_i64(t3);
1386 static void gen_acc8_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
1388 gen_acc(d, a, b, ES_8);
1391 static void gen_acc16_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
1393 gen_acc(d, a, b, ES_16);
1396 static void gen_acc_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
1398 TCGv_i32 t = tcg_temp_new_i32();
1400 tcg_gen_add_i32(t, a, b);
1401 tcg_gen_setcond_i32(TCG_COND_LTU, d, t, b);
1402 tcg_temp_free_i32(t);
1405 static void gen_acc_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
1407 TCGv_i64 t = tcg_temp_new_i64();
1409 tcg_gen_add_i64(t, a, b);
1410 tcg_gen_setcond_i64(TCG_COND_LTU, d, t, b);
1411 tcg_temp_free_i64(t);
1414 static void gen_acc2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al,
1415 TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh)
1417 TCGv_i64 th = tcg_temp_new_i64();
1418 TCGv_i64 tl = tcg_temp_new_i64();
1419 TCGv_i64 zero = tcg_const_i64(0);
1421 tcg_gen_add2_i64(tl, th, al, zero, bl, zero);
1422 tcg_gen_add2_i64(tl, th, th, zero, ah, zero);
1423 tcg_gen_add2_i64(tl, dl, tl, th, bh, zero);
1424 tcg_gen_mov_i64(dh, zero);
1426 tcg_temp_free_i64(th);
1427 tcg_temp_free_i64(tl);
1428 tcg_temp_free_i64(zero);
1431 static DisasJumpType op_vacc(DisasContext *s, DisasOps *o)
1433 const uint8_t es = get_field(s, m4);
1434 static const GVecGen3 g[4] = {
1435 { .fni8 = gen_acc8_i64, },
1436 { .fni8 = gen_acc16_i64, },
1437 { .fni4 = gen_acc_i32, },
1438 { .fni8 = gen_acc_i64, },
1442 gen_program_exception(s, PGM_SPECIFICATION);
1443 return DISAS_NORETURN;
1444 } else if (es == ES_128) {
1445 gen_gvec128_3_i64(gen_acc2_i64, get_field(s, v1),
1446 get_field(s, v2), get_field(s, v3));
1449 gen_gvec_3(get_field(s, v1), get_field(s, v2),
1450 get_field(s, v3), &g[es]);
1454 static void gen_ac2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
1455 TCGv_i64 bl, TCGv_i64 bh, TCGv_i64 cl, TCGv_i64 ch)
1457 TCGv_i64 tl = tcg_temp_new_i64();
1458 TCGv_i64 th = tcg_const_i64(0);
1460 /* extract the carry only */
1461 tcg_gen_extract_i64(tl, cl, 0, 1);
1462 tcg_gen_add2_i64(dl, dh, al, ah, bl, bh);
1463 tcg_gen_add2_i64(dl, dh, dl, dh, tl, th);
1465 tcg_temp_free_i64(tl);
1466 tcg_temp_free_i64(th);
1469 static DisasJumpType op_vac(DisasContext *s, DisasOps *o)
1471 if (get_field(s, m5) != ES_128) {
1472 gen_program_exception(s, PGM_SPECIFICATION);
1473 return DISAS_NORETURN;
1476 gen_gvec128_4_i64(gen_ac2_i64, get_field(s, v1),
1477 get_field(s, v2), get_field(s, v3),
1482 static void gen_accc2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
1483 TCGv_i64 bl, TCGv_i64 bh, TCGv_i64 cl, TCGv_i64 ch)
1485 TCGv_i64 tl = tcg_temp_new_i64();
1486 TCGv_i64 th = tcg_temp_new_i64();
1487 TCGv_i64 zero = tcg_const_i64(0);
1489 tcg_gen_andi_i64(tl, cl, 1);
1490 tcg_gen_add2_i64(tl, th, tl, zero, al, zero);
1491 tcg_gen_add2_i64(tl, th, tl, th, bl, zero);
1492 tcg_gen_add2_i64(tl, th, th, zero, ah, zero);
1493 tcg_gen_add2_i64(tl, dl, tl, th, bh, zero);
1494 tcg_gen_mov_i64(dh, zero);
1496 tcg_temp_free_i64(tl);
1497 tcg_temp_free_i64(th);
1498 tcg_temp_free_i64(zero);
1501 static DisasJumpType op_vaccc(DisasContext *s, DisasOps *o)
1503 if (get_field(s, m5) != ES_128) {
1504 gen_program_exception(s, PGM_SPECIFICATION);
1505 return DISAS_NORETURN;
1508 gen_gvec128_4_i64(gen_accc2_i64, get_field(s, v1),
1509 get_field(s, v2), get_field(s, v3),
1514 static DisasJumpType op_vn(DisasContext *s, DisasOps *o)
1516 gen_gvec_fn_3(and, ES_8, get_field(s, v1), get_field(s, v2),
1521 static DisasJumpType op_vnc(DisasContext *s, DisasOps *o)
1523 gen_gvec_fn_3(andc, ES_8, get_field(s, v1),
1524 get_field(s, v2), get_field(s, v3));
1528 static void gen_avg_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
1530 TCGv_i64 t0 = tcg_temp_new_i64();
1531 TCGv_i64 t1 = tcg_temp_new_i64();
1533 tcg_gen_ext_i32_i64(t0, a);
1534 tcg_gen_ext_i32_i64(t1, b);
1535 tcg_gen_add_i64(t0, t0, t1);
1536 tcg_gen_addi_i64(t0, t0, 1);
1537 tcg_gen_shri_i64(t0, t0, 1);
1538 tcg_gen_extrl_i64_i32(d, t0);
1544 static void gen_avg_i64(TCGv_i64 dl, TCGv_i64 al, TCGv_i64 bl)
1546 TCGv_i64 dh = tcg_temp_new_i64();
1547 TCGv_i64 ah = tcg_temp_new_i64();
1548 TCGv_i64 bh = tcg_temp_new_i64();
1550 /* extending the sign by one bit is sufficient */
1551 tcg_gen_extract_i64(ah, al, 63, 1);
1552 tcg_gen_extract_i64(bh, bl, 63, 1);
1553 tcg_gen_add2_i64(dl, dh, al, ah, bl, bh);
1554 gen_addi2_i64(dl, dh, dl, dh, 1);
1555 tcg_gen_extract2_i64(dl, dl, dh, 1);
1557 tcg_temp_free_i64(dh);
1558 tcg_temp_free_i64(ah);
1559 tcg_temp_free_i64(bh);
1562 static DisasJumpType op_vavg(DisasContext *s, DisasOps *o)
1564 const uint8_t es = get_field(s, m4);
1565 static const GVecGen3 g[4] = {
1566 { .fno = gen_helper_gvec_vavg8, },
1567 { .fno = gen_helper_gvec_vavg16, },
1568 { .fni4 = gen_avg_i32, },
1569 { .fni8 = gen_avg_i64, },
1573 gen_program_exception(s, PGM_SPECIFICATION);
1574 return DISAS_NORETURN;
1576 gen_gvec_3(get_field(s, v1), get_field(s, v2),
1577 get_field(s, v3), &g[es]);
1581 static void gen_avgl_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
1583 TCGv_i64 t0 = tcg_temp_new_i64();
1584 TCGv_i64 t1 = tcg_temp_new_i64();
1586 tcg_gen_extu_i32_i64(t0, a);
1587 tcg_gen_extu_i32_i64(t1, b);
1588 tcg_gen_add_i64(t0, t0, t1);
1589 tcg_gen_addi_i64(t0, t0, 1);
1590 tcg_gen_shri_i64(t0, t0, 1);
1591 tcg_gen_extrl_i64_i32(d, t0);
1597 static void gen_avgl_i64(TCGv_i64 dl, TCGv_i64 al, TCGv_i64 bl)
1599 TCGv_i64 dh = tcg_temp_new_i64();
1600 TCGv_i64 zero = tcg_const_i64(0);
1602 tcg_gen_add2_i64(dl, dh, al, zero, bl, zero);
1603 gen_addi2_i64(dl, dh, dl, dh, 1);
1604 tcg_gen_extract2_i64(dl, dl, dh, 1);
1606 tcg_temp_free_i64(dh);
1607 tcg_temp_free_i64(zero);
1610 static DisasJumpType op_vavgl(DisasContext *s, DisasOps *o)
1612 const uint8_t es = get_field(s, m4);
1613 static const GVecGen3 g[4] = {
1614 { .fno = gen_helper_gvec_vavgl8, },
1615 { .fno = gen_helper_gvec_vavgl16, },
1616 { .fni4 = gen_avgl_i32, },
1617 { .fni8 = gen_avgl_i64, },
1621 gen_program_exception(s, PGM_SPECIFICATION);
1622 return DISAS_NORETURN;
1624 gen_gvec_3(get_field(s, v1), get_field(s, v2),
1625 get_field(s, v3), &g[es]);
1629 static DisasJumpType op_vcksm(DisasContext *s, DisasOps *o)
1631 TCGv_i32 tmp = tcg_temp_new_i32();
1632 TCGv_i32 sum = tcg_temp_new_i32();
1635 read_vec_element_i32(sum, get_field(s, v3), 1, ES_32);
1636 for (i = 0; i < 4; i++) {
1637 read_vec_element_i32(tmp, get_field(s, v2), i, ES_32);
1638 tcg_gen_add2_i32(tmp, sum, sum, sum, tmp, tmp);
1640 gen_gvec_dup_imm(ES_32, get_field(s, v1), 0);
1641 write_vec_element_i32(sum, get_field(s, v1), 1, ES_32);
1643 tcg_temp_free_i32(tmp);
1644 tcg_temp_free_i32(sum);
1648 static DisasJumpType op_vec(DisasContext *s, DisasOps *o)
1650 uint8_t es = get_field(s, m3);
1651 const uint8_t enr = NUM_VEC_ELEMENTS(es) / 2 - 1;
1654 gen_program_exception(s, PGM_SPECIFICATION);
1655 return DISAS_NORETURN;
1657 if (s->fields.op2 == 0xdb) {
1661 o->in1 = tcg_temp_new_i64();
1662 o->in2 = tcg_temp_new_i64();
1663 read_vec_element_i64(o->in1, get_field(s, v1), enr, es);
1664 read_vec_element_i64(o->in2, get_field(s, v2), enr, es);
1668 static DisasJumpType op_vc(DisasContext *s, DisasOps *o)
1670 const uint8_t es = get_field(s, m4);
1671 TCGCond cond = s->insn->data;
1674 gen_program_exception(s, PGM_SPECIFICATION);
1675 return DISAS_NORETURN;
1678 tcg_gen_gvec_cmp(cond, es,
1679 vec_full_reg_offset(get_field(s, v1)),
1680 vec_full_reg_offset(get_field(s, v2)),
1681 vec_full_reg_offset(get_field(s, v3)), 16, 16);
1682 if (get_field(s, m5) & 0x1) {
1683 TCGv_i64 low = tcg_temp_new_i64();
1684 TCGv_i64 high = tcg_temp_new_i64();
1686 read_vec_element_i64(high, get_field(s, v1), 0, ES_64);
1687 read_vec_element_i64(low, get_field(s, v1), 1, ES_64);
1688 gen_op_update2_cc_i64(s, CC_OP_VC, low, high);
1690 tcg_temp_free_i64(low);
1691 tcg_temp_free_i64(high);
1696 static void gen_clz_i32(TCGv_i32 d, TCGv_i32 a)
1698 tcg_gen_clzi_i32(d, a, 32);
1701 static void gen_clz_i64(TCGv_i64 d, TCGv_i64 a)
1703 tcg_gen_clzi_i64(d, a, 64);
1706 static DisasJumpType op_vclz(DisasContext *s, DisasOps *o)
1708 const uint8_t es = get_field(s, m3);
1709 static const GVecGen2 g[4] = {
1710 { .fno = gen_helper_gvec_vclz8, },
1711 { .fno = gen_helper_gvec_vclz16, },
1712 { .fni4 = gen_clz_i32, },
1713 { .fni8 = gen_clz_i64, },
1717 gen_program_exception(s, PGM_SPECIFICATION);
1718 return DISAS_NORETURN;
1720 gen_gvec_2(get_field(s, v1), get_field(s, v2), &g[es]);
1724 static void gen_ctz_i32(TCGv_i32 d, TCGv_i32 a)
1726 tcg_gen_ctzi_i32(d, a, 32);
1729 static void gen_ctz_i64(TCGv_i64 d, TCGv_i64 a)
1731 tcg_gen_ctzi_i64(d, a, 64);
1734 static DisasJumpType op_vctz(DisasContext *s, DisasOps *o)
1736 const uint8_t es = get_field(s, m3);
1737 static const GVecGen2 g[4] = {
1738 { .fno = gen_helper_gvec_vctz8, },
1739 { .fno = gen_helper_gvec_vctz16, },
1740 { .fni4 = gen_ctz_i32, },
1741 { .fni8 = gen_ctz_i64, },
1745 gen_program_exception(s, PGM_SPECIFICATION);
1746 return DISAS_NORETURN;
1748 gen_gvec_2(get_field(s, v1), get_field(s, v2), &g[es]);
1752 static DisasJumpType op_vx(DisasContext *s, DisasOps *o)
1754 gen_gvec_fn_3(xor, ES_8, get_field(s, v1), get_field(s, v2),
1759 static DisasJumpType op_vgfm(DisasContext *s, DisasOps *o)
1761 const uint8_t es = get_field(s, m4);
1762 static const GVecGen3 g[4] = {
1763 { .fno = gen_helper_gvec_vgfm8, },
1764 { .fno = gen_helper_gvec_vgfm16, },
1765 { .fno = gen_helper_gvec_vgfm32, },
1766 { .fno = gen_helper_gvec_vgfm64, },
1770 gen_program_exception(s, PGM_SPECIFICATION);
1771 return DISAS_NORETURN;
1773 gen_gvec_3(get_field(s, v1), get_field(s, v2),
1774 get_field(s, v3), &g[es]);
1778 static DisasJumpType op_vgfma(DisasContext *s, DisasOps *o)
1780 const uint8_t es = get_field(s, m5);
1781 static const GVecGen4 g[4] = {
1782 { .fno = gen_helper_gvec_vgfma8, },
1783 { .fno = gen_helper_gvec_vgfma16, },
1784 { .fno = gen_helper_gvec_vgfma32, },
1785 { .fno = gen_helper_gvec_vgfma64, },
1789 gen_program_exception(s, PGM_SPECIFICATION);
1790 return DISAS_NORETURN;
1792 gen_gvec_4(get_field(s, v1), get_field(s, v2),
1793 get_field(s, v3), get_field(s, v4), &g[es]);
1797 static DisasJumpType op_vlc(DisasContext *s, DisasOps *o)
1799 const uint8_t es = get_field(s, m3);
1802 gen_program_exception(s, PGM_SPECIFICATION);
1803 return DISAS_NORETURN;
1806 gen_gvec_fn_2(neg, es, get_field(s, v1), get_field(s, v2));
1810 static DisasJumpType op_vlp(DisasContext *s, DisasOps *o)
1812 const uint8_t es = get_field(s, m3);
1815 gen_program_exception(s, PGM_SPECIFICATION);
1816 return DISAS_NORETURN;
1819 gen_gvec_fn_2(abs, es, get_field(s, v1), get_field(s, v2));
1823 static DisasJumpType op_vmx(DisasContext *s, DisasOps *o)
1825 const uint8_t v1 = get_field(s, v1);
1826 const uint8_t v2 = get_field(s, v2);
1827 const uint8_t v3 = get_field(s, v3);
1828 const uint8_t es = get_field(s, m4);
1831 gen_program_exception(s, PGM_SPECIFICATION);
1832 return DISAS_NORETURN;
1835 switch (s->fields.op2) {
1837 gen_gvec_fn_3(smax, es, v1, v2, v3);
1840 gen_gvec_fn_3(umax, es, v1, v2, v3);
1843 gen_gvec_fn_3(smin, es, v1, v2, v3);
1846 gen_gvec_fn_3(umin, es, v1, v2, v3);
1849 g_assert_not_reached();
1854 static void gen_mal_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b, TCGv_i32 c)
1856 TCGv_i32 t0 = tcg_temp_new_i32();
1858 tcg_gen_mul_i32(t0, a, b);
1859 tcg_gen_add_i32(d, t0, c);
1861 tcg_temp_free_i32(t0);
1864 static void gen_mah_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b, TCGv_i32 c)
1866 TCGv_i64 t0 = tcg_temp_new_i64();
1867 TCGv_i64 t1 = tcg_temp_new_i64();
1868 TCGv_i64 t2 = tcg_temp_new_i64();
1870 tcg_gen_ext_i32_i64(t0, a);
1871 tcg_gen_ext_i32_i64(t1, b);
1872 tcg_gen_ext_i32_i64(t2, c);
1873 tcg_gen_mul_i64(t0, t0, t1);
1874 tcg_gen_add_i64(t0, t0, t2);
1875 tcg_gen_extrh_i64_i32(d, t0);
1882 static void gen_malh_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b, TCGv_i32 c)
1884 TCGv_i64 t0 = tcg_temp_new_i64();
1885 TCGv_i64 t1 = tcg_temp_new_i64();
1886 TCGv_i64 t2 = tcg_temp_new_i64();
1888 tcg_gen_extu_i32_i64(t0, a);
1889 tcg_gen_extu_i32_i64(t1, b);
1890 tcg_gen_extu_i32_i64(t2, c);
1891 tcg_gen_mul_i64(t0, t0, t1);
1892 tcg_gen_add_i64(t0, t0, t2);
1893 tcg_gen_extrh_i64_i32(d, t0);
1900 static DisasJumpType op_vma(DisasContext *s, DisasOps *o)
1902 const uint8_t es = get_field(s, m5);
1903 static const GVecGen4 g_vmal[3] = {
1904 { .fno = gen_helper_gvec_vmal8, },
1905 { .fno = gen_helper_gvec_vmal16, },
1906 { .fni4 = gen_mal_i32, },
1908 static const GVecGen4 g_vmah[3] = {
1909 { .fno = gen_helper_gvec_vmah8, },
1910 { .fno = gen_helper_gvec_vmah16, },
1911 { .fni4 = gen_mah_i32, },
1913 static const GVecGen4 g_vmalh[3] = {
1914 { .fno = gen_helper_gvec_vmalh8, },
1915 { .fno = gen_helper_gvec_vmalh16, },
1916 { .fni4 = gen_malh_i32, },
1918 static const GVecGen4 g_vmae[3] = {
1919 { .fno = gen_helper_gvec_vmae8, },
1920 { .fno = gen_helper_gvec_vmae16, },
1921 { .fno = gen_helper_gvec_vmae32, },
1923 static const GVecGen4 g_vmale[3] = {
1924 { .fno = gen_helper_gvec_vmale8, },
1925 { .fno = gen_helper_gvec_vmale16, },
1926 { .fno = gen_helper_gvec_vmale32, },
1928 static const GVecGen4 g_vmao[3] = {
1929 { .fno = gen_helper_gvec_vmao8, },
1930 { .fno = gen_helper_gvec_vmao16, },
1931 { .fno = gen_helper_gvec_vmao32, },
1933 static const GVecGen4 g_vmalo[3] = {
1934 { .fno = gen_helper_gvec_vmalo8, },
1935 { .fno = gen_helper_gvec_vmalo16, },
1936 { .fno = gen_helper_gvec_vmalo32, },
1941 gen_program_exception(s, PGM_SPECIFICATION);
1942 return DISAS_NORETURN;
1945 switch (s->fields.op2) {
1968 g_assert_not_reached();
1971 gen_gvec_4(get_field(s, v1), get_field(s, v2),
1972 get_field(s, v3), get_field(s, v4), fn);
1976 static void gen_mh_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
1978 TCGv_i32 t = tcg_temp_new_i32();
1980 tcg_gen_muls2_i32(t, d, a, b);
1981 tcg_temp_free_i32(t);
1984 static void gen_mlh_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
1986 TCGv_i32 t = tcg_temp_new_i32();
1988 tcg_gen_mulu2_i32(t, d, a, b);
1989 tcg_temp_free_i32(t);
1992 static DisasJumpType op_vm(DisasContext *s, DisasOps *o)
1994 const uint8_t es = get_field(s, m4);
1995 static const GVecGen3 g_vmh[3] = {
1996 { .fno = gen_helper_gvec_vmh8, },
1997 { .fno = gen_helper_gvec_vmh16, },
1998 { .fni4 = gen_mh_i32, },
2000 static const GVecGen3 g_vmlh[3] = {
2001 { .fno = gen_helper_gvec_vmlh8, },
2002 { .fno = gen_helper_gvec_vmlh16, },
2003 { .fni4 = gen_mlh_i32, },
2005 static const GVecGen3 g_vme[3] = {
2006 { .fno = gen_helper_gvec_vme8, },
2007 { .fno = gen_helper_gvec_vme16, },
2008 { .fno = gen_helper_gvec_vme32, },
2010 static const GVecGen3 g_vmle[3] = {
2011 { .fno = gen_helper_gvec_vmle8, },
2012 { .fno = gen_helper_gvec_vmle16, },
2013 { .fno = gen_helper_gvec_vmle32, },
2015 static const GVecGen3 g_vmo[3] = {
2016 { .fno = gen_helper_gvec_vmo8, },
2017 { .fno = gen_helper_gvec_vmo16, },
2018 { .fno = gen_helper_gvec_vmo32, },
2020 static const GVecGen3 g_vmlo[3] = {
2021 { .fno = gen_helper_gvec_vmlo8, },
2022 { .fno = gen_helper_gvec_vmlo16, },
2023 { .fno = gen_helper_gvec_vmlo32, },
2028 gen_program_exception(s, PGM_SPECIFICATION);
2029 return DISAS_NORETURN;
2032 switch (s->fields.op2) {
2034 gen_gvec_fn_3(mul, es, get_field(s, v1),
2035 get_field(s, v2), get_field(s, v3));
2056 g_assert_not_reached();
2059 gen_gvec_3(get_field(s, v1), get_field(s, v2),
2060 get_field(s, v3), fn);
2064 static DisasJumpType op_vmsl(DisasContext *s, DisasOps *o)
2066 TCGv_i64 l1, h1, l2, h2;
2068 if (get_field(s, m5) != ES_64) {
2069 gen_program_exception(s, PGM_SPECIFICATION);
2070 return DISAS_NORETURN;
2073 l1 = tcg_temp_new_i64();
2074 h1 = tcg_temp_new_i64();
2075 l2 = tcg_temp_new_i64();
2076 h2 = tcg_temp_new_i64();
2078 /* Multipy both even elements from v2 and v3 */
2079 read_vec_element_i64(l1, get_field(s, v2), 0, ES_64);
2080 read_vec_element_i64(h1, get_field(s, v3), 0, ES_64);
2081 tcg_gen_mulu2_i64(l1, h1, l1, h1);
2082 /* Shift result left by one (x2) if requested */
2083 if (extract32(get_field(s, m6), 3, 1)) {
2084 tcg_gen_add2_i64(l1, h1, l1, h1, l1, h1);
2087 /* Multipy both odd elements from v2 and v3 */
2088 read_vec_element_i64(l2, get_field(s, v2), 1, ES_64);
2089 read_vec_element_i64(h2, get_field(s, v3), 1, ES_64);
2090 tcg_gen_mulu2_i64(l2, h2, l2, h2);
2091 /* Shift result left by one (x2) if requested */
2092 if (extract32(get_field(s, m6), 2, 1)) {
2093 tcg_gen_add2_i64(l2, h2, l2, h2, l2, h2);
2096 /* Add both intermediate results */
2097 tcg_gen_add2_i64(l1, h1, l1, h1, l2, h2);
2099 read_vec_element_i64(h2, get_field(s, v4), 0, ES_64);
2100 read_vec_element_i64(l2, get_field(s, v4), 1, ES_64);
2101 tcg_gen_add2_i64(l1, h1, l1, h1, l2, h2);
2103 /* Store final result into v1. */
2104 write_vec_element_i64(h1, get_field(s, v1), 0, ES_64);
2105 write_vec_element_i64(l1, get_field(s, v1), 1, ES_64);
2107 tcg_temp_free_i64(l1);
2108 tcg_temp_free_i64(h1);
2109 tcg_temp_free_i64(l2);
2110 tcg_temp_free_i64(h2);
2114 static DisasJumpType op_vnn(DisasContext *s, DisasOps *o)
2116 gen_gvec_fn_3(nand, ES_8, get_field(s, v1),
2117 get_field(s, v2), get_field(s, v3));
2121 static DisasJumpType op_vno(DisasContext *s, DisasOps *o)
2123 gen_gvec_fn_3(nor, ES_8, get_field(s, v1), get_field(s, v2),
2128 static DisasJumpType op_vnx(DisasContext *s, DisasOps *o)
2130 gen_gvec_fn_3(eqv, ES_8, get_field(s, v1), get_field(s, v2),
2135 static DisasJumpType op_vo(DisasContext *s, DisasOps *o)
2137 gen_gvec_fn_3(or, ES_8, get_field(s, v1), get_field(s, v2),
2142 static DisasJumpType op_voc(DisasContext *s, DisasOps *o)
2144 gen_gvec_fn_3(orc, ES_8, get_field(s, v1), get_field(s, v2),
2149 static DisasJumpType op_vpopct(DisasContext *s, DisasOps *o)
2151 const uint8_t es = get_field(s, m3);
2152 static const GVecGen2 g[4] = {
2153 { .fno = gen_helper_gvec_vpopct8, },
2154 { .fno = gen_helper_gvec_vpopct16, },
2155 { .fni4 = tcg_gen_ctpop_i32, },
2156 { .fni8 = tcg_gen_ctpop_i64, },
2159 if (es > ES_64 || (es != ES_8 && !s390_has_feat(S390_FEAT_VECTOR_ENH))) {
2160 gen_program_exception(s, PGM_SPECIFICATION);
2161 return DISAS_NORETURN;
2164 gen_gvec_2(get_field(s, v1), get_field(s, v2), &g[es]);
2168 static void gen_rim_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b, int32_t c)
2170 TCGv_i32 t = tcg_temp_new_i32();
2172 tcg_gen_rotli_i32(t, a, c & 31);
2173 tcg_gen_and_i32(t, t, b);
2174 tcg_gen_andc_i32(d, d, b);
2175 tcg_gen_or_i32(d, d, t);
2177 tcg_temp_free_i32(t);
2180 static void gen_rim_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b, int64_t c)
2182 TCGv_i64 t = tcg_temp_new_i64();
2184 tcg_gen_rotli_i64(t, a, c & 63);
2185 tcg_gen_and_i64(t, t, b);
2186 tcg_gen_andc_i64(d, d, b);
2187 tcg_gen_or_i64(d, d, t);
2189 tcg_temp_free_i64(t);
2192 static DisasJumpType op_verim(DisasContext *s, DisasOps *o)
2194 const uint8_t es = get_field(s, m5);
2195 const uint8_t i4 = get_field(s, i4) &
2196 (NUM_VEC_ELEMENT_BITS(es) - 1);
2197 static const GVecGen3i g[4] = {
2198 { .fno = gen_helper_gvec_verim8, },
2199 { .fno = gen_helper_gvec_verim16, },
2200 { .fni4 = gen_rim_i32,
2201 .load_dest = true, },
2202 { .fni8 = gen_rim_i64,
2203 .load_dest = true, },
2207 gen_program_exception(s, PGM_SPECIFICATION);
2208 return DISAS_NORETURN;
2211 gen_gvec_3i(get_field(s, v1), get_field(s, v2),
2212 get_field(s, v3), i4, &g[es]);
2216 static DisasJumpType op_vesv(DisasContext *s, DisasOps *o)
2218 const uint8_t es = get_field(s, m4);
2219 const uint8_t v1 = get_field(s, v1);
2220 const uint8_t v2 = get_field(s, v2);
2221 const uint8_t v3 = get_field(s, v3);
2224 gen_program_exception(s, PGM_SPECIFICATION);
2225 return DISAS_NORETURN;
2228 switch (s->fields.op2) {
2230 gen_gvec_fn_3(shlv, es, v1, v2, v3);
2233 gen_gvec_fn_3(rotlv, es, v1, v2, v3);
2236 gen_gvec_fn_3(sarv, es, v1, v2, v3);
2239 gen_gvec_fn_3(shrv, es, v1, v2, v3);
2242 g_assert_not_reached();
2247 static DisasJumpType op_ves(DisasContext *s, DisasOps *o)
2249 const uint8_t es = get_field(s, m4);
2250 const uint8_t d2 = get_field(s, d2) &
2251 (NUM_VEC_ELEMENT_BITS(es) - 1);
2252 const uint8_t v1 = get_field(s, v1);
2253 const uint8_t v3 = get_field(s, v3);
2257 gen_program_exception(s, PGM_SPECIFICATION);
2258 return DISAS_NORETURN;
2261 if (likely(!get_field(s, b2))) {
2262 switch (s->fields.op2) {
2264 gen_gvec_fn_2i(shli, es, v1, v3, d2);
2267 gen_gvec_fn_2i(rotli, es, v1, v3, d2);
2270 gen_gvec_fn_2i(sari, es, v1, v3, d2);
2273 gen_gvec_fn_2i(shri, es, v1, v3, d2);
2276 g_assert_not_reached();
2279 shift = tcg_temp_new_i32();
2280 tcg_gen_extrl_i64_i32(shift, o->addr1);
2281 tcg_gen_andi_i32(shift, shift, NUM_VEC_ELEMENT_BITS(es) - 1);
2282 switch (s->fields.op2) {
2284 gen_gvec_fn_2s(shls, es, v1, v3, shift);
2287 gen_gvec_fn_2s(rotls, es, v1, v3, shift);
2290 gen_gvec_fn_2s(sars, es, v1, v3, shift);
2293 gen_gvec_fn_2s(shrs, es, v1, v3, shift);
2296 g_assert_not_reached();
2298 tcg_temp_free_i32(shift);
2303 static DisasJumpType gen_vsh_by_byte(DisasContext *s, DisasOps *o,
2304 gen_helper_gvec_2i *gen,
2305 gen_helper_gvec_3 *gen_ve2)
2307 bool byte = s->insn->data;
2309 if (!byte && s390_has_feat(S390_FEAT_VECTOR_ENH2)) {
2310 gen_gvec_3_ool(get_field(s, v1), get_field(s, v2),
2311 get_field(s, v3), 0, gen_ve2);
2313 TCGv_i64 shift = tcg_temp_new_i64();
2315 read_vec_element_i64(shift, get_field(s, v3), 7, ES_8);
2316 tcg_gen_andi_i64(shift, shift, byte ? 0x78 : 7);
2317 gen_gvec_2i_ool(get_field(s, v1), get_field(s, v2), shift, 0, gen);
2318 tcg_temp_free_i64(shift);
2323 static DisasJumpType op_vsl(DisasContext *s, DisasOps *o)
2325 return gen_vsh_by_byte(s, o, gen_helper_gvec_vsl,
2326 gen_helper_gvec_vsl_ve2);
2329 static DisasJumpType op_vsra(DisasContext *s, DisasOps *o)
2331 return gen_vsh_by_byte(s, o, gen_helper_gvec_vsra,
2332 gen_helper_gvec_vsra_ve2);
2335 static DisasJumpType op_vsrl(DisasContext *s, DisasOps *o)
2337 return gen_vsh_by_byte(s, o, gen_helper_gvec_vsrl,
2338 gen_helper_gvec_vsrl_ve2);
2341 static DisasJumpType op_vsld(DisasContext *s, DisasOps *o)
2343 const bool byte = s->insn->data;
2344 const uint8_t mask = byte ? 15 : 7;
2345 const uint8_t mul = byte ? 8 : 1;
2346 const uint8_t i4 = get_field(s, i4);
2347 const int right_shift = 64 - (i4 & 7) * mul;
2348 TCGv_i64 t0, t1, t2;
2351 gen_program_exception(s, PGM_SPECIFICATION);
2352 return DISAS_NORETURN;
2355 t0 = tcg_temp_new_i64();
2356 t1 = tcg_temp_new_i64();
2357 t2 = tcg_temp_new_i64();
2359 if ((i4 & 8) == 0) {
2360 read_vec_element_i64(t0, get_field(s, v2), 0, ES_64);
2361 read_vec_element_i64(t1, get_field(s, v2), 1, ES_64);
2362 read_vec_element_i64(t2, get_field(s, v3), 0, ES_64);
2364 read_vec_element_i64(t0, get_field(s, v2), 1, ES_64);
2365 read_vec_element_i64(t1, get_field(s, v3), 0, ES_64);
2366 read_vec_element_i64(t2, get_field(s, v3), 1, ES_64);
2369 tcg_gen_extract2_i64(t0, t1, t0, right_shift);
2370 tcg_gen_extract2_i64(t1, t2, t1, right_shift);
2372 write_vec_element_i64(t0, get_field(s, v1), 0, ES_64);
2373 write_vec_element_i64(t1, get_field(s, v1), 1, ES_64);
2381 static DisasJumpType op_vsrd(DisasContext *s, DisasOps *o)
2383 const uint8_t i4 = get_field(s, i4);
2384 TCGv_i64 t0, t1, t2;
2387 gen_program_exception(s, PGM_SPECIFICATION);
2388 return DISAS_NORETURN;
2391 t0 = tcg_temp_new_i64();
2392 t1 = tcg_temp_new_i64();
2393 t2 = tcg_temp_new_i64();
2395 read_vec_element_i64(t0, get_field(s, v2), 1, ES_64);
2396 read_vec_element_i64(t1, get_field(s, v3), 0, ES_64);
2397 read_vec_element_i64(t2, get_field(s, v3), 1, ES_64);
2399 tcg_gen_extract2_i64(t0, t1, t0, i4);
2400 tcg_gen_extract2_i64(t1, t2, t1, i4);
2402 write_vec_element_i64(t0, get_field(s, v1), 0, ES_64);
2403 write_vec_element_i64(t1, get_field(s, v1), 1, ES_64);
2411 static DisasJumpType op_vs(DisasContext *s, DisasOps *o)
2413 const uint8_t es = get_field(s, m4);
2416 gen_program_exception(s, PGM_SPECIFICATION);
2417 return DISAS_NORETURN;
2418 } else if (es == ES_128) {
2419 gen_gvec128_3_i64(tcg_gen_sub2_i64, get_field(s, v1),
2420 get_field(s, v2), get_field(s, v3));
2423 gen_gvec_fn_3(sub, es, get_field(s, v1), get_field(s, v2),
2428 static void gen_scbi_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
2430 tcg_gen_setcond_i32(TCG_COND_GEU, d, a, b);
2433 static void gen_scbi_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
2435 tcg_gen_setcond_i64(TCG_COND_GEU, d, a, b);
2438 static void gen_scbi2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al,
2439 TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh)
2441 TCGv_i64 th = tcg_temp_new_i64();
2442 TCGv_i64 tl = tcg_temp_new_i64();
2443 TCGv_i64 zero = tcg_const_i64(0);
2445 tcg_gen_sub2_i64(tl, th, al, zero, bl, zero);
2446 tcg_gen_andi_i64(th, th, 1);
2447 tcg_gen_sub2_i64(tl, th, ah, zero, th, zero);
2448 tcg_gen_sub2_i64(tl, th, tl, th, bh, zero);
2449 /* "invert" the result: -1 -> 0; 0 -> 1 */
2450 tcg_gen_addi_i64(dl, th, 1);
2451 tcg_gen_mov_i64(dh, zero);
2453 tcg_temp_free_i64(th);
2454 tcg_temp_free_i64(tl);
2455 tcg_temp_free_i64(zero);
2458 static DisasJumpType op_vscbi(DisasContext *s, DisasOps *o)
2460 const uint8_t es = get_field(s, m4);
2461 static const GVecGen3 g[4] = {
2462 { .fno = gen_helper_gvec_vscbi8, },
2463 { .fno = gen_helper_gvec_vscbi16, },
2464 { .fni4 = gen_scbi_i32, },
2465 { .fni8 = gen_scbi_i64, },
2469 gen_program_exception(s, PGM_SPECIFICATION);
2470 return DISAS_NORETURN;
2471 } else if (es == ES_128) {
2472 gen_gvec128_3_i64(gen_scbi2_i64, get_field(s, v1),
2473 get_field(s, v2), get_field(s, v3));
2476 gen_gvec_3(get_field(s, v1), get_field(s, v2),
2477 get_field(s, v3), &g[es]);
2481 static void gen_sbi2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
2482 TCGv_i64 bl, TCGv_i64 bh, TCGv_i64 cl, TCGv_i64 ch)
2484 TCGv_i64 tl = tcg_temp_new_i64();
2485 TCGv_i64 th = tcg_temp_new_i64();
2487 tcg_gen_not_i64(tl, bl);
2488 tcg_gen_not_i64(th, bh);
2489 gen_ac2_i64(dl, dh, al, ah, tl, th, cl, ch);
2490 tcg_temp_free_i64(tl);
2491 tcg_temp_free_i64(th);
2494 static DisasJumpType op_vsbi(DisasContext *s, DisasOps *o)
2496 if (get_field(s, m5) != ES_128) {
2497 gen_program_exception(s, PGM_SPECIFICATION);
2498 return DISAS_NORETURN;
2501 gen_gvec128_4_i64(gen_sbi2_i64, get_field(s, v1),
2502 get_field(s, v2), get_field(s, v3),
2507 static void gen_sbcbi2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
2508 TCGv_i64 bl, TCGv_i64 bh, TCGv_i64 cl, TCGv_i64 ch)
2510 TCGv_i64 th = tcg_temp_new_i64();
2511 TCGv_i64 tl = tcg_temp_new_i64();
2513 tcg_gen_not_i64(tl, bl);
2514 tcg_gen_not_i64(th, bh);
2515 gen_accc2_i64(dl, dh, al, ah, tl, th, cl, ch);
2517 tcg_temp_free_i64(tl);
2518 tcg_temp_free_i64(th);
2521 static DisasJumpType op_vsbcbi(DisasContext *s, DisasOps *o)
2523 if (get_field(s, m5) != ES_128) {
2524 gen_program_exception(s, PGM_SPECIFICATION);
2525 return DISAS_NORETURN;
2528 gen_gvec128_4_i64(gen_sbcbi2_i64, get_field(s, v1),
2529 get_field(s, v2), get_field(s, v3),
2534 static DisasJumpType op_vsumg(DisasContext *s, DisasOps *o)
2536 const uint8_t es = get_field(s, m4);
2540 if (es == ES_8 || es > ES_32) {
2541 gen_program_exception(s, PGM_SPECIFICATION);
2542 return DISAS_NORETURN;
2545 sum = tcg_temp_new_i64();
2546 tmp = tcg_temp_new_i64();
2547 for (dst_idx = 0; dst_idx < 2; dst_idx++) {
2548 uint8_t idx = dst_idx * NUM_VEC_ELEMENTS(es) / 2;
2549 const uint8_t max_idx = idx + NUM_VEC_ELEMENTS(es) / 2 - 1;
2551 read_vec_element_i64(sum, get_field(s, v3), max_idx, es);
2552 for (; idx <= max_idx; idx++) {
2553 read_vec_element_i64(tmp, get_field(s, v2), idx, es);
2554 tcg_gen_add_i64(sum, sum, tmp);
2556 write_vec_element_i64(sum, get_field(s, v1), dst_idx, ES_64);
2558 tcg_temp_free_i64(sum);
2559 tcg_temp_free_i64(tmp);
2563 static DisasJumpType op_vsumq(DisasContext *s, DisasOps *o)
2565 const uint8_t es = get_field(s, m4);
2566 const uint8_t max_idx = NUM_VEC_ELEMENTS(es) - 1;
2567 TCGv_i64 sumh, suml, zero, tmpl;
2570 if (es < ES_32 || es > ES_64) {
2571 gen_program_exception(s, PGM_SPECIFICATION);
2572 return DISAS_NORETURN;
2575 sumh = tcg_const_i64(0);
2576 suml = tcg_temp_new_i64();
2577 zero = tcg_const_i64(0);
2578 tmpl = tcg_temp_new_i64();
2580 read_vec_element_i64(suml, get_field(s, v3), max_idx, es);
2581 for (idx = 0; idx <= max_idx; idx++) {
2582 read_vec_element_i64(tmpl, get_field(s, v2), idx, es);
2583 tcg_gen_add2_i64(suml, sumh, suml, sumh, tmpl, zero);
2585 write_vec_element_i64(sumh, get_field(s, v1), 0, ES_64);
2586 write_vec_element_i64(suml, get_field(s, v1), 1, ES_64);
2588 tcg_temp_free_i64(sumh);
2589 tcg_temp_free_i64(suml);
2590 tcg_temp_free_i64(zero);
2591 tcg_temp_free_i64(tmpl);
2595 static DisasJumpType op_vsum(DisasContext *s, DisasOps *o)
2597 const uint8_t es = get_field(s, m4);
2602 gen_program_exception(s, PGM_SPECIFICATION);
2603 return DISAS_NORETURN;
2606 sum = tcg_temp_new_i32();
2607 tmp = tcg_temp_new_i32();
2608 for (dst_idx = 0; dst_idx < 4; dst_idx++) {
2609 uint8_t idx = dst_idx * NUM_VEC_ELEMENTS(es) / 4;
2610 const uint8_t max_idx = idx + NUM_VEC_ELEMENTS(es) / 4 - 1;
2612 read_vec_element_i32(sum, get_field(s, v3), max_idx, es);
2613 for (; idx <= max_idx; idx++) {
2614 read_vec_element_i32(tmp, get_field(s, v2), idx, es);
2615 tcg_gen_add_i32(sum, sum, tmp);
2617 write_vec_element_i32(sum, get_field(s, v1), dst_idx, ES_32);
2619 tcg_temp_free_i32(sum);
2620 tcg_temp_free_i32(tmp);
2624 static DisasJumpType op_vtm(DisasContext *s, DisasOps *o)
2626 gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2),
2627 cpu_env, 0, gen_helper_gvec_vtm);
2632 static DisasJumpType op_vfae(DisasContext *s, DisasOps *o)
2634 const uint8_t es = get_field(s, m4);
2635 const uint8_t m5 = get_field(s, m5);
2636 static gen_helper_gvec_3 * const g[3] = {
2637 gen_helper_gvec_vfae8,
2638 gen_helper_gvec_vfae16,
2639 gen_helper_gvec_vfae32,
2641 static gen_helper_gvec_3_ptr * const g_cc[3] = {
2642 gen_helper_gvec_vfae_cc8,
2643 gen_helper_gvec_vfae_cc16,
2644 gen_helper_gvec_vfae_cc32,
2647 gen_program_exception(s, PGM_SPECIFICATION);
2648 return DISAS_NORETURN;
2651 if (extract32(m5, 0, 1)) {
2652 gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2),
2653 get_field(s, v3), cpu_env, m5, g_cc[es]);
2656 gen_gvec_3_ool(get_field(s, v1), get_field(s, v2),
2657 get_field(s, v3), m5, g[es]);
2662 static DisasJumpType op_vfee(DisasContext *s, DisasOps *o)
2664 const uint8_t es = get_field(s, m4);
2665 const uint8_t m5 = get_field(s, m5);
2666 static gen_helper_gvec_3 * const g[3] = {
2667 gen_helper_gvec_vfee8,
2668 gen_helper_gvec_vfee16,
2669 gen_helper_gvec_vfee32,
2671 static gen_helper_gvec_3_ptr * const g_cc[3] = {
2672 gen_helper_gvec_vfee_cc8,
2673 gen_helper_gvec_vfee_cc16,
2674 gen_helper_gvec_vfee_cc32,
2677 if (es > ES_32 || m5 & ~0x3) {
2678 gen_program_exception(s, PGM_SPECIFICATION);
2679 return DISAS_NORETURN;
2682 if (extract32(m5, 0, 1)) {
2683 gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2),
2684 get_field(s, v3), cpu_env, m5, g_cc[es]);
2687 gen_gvec_3_ool(get_field(s, v1), get_field(s, v2),
2688 get_field(s, v3), m5, g[es]);
2693 static DisasJumpType op_vfene(DisasContext *s, DisasOps *o)
2695 const uint8_t es = get_field(s, m4);
2696 const uint8_t m5 = get_field(s, m5);
2697 static gen_helper_gvec_3 * const g[3] = {
2698 gen_helper_gvec_vfene8,
2699 gen_helper_gvec_vfene16,
2700 gen_helper_gvec_vfene32,
2702 static gen_helper_gvec_3_ptr * const g_cc[3] = {
2703 gen_helper_gvec_vfene_cc8,
2704 gen_helper_gvec_vfene_cc16,
2705 gen_helper_gvec_vfene_cc32,
2708 if (es > ES_32 || m5 & ~0x3) {
2709 gen_program_exception(s, PGM_SPECIFICATION);
2710 return DISAS_NORETURN;
2713 if (extract32(m5, 0, 1)) {
2714 gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2),
2715 get_field(s, v3), cpu_env, m5, g_cc[es]);
2718 gen_gvec_3_ool(get_field(s, v1), get_field(s, v2),
2719 get_field(s, v3), m5, g[es]);
2724 static DisasJumpType op_vistr(DisasContext *s, DisasOps *o)
2726 const uint8_t es = get_field(s, m4);
2727 const uint8_t m5 = get_field(s, m5);
2728 static gen_helper_gvec_2 * const g[3] = {
2729 gen_helper_gvec_vistr8,
2730 gen_helper_gvec_vistr16,
2731 gen_helper_gvec_vistr32,
2733 static gen_helper_gvec_2_ptr * const g_cc[3] = {
2734 gen_helper_gvec_vistr_cc8,
2735 gen_helper_gvec_vistr_cc16,
2736 gen_helper_gvec_vistr_cc32,
2739 if (es > ES_32 || m5 & ~0x1) {
2740 gen_program_exception(s, PGM_SPECIFICATION);
2741 return DISAS_NORETURN;
2744 if (extract32(m5, 0, 1)) {
2745 gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2),
2746 cpu_env, 0, g_cc[es]);
2749 gen_gvec_2_ool(get_field(s, v1), get_field(s, v2), 0,
2755 static DisasJumpType op_vstrc(DisasContext *s, DisasOps *o)
2757 const uint8_t es = get_field(s, m5);
2758 const uint8_t m6 = get_field(s, m6);
2759 static gen_helper_gvec_4 * const g[3] = {
2760 gen_helper_gvec_vstrc8,
2761 gen_helper_gvec_vstrc16,
2762 gen_helper_gvec_vstrc32,
2764 static gen_helper_gvec_4 * const g_rt[3] = {
2765 gen_helper_gvec_vstrc_rt8,
2766 gen_helper_gvec_vstrc_rt16,
2767 gen_helper_gvec_vstrc_rt32,
2769 static gen_helper_gvec_4_ptr * const g_cc[3] = {
2770 gen_helper_gvec_vstrc_cc8,
2771 gen_helper_gvec_vstrc_cc16,
2772 gen_helper_gvec_vstrc_cc32,
2774 static gen_helper_gvec_4_ptr * const g_cc_rt[3] = {
2775 gen_helper_gvec_vstrc_cc_rt8,
2776 gen_helper_gvec_vstrc_cc_rt16,
2777 gen_helper_gvec_vstrc_cc_rt32,
2781 gen_program_exception(s, PGM_SPECIFICATION);
2782 return DISAS_NORETURN;
2785 if (extract32(m6, 0, 1)) {
2786 if (extract32(m6, 2, 1)) {
2787 gen_gvec_4_ptr(get_field(s, v1), get_field(s, v2),
2788 get_field(s, v3), get_field(s, v4),
2789 cpu_env, m6, g_cc_rt[es]);
2791 gen_gvec_4_ptr(get_field(s, v1), get_field(s, v2),
2792 get_field(s, v3), get_field(s, v4),
2793 cpu_env, m6, g_cc[es]);
2797 if (extract32(m6, 2, 1)) {
2798 gen_gvec_4_ool(get_field(s, v1), get_field(s, v2),
2799 get_field(s, v3), get_field(s, v4),
2802 gen_gvec_4_ool(get_field(s, v1), get_field(s, v2),
2803 get_field(s, v3), get_field(s, v4),
2810 static DisasJumpType op_vstrs(DisasContext *s, DisasOps *o)
2812 typedef void (*helper_vstrs)(TCGv_ptr, TCGv_ptr, TCGv_ptr,
2813 TCGv_ptr, TCGv_ptr, TCGv_i32);
2814 static const helper_vstrs fns[3][2] = {
2815 { gen_helper_gvec_vstrs_8, gen_helper_gvec_vstrs_zs8 },
2816 { gen_helper_gvec_vstrs_16, gen_helper_gvec_vstrs_zs16 },
2817 { gen_helper_gvec_vstrs_32, gen_helper_gvec_vstrs_zs32 },
2819 const uint8_t es = get_field(s, m5);
2820 const uint8_t m6 = get_field(s, m6);
2821 const bool zs = extract32(m6, 1, 1);
2823 if (es > ES_32 || m6 & ~2) {
2824 gen_program_exception(s, PGM_SPECIFICATION);
2825 return DISAS_NORETURN;
2828 gen_gvec_4_ptr(get_field(s, v1), get_field(s, v2),
2829 get_field(s, v3), get_field(s, v4),
2830 cpu_env, 0, fns[es][zs]);
2835 static DisasJumpType op_vfa(DisasContext *s, DisasOps *o)
2837 const uint8_t fpf = get_field(s, m4);
2838 const uint8_t m5 = get_field(s, m5);
2839 gen_helper_gvec_3_ptr *fn = NULL;
2841 switch (s->fields.op2) {
2845 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
2846 fn = gen_helper_gvec_vfa32;
2850 fn = gen_helper_gvec_vfa64;
2853 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
2854 fn = gen_helper_gvec_vfa128;
2864 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
2865 fn = gen_helper_gvec_vfd32;
2869 fn = gen_helper_gvec_vfd64;
2872 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
2873 fn = gen_helper_gvec_vfd128;
2883 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
2884 fn = gen_helper_gvec_vfm32;
2888 fn = gen_helper_gvec_vfm64;
2891 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
2892 fn = gen_helper_gvec_vfm128;
2902 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
2903 fn = gen_helper_gvec_vfs32;
2907 fn = gen_helper_gvec_vfs64;
2910 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
2911 fn = gen_helper_gvec_vfs128;
2919 g_assert_not_reached();
2922 if (!fn || extract32(m5, 0, 3)) {
2923 gen_program_exception(s, PGM_SPECIFICATION);
2924 return DISAS_NORETURN;
2927 gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2),
2928 get_field(s, v3), cpu_env, m5, fn);
2932 static DisasJumpType op_wfc(DisasContext *s, DisasOps *o)
2934 const uint8_t fpf = get_field(s, m3);
2935 const uint8_t m4 = get_field(s, m4);
2936 gen_helper_gvec_2_ptr *fn = NULL;
2940 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
2941 fn = gen_helper_gvec_wfk32;
2942 if (s->fields.op2 == 0xcb) {
2943 fn = gen_helper_gvec_wfc32;
2948 fn = gen_helper_gvec_wfk64;
2949 if (s->fields.op2 == 0xcb) {
2950 fn = gen_helper_gvec_wfc64;
2954 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
2955 fn = gen_helper_gvec_wfk128;
2956 if (s->fields.op2 == 0xcb) {
2957 fn = gen_helper_gvec_wfc128;
2966 gen_program_exception(s, PGM_SPECIFICATION);
2967 return DISAS_NORETURN;
2970 gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, 0, fn);
2975 static DisasJumpType op_vfc(DisasContext *s, DisasOps *o)
2977 const uint8_t fpf = get_field(s, m4);
2978 const uint8_t m5 = get_field(s, m5);
2979 const uint8_t m6 = get_field(s, m6);
2980 const bool cs = extract32(m6, 0, 1);
2981 const bool sq = extract32(m5, 2, 1);
2982 gen_helper_gvec_3_ptr *fn = NULL;
2984 switch (s->fields.op2) {
2988 fn = cs ? gen_helper_gvec_vfce32_cc : gen_helper_gvec_vfce32;
2991 fn = cs ? gen_helper_gvec_vfce64_cc : gen_helper_gvec_vfce64;
2994 fn = cs ? gen_helper_gvec_vfce128_cc : gen_helper_gvec_vfce128;
3003 fn = cs ? gen_helper_gvec_vfch32_cc : gen_helper_gvec_vfch32;
3006 fn = cs ? gen_helper_gvec_vfch64_cc : gen_helper_gvec_vfch64;
3009 fn = cs ? gen_helper_gvec_vfch128_cc : gen_helper_gvec_vfch128;
3018 fn = cs ? gen_helper_gvec_vfche32_cc : gen_helper_gvec_vfche32;
3021 fn = cs ? gen_helper_gvec_vfche64_cc : gen_helper_gvec_vfche64;
3024 fn = cs ? gen_helper_gvec_vfche128_cc : gen_helper_gvec_vfche128;
3031 g_assert_not_reached();
3034 if (!fn || extract32(m5, 0, 2) || extract32(m6, 1, 3) ||
3035 (!s390_has_feat(S390_FEAT_VECTOR_ENH) && (fpf != FPF_LONG || sq))) {
3036 gen_program_exception(s, PGM_SPECIFICATION);
3037 return DISAS_NORETURN;
3040 gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2), get_field(s, v3),
3048 static DisasJumpType op_vcdg(DisasContext *s, DisasOps *o)
3050 const uint8_t fpf = get_field(s, m3);
3051 const uint8_t m4 = get_field(s, m4);
3052 const uint8_t erm = get_field(s, m5);
3053 gen_helper_gvec_2_ptr *fn = NULL;
3056 switch (s->fields.op2) {
3060 fn = gen_helper_gvec_vcdg64;
3063 if (s390_has_feat(S390_FEAT_VECTOR_ENH2)) {
3064 fn = gen_helper_gvec_vcdg32;
3074 fn = gen_helper_gvec_vcdlg64;
3077 if (s390_has_feat(S390_FEAT_VECTOR_ENH2)) {
3078 fn = gen_helper_gvec_vcdlg32;
3088 fn = gen_helper_gvec_vcgd64;
3091 if (s390_has_feat(S390_FEAT_VECTOR_ENH2)) {
3092 fn = gen_helper_gvec_vcgd32;
3102 fn = gen_helper_gvec_vclgd64;
3105 if (s390_has_feat(S390_FEAT_VECTOR_ENH2)) {
3106 fn = gen_helper_gvec_vclgd32;
3116 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
3117 fn = gen_helper_gvec_vfi32;
3121 fn = gen_helper_gvec_vfi64;
3124 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
3125 fn = gen_helper_gvec_vfi128;
3135 fn = gen_helper_gvec_vflr64;
3138 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
3139 fn = gen_helper_gvec_vflr128;
3147 g_assert_not_reached();
3150 if (!fn || extract32(m4, 0, 2) || erm > 7 || erm == 2) {
3151 gen_program_exception(s, PGM_SPECIFICATION);
3152 return DISAS_NORETURN;
3155 gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env,
3156 deposit32(m4, 4, 4, erm), fn);
3160 static DisasJumpType op_vfll(DisasContext *s, DisasOps *o)
3162 const uint8_t fpf = get_field(s, m3);
3163 const uint8_t m4 = get_field(s, m4);
3164 gen_helper_gvec_2_ptr *fn = NULL;
3168 fn = gen_helper_gvec_vfll32;
3171 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
3172 fn = gen_helper_gvec_vfll64;
3179 if (!fn || extract32(m4, 0, 3)) {
3180 gen_program_exception(s, PGM_SPECIFICATION);
3181 return DISAS_NORETURN;
3184 gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, m4, fn);
3188 static DisasJumpType op_vfmax(DisasContext *s, DisasOps *o)
3190 const uint8_t fpf = get_field(s, m4);
3191 const uint8_t m6 = get_field(s, m6);
3192 const uint8_t m5 = get_field(s, m5);
3193 gen_helper_gvec_3_ptr *fn;
3195 if (m6 == 5 || m6 == 6 || m6 == 7 || m6 > 13) {
3196 gen_program_exception(s, PGM_SPECIFICATION);
3197 return DISAS_NORETURN;
3202 if (s->fields.op2 == 0xef) {
3203 fn = gen_helper_gvec_vfmax32;
3205 fn = gen_helper_gvec_vfmin32;
3209 if (s->fields.op2 == 0xef) {
3210 fn = gen_helper_gvec_vfmax64;
3212 fn = gen_helper_gvec_vfmin64;
3216 if (s->fields.op2 == 0xef) {
3217 fn = gen_helper_gvec_vfmax128;
3219 fn = gen_helper_gvec_vfmin128;
3223 gen_program_exception(s, PGM_SPECIFICATION);
3224 return DISAS_NORETURN;
3227 gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2), get_field(s, v3),
3228 cpu_env, deposit32(m5, 4, 4, m6), fn);
3232 static DisasJumpType op_vfma(DisasContext *s, DisasOps *o)
3234 const uint8_t m5 = get_field(s, m5);
3235 const uint8_t fpf = get_field(s, m6);
3236 gen_helper_gvec_4_ptr *fn = NULL;
3238 switch (s->fields.op2) {
3242 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
3243 fn = gen_helper_gvec_vfma32;
3247 fn = gen_helper_gvec_vfma64;
3250 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
3251 fn = gen_helper_gvec_vfma128;
3261 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
3262 fn = gen_helper_gvec_vfms32;
3266 fn = gen_helper_gvec_vfms64;
3269 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
3270 fn = gen_helper_gvec_vfms128;
3280 fn = gen_helper_gvec_vfnma32;
3283 fn = gen_helper_gvec_vfnma64;
3286 fn = gen_helper_gvec_vfnma128;
3295 fn = gen_helper_gvec_vfnms32;
3298 fn = gen_helper_gvec_vfnms64;
3301 fn = gen_helper_gvec_vfnms128;
3308 g_assert_not_reached();
3311 if (!fn || extract32(m5, 0, 3)) {
3312 gen_program_exception(s, PGM_SPECIFICATION);
3313 return DISAS_NORETURN;
3316 gen_gvec_4_ptr(get_field(s, v1), get_field(s, v2),
3317 get_field(s, v3), get_field(s, v4), cpu_env, m5, fn);
3321 static DisasJumpType op_vfpso(DisasContext *s, DisasOps *o)
3323 const uint8_t v1 = get_field(s, v1);
3324 const uint8_t v2 = get_field(s, v2);
3325 const uint8_t fpf = get_field(s, m3);
3326 const uint8_t m4 = get_field(s, m4);
3327 const uint8_t m5 = get_field(s, m5);
3328 const bool se = extract32(m4, 3, 1);
3331 if ((fpf != FPF_LONG && !s390_has_feat(S390_FEAT_VECTOR_ENH)) ||
3332 extract32(m4, 0, 3) || m5 > 2) {
3333 gen_program_exception(s, PGM_SPECIFICATION);
3334 return DISAS_NORETURN;
3342 /* sign bit is inverted (complement) */
3343 gen_gvec_fn_2i(xori, ES_32, v1, v2, 1ull << 31);
3346 /* sign bit is set to one (negative) */
3347 gen_gvec_fn_2i(ori, ES_32, v1, v2, 1ull << 31);
3350 /* sign bit is set to zero (positive) */
3351 gen_gvec_fn_2i(andi, ES_32, v1, v2, (1ull << 31) - 1);
3361 /* sign bit is inverted (complement) */
3362 gen_gvec_fn_2i(xori, ES_64, v1, v2, 1ull << 63);
3365 /* sign bit is set to one (negative) */
3366 gen_gvec_fn_2i(ori, ES_64, v1, v2, 1ull << 63);
3369 /* sign bit is set to zero (positive) */
3370 gen_gvec_fn_2i(andi, ES_64, v1, v2, (1ull << 63) - 1);
3377 /* Only a single element. */
3380 gen_program_exception(s, PGM_SPECIFICATION);
3381 return DISAS_NORETURN;
3384 /* With a single element, we are only interested in bit 0. */
3385 tmp = tcg_temp_new_i64();
3386 read_vec_element_i64(tmp, v2, 0, ES_64);
3389 /* sign bit is inverted (complement) */
3390 tcg_gen_xori_i64(tmp, tmp, 1ull << 63);
3393 /* sign bit is set to one (negative) */
3394 tcg_gen_ori_i64(tmp, tmp, 1ull << 63);
3397 /* sign bit is set to zero (positive) */
3398 tcg_gen_andi_i64(tmp, tmp, (1ull << 63) - 1);
3401 write_vec_element_i64(tmp, v1, 0, ES_64);
3403 if (fpf == FPF_EXT) {
3404 read_vec_element_i64(tmp, v2, 1, ES_64);
3405 write_vec_element_i64(tmp, v1, 1, ES_64);
3408 tcg_temp_free_i64(tmp);
3413 static DisasJumpType op_vfsq(DisasContext *s, DisasOps *o)
3415 const uint8_t fpf = get_field(s, m3);
3416 const uint8_t m4 = get_field(s, m4);
3417 gen_helper_gvec_2_ptr *fn = NULL;
3421 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
3422 fn = gen_helper_gvec_vfsq32;
3426 fn = gen_helper_gvec_vfsq64;
3429 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
3430 fn = gen_helper_gvec_vfsq128;
3437 if (!fn || extract32(m4, 0, 3)) {
3438 gen_program_exception(s, PGM_SPECIFICATION);
3439 return DISAS_NORETURN;
3442 gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, m4, fn);
3446 static DisasJumpType op_vftci(DisasContext *s, DisasOps *o)
3448 const uint16_t i3 = get_field(s, i3);
3449 const uint8_t fpf = get_field(s, m4);
3450 const uint8_t m5 = get_field(s, m5);
3451 gen_helper_gvec_2_ptr *fn = NULL;
3455 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
3456 fn = gen_helper_gvec_vftci32;
3460 fn = gen_helper_gvec_vftci64;
3463 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
3464 fn = gen_helper_gvec_vftci128;
3471 if (!fn || extract32(m5, 0, 3)) {
3472 gen_program_exception(s, PGM_SPECIFICATION);
3473 return DISAS_NORETURN;
3476 gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env,
3477 deposit32(m5, 4, 12, i3), fn);