2 * QEMU TCG support -- s390x vector instruction translation functions
4 * Copyright (C) 2019 Red Hat Inc
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, TCGMemOp 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);
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);
178 #ifndef HOST_WORDS_BIGENDIAN
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), c, 16, 16, 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_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), \
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)
250 * Helper to carry out a 128 bit vector computation using 2 i64 values per
253 typedef void (*gen_gvec128_3_i64_fn)(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al,
254 TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh);
255 static void gen_gvec128_3_i64(gen_gvec128_3_i64_fn fn, uint8_t d, uint8_t a,
258 TCGv_i64 dh = tcg_temp_new_i64();
259 TCGv_i64 dl = tcg_temp_new_i64();
260 TCGv_i64 ah = tcg_temp_new_i64();
261 TCGv_i64 al = tcg_temp_new_i64();
262 TCGv_i64 bh = tcg_temp_new_i64();
263 TCGv_i64 bl = tcg_temp_new_i64();
265 read_vec_element_i64(ah, a, 0, ES_64);
266 read_vec_element_i64(al, a, 1, ES_64);
267 read_vec_element_i64(bh, b, 0, ES_64);
268 read_vec_element_i64(bl, b, 1, ES_64);
269 fn(dl, dh, al, ah, bl, bh);
270 write_vec_element_i64(dh, d, 0, ES_64);
271 write_vec_element_i64(dl, d, 1, ES_64);
273 tcg_temp_free_i64(dh);
274 tcg_temp_free_i64(dl);
275 tcg_temp_free_i64(ah);
276 tcg_temp_free_i64(al);
277 tcg_temp_free_i64(bh);
278 tcg_temp_free_i64(bl);
281 typedef void (*gen_gvec128_4_i64_fn)(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al,
282 TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh,
283 TCGv_i64 cl, TCGv_i64 ch);
284 static void gen_gvec128_4_i64(gen_gvec128_4_i64_fn fn, uint8_t d, uint8_t a,
285 uint8_t b, uint8_t c)
287 TCGv_i64 dh = tcg_temp_new_i64();
288 TCGv_i64 dl = tcg_temp_new_i64();
289 TCGv_i64 ah = tcg_temp_new_i64();
290 TCGv_i64 al = tcg_temp_new_i64();
291 TCGv_i64 bh = tcg_temp_new_i64();
292 TCGv_i64 bl = tcg_temp_new_i64();
293 TCGv_i64 ch = tcg_temp_new_i64();
294 TCGv_i64 cl = tcg_temp_new_i64();
296 read_vec_element_i64(ah, a, 0, ES_64);
297 read_vec_element_i64(al, a, 1, ES_64);
298 read_vec_element_i64(bh, b, 0, ES_64);
299 read_vec_element_i64(bl, b, 1, ES_64);
300 read_vec_element_i64(ch, c, 0, ES_64);
301 read_vec_element_i64(cl, c, 1, ES_64);
302 fn(dl, dh, al, ah, bl, bh, cl, ch);
303 write_vec_element_i64(dh, d, 0, ES_64);
304 write_vec_element_i64(dl, d, 1, ES_64);
306 tcg_temp_free_i64(dh);
307 tcg_temp_free_i64(dl);
308 tcg_temp_free_i64(ah);
309 tcg_temp_free_i64(al);
310 tcg_temp_free_i64(bh);
311 tcg_temp_free_i64(bl);
312 tcg_temp_free_i64(ch);
313 tcg_temp_free_i64(cl);
316 static void gen_gvec_dupi(uint8_t es, uint8_t reg, uint64_t c)
320 tcg_gen_gvec_dup8i(vec_full_reg_offset(reg), 16, 16, c);
323 tcg_gen_gvec_dup16i(vec_full_reg_offset(reg), 16, 16, c);
326 tcg_gen_gvec_dup32i(vec_full_reg_offset(reg), 16, 16, c);
329 gen_gvec_dup64i(reg, c);
332 g_assert_not_reached();
336 static void zero_vec(uint8_t reg)
338 tcg_gen_gvec_dup8i(vec_full_reg_offset(reg), 16, 16, 0);
341 static void gen_addi2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
344 TCGv_i64 bl = tcg_const_i64(b);
345 TCGv_i64 bh = tcg_const_i64(0);
347 tcg_gen_add2_i64(dl, dh, al, ah, bl, bh);
348 tcg_temp_free_i64(bl);
349 tcg_temp_free_i64(bh);
352 static DisasJumpType op_vge(DisasContext *s, DisasOps *o)
354 const uint8_t es = s->insn->data;
355 const uint8_t enr = get_field(s->fields, m3);
358 if (!valid_vec_element(enr, es)) {
359 gen_program_exception(s, PGM_SPECIFICATION);
360 return DISAS_NORETURN;
363 tmp = tcg_temp_new_i64();
364 read_vec_element_i64(tmp, get_field(s->fields, v2), enr, es);
365 tcg_gen_add_i64(o->addr1, o->addr1, tmp);
366 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 0);
368 tcg_gen_qemu_ld_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
369 write_vec_element_i64(tmp, get_field(s->fields, v1), enr, es);
370 tcg_temp_free_i64(tmp);
374 static uint64_t generate_byte_mask(uint8_t mask)
379 for (i = 0; i < 8; i++) {
380 if ((mask >> i) & 1) {
381 r |= 0xffull << (i * 8);
387 static DisasJumpType op_vgbm(DisasContext *s, DisasOps *o)
389 const uint16_t i2 = get_field(s->fields, i2);
391 if (i2 == (i2 & 0xff) * 0x0101) {
393 * Masks for both 64 bit elements of the vector are the same.
394 * Trust tcg to produce a good constant loading.
396 gen_gvec_dup64i(get_field(s->fields, v1),
397 generate_byte_mask(i2 & 0xff));
399 TCGv_i64 t = tcg_temp_new_i64();
401 tcg_gen_movi_i64(t, generate_byte_mask(i2 >> 8));
402 write_vec_element_i64(t, get_field(s->fields, v1), 0, ES_64);
403 tcg_gen_movi_i64(t, generate_byte_mask(i2));
404 write_vec_element_i64(t, get_field(s->fields, v1), 1, ES_64);
405 tcg_temp_free_i64(t);
410 static DisasJumpType op_vgm(DisasContext *s, DisasOps *o)
412 const uint8_t es = get_field(s->fields, m4);
413 const uint8_t bits = NUM_VEC_ELEMENT_BITS(es);
414 const uint8_t i2 = get_field(s->fields, i2) & (bits - 1);
415 const uint8_t i3 = get_field(s->fields, i3) & (bits - 1);
420 gen_program_exception(s, PGM_SPECIFICATION);
421 return DISAS_NORETURN;
424 /* generate the mask - take care of wrapping */
425 for (i = i2; ; i = (i + 1) % bits) {
426 mask |= 1ull << (bits - i - 1);
432 gen_gvec_dupi(es, get_field(s->fields, v1), mask);
436 static DisasJumpType op_vl(DisasContext *s, DisasOps *o)
438 TCGv_i64 t0 = tcg_temp_new_i64();
439 TCGv_i64 t1 = tcg_temp_new_i64();
441 tcg_gen_qemu_ld_i64(t0, o->addr1, get_mem_index(s), MO_TEQ);
442 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
443 tcg_gen_qemu_ld_i64(t1, o->addr1, get_mem_index(s), MO_TEQ);
444 write_vec_element_i64(t0, get_field(s->fields, v1), 0, ES_64);
445 write_vec_element_i64(t1, get_field(s->fields, v1), 1, ES_64);
451 static DisasJumpType op_vlr(DisasContext *s, DisasOps *o)
453 gen_gvec_mov(get_field(s->fields, v1), get_field(s->fields, v2));
457 static DisasJumpType op_vlrep(DisasContext *s, DisasOps *o)
459 const uint8_t es = get_field(s->fields, m3);
463 gen_program_exception(s, PGM_SPECIFICATION);
464 return DISAS_NORETURN;
467 tmp = tcg_temp_new_i64();
468 tcg_gen_qemu_ld_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
469 gen_gvec_dup_i64(es, get_field(s->fields, v1), tmp);
470 tcg_temp_free_i64(tmp);
474 static DisasJumpType op_vle(DisasContext *s, DisasOps *o)
476 const uint8_t es = s->insn->data;
477 const uint8_t enr = get_field(s->fields, m3);
480 if (!valid_vec_element(enr, es)) {
481 gen_program_exception(s, PGM_SPECIFICATION);
482 return DISAS_NORETURN;
485 tmp = tcg_temp_new_i64();
486 tcg_gen_qemu_ld_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
487 write_vec_element_i64(tmp, get_field(s->fields, v1), enr, es);
488 tcg_temp_free_i64(tmp);
492 static DisasJumpType op_vlei(DisasContext *s, DisasOps *o)
494 const uint8_t es = s->insn->data;
495 const uint8_t enr = get_field(s->fields, m3);
498 if (!valid_vec_element(enr, es)) {
499 gen_program_exception(s, PGM_SPECIFICATION);
500 return DISAS_NORETURN;
503 tmp = tcg_const_i64((int16_t)get_field(s->fields, i2));
504 write_vec_element_i64(tmp, get_field(s->fields, v1), enr, es);
505 tcg_temp_free_i64(tmp);
509 static DisasJumpType op_vlgv(DisasContext *s, DisasOps *o)
511 const uint8_t es = get_field(s->fields, m4);
515 gen_program_exception(s, PGM_SPECIFICATION);
516 return DISAS_NORETURN;
519 /* fast path if we don't need the register content */
520 if (!get_field(s->fields, b2)) {
521 uint8_t enr = get_field(s->fields, d2) & (NUM_VEC_ELEMENTS(es) - 1);
523 read_vec_element_i64(o->out, get_field(s->fields, v3), enr, es);
527 ptr = tcg_temp_new_ptr();
528 get_vec_element_ptr_i64(ptr, get_field(s->fields, v3), o->addr1, es);
531 tcg_gen_ld8u_i64(o->out, ptr, 0);
534 tcg_gen_ld16u_i64(o->out, ptr, 0);
537 tcg_gen_ld32u_i64(o->out, ptr, 0);
540 tcg_gen_ld_i64(o->out, ptr, 0);
543 g_assert_not_reached();
545 tcg_temp_free_ptr(ptr);
550 static DisasJumpType op_vllez(DisasContext *s, DisasOps *o)
552 uint8_t es = get_field(s->fields, m3);
557 /* rightmost sub-element of leftmost doubleword */
570 /* leftmost sub-element of leftmost doubleword */
572 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
579 gen_program_exception(s, PGM_SPECIFICATION);
580 return DISAS_NORETURN;
583 t = tcg_temp_new_i64();
584 tcg_gen_qemu_ld_i64(t, o->addr1, get_mem_index(s), MO_TE | es);
585 zero_vec(get_field(s->fields, v1));
586 write_vec_element_i64(t, get_field(s->fields, v1), enr, es);
587 tcg_temp_free_i64(t);
591 static DisasJumpType op_vlm(DisasContext *s, DisasOps *o)
593 const uint8_t v3 = get_field(s->fields, v3);
594 uint8_t v1 = get_field(s->fields, v1);
597 if (v3 < v1 || (v3 - v1 + 1) > 16) {
598 gen_program_exception(s, PGM_SPECIFICATION);
599 return DISAS_NORETURN;
603 * Check for possible access exceptions by trying to load the last
604 * element. The first element will be checked first next.
606 t0 = tcg_temp_new_i64();
607 t1 = tcg_temp_new_i64();
608 gen_addi_and_wrap_i64(s, t0, o->addr1, (v3 - v1) * 16 + 8);
609 tcg_gen_qemu_ld_i64(t0, t0, get_mem_index(s), MO_TEQ);
612 tcg_gen_qemu_ld_i64(t1, o->addr1, get_mem_index(s), MO_TEQ);
613 write_vec_element_i64(t1, v1, 0, ES_64);
617 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
618 tcg_gen_qemu_ld_i64(t1, o->addr1, get_mem_index(s), MO_TEQ);
619 write_vec_element_i64(t1, v1, 1, ES_64);
620 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
623 /* Store the last element, loaded first */
624 write_vec_element_i64(t0, v1, 1, ES_64);
626 tcg_temp_free_i64(t0);
627 tcg_temp_free_i64(t1);
631 static DisasJumpType op_vlbb(DisasContext *s, DisasOps *o)
633 const int64_t block_size = (1ull << (get_field(s->fields, m3) + 6));
634 const int v1_offs = vec_full_reg_offset(get_field(s->fields, v1));
638 if (get_field(s->fields, m3) > 6) {
639 gen_program_exception(s, PGM_SPECIFICATION);
640 return DISAS_NORETURN;
643 bytes = tcg_temp_new_i64();
644 a0 = tcg_temp_new_ptr();
645 /* calculate the number of bytes until the next block boundary */
646 tcg_gen_ori_i64(bytes, o->addr1, -block_size);
647 tcg_gen_neg_i64(bytes, bytes);
649 tcg_gen_addi_ptr(a0, cpu_env, v1_offs);
650 gen_helper_vll(cpu_env, a0, o->addr1, bytes);
651 tcg_temp_free_i64(bytes);
652 tcg_temp_free_ptr(a0);
656 static DisasJumpType op_vlvg(DisasContext *s, DisasOps *o)
658 const uint8_t es = get_field(s->fields, m4);
662 gen_program_exception(s, PGM_SPECIFICATION);
663 return DISAS_NORETURN;
666 /* fast path if we don't need the register content */
667 if (!get_field(s->fields, b2)) {
668 uint8_t enr = get_field(s->fields, d2) & (NUM_VEC_ELEMENTS(es) - 1);
670 write_vec_element_i64(o->in2, get_field(s->fields, v1), enr, es);
674 ptr = tcg_temp_new_ptr();
675 get_vec_element_ptr_i64(ptr, get_field(s->fields, v1), o->addr1, es);
678 tcg_gen_st8_i64(o->in2, ptr, 0);
681 tcg_gen_st16_i64(o->in2, ptr, 0);
684 tcg_gen_st32_i64(o->in2, ptr, 0);
687 tcg_gen_st_i64(o->in2, ptr, 0);
690 g_assert_not_reached();
692 tcg_temp_free_ptr(ptr);
697 static DisasJumpType op_vlvgp(DisasContext *s, DisasOps *o)
699 write_vec_element_i64(o->in1, get_field(s->fields, v1), 0, ES_64);
700 write_vec_element_i64(o->in2, get_field(s->fields, v1), 1, ES_64);
704 static DisasJumpType op_vll(DisasContext *s, DisasOps *o)
706 const int v1_offs = vec_full_reg_offset(get_field(s->fields, v1));
707 TCGv_ptr a0 = tcg_temp_new_ptr();
709 /* convert highest index into an actual length */
710 tcg_gen_addi_i64(o->in2, o->in2, 1);
711 tcg_gen_addi_ptr(a0, cpu_env, v1_offs);
712 gen_helper_vll(cpu_env, a0, o->addr1, o->in2);
713 tcg_temp_free_ptr(a0);
717 static DisasJumpType op_vmr(DisasContext *s, DisasOps *o)
719 const uint8_t v1 = get_field(s->fields, v1);
720 const uint8_t v2 = get_field(s->fields, v2);
721 const uint8_t v3 = get_field(s->fields, v3);
722 const uint8_t es = get_field(s->fields, m4);
723 int dst_idx, src_idx;
727 gen_program_exception(s, PGM_SPECIFICATION);
728 return DISAS_NORETURN;
731 tmp = tcg_temp_new_i64();
732 if (s->fields->op2 == 0x61) {
733 /* iterate backwards to avoid overwriting data we might need later */
734 for (dst_idx = NUM_VEC_ELEMENTS(es) - 1; dst_idx >= 0; dst_idx--) {
735 src_idx = dst_idx / 2;
736 if (dst_idx % 2 == 0) {
737 read_vec_element_i64(tmp, v2, src_idx, es);
739 read_vec_element_i64(tmp, v3, src_idx, es);
741 write_vec_element_i64(tmp, v1, dst_idx, es);
744 /* iterate forward to avoid overwriting data we might need later */
745 for (dst_idx = 0; dst_idx < NUM_VEC_ELEMENTS(es); dst_idx++) {
746 src_idx = (dst_idx + NUM_VEC_ELEMENTS(es)) / 2;
747 if (dst_idx % 2 == 0) {
748 read_vec_element_i64(tmp, v2, src_idx, es);
750 read_vec_element_i64(tmp, v3, src_idx, es);
752 write_vec_element_i64(tmp, v1, dst_idx, es);
755 tcg_temp_free_i64(tmp);
759 static DisasJumpType op_vpk(DisasContext *s, DisasOps *o)
761 const uint8_t v1 = get_field(s->fields, v1);
762 const uint8_t v2 = get_field(s->fields, v2);
763 const uint8_t v3 = get_field(s->fields, v3);
764 const uint8_t es = get_field(s->fields, m4);
765 static gen_helper_gvec_3 * const vpk[3] = {
766 gen_helper_gvec_vpk16,
767 gen_helper_gvec_vpk32,
768 gen_helper_gvec_vpk64,
770 static gen_helper_gvec_3 * const vpks[3] = {
771 gen_helper_gvec_vpks16,
772 gen_helper_gvec_vpks32,
773 gen_helper_gvec_vpks64,
775 static gen_helper_gvec_3_ptr * const vpks_cc[3] = {
776 gen_helper_gvec_vpks_cc16,
777 gen_helper_gvec_vpks_cc32,
778 gen_helper_gvec_vpks_cc64,
780 static gen_helper_gvec_3 * const vpkls[3] = {
781 gen_helper_gvec_vpkls16,
782 gen_helper_gvec_vpkls32,
783 gen_helper_gvec_vpkls64,
785 static gen_helper_gvec_3_ptr * const vpkls_cc[3] = {
786 gen_helper_gvec_vpkls_cc16,
787 gen_helper_gvec_vpkls_cc32,
788 gen_helper_gvec_vpkls_cc64,
791 if (es == ES_8 || es > ES_64) {
792 gen_program_exception(s, PGM_SPECIFICATION);
793 return DISAS_NORETURN;
796 switch (s->fields->op2) {
798 if (get_field(s->fields, m5) & 0x1) {
799 gen_gvec_3_ptr(v1, v2, v3, cpu_env, 0, vpks_cc[es - 1]);
802 gen_gvec_3_ool(v1, v2, v3, 0, vpks[es - 1]);
806 if (get_field(s->fields, m5) & 0x1) {
807 gen_gvec_3_ptr(v1, v2, v3, cpu_env, 0, vpkls_cc[es - 1]);
810 gen_gvec_3_ool(v1, v2, v3, 0, vpkls[es - 1]);
814 /* If sources and destination dont't overlap -> fast path */
815 if (v1 != v2 && v1 != v3) {
816 const uint8_t src_es = get_field(s->fields, m4);
817 const uint8_t dst_es = src_es - 1;
818 TCGv_i64 tmp = tcg_temp_new_i64();
819 int dst_idx, src_idx;
821 for (dst_idx = 0; dst_idx < NUM_VEC_ELEMENTS(dst_es); dst_idx++) {
823 if (src_idx < NUM_VEC_ELEMENTS(src_es)) {
824 read_vec_element_i64(tmp, v2, src_idx, src_es);
826 src_idx -= NUM_VEC_ELEMENTS(src_es);
827 read_vec_element_i64(tmp, v3, src_idx, src_es);
829 write_vec_element_i64(tmp, v1, dst_idx, dst_es);
831 tcg_temp_free_i64(tmp);
833 gen_gvec_3_ool(v1, v2, v3, 0, vpk[es - 1]);
837 g_assert_not_reached();
842 static DisasJumpType op_vperm(DisasContext *s, DisasOps *o)
844 gen_gvec_4_ool(get_field(s->fields, v1), get_field(s->fields, v2),
845 get_field(s->fields, v3), get_field(s->fields, v4),
846 0, gen_helper_gvec_vperm);
850 static DisasJumpType op_vpdi(DisasContext *s, DisasOps *o)
852 const uint8_t i2 = extract32(get_field(s->fields, m4), 2, 1);
853 const uint8_t i3 = extract32(get_field(s->fields, m4), 0, 1);
854 TCGv_i64 t0 = tcg_temp_new_i64();
855 TCGv_i64 t1 = tcg_temp_new_i64();
857 read_vec_element_i64(t0, get_field(s->fields, v2), i2, ES_64);
858 read_vec_element_i64(t1, get_field(s->fields, v3), i3, ES_64);
859 write_vec_element_i64(t0, get_field(s->fields, v1), 0, ES_64);
860 write_vec_element_i64(t1, get_field(s->fields, v1), 1, ES_64);
861 tcg_temp_free_i64(t0);
862 tcg_temp_free_i64(t1);
866 static DisasJumpType op_vrep(DisasContext *s, DisasOps *o)
868 const uint8_t enr = get_field(s->fields, i2);
869 const uint8_t es = get_field(s->fields, m4);
871 if (es > ES_64 || !valid_vec_element(enr, es)) {
872 gen_program_exception(s, PGM_SPECIFICATION);
873 return DISAS_NORETURN;
876 tcg_gen_gvec_dup_mem(es, vec_full_reg_offset(get_field(s->fields, v1)),
877 vec_reg_offset(get_field(s->fields, v3), enr, es),
882 static DisasJumpType op_vrepi(DisasContext *s, DisasOps *o)
884 const int64_t data = (int16_t)get_field(s->fields, i2);
885 const uint8_t es = get_field(s->fields, m3);
888 gen_program_exception(s, PGM_SPECIFICATION);
889 return DISAS_NORETURN;
892 gen_gvec_dupi(es, get_field(s->fields, v1), data);
896 static DisasJumpType op_vsce(DisasContext *s, DisasOps *o)
898 const uint8_t es = s->insn->data;
899 const uint8_t enr = get_field(s->fields, m3);
902 if (!valid_vec_element(enr, es)) {
903 gen_program_exception(s, PGM_SPECIFICATION);
904 return DISAS_NORETURN;
907 tmp = tcg_temp_new_i64();
908 read_vec_element_i64(tmp, get_field(s->fields, v2), enr, es);
909 tcg_gen_add_i64(o->addr1, o->addr1, tmp);
910 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 0);
912 read_vec_element_i64(tmp, get_field(s->fields, v1), enr, es);
913 tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
914 tcg_temp_free_i64(tmp);
918 static void gen_sel_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b, TCGv_i64 c)
920 TCGv_i64 t = tcg_temp_new_i64();
922 /* bit in c not set -> copy bit from b */
923 tcg_gen_andc_i64(t, b, c);
924 /* bit in c set -> copy bit from a */
925 tcg_gen_and_i64(d, a, c);
926 /* merge the results */
927 tcg_gen_or_i64(d, d, t);
928 tcg_temp_free_i64(t);
931 static void gen_sel_vec(unsigned vece, TCGv_vec d, TCGv_vec a, TCGv_vec b,
934 TCGv_vec t = tcg_temp_new_vec_matching(d);
936 tcg_gen_andc_vec(vece, t, b, c);
937 tcg_gen_and_vec(vece, d, a, c);
938 tcg_gen_or_vec(vece, d, d, t);
939 tcg_temp_free_vec(t);
942 static DisasJumpType op_vsel(DisasContext *s, DisasOps *o)
944 static const GVecGen4 gvec_op = {
947 .prefer_i64 = TCG_TARGET_REG_BITS == 64,
950 gen_gvec_4(get_field(s->fields, v1), get_field(s->fields, v2),
951 get_field(s->fields, v3), get_field(s->fields, v4), &gvec_op);
955 static DisasJumpType op_vseg(DisasContext *s, DisasOps *o)
957 const uint8_t es = get_field(s->fields, m3);
975 gen_program_exception(s, PGM_SPECIFICATION);
976 return DISAS_NORETURN;
979 tmp = tcg_temp_new_i64();
980 read_vec_element_i64(tmp, get_field(s->fields, v2), idx1, es | MO_SIGN);
981 write_vec_element_i64(tmp, get_field(s->fields, v1), 0, ES_64);
982 read_vec_element_i64(tmp, get_field(s->fields, v2), idx2, es | MO_SIGN);
983 write_vec_element_i64(tmp, get_field(s->fields, v1), 1, ES_64);
984 tcg_temp_free_i64(tmp);
988 static DisasJumpType op_vst(DisasContext *s, DisasOps *o)
990 TCGv_i64 tmp = tcg_const_i64(16);
992 /* Probe write access before actually modifying memory */
993 gen_helper_probe_write_access(cpu_env, o->addr1, tmp);
995 read_vec_element_i64(tmp, get_field(s->fields, v1), 0, ES_64);
996 tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEQ);
997 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
998 read_vec_element_i64(tmp, get_field(s->fields, v1), 1, ES_64);
999 tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEQ);
1000 tcg_temp_free_i64(tmp);
1004 static DisasJumpType op_vste(DisasContext *s, DisasOps *o)
1006 const uint8_t es = s->insn->data;
1007 const uint8_t enr = get_field(s->fields, m3);
1010 if (!valid_vec_element(enr, es)) {
1011 gen_program_exception(s, PGM_SPECIFICATION);
1012 return DISAS_NORETURN;
1015 tmp = tcg_temp_new_i64();
1016 read_vec_element_i64(tmp, get_field(s->fields, v1), enr, es);
1017 tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
1018 tcg_temp_free_i64(tmp);
1022 static DisasJumpType op_vstm(DisasContext *s, DisasOps *o)
1024 const uint8_t v3 = get_field(s->fields, v3);
1025 uint8_t v1 = get_field(s->fields, v1);
1028 while (v3 < v1 || (v3 - v1 + 1) > 16) {
1029 gen_program_exception(s, PGM_SPECIFICATION);
1030 return DISAS_NORETURN;
1033 /* Probe write access before actually modifying memory */
1034 tmp = tcg_const_i64((v3 - v1 + 1) * 16);
1035 gen_helper_probe_write_access(cpu_env, o->addr1, tmp);
1038 read_vec_element_i64(tmp, v1, 0, ES_64);
1039 tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEQ);
1040 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
1041 read_vec_element_i64(tmp, v1, 1, ES_64);
1042 tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEQ);
1046 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
1048 tcg_temp_free_i64(tmp);
1052 static DisasJumpType op_vstl(DisasContext *s, DisasOps *o)
1054 const int v1_offs = vec_full_reg_offset(get_field(s->fields, v1));
1055 TCGv_ptr a0 = tcg_temp_new_ptr();
1057 /* convert highest index into an actual length */
1058 tcg_gen_addi_i64(o->in2, o->in2, 1);
1059 tcg_gen_addi_ptr(a0, cpu_env, v1_offs);
1060 gen_helper_vstl(cpu_env, a0, o->addr1, o->in2);
1061 tcg_temp_free_ptr(a0);
1065 static DisasJumpType op_vup(DisasContext *s, DisasOps *o)
1067 const bool logical = s->fields->op2 == 0xd4 || s->fields->op2 == 0xd5;
1068 const uint8_t v1 = get_field(s->fields, v1);
1069 const uint8_t v2 = get_field(s->fields, v2);
1070 const uint8_t src_es = get_field(s->fields, m3);
1071 const uint8_t dst_es = src_es + 1;
1072 int dst_idx, src_idx;
1075 if (src_es > ES_32) {
1076 gen_program_exception(s, PGM_SPECIFICATION);
1077 return DISAS_NORETURN;
1080 tmp = tcg_temp_new_i64();
1081 if (s->fields->op2 == 0xd7 || s->fields->op2 == 0xd5) {
1082 /* iterate backwards to avoid overwriting data we might need later */
1083 for (dst_idx = NUM_VEC_ELEMENTS(dst_es) - 1; dst_idx >= 0; dst_idx--) {
1085 read_vec_element_i64(tmp, v2, src_idx,
1086 src_es | (logical ? 0 : MO_SIGN));
1087 write_vec_element_i64(tmp, v1, dst_idx, dst_es);
1091 /* iterate forward to avoid overwriting data we might need later */
1092 for (dst_idx = 0; dst_idx < NUM_VEC_ELEMENTS(dst_es); dst_idx++) {
1093 src_idx = dst_idx + NUM_VEC_ELEMENTS(src_es) / 2;
1094 read_vec_element_i64(tmp, v2, src_idx,
1095 src_es | (logical ? 0 : MO_SIGN));
1096 write_vec_element_i64(tmp, v1, dst_idx, dst_es);
1099 tcg_temp_free_i64(tmp);
1103 static DisasJumpType op_va(DisasContext *s, DisasOps *o)
1105 const uint8_t es = get_field(s->fields, m4);
1108 gen_program_exception(s, PGM_SPECIFICATION);
1109 return DISAS_NORETURN;
1110 } else if (es == ES_128) {
1111 gen_gvec128_3_i64(tcg_gen_add2_i64, get_field(s->fields, v1),
1112 get_field(s->fields, v2), get_field(s->fields, v3));
1115 gen_gvec_fn_3(add, es, get_field(s->fields, v1), get_field(s->fields, v2),
1116 get_field(s->fields, v3));
1120 static void gen_acc(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b, uint8_t es)
1122 const uint8_t msb_bit_nr = NUM_VEC_ELEMENT_BITS(es) - 1;
1123 TCGv_i64 msb_mask = tcg_const_i64(dup_const(es, 1ull << msb_bit_nr));
1124 TCGv_i64 t1 = tcg_temp_new_i64();
1125 TCGv_i64 t2 = tcg_temp_new_i64();
1126 TCGv_i64 t3 = tcg_temp_new_i64();
1128 /* Calculate the carry into the MSB, ignoring the old MSBs */
1129 tcg_gen_andc_i64(t1, a, msb_mask);
1130 tcg_gen_andc_i64(t2, b, msb_mask);
1131 tcg_gen_add_i64(t1, t1, t2);
1132 /* Calculate the MSB without any carry into it */
1133 tcg_gen_xor_i64(t3, a, b);
1134 /* Calculate the carry out of the MSB in the MSB bit position */
1135 tcg_gen_and_i64(d, a, b);
1136 tcg_gen_and_i64(t1, t1, t3);
1137 tcg_gen_or_i64(d, d, t1);
1138 /* Isolate and shift the carry into position */
1139 tcg_gen_and_i64(d, d, msb_mask);
1140 tcg_gen_shri_i64(d, d, msb_bit_nr);
1142 tcg_temp_free_i64(t1);
1143 tcg_temp_free_i64(t2);
1144 tcg_temp_free_i64(t3);
1147 static void gen_acc8_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
1149 gen_acc(d, a, b, ES_8);
1152 static void gen_acc16_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
1154 gen_acc(d, a, b, ES_16);
1157 static void gen_acc_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
1159 TCGv_i32 t = tcg_temp_new_i32();
1161 tcg_gen_add_i32(t, a, b);
1162 tcg_gen_setcond_i32(TCG_COND_LTU, d, t, b);
1163 tcg_temp_free_i32(t);
1166 static void gen_acc_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
1168 TCGv_i64 t = tcg_temp_new_i64();
1170 tcg_gen_add_i64(t, a, b);
1171 tcg_gen_setcond_i64(TCG_COND_LTU, d, t, b);
1172 tcg_temp_free_i64(t);
1175 static void gen_acc2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al,
1176 TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh)
1178 TCGv_i64 th = tcg_temp_new_i64();
1179 TCGv_i64 tl = tcg_temp_new_i64();
1180 TCGv_i64 zero = tcg_const_i64(0);
1182 tcg_gen_add2_i64(tl, th, al, zero, bl, zero);
1183 tcg_gen_add2_i64(tl, th, th, zero, ah, zero);
1184 tcg_gen_add2_i64(tl, dl, tl, th, bh, zero);
1185 tcg_gen_mov_i64(dh, zero);
1187 tcg_temp_free_i64(th);
1188 tcg_temp_free_i64(tl);
1189 tcg_temp_free_i64(zero);
1192 static DisasJumpType op_vacc(DisasContext *s, DisasOps *o)
1194 const uint8_t es = get_field(s->fields, m4);
1195 static const GVecGen3 g[4] = {
1196 { .fni8 = gen_acc8_i64, },
1197 { .fni8 = gen_acc16_i64, },
1198 { .fni4 = gen_acc_i32, },
1199 { .fni8 = gen_acc_i64, },
1203 gen_program_exception(s, PGM_SPECIFICATION);
1204 return DISAS_NORETURN;
1205 } else if (es == ES_128) {
1206 gen_gvec128_3_i64(gen_acc2_i64, get_field(s->fields, v1),
1207 get_field(s->fields, v2), get_field(s->fields, v3));
1210 gen_gvec_3(get_field(s->fields, v1), get_field(s->fields, v2),
1211 get_field(s->fields, v3), &g[es]);
1215 static void gen_ac2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
1216 TCGv_i64 bl, TCGv_i64 bh, TCGv_i64 cl, TCGv_i64 ch)
1218 TCGv_i64 tl = tcg_temp_new_i64();
1219 TCGv_i64 th = tcg_const_i64(0);
1221 /* extract the carry only */
1222 tcg_gen_extract_i64(tl, cl, 0, 1);
1223 tcg_gen_add2_i64(dl, dh, al, ah, bl, bh);
1224 tcg_gen_add2_i64(dl, dh, dl, dh, tl, th);
1226 tcg_temp_free_i64(tl);
1227 tcg_temp_free_i64(th);
1230 static DisasJumpType op_vac(DisasContext *s, DisasOps *o)
1232 if (get_field(s->fields, m5) != ES_128) {
1233 gen_program_exception(s, PGM_SPECIFICATION);
1234 return DISAS_NORETURN;
1237 gen_gvec128_4_i64(gen_ac2_i64, get_field(s->fields, v1),
1238 get_field(s->fields, v2), get_field(s->fields, v3),
1239 get_field(s->fields, v4));
1243 static void gen_accc2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
1244 TCGv_i64 bl, TCGv_i64 bh, TCGv_i64 cl, TCGv_i64 ch)
1246 TCGv_i64 tl = tcg_temp_new_i64();
1247 TCGv_i64 th = tcg_temp_new_i64();
1248 TCGv_i64 zero = tcg_const_i64(0);
1250 tcg_gen_andi_i64(tl, cl, 1);
1251 tcg_gen_add2_i64(tl, th, tl, zero, al, zero);
1252 tcg_gen_add2_i64(tl, th, tl, th, bl, zero);
1253 tcg_gen_add2_i64(tl, th, th, zero, ah, zero);
1254 tcg_gen_add2_i64(tl, dl, tl, th, bh, zero);
1255 tcg_gen_mov_i64(dh, zero);
1257 tcg_temp_free_i64(tl);
1258 tcg_temp_free_i64(th);
1259 tcg_temp_free_i64(zero);
1262 static DisasJumpType op_vaccc(DisasContext *s, DisasOps *o)
1264 if (get_field(s->fields, m5) != ES_128) {
1265 gen_program_exception(s, PGM_SPECIFICATION);
1266 return DISAS_NORETURN;
1269 gen_gvec128_4_i64(gen_accc2_i64, get_field(s->fields, v1),
1270 get_field(s->fields, v2), get_field(s->fields, v3),
1271 get_field(s->fields, v4));
1275 static DisasJumpType op_vn(DisasContext *s, DisasOps *o)
1277 gen_gvec_fn_3(and, ES_8, get_field(s->fields, v1), get_field(s->fields, v2),
1278 get_field(s->fields, v3));
1282 static DisasJumpType op_vnc(DisasContext *s, DisasOps *o)
1284 gen_gvec_fn_3(andc, ES_8, get_field(s->fields, v1),
1285 get_field(s->fields, v2), get_field(s->fields, v3));
1289 static void gen_avg_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
1291 TCGv_i64 t0 = tcg_temp_new_i64();
1292 TCGv_i64 t1 = tcg_temp_new_i64();
1294 tcg_gen_ext_i32_i64(t0, a);
1295 tcg_gen_ext_i32_i64(t1, b);
1296 tcg_gen_add_i64(t0, t0, t1);
1297 tcg_gen_addi_i64(t0, t0, 1);
1298 tcg_gen_shri_i64(t0, t0, 1);
1299 tcg_gen_extrl_i64_i32(d, t0);
1305 static void gen_avg_i64(TCGv_i64 dl, TCGv_i64 al, TCGv_i64 bl)
1307 TCGv_i64 dh = tcg_temp_new_i64();
1308 TCGv_i64 ah = tcg_temp_new_i64();
1309 TCGv_i64 bh = tcg_temp_new_i64();
1311 /* extending the sign by one bit is sufficient */
1312 tcg_gen_extract_i64(ah, al, 63, 1);
1313 tcg_gen_extract_i64(bh, bl, 63, 1);
1314 tcg_gen_add2_i64(dl, dh, al, ah, bl, bh);
1315 gen_addi2_i64(dl, dh, dl, dh, 1);
1316 tcg_gen_extract2_i64(dl, dl, dh, 1);
1318 tcg_temp_free_i64(dh);
1319 tcg_temp_free_i64(ah);
1320 tcg_temp_free_i64(bh);
1323 static DisasJumpType op_vavg(DisasContext *s, DisasOps *o)
1325 const uint8_t es = get_field(s->fields, m4);
1326 static const GVecGen3 g[4] = {
1327 { .fno = gen_helper_gvec_vavg8, },
1328 { .fno = gen_helper_gvec_vavg16, },
1329 { .fni4 = gen_avg_i32, },
1330 { .fni8 = gen_avg_i64, },
1334 gen_program_exception(s, PGM_SPECIFICATION);
1335 return DISAS_NORETURN;
1337 gen_gvec_3(get_field(s->fields, v1), get_field(s->fields, v2),
1338 get_field(s->fields, v3), &g[es]);
1342 static void gen_avgl_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
1344 TCGv_i64 t0 = tcg_temp_new_i64();
1345 TCGv_i64 t1 = tcg_temp_new_i64();
1347 tcg_gen_extu_i32_i64(t0, a);
1348 tcg_gen_extu_i32_i64(t1, b);
1349 tcg_gen_add_i64(t0, t0, t1);
1350 tcg_gen_addi_i64(t0, t0, 1);
1351 tcg_gen_shri_i64(t0, t0, 1);
1352 tcg_gen_extrl_i64_i32(d, t0);
1358 static void gen_avgl_i64(TCGv_i64 dl, TCGv_i64 al, TCGv_i64 bl)
1360 TCGv_i64 dh = tcg_temp_new_i64();
1361 TCGv_i64 zero = tcg_const_i64(0);
1363 tcg_gen_add2_i64(dl, dh, al, zero, bl, zero);
1364 gen_addi2_i64(dl, dh, dl, dh, 1);
1365 tcg_gen_extract2_i64(dl, dl, dh, 1);
1367 tcg_temp_free_i64(dh);
1368 tcg_temp_free_i64(zero);
1371 static DisasJumpType op_vavgl(DisasContext *s, DisasOps *o)
1373 const uint8_t es = get_field(s->fields, m4);
1374 static const GVecGen3 g[4] = {
1375 { .fno = gen_helper_gvec_vavgl8, },
1376 { .fno = gen_helper_gvec_vavgl16, },
1377 { .fni4 = gen_avgl_i32, },
1378 { .fni8 = gen_avgl_i64, },
1382 gen_program_exception(s, PGM_SPECIFICATION);
1383 return DISAS_NORETURN;
1385 gen_gvec_3(get_field(s->fields, v1), get_field(s->fields, v2),
1386 get_field(s->fields, v3), &g[es]);
1390 static DisasJumpType op_vcksm(DisasContext *s, DisasOps *o)
1392 TCGv_i32 tmp = tcg_temp_new_i32();
1393 TCGv_i32 sum = tcg_temp_new_i32();
1396 read_vec_element_i32(sum, get_field(s->fields, v3), 1, ES_32);
1397 for (i = 0; i < 4; i++) {
1398 read_vec_element_i32(tmp, get_field(s->fields, v2), i, ES_32);
1399 tcg_gen_add2_i32(tmp, sum, sum, sum, tmp, tmp);
1401 zero_vec(get_field(s->fields, v1));
1402 write_vec_element_i32(sum, get_field(s->fields, v1), 1, ES_32);
1404 tcg_temp_free_i32(tmp);
1405 tcg_temp_free_i32(sum);
1409 static DisasJumpType op_vec(DisasContext *s, DisasOps *o)
1411 uint8_t es = get_field(s->fields, m3);
1412 const uint8_t enr = NUM_VEC_ELEMENTS(es) / 2 - 1;
1415 gen_program_exception(s, PGM_SPECIFICATION);
1416 return DISAS_NORETURN;
1418 if (s->fields->op2 == 0xdb) {
1422 o->in1 = tcg_temp_new_i64();
1423 o->in2 = tcg_temp_new_i64();
1424 read_vec_element_i64(o->in1, get_field(s->fields, v1), enr, es);
1425 read_vec_element_i64(o->in2, get_field(s->fields, v2), enr, es);
1429 static DisasJumpType op_vc(DisasContext *s, DisasOps *o)
1431 const uint8_t es = get_field(s->fields, m4);
1432 TCGCond cond = s->insn->data;
1435 gen_program_exception(s, PGM_SPECIFICATION);
1436 return DISAS_NORETURN;
1439 tcg_gen_gvec_cmp(cond, es,
1440 vec_full_reg_offset(get_field(s->fields, v1)),
1441 vec_full_reg_offset(get_field(s->fields, v2)),
1442 vec_full_reg_offset(get_field(s->fields, v3)), 16, 16);
1443 if (get_field(s->fields, m5) & 0x1) {
1444 TCGv_i64 low = tcg_temp_new_i64();
1445 TCGv_i64 high = tcg_temp_new_i64();
1447 read_vec_element_i64(high, get_field(s->fields, v1), 0, ES_64);
1448 read_vec_element_i64(low, get_field(s->fields, v1), 1, ES_64);
1449 gen_op_update2_cc_i64(s, CC_OP_VC, low, high);
1451 tcg_temp_free_i64(low);
1452 tcg_temp_free_i64(high);
1457 static void gen_clz_i32(TCGv_i32 d, TCGv_i32 a)
1459 tcg_gen_clzi_i32(d, a, 32);
1462 static void gen_clz_i64(TCGv_i64 d, TCGv_i64 a)
1464 tcg_gen_clzi_i64(d, a, 64);
1467 static DisasJumpType op_vclz(DisasContext *s, DisasOps *o)
1469 const uint8_t es = get_field(s->fields, m3);
1470 static const GVecGen2 g[4] = {
1471 { .fno = gen_helper_gvec_vclz8, },
1472 { .fno = gen_helper_gvec_vclz16, },
1473 { .fni4 = gen_clz_i32, },
1474 { .fni8 = gen_clz_i64, },
1478 gen_program_exception(s, PGM_SPECIFICATION);
1479 return DISAS_NORETURN;
1481 gen_gvec_2(get_field(s->fields, v1), get_field(s->fields, v2), &g[es]);
1485 static void gen_ctz_i32(TCGv_i32 d, TCGv_i32 a)
1487 tcg_gen_ctzi_i32(d, a, 32);
1490 static void gen_ctz_i64(TCGv_i64 d, TCGv_i64 a)
1492 tcg_gen_ctzi_i64(d, a, 64);
1495 static DisasJumpType op_vctz(DisasContext *s, DisasOps *o)
1497 const uint8_t es = get_field(s->fields, m3);
1498 static const GVecGen2 g[4] = {
1499 { .fno = gen_helper_gvec_vctz8, },
1500 { .fno = gen_helper_gvec_vctz16, },
1501 { .fni4 = gen_ctz_i32, },
1502 { .fni8 = gen_ctz_i64, },
1506 gen_program_exception(s, PGM_SPECIFICATION);
1507 return DISAS_NORETURN;
1509 gen_gvec_2(get_field(s->fields, v1), get_field(s->fields, v2), &g[es]);
1513 static DisasJumpType op_vx(DisasContext *s, DisasOps *o)
1515 gen_gvec_fn_3(xor, ES_8, get_field(s->fields, v1), get_field(s->fields, v2),
1516 get_field(s->fields, v3));
1520 static DisasJumpType op_vgfm(DisasContext *s, DisasOps *o)
1522 const uint8_t es = get_field(s->fields, m4);
1523 static const GVecGen3 g[4] = {
1524 { .fno = gen_helper_gvec_vgfm8, },
1525 { .fno = gen_helper_gvec_vgfm16, },
1526 { .fno = gen_helper_gvec_vgfm32, },
1527 { .fno = gen_helper_gvec_vgfm64, },
1531 gen_program_exception(s, PGM_SPECIFICATION);
1532 return DISAS_NORETURN;
1534 gen_gvec_3(get_field(s->fields, v1), get_field(s->fields, v2),
1535 get_field(s->fields, v3), &g[es]);
1539 static DisasJumpType op_vgfma(DisasContext *s, DisasOps *o)
1541 const uint8_t es = get_field(s->fields, m5);
1542 static const GVecGen4 g[4] = {
1543 { .fno = gen_helper_gvec_vgfma8, },
1544 { .fno = gen_helper_gvec_vgfma16, },
1545 { .fno = gen_helper_gvec_vgfma32, },
1546 { .fno = gen_helper_gvec_vgfma64, },
1550 gen_program_exception(s, PGM_SPECIFICATION);
1551 return DISAS_NORETURN;
1553 gen_gvec_4(get_field(s->fields, v1), get_field(s->fields, v2),
1554 get_field(s->fields, v3), get_field(s->fields, v4), &g[es]);
1558 static DisasJumpType op_vlc(DisasContext *s, DisasOps *o)
1560 const uint8_t es = get_field(s->fields, m3);
1563 gen_program_exception(s, PGM_SPECIFICATION);
1564 return DISAS_NORETURN;
1567 gen_gvec_fn_2(neg, es, get_field(s->fields, v1), get_field(s->fields, v2));
1571 static DisasJumpType op_vlp(DisasContext *s, DisasOps *o)
1573 const uint8_t es = get_field(s->fields, m3);
1576 gen_program_exception(s, PGM_SPECIFICATION);
1577 return DISAS_NORETURN;
1580 gen_gvec_fn_2(abs, es, get_field(s->fields, v1), get_field(s->fields, v2));
1584 static DisasJumpType op_vmx(DisasContext *s, DisasOps *o)
1586 const uint8_t v1 = get_field(s->fields, v1);
1587 const uint8_t v2 = get_field(s->fields, v2);
1588 const uint8_t v3 = get_field(s->fields, v3);
1589 const uint8_t es = get_field(s->fields, m4);
1592 gen_program_exception(s, PGM_SPECIFICATION);
1593 return DISAS_NORETURN;
1596 switch (s->fields->op2) {
1598 gen_gvec_fn_3(smax, es, v1, v2, v3);
1601 gen_gvec_fn_3(umax, es, v1, v2, v3);
1604 gen_gvec_fn_3(smin, es, v1, v2, v3);
1607 gen_gvec_fn_3(umin, es, v1, v2, v3);
1610 g_assert_not_reached();
1615 static void gen_mal_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b, TCGv_i32 c)
1617 TCGv_i32 t0 = tcg_temp_new_i32();
1619 tcg_gen_mul_i32(t0, a, b);
1620 tcg_gen_add_i32(d, t0, c);
1622 tcg_temp_free_i32(t0);
1625 static void gen_mah_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b, TCGv_i32 c)
1627 TCGv_i64 t0 = tcg_temp_new_i64();
1628 TCGv_i64 t1 = tcg_temp_new_i64();
1629 TCGv_i64 t2 = tcg_temp_new_i64();
1631 tcg_gen_ext_i32_i64(t0, a);
1632 tcg_gen_ext_i32_i64(t1, b);
1633 tcg_gen_ext_i32_i64(t2, c);
1634 tcg_gen_mul_i64(t0, t0, t1);
1635 tcg_gen_add_i64(t0, t0, t2);
1636 tcg_gen_extrh_i64_i32(d, t0);
1643 static void gen_malh_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b, TCGv_i32 c)
1645 TCGv_i64 t0 = tcg_temp_new_i64();
1646 TCGv_i64 t1 = tcg_temp_new_i64();
1647 TCGv_i64 t2 = tcg_temp_new_i64();
1649 tcg_gen_extu_i32_i64(t0, a);
1650 tcg_gen_extu_i32_i64(t1, b);
1651 tcg_gen_extu_i32_i64(t2, c);
1652 tcg_gen_mul_i64(t0, t0, t1);
1653 tcg_gen_add_i64(t0, t0, t2);
1654 tcg_gen_extrh_i64_i32(d, t0);
1661 static DisasJumpType op_vma(DisasContext *s, DisasOps *o)
1663 const uint8_t es = get_field(s->fields, m5);
1664 static const GVecGen4 g_vmal[3] = {
1665 { .fno = gen_helper_gvec_vmal8, },
1666 { .fno = gen_helper_gvec_vmal16, },
1667 { .fni4 = gen_mal_i32, },
1669 static const GVecGen4 g_vmah[3] = {
1670 { .fno = gen_helper_gvec_vmah8, },
1671 { .fno = gen_helper_gvec_vmah16, },
1672 { .fni4 = gen_mah_i32, },
1674 static const GVecGen4 g_vmalh[3] = {
1675 { .fno = gen_helper_gvec_vmalh8, },
1676 { .fno = gen_helper_gvec_vmalh16, },
1677 { .fni4 = gen_malh_i32, },
1679 static const GVecGen4 g_vmae[3] = {
1680 { .fno = gen_helper_gvec_vmae8, },
1681 { .fno = gen_helper_gvec_vmae16, },
1682 { .fno = gen_helper_gvec_vmae32, },
1684 static const GVecGen4 g_vmale[3] = {
1685 { .fno = gen_helper_gvec_vmale8, },
1686 { .fno = gen_helper_gvec_vmale16, },
1687 { .fno = gen_helper_gvec_vmale32, },
1689 static const GVecGen4 g_vmao[3] = {
1690 { .fno = gen_helper_gvec_vmao8, },
1691 { .fno = gen_helper_gvec_vmao16, },
1692 { .fno = gen_helper_gvec_vmao32, },
1694 static const GVecGen4 g_vmalo[3] = {
1695 { .fno = gen_helper_gvec_vmalo8, },
1696 { .fno = gen_helper_gvec_vmalo16, },
1697 { .fno = gen_helper_gvec_vmalo32, },
1702 gen_program_exception(s, PGM_SPECIFICATION);
1703 return DISAS_NORETURN;
1706 switch (s->fields->op2) {
1729 g_assert_not_reached();
1732 gen_gvec_4(get_field(s->fields, v1), get_field(s->fields, v2),
1733 get_field(s->fields, v3), get_field(s->fields, v4), fn);
1737 static void gen_mh_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
1739 TCGv_i32 t = tcg_temp_new_i32();
1741 tcg_gen_muls2_i32(t, d, a, b);
1742 tcg_temp_free_i32(t);
1745 static void gen_mlh_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
1747 TCGv_i32 t = tcg_temp_new_i32();
1749 tcg_gen_mulu2_i32(t, d, a, b);
1750 tcg_temp_free_i32(t);
1753 static DisasJumpType op_vm(DisasContext *s, DisasOps *o)
1755 const uint8_t es = get_field(s->fields, m4);
1756 static const GVecGen3 g_vmh[3] = {
1757 { .fno = gen_helper_gvec_vmh8, },
1758 { .fno = gen_helper_gvec_vmh16, },
1759 { .fni4 = gen_mh_i32, },
1761 static const GVecGen3 g_vmlh[3] = {
1762 { .fno = gen_helper_gvec_vmlh8, },
1763 { .fno = gen_helper_gvec_vmlh16, },
1764 { .fni4 = gen_mlh_i32, },
1766 static const GVecGen3 g_vme[3] = {
1767 { .fno = gen_helper_gvec_vme8, },
1768 { .fno = gen_helper_gvec_vme16, },
1769 { .fno = gen_helper_gvec_vme32, },
1771 static const GVecGen3 g_vmle[3] = {
1772 { .fno = gen_helper_gvec_vmle8, },
1773 { .fno = gen_helper_gvec_vmle16, },
1774 { .fno = gen_helper_gvec_vmle32, },
1776 static const GVecGen3 g_vmo[3] = {
1777 { .fno = gen_helper_gvec_vmo8, },
1778 { .fno = gen_helper_gvec_vmo16, },
1779 { .fno = gen_helper_gvec_vmo32, },
1781 static const GVecGen3 g_vmlo[3] = {
1782 { .fno = gen_helper_gvec_vmlo8, },
1783 { .fno = gen_helper_gvec_vmlo16, },
1784 { .fno = gen_helper_gvec_vmlo32, },
1789 gen_program_exception(s, PGM_SPECIFICATION);
1790 return DISAS_NORETURN;
1793 switch (s->fields->op2) {
1795 gen_gvec_fn_3(mul, es, get_field(s->fields, v1),
1796 get_field(s->fields, v2), get_field(s->fields, v3));
1817 g_assert_not_reached();
1820 gen_gvec_3(get_field(s->fields, v1), get_field(s->fields, v2),
1821 get_field(s->fields, v3), fn);
1825 static DisasJumpType op_vnn(DisasContext *s, DisasOps *o)
1827 gen_gvec_fn_3(nand, ES_8, get_field(s->fields, v1),
1828 get_field(s->fields, v2), get_field(s->fields, v3));
1832 static DisasJumpType op_vno(DisasContext *s, DisasOps *o)
1834 gen_gvec_fn_3(nor, ES_8, get_field(s->fields, v1), get_field(s->fields, v2),
1835 get_field(s->fields, v3));
1839 static DisasJumpType op_vnx(DisasContext *s, DisasOps *o)
1841 gen_gvec_fn_3(eqv, ES_8, get_field(s->fields, v1), get_field(s->fields, v2),
1842 get_field(s->fields, v3));
1846 static DisasJumpType op_vo(DisasContext *s, DisasOps *o)
1848 gen_gvec_fn_3(or, ES_8, get_field(s->fields, v1), get_field(s->fields, v2),
1849 get_field(s->fields, v3));
1853 static DisasJumpType op_voc(DisasContext *s, DisasOps *o)
1855 gen_gvec_fn_3(orc, ES_8, get_field(s->fields, v1), get_field(s->fields, v2),
1856 get_field(s->fields, v3));
1860 static DisasJumpType op_vpopct(DisasContext *s, DisasOps *o)
1862 const uint8_t es = get_field(s->fields, m3);
1863 static const GVecGen2 g[4] = {
1864 { .fno = gen_helper_gvec_vpopct8, },
1865 { .fno = gen_helper_gvec_vpopct16, },
1866 { .fni4 = tcg_gen_ctpop_i32, },
1867 { .fni8 = tcg_gen_ctpop_i64, },
1870 if (es > ES_64 || (es != ES_8 && !s390_has_feat(S390_FEAT_VECTOR_ENH))) {
1871 gen_program_exception(s, PGM_SPECIFICATION);
1872 return DISAS_NORETURN;
1875 gen_gvec_2(get_field(s->fields, v1), get_field(s->fields, v2), &g[es]);
1879 static void gen_rll_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
1881 TCGv_i32 t0 = tcg_temp_new_i32();
1883 tcg_gen_andi_i32(t0, b, 31);
1884 tcg_gen_rotl_i32(d, a, t0);
1885 tcg_temp_free_i32(t0);
1888 static void gen_rll_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
1890 TCGv_i64 t0 = tcg_temp_new_i64();
1892 tcg_gen_andi_i64(t0, b, 63);
1893 tcg_gen_rotl_i64(d, a, t0);
1894 tcg_temp_free_i64(t0);
1897 static DisasJumpType op_verllv(DisasContext *s, DisasOps *o)
1899 const uint8_t es = get_field(s->fields, m4);
1900 static const GVecGen3 g[4] = {
1901 { .fno = gen_helper_gvec_verllv8, },
1902 { .fno = gen_helper_gvec_verllv16, },
1903 { .fni4 = gen_rll_i32, },
1904 { .fni8 = gen_rll_i64, },
1908 gen_program_exception(s, PGM_SPECIFICATION);
1909 return DISAS_NORETURN;
1912 gen_gvec_3(get_field(s->fields, v1), get_field(s->fields, v2),
1913 get_field(s->fields, v3), &g[es]);
1917 static DisasJumpType op_verll(DisasContext *s, DisasOps *o)
1919 const uint8_t es = get_field(s->fields, m4);
1920 static const GVecGen2s g[4] = {
1921 { .fno = gen_helper_gvec_verll8, },
1922 { .fno = gen_helper_gvec_verll16, },
1923 { .fni4 = gen_rll_i32, },
1924 { .fni8 = gen_rll_i64, },
1928 gen_program_exception(s, PGM_SPECIFICATION);
1929 return DISAS_NORETURN;
1931 gen_gvec_2s(get_field(s->fields, v1), get_field(s->fields, v3), o->addr1,
1936 static void gen_rim_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b, int32_t c)
1938 TCGv_i32 t = tcg_temp_new_i32();
1940 tcg_gen_rotli_i32(t, a, c & 31);
1941 tcg_gen_and_i32(t, t, b);
1942 tcg_gen_andc_i32(d, d, b);
1943 tcg_gen_or_i32(d, d, t);
1945 tcg_temp_free_i32(t);
1948 static void gen_rim_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b, int64_t c)
1950 TCGv_i64 t = tcg_temp_new_i64();
1952 tcg_gen_rotli_i64(t, a, c & 63);
1953 tcg_gen_and_i64(t, t, b);
1954 tcg_gen_andc_i64(d, d, b);
1955 tcg_gen_or_i64(d, d, t);
1957 tcg_temp_free_i64(t);
1960 static DisasJumpType op_verim(DisasContext *s, DisasOps *o)
1962 const uint8_t es = get_field(s->fields, m5);
1963 const uint8_t i4 = get_field(s->fields, i4) &
1964 (NUM_VEC_ELEMENT_BITS(es) - 1);
1965 static const GVecGen3i g[4] = {
1966 { .fno = gen_helper_gvec_verim8, },
1967 { .fno = gen_helper_gvec_verim16, },
1968 { .fni4 = gen_rim_i32,
1969 .load_dest = true, },
1970 { .fni8 = gen_rim_i64,
1971 .load_dest = true, },
1975 gen_program_exception(s, PGM_SPECIFICATION);
1976 return DISAS_NORETURN;
1979 gen_gvec_3i(get_field(s->fields, v1), get_field(s->fields, v2),
1980 get_field(s->fields, v3), i4, &g[es]);
1984 static DisasJumpType op_vesv(DisasContext *s, DisasOps *o)
1986 const uint8_t es = get_field(s->fields, m4);
1987 const uint8_t v1 = get_field(s->fields, v1);
1988 const uint8_t v2 = get_field(s->fields, v2);
1989 const uint8_t v3 = get_field(s->fields, v3);
1992 gen_program_exception(s, PGM_SPECIFICATION);
1993 return DISAS_NORETURN;
1996 switch (s->fields->op2) {
1998 gen_gvec_fn_3(shlv, es, v1, v2, v3);
2001 gen_gvec_fn_3(sarv, es, v1, v2, v3);
2004 gen_gvec_fn_3(shrv, es, v1, v2, v3);
2007 g_assert_not_reached();
2012 static DisasJumpType op_ves(DisasContext *s, DisasOps *o)
2014 const uint8_t es = get_field(s->fields, m4);
2015 const uint8_t d2 = get_field(s->fields, d2) &
2016 (NUM_VEC_ELEMENT_BITS(es) - 1);
2017 const uint8_t v1 = get_field(s->fields, v1);
2018 const uint8_t v3 = get_field(s->fields, v3);
2022 gen_program_exception(s, PGM_SPECIFICATION);
2023 return DISAS_NORETURN;
2026 if (likely(!get_field(s->fields, b2))) {
2027 switch (s->fields->op2) {
2029 gen_gvec_fn_2i(shli, es, v1, v3, d2);
2032 gen_gvec_fn_2i(sari, es, v1, v3, d2);
2035 gen_gvec_fn_2i(shri, es, v1, v3, d2);
2038 g_assert_not_reached();
2041 shift = tcg_temp_new_i32();
2042 tcg_gen_extrl_i64_i32(shift, o->addr1);
2043 tcg_gen_andi_i32(shift, shift, NUM_VEC_ELEMENT_BITS(es) - 1);
2044 switch (s->fields->op2) {
2046 gen_gvec_fn_2s(shls, es, v1, v3, shift);
2049 gen_gvec_fn_2s(sars, es, v1, v3, shift);
2052 gen_gvec_fn_2s(shrs, es, v1, v3, shift);
2055 g_assert_not_reached();
2057 tcg_temp_free_i32(shift);
2062 static DisasJumpType op_vsl(DisasContext *s, DisasOps *o)
2064 TCGv_i64 shift = tcg_temp_new_i64();
2066 read_vec_element_i64(shift, get_field(s->fields, v3), 7, ES_8);
2067 if (s->fields->op2 == 0x74) {
2068 tcg_gen_andi_i64(shift, shift, 0x7);
2070 tcg_gen_andi_i64(shift, shift, 0x78);
2073 gen_gvec_2i_ool(get_field(s->fields, v1), get_field(s->fields, v2),
2074 shift, 0, gen_helper_gvec_vsl);
2075 tcg_temp_free_i64(shift);
2079 static DisasJumpType op_vsldb(DisasContext *s, DisasOps *o)
2081 const uint8_t i4 = get_field(s->fields, i4) & 0xf;
2082 const int left_shift = (i4 & 7) * 8;
2083 const int right_shift = 64 - left_shift;
2084 TCGv_i64 t0 = tcg_temp_new_i64();
2085 TCGv_i64 t1 = tcg_temp_new_i64();
2086 TCGv_i64 t2 = tcg_temp_new_i64();
2088 if ((i4 & 8) == 0) {
2089 read_vec_element_i64(t0, get_field(s->fields, v2), 0, ES_64);
2090 read_vec_element_i64(t1, get_field(s->fields, v2), 1, ES_64);
2091 read_vec_element_i64(t2, get_field(s->fields, v3), 0, ES_64);
2093 read_vec_element_i64(t0, get_field(s->fields, v2), 1, ES_64);
2094 read_vec_element_i64(t1, get_field(s->fields, v3), 0, ES_64);
2095 read_vec_element_i64(t2, get_field(s->fields, v3), 1, ES_64);
2097 tcg_gen_extract2_i64(t0, t1, t0, right_shift);
2098 tcg_gen_extract2_i64(t1, t2, t1, right_shift);
2099 write_vec_element_i64(t0, get_field(s->fields, v1), 0, ES_64);
2100 write_vec_element_i64(t1, get_field(s->fields, v1), 1, ES_64);
2108 static DisasJumpType op_vsra(DisasContext *s, DisasOps *o)
2110 TCGv_i64 shift = tcg_temp_new_i64();
2112 read_vec_element_i64(shift, get_field(s->fields, v3), 7, ES_8);
2113 if (s->fields->op2 == 0x7e) {
2114 tcg_gen_andi_i64(shift, shift, 0x7);
2116 tcg_gen_andi_i64(shift, shift, 0x78);
2119 gen_gvec_2i_ool(get_field(s->fields, v1), get_field(s->fields, v2),
2120 shift, 0, gen_helper_gvec_vsra);
2121 tcg_temp_free_i64(shift);
2125 static DisasJumpType op_vsrl(DisasContext *s, DisasOps *o)
2127 TCGv_i64 shift = tcg_temp_new_i64();
2129 read_vec_element_i64(shift, get_field(s->fields, v3), 7, ES_8);
2130 if (s->fields->op2 == 0x7c) {
2131 tcg_gen_andi_i64(shift, shift, 0x7);
2133 tcg_gen_andi_i64(shift, shift, 0x78);
2136 gen_gvec_2i_ool(get_field(s->fields, v1), get_field(s->fields, v2),
2137 shift, 0, gen_helper_gvec_vsrl);
2138 tcg_temp_free_i64(shift);
2142 static DisasJumpType op_vs(DisasContext *s, DisasOps *o)
2144 const uint8_t es = get_field(s->fields, m4);
2147 gen_program_exception(s, PGM_SPECIFICATION);
2148 return DISAS_NORETURN;
2149 } else if (es == ES_128) {
2150 gen_gvec128_3_i64(tcg_gen_sub2_i64, get_field(s->fields, v1),
2151 get_field(s->fields, v2), get_field(s->fields, v3));
2154 gen_gvec_fn_3(sub, es, get_field(s->fields, v1), get_field(s->fields, v2),
2155 get_field(s->fields, v3));
2159 static void gen_scbi_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
2161 tcg_gen_setcond_i32(TCG_COND_LTU, d, a, b);
2164 static void gen_scbi_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
2166 tcg_gen_setcond_i64(TCG_COND_LTU, d, a, b);
2169 static void gen_scbi2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al,
2170 TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh)
2172 TCGv_i64 th = tcg_temp_new_i64();
2173 TCGv_i64 tl = tcg_temp_new_i64();
2174 TCGv_i64 zero = tcg_const_i64(0);
2176 tcg_gen_sub2_i64(tl, th, al, zero, bl, zero);
2177 tcg_gen_andi_i64(th, th, 1);
2178 tcg_gen_sub2_i64(tl, th, ah, zero, th, zero);
2179 tcg_gen_sub2_i64(tl, th, tl, th, bh, zero);
2180 tcg_gen_andi_i64(dl, th, 1);
2181 tcg_gen_mov_i64(dh, zero);
2183 tcg_temp_free_i64(th);
2184 tcg_temp_free_i64(tl);
2185 tcg_temp_free_i64(zero);
2188 static DisasJumpType op_vscbi(DisasContext *s, DisasOps *o)
2190 const uint8_t es = get_field(s->fields, m4);
2191 static const GVecGen3 g[4] = {
2192 { .fno = gen_helper_gvec_vscbi8, },
2193 { .fno = gen_helper_gvec_vscbi16, },
2194 { .fni4 = gen_scbi_i32, },
2195 { .fni8 = gen_scbi_i64, },
2199 gen_program_exception(s, PGM_SPECIFICATION);
2200 return DISAS_NORETURN;
2201 } else if (es == ES_128) {
2202 gen_gvec128_3_i64(gen_scbi2_i64, get_field(s->fields, v1),
2203 get_field(s->fields, v2), get_field(s->fields, v3));
2206 gen_gvec_3(get_field(s->fields, v1), get_field(s->fields, v2),
2207 get_field(s->fields, v3), &g[es]);
2211 static void gen_sbi2_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)
2214 TCGv_i64 tl = tcg_temp_new_i64();
2215 TCGv_i64 zero = tcg_const_i64(0);
2217 tcg_gen_andi_i64(tl, cl, 1);
2218 tcg_gen_sub2_i64(dl, dh, al, ah, bl, bh);
2219 tcg_gen_sub2_i64(dl, dh, dl, dh, tl, zero);
2220 tcg_temp_free_i64(tl);
2221 tcg_temp_free_i64(zero);
2224 static DisasJumpType op_vsbi(DisasContext *s, DisasOps *o)
2226 if (get_field(s->fields, m5) != ES_128) {
2227 gen_program_exception(s, PGM_SPECIFICATION);
2228 return DISAS_NORETURN;
2231 gen_gvec128_4_i64(gen_sbi2_i64, get_field(s->fields, v1),
2232 get_field(s->fields, v2), get_field(s->fields, v3),
2233 get_field(s->fields, v4));
2237 static void gen_sbcbi2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
2238 TCGv_i64 bl, TCGv_i64 bh, TCGv_i64 cl, TCGv_i64 ch)
2240 TCGv_i64 th = tcg_temp_new_i64();
2241 TCGv_i64 tl = tcg_temp_new_i64();
2242 TCGv_i64 zero = tcg_const_i64(0);
2244 tcg_gen_andi_i64(tl, cl, 1);
2245 tcg_gen_sub2_i64(tl, th, al, zero, tl, zero);
2246 tcg_gen_sub2_i64(tl, th, tl, th, bl, zero);
2247 tcg_gen_andi_i64(th, th, 1);
2248 tcg_gen_sub2_i64(tl, th, ah, zero, th, zero);
2249 tcg_gen_sub2_i64(tl, th, tl, th, bh, zero);
2250 tcg_gen_andi_i64(dl, th, 1);
2251 tcg_gen_mov_i64(dh, zero);
2253 tcg_temp_free_i64(tl);
2254 tcg_temp_free_i64(th);
2255 tcg_temp_free_i64(zero);
2258 static DisasJumpType op_vsbcbi(DisasContext *s, DisasOps *o)
2260 if (get_field(s->fields, m5) != ES_128) {
2261 gen_program_exception(s, PGM_SPECIFICATION);
2262 return DISAS_NORETURN;
2265 gen_gvec128_4_i64(gen_sbcbi2_i64, get_field(s->fields, v1),
2266 get_field(s->fields, v2), get_field(s->fields, v3),
2267 get_field(s->fields, v4));
2271 static DisasJumpType op_vsumg(DisasContext *s, DisasOps *o)
2273 const uint8_t es = get_field(s->fields, m4);
2277 if (es == ES_8 || es > ES_32) {
2278 gen_program_exception(s, PGM_SPECIFICATION);
2279 return DISAS_NORETURN;
2282 sum = tcg_temp_new_i64();
2283 tmp = tcg_temp_new_i64();
2284 for (dst_idx = 0; dst_idx < 2; dst_idx++) {
2285 uint8_t idx = dst_idx * NUM_VEC_ELEMENTS(es) / 2;
2286 const uint8_t max_idx = idx + NUM_VEC_ELEMENTS(es) / 2 - 1;
2288 read_vec_element_i64(sum, get_field(s->fields, v3), max_idx, es);
2289 for (; idx <= max_idx; idx++) {
2290 read_vec_element_i64(tmp, get_field(s->fields, v2), idx, es);
2291 tcg_gen_add_i64(sum, sum, tmp);
2293 write_vec_element_i64(sum, get_field(s->fields, v1), dst_idx, ES_64);
2295 tcg_temp_free_i64(sum);
2296 tcg_temp_free_i64(tmp);
2300 static DisasJumpType op_vsumq(DisasContext *s, DisasOps *o)
2302 const uint8_t es = get_field(s->fields, m4);
2303 const uint8_t max_idx = NUM_VEC_ELEMENTS(es) - 1;
2304 TCGv_i64 sumh, suml, zero, tmpl;
2307 if (es < ES_32 || es > ES_64) {
2308 gen_program_exception(s, PGM_SPECIFICATION);
2309 return DISAS_NORETURN;
2312 sumh = tcg_const_i64(0);
2313 suml = tcg_temp_new_i64();
2314 zero = tcg_const_i64(0);
2315 tmpl = tcg_temp_new_i64();
2317 read_vec_element_i64(suml, get_field(s->fields, v3), max_idx, es);
2318 for (idx = 0; idx <= max_idx; idx++) {
2319 read_vec_element_i64(tmpl, get_field(s->fields, v2), idx, es);
2320 tcg_gen_add2_i64(suml, sumh, suml, sumh, tmpl, zero);
2322 write_vec_element_i64(sumh, get_field(s->fields, v1), 0, ES_64);
2323 write_vec_element_i64(suml, get_field(s->fields, v1), 1, ES_64);
2325 tcg_temp_free_i64(sumh);
2326 tcg_temp_free_i64(suml);
2327 tcg_temp_free_i64(zero);
2328 tcg_temp_free_i64(tmpl);
2332 static DisasJumpType op_vsum(DisasContext *s, DisasOps *o)
2334 const uint8_t es = get_field(s->fields, m4);
2339 gen_program_exception(s, PGM_SPECIFICATION);
2340 return DISAS_NORETURN;
2343 sum = tcg_temp_new_i32();
2344 tmp = tcg_temp_new_i32();
2345 for (dst_idx = 0; dst_idx < 4; dst_idx++) {
2346 uint8_t idx = dst_idx * NUM_VEC_ELEMENTS(es) / 4;
2347 const uint8_t max_idx = idx + NUM_VEC_ELEMENTS(es) / 4 - 1;
2349 read_vec_element_i32(sum, get_field(s->fields, v3), max_idx, es);
2350 for (; idx <= max_idx; idx++) {
2351 read_vec_element_i32(tmp, get_field(s->fields, v2), idx, es);
2352 tcg_gen_add_i32(sum, sum, tmp);
2354 write_vec_element_i32(sum, get_field(s->fields, v1), dst_idx, ES_32);
2356 tcg_temp_free_i32(sum);
2357 tcg_temp_free_i32(tmp);
2361 static DisasJumpType op_vtm(DisasContext *s, DisasOps *o)
2363 gen_gvec_2_ptr(get_field(s->fields, v1), get_field(s->fields, v2),
2364 cpu_env, 0, gen_helper_gvec_vtm);
2369 static DisasJumpType op_vfae(DisasContext *s, DisasOps *o)
2371 const uint8_t es = get_field(s->fields, m4);
2372 const uint8_t m5 = get_field(s->fields, m5);
2373 static gen_helper_gvec_3 * const g[3] = {
2374 gen_helper_gvec_vfae8,
2375 gen_helper_gvec_vfae16,
2376 gen_helper_gvec_vfae32,
2378 static gen_helper_gvec_3_ptr * const g_cc[3] = {
2379 gen_helper_gvec_vfae_cc8,
2380 gen_helper_gvec_vfae_cc16,
2381 gen_helper_gvec_vfae_cc32,
2384 gen_program_exception(s, PGM_SPECIFICATION);
2385 return DISAS_NORETURN;
2388 if (extract32(m5, 0, 1)) {
2389 gen_gvec_3_ptr(get_field(s->fields, v1), get_field(s->fields, v2),
2390 get_field(s->fields, v3), cpu_env, m5, g_cc[es]);
2393 gen_gvec_3_ool(get_field(s->fields, v1), get_field(s->fields, v2),
2394 get_field(s->fields, v3), m5, g[es]);
2399 static DisasJumpType op_vfee(DisasContext *s, DisasOps *o)
2401 const uint8_t es = get_field(s->fields, m4);
2402 const uint8_t m5 = get_field(s->fields, m5);
2403 static gen_helper_gvec_3 * const g[3] = {
2404 gen_helper_gvec_vfee8,
2405 gen_helper_gvec_vfee16,
2406 gen_helper_gvec_vfee32,
2408 static gen_helper_gvec_3_ptr * const g_cc[3] = {
2409 gen_helper_gvec_vfee_cc8,
2410 gen_helper_gvec_vfee_cc16,
2411 gen_helper_gvec_vfee_cc32,
2414 if (es > ES_32 || m5 & ~0x3) {
2415 gen_program_exception(s, PGM_SPECIFICATION);
2416 return DISAS_NORETURN;
2419 if (extract32(m5, 0, 1)) {
2420 gen_gvec_3_ptr(get_field(s->fields, v1), get_field(s->fields, v2),
2421 get_field(s->fields, v3), cpu_env, m5, g_cc[es]);
2424 gen_gvec_3_ool(get_field(s->fields, v1), get_field(s->fields, v2),
2425 get_field(s->fields, v3), m5, g[es]);
2430 static DisasJumpType op_vfene(DisasContext *s, DisasOps *o)
2432 const uint8_t es = get_field(s->fields, m4);
2433 const uint8_t m5 = get_field(s->fields, m5);
2434 static gen_helper_gvec_3 * const g[3] = {
2435 gen_helper_gvec_vfene8,
2436 gen_helper_gvec_vfene16,
2437 gen_helper_gvec_vfene32,
2439 static gen_helper_gvec_3_ptr * const g_cc[3] = {
2440 gen_helper_gvec_vfene_cc8,
2441 gen_helper_gvec_vfene_cc16,
2442 gen_helper_gvec_vfene_cc32,
2445 if (es > ES_32 || m5 & ~0x3) {
2446 gen_program_exception(s, PGM_SPECIFICATION);
2447 return DISAS_NORETURN;
2450 if (extract32(m5, 0, 1)) {
2451 gen_gvec_3_ptr(get_field(s->fields, v1), get_field(s->fields, v2),
2452 get_field(s->fields, v3), cpu_env, m5, g_cc[es]);
2455 gen_gvec_3_ool(get_field(s->fields, v1), get_field(s->fields, v2),
2456 get_field(s->fields, v3), m5, g[es]);
2461 static DisasJumpType op_vistr(DisasContext *s, DisasOps *o)
2463 const uint8_t es = get_field(s->fields, m4);
2464 const uint8_t m5 = get_field(s->fields, m5);
2465 static gen_helper_gvec_2 * const g[3] = {
2466 gen_helper_gvec_vistr8,
2467 gen_helper_gvec_vistr16,
2468 gen_helper_gvec_vistr32,
2470 static gen_helper_gvec_2_ptr * const g_cc[3] = {
2471 gen_helper_gvec_vistr_cc8,
2472 gen_helper_gvec_vistr_cc16,
2473 gen_helper_gvec_vistr_cc32,
2476 if (es > ES_32 || m5 & ~0x1) {
2477 gen_program_exception(s, PGM_SPECIFICATION);
2478 return DISAS_NORETURN;
2481 if (extract32(m5, 0, 1)) {
2482 gen_gvec_2_ptr(get_field(s->fields, v1), get_field(s->fields, v2),
2483 cpu_env, 0, g_cc[es]);
2486 gen_gvec_2_ool(get_field(s->fields, v1), get_field(s->fields, v2), 0,
2492 static DisasJumpType op_vstrc(DisasContext *s, DisasOps *o)
2494 const uint8_t es = get_field(s->fields, m5);
2495 const uint8_t m6 = get_field(s->fields, m6);
2496 static gen_helper_gvec_4 * const g[3] = {
2497 gen_helper_gvec_vstrc8,
2498 gen_helper_gvec_vstrc16,
2499 gen_helper_gvec_vstrc32,
2501 static gen_helper_gvec_4 * const g_rt[3] = {
2502 gen_helper_gvec_vstrc_rt8,
2503 gen_helper_gvec_vstrc_rt16,
2504 gen_helper_gvec_vstrc_rt32,
2506 static gen_helper_gvec_4_ptr * const g_cc[3] = {
2507 gen_helper_gvec_vstrc_cc8,
2508 gen_helper_gvec_vstrc_cc16,
2509 gen_helper_gvec_vstrc_cc32,
2511 static gen_helper_gvec_4_ptr * const g_cc_rt[3] = {
2512 gen_helper_gvec_vstrc_cc_rt8,
2513 gen_helper_gvec_vstrc_cc_rt16,
2514 gen_helper_gvec_vstrc_cc_rt32,
2518 gen_program_exception(s, PGM_SPECIFICATION);
2519 return DISAS_NORETURN;
2522 if (extract32(m6, 0, 1)) {
2523 if (extract32(m6, 2, 1)) {
2524 gen_gvec_4_ptr(get_field(s->fields, v1), get_field(s->fields, v2),
2525 get_field(s->fields, v3), get_field(s->fields, v4),
2526 cpu_env, m6, g_cc_rt[es]);
2528 gen_gvec_4_ptr(get_field(s->fields, v1), get_field(s->fields, v2),
2529 get_field(s->fields, v3), get_field(s->fields, v4),
2530 cpu_env, m6, g_cc[es]);
2534 if (extract32(m6, 2, 1)) {
2535 gen_gvec_4_ool(get_field(s->fields, v1), get_field(s->fields, v2),
2536 get_field(s->fields, v3), get_field(s->fields, v4),
2539 gen_gvec_4_ool(get_field(s->fields, v1), get_field(s->fields, v2),
2540 get_field(s->fields, v3), get_field(s->fields, v4),
2547 static DisasJumpType op_vfa(DisasContext *s, DisasOps *o)
2549 const uint8_t fpf = get_field(s->fields, m4);
2550 const uint8_t m5 = get_field(s->fields, m5);
2551 const bool se = extract32(m5, 3, 1);
2552 gen_helper_gvec_3_ptr *fn;
2554 if (fpf != FPF_LONG || extract32(m5, 0, 3)) {
2555 gen_program_exception(s, PGM_SPECIFICATION);
2556 return DISAS_NORETURN;
2559 switch (s->fields->op2) {
2561 fn = se ? gen_helper_gvec_vfa64s : gen_helper_gvec_vfa64;
2564 fn = se ? gen_helper_gvec_vfd64s : gen_helper_gvec_vfd64;
2567 g_assert_not_reached();
2569 gen_gvec_3_ptr(get_field(s->fields, v1), get_field(s->fields, v2),
2570 get_field(s->fields, v3), cpu_env, 0, fn);
2574 static DisasJumpType op_wfc(DisasContext *s, DisasOps *o)
2576 const uint8_t fpf = get_field(s->fields, m3);
2577 const uint8_t m4 = get_field(s->fields, m4);
2579 if (fpf != FPF_LONG || m4) {
2580 gen_program_exception(s, PGM_SPECIFICATION);
2581 return DISAS_NORETURN;
2584 if (s->fields->op2 == 0xcb) {
2585 gen_gvec_2_ptr(get_field(s->fields, v1), get_field(s->fields, v2),
2586 cpu_env, 0, gen_helper_gvec_wfc64);
2588 gen_gvec_2_ptr(get_field(s->fields, v1), get_field(s->fields, v2),
2589 cpu_env, 0, gen_helper_gvec_wfk64);
2595 static DisasJumpType op_vfc(DisasContext *s, DisasOps *o)
2597 const uint8_t fpf = get_field(s->fields, m4);
2598 const uint8_t m5 = get_field(s->fields, m5);
2599 const uint8_t m6 = get_field(s->fields, m6);
2600 const bool se = extract32(m5, 3, 1);
2601 const bool cs = extract32(m6, 0, 1);
2602 gen_helper_gvec_3_ptr *fn;
2604 if (fpf != FPF_LONG || extract32(m5, 0, 3) || extract32(m6, 1, 3)) {
2605 gen_program_exception(s, PGM_SPECIFICATION);
2606 return DISAS_NORETURN;
2610 switch (s->fields->op2) {
2612 fn = se ? gen_helper_gvec_vfce64s_cc : gen_helper_gvec_vfce64_cc;
2615 fn = se ? gen_helper_gvec_vfch64s_cc : gen_helper_gvec_vfch64_cc;
2618 fn = se ? gen_helper_gvec_vfche64s_cc : gen_helper_gvec_vfche64_cc;
2621 g_assert_not_reached();
2624 switch (s->fields->op2) {
2626 fn = se ? gen_helper_gvec_vfce64s : gen_helper_gvec_vfce64;
2629 fn = se ? gen_helper_gvec_vfch64s : gen_helper_gvec_vfch64;
2632 fn = se ? gen_helper_gvec_vfche64s : gen_helper_gvec_vfche64;
2635 g_assert_not_reached();
2638 gen_gvec_3_ptr(get_field(s->fields, v1), get_field(s->fields, v2),
2639 get_field(s->fields, v3), cpu_env, 0, fn);
2646 static DisasJumpType op_vcdg(DisasContext *s, DisasOps *o)
2648 const uint8_t fpf = get_field(s->fields, m3);
2649 const uint8_t m4 = get_field(s->fields, m4);
2650 const uint8_t erm = get_field(s->fields, m5);
2651 const bool se = extract32(m4, 3, 1);
2652 gen_helper_gvec_2_ptr *fn;
2654 if (fpf != FPF_LONG || extract32(m4, 0, 2) || erm > 7 || erm == 2) {
2655 gen_program_exception(s, PGM_SPECIFICATION);
2656 return DISAS_NORETURN;
2659 switch (s->fields->op2) {
2661 fn = se ? gen_helper_gvec_vcdg64s : gen_helper_gvec_vcdg64;
2664 fn = se ? gen_helper_gvec_vcdlg64s : gen_helper_gvec_vcdlg64;
2667 fn = se ? gen_helper_gvec_vcgd64s : gen_helper_gvec_vcgd64;
2670 fn = se ? gen_helper_gvec_vclgd64s : gen_helper_gvec_vclgd64;
2673 fn = se ? gen_helper_gvec_vfi64s : gen_helper_gvec_vfi64;
2676 g_assert_not_reached();
2678 gen_gvec_2_ptr(get_field(s->fields, v1), get_field(s->fields, v2), cpu_env,
2679 deposit32(m4, 4, 4, erm), fn);