s390x/tcg: Implement VECTOR OR WITH COMPLEMENT
[qemu/ar7.git] / target / s390x / translate_vx.inc.c
blob2ab82a2dcc6131ab0e1166b24fab8afd893fe5b5
1 /*
2 * QEMU TCG support -- s390x vector instruction translation functions
4 * Copyright (C) 2019 Red Hat Inc
6 * Authors:
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.
26 * 128 bit elements:
27 * As we only have i32/i64, such elements have to be loaded into two
28 * i64 values and can then be processed e.g. by tcg_gen_add2_i64.
30 * Sizes:
31 * On s390x, the operand size (oprsz) and the maximum size (maxsz) are
32 * always 16 (128 bit). What gvec code calls "vece", s390x calls "es",
33 * a.k.a. "element size". These values nicely map to MO_8 ... MO_64. Only
34 * 128 bit element size has to be treated in a special way (MO_64 + 1).
35 * We will use ES_* instead of MO_* for this reason in this file.
37 * CC handling:
38 * As gvec ool-helpers can currently not return values (besides via
39 * pointers like vectors or cpu_env), whenever we have to set the CC and
40 * can't conclude the value from the result vector, we will directly
41 * set it in "env->cc_op" and mark it as static via set_cc_static()".
42 * Whenever this is done, the helper writes globals (cc_op).
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)
49 #define ES_8 MO_8
50 #define ES_16 MO_16
51 #define ES_32 MO_32
52 #define ES_64 MO_64
53 #define ES_128 4
55 static inline bool valid_vec_element(uint8_t enr, TCGMemOp es)
57 return !(enr & ~(NUM_VEC_ELEMENTS(es) - 1));
60 static void read_vec_element_i64(TCGv_i64 dst, uint8_t reg, uint8_t enr,
61 TCGMemOp memop)
63 const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE);
65 switch (memop) {
66 case ES_8:
67 tcg_gen_ld8u_i64(dst, cpu_env, offs);
68 break;
69 case ES_16:
70 tcg_gen_ld16u_i64(dst, cpu_env, offs);
71 break;
72 case ES_32:
73 tcg_gen_ld32u_i64(dst, cpu_env, offs);
74 break;
75 case ES_8 | MO_SIGN:
76 tcg_gen_ld8s_i64(dst, cpu_env, offs);
77 break;
78 case ES_16 | MO_SIGN:
79 tcg_gen_ld16s_i64(dst, cpu_env, offs);
80 break;
81 case ES_32 | MO_SIGN:
82 tcg_gen_ld32s_i64(dst, cpu_env, offs);
83 break;
84 case ES_64:
85 case ES_64 | MO_SIGN:
86 tcg_gen_ld_i64(dst, cpu_env, offs);
87 break;
88 default:
89 g_assert_not_reached();
93 static void read_vec_element_i32(TCGv_i32 dst, uint8_t reg, uint8_t enr,
94 TCGMemOp memop)
96 const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE);
98 switch (memop) {
99 case ES_8:
100 tcg_gen_ld8u_i32(dst, cpu_env, offs);
101 break;
102 case ES_16:
103 tcg_gen_ld16u_i32(dst, cpu_env, offs);
104 break;
105 case ES_8 | MO_SIGN:
106 tcg_gen_ld8s_i32(dst, cpu_env, offs);
107 break;
108 case ES_16 | MO_SIGN:
109 tcg_gen_ld16s_i32(dst, cpu_env, offs);
110 break;
111 case ES_32:
112 case ES_32 | MO_SIGN:
113 tcg_gen_ld_i32(dst, cpu_env, offs);
114 break;
115 default:
116 g_assert_not_reached();
120 static void write_vec_element_i64(TCGv_i64 src, int reg, uint8_t enr,
121 TCGMemOp memop)
123 const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE);
125 switch (memop) {
126 case ES_8:
127 tcg_gen_st8_i64(src, cpu_env, offs);
128 break;
129 case ES_16:
130 tcg_gen_st16_i64(src, cpu_env, offs);
131 break;
132 case ES_32:
133 tcg_gen_st32_i64(src, cpu_env, offs);
134 break;
135 case ES_64:
136 tcg_gen_st_i64(src, cpu_env, offs);
137 break;
138 default:
139 g_assert_not_reached();
143 static void write_vec_element_i32(TCGv_i32 src, int reg, uint8_t enr,
144 TCGMemOp memop)
146 const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE);
148 switch (memop) {
149 case ES_8:
150 tcg_gen_st8_i32(src, cpu_env, offs);
151 break;
152 case ES_16:
153 tcg_gen_st16_i32(src, cpu_env, offs);
154 break;
155 case ES_32:
156 tcg_gen_st_i32(src, cpu_env, offs);
157 break;
158 default:
159 g_assert_not_reached();
163 static void get_vec_element_ptr_i64(TCGv_ptr ptr, uint8_t reg, TCGv_i64 enr,
164 uint8_t es)
166 TCGv_i64 tmp = tcg_temp_new_i64();
168 /* mask off invalid parts from the element nr */
169 tcg_gen_andi_i64(tmp, enr, NUM_VEC_ELEMENTS(es) - 1);
171 /* convert it to an element offset relative to cpu_env (vec_reg_offset() */
172 tcg_gen_shli_i64(tmp, tmp, es);
173 #ifndef HOST_WORDS_BIGENDIAN
174 tcg_gen_xori_i64(tmp, tmp, 8 - NUM_VEC_ELEMENT_BYTES(es));
175 #endif
176 tcg_gen_addi_i64(tmp, tmp, vec_full_reg_offset(reg));
178 /* generate the final ptr by adding cpu_env */
179 tcg_gen_trunc_i64_ptr(ptr, tmp);
180 tcg_gen_add_ptr(ptr, ptr, cpu_env);
182 tcg_temp_free_i64(tmp);
185 #define gen_gvec_2(v1, v2, gen) \
186 tcg_gen_gvec_2(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
187 16, 16, gen)
188 #define gen_gvec_3(v1, v2, v3, gen) \
189 tcg_gen_gvec_3(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
190 vec_full_reg_offset(v3), 16, 16, gen)
191 #define gen_gvec_3_ool(v1, v2, v3, data, fn) \
192 tcg_gen_gvec_3_ool(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
193 vec_full_reg_offset(v3), 16, 16, data, fn)
194 #define gen_gvec_3_ptr(v1, v2, v3, ptr, data, fn) \
195 tcg_gen_gvec_3_ptr(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
196 vec_full_reg_offset(v3), ptr, 16, 16, data, fn)
197 #define gen_gvec_4(v1, v2, v3, v4, gen) \
198 tcg_gen_gvec_4(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
199 vec_full_reg_offset(v3), vec_full_reg_offset(v4), \
200 16, 16, gen)
201 #define gen_gvec_4_ool(v1, v2, v3, v4, data, fn) \
202 tcg_gen_gvec_4_ool(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
203 vec_full_reg_offset(v3), vec_full_reg_offset(v4), \
204 16, 16, data, fn)
205 #define gen_gvec_dup_i64(es, v1, c) \
206 tcg_gen_gvec_dup_i64(es, vec_full_reg_offset(v1), 16, 16, c)
207 #define gen_gvec_mov(v1, v2) \
208 tcg_gen_gvec_mov(0, vec_full_reg_offset(v1), vec_full_reg_offset(v2), 16, \
210 #define gen_gvec_dup64i(v1, c) \
211 tcg_gen_gvec_dup64i(vec_full_reg_offset(v1), 16, 16, c)
212 #define gen_gvec_fn_2(fn, es, v1, v2) \
213 tcg_gen_gvec_##fn(es, vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
214 16, 16)
215 #define gen_gvec_fn_3(fn, es, v1, v2, v3) \
216 tcg_gen_gvec_##fn(es, vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
217 vec_full_reg_offset(v3), 16, 16)
220 * Helper to carry out a 128 bit vector computation using 2 i64 values per
221 * vector.
223 typedef void (*gen_gvec128_3_i64_fn)(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al,
224 TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh);
225 static void gen_gvec128_3_i64(gen_gvec128_3_i64_fn fn, uint8_t d, uint8_t a,
226 uint8_t b)
228 TCGv_i64 dh = tcg_temp_new_i64();
229 TCGv_i64 dl = tcg_temp_new_i64();
230 TCGv_i64 ah = tcg_temp_new_i64();
231 TCGv_i64 al = tcg_temp_new_i64();
232 TCGv_i64 bh = tcg_temp_new_i64();
233 TCGv_i64 bl = tcg_temp_new_i64();
235 read_vec_element_i64(ah, a, 0, ES_64);
236 read_vec_element_i64(al, a, 1, ES_64);
237 read_vec_element_i64(bh, b, 0, ES_64);
238 read_vec_element_i64(bl, b, 1, ES_64);
239 fn(dl, dh, al, ah, bl, bh);
240 write_vec_element_i64(dh, d, 0, ES_64);
241 write_vec_element_i64(dl, d, 1, ES_64);
243 tcg_temp_free_i64(dh);
244 tcg_temp_free_i64(dl);
245 tcg_temp_free_i64(ah);
246 tcg_temp_free_i64(al);
247 tcg_temp_free_i64(bh);
248 tcg_temp_free_i64(bl);
251 typedef void (*gen_gvec128_4_i64_fn)(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al,
252 TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh,
253 TCGv_i64 cl, TCGv_i64 ch);
254 static void gen_gvec128_4_i64(gen_gvec128_4_i64_fn fn, uint8_t d, uint8_t a,
255 uint8_t b, uint8_t c)
257 TCGv_i64 dh = tcg_temp_new_i64();
258 TCGv_i64 dl = tcg_temp_new_i64();
259 TCGv_i64 ah = tcg_temp_new_i64();
260 TCGv_i64 al = tcg_temp_new_i64();
261 TCGv_i64 bh = tcg_temp_new_i64();
262 TCGv_i64 bl = tcg_temp_new_i64();
263 TCGv_i64 ch = tcg_temp_new_i64();
264 TCGv_i64 cl = tcg_temp_new_i64();
266 read_vec_element_i64(ah, a, 0, ES_64);
267 read_vec_element_i64(al, a, 1, ES_64);
268 read_vec_element_i64(bh, b, 0, ES_64);
269 read_vec_element_i64(bl, b, 1, ES_64);
270 read_vec_element_i64(ch, c, 0, ES_64);
271 read_vec_element_i64(cl, c, 1, ES_64);
272 fn(dl, dh, al, ah, bl, bh, cl, ch);
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);
282 tcg_temp_free_i64(ch);
283 tcg_temp_free_i64(cl);
286 static void gen_gvec_dupi(uint8_t es, uint8_t reg, uint64_t c)
288 switch (es) {
289 case ES_8:
290 tcg_gen_gvec_dup8i(vec_full_reg_offset(reg), 16, 16, c);
291 break;
292 case ES_16:
293 tcg_gen_gvec_dup16i(vec_full_reg_offset(reg), 16, 16, c);
294 break;
295 case ES_32:
296 tcg_gen_gvec_dup32i(vec_full_reg_offset(reg), 16, 16, c);
297 break;
298 case ES_64:
299 gen_gvec_dup64i(reg, c);
300 break;
301 default:
302 g_assert_not_reached();
306 static void zero_vec(uint8_t reg)
308 tcg_gen_gvec_dup8i(vec_full_reg_offset(reg), 16, 16, 0);
311 static void gen_addi2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
312 uint64_t b)
314 TCGv_i64 bl = tcg_const_i64(b);
315 TCGv_i64 bh = tcg_const_i64(0);
317 tcg_gen_add2_i64(dl, dh, al, ah, bl, bh);
318 tcg_temp_free_i64(bl);
319 tcg_temp_free_i64(bh);
322 static DisasJumpType op_vge(DisasContext *s, DisasOps *o)
324 const uint8_t es = s->insn->data;
325 const uint8_t enr = get_field(s->fields, m3);
326 TCGv_i64 tmp;
328 if (!valid_vec_element(enr, es)) {
329 gen_program_exception(s, PGM_SPECIFICATION);
330 return DISAS_NORETURN;
333 tmp = tcg_temp_new_i64();
334 read_vec_element_i64(tmp, get_field(s->fields, v2), enr, es);
335 tcg_gen_add_i64(o->addr1, o->addr1, tmp);
336 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 0);
338 tcg_gen_qemu_ld_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
339 write_vec_element_i64(tmp, get_field(s->fields, v1), enr, es);
340 tcg_temp_free_i64(tmp);
341 return DISAS_NEXT;
344 static uint64_t generate_byte_mask(uint8_t mask)
346 uint64_t r = 0;
347 int i;
349 for (i = 0; i < 8; i++) {
350 if ((mask >> i) & 1) {
351 r |= 0xffull << (i * 8);
354 return r;
357 static DisasJumpType op_vgbm(DisasContext *s, DisasOps *o)
359 const uint16_t i2 = get_field(s->fields, i2);
361 if (i2 == (i2 & 0xff) * 0x0101) {
363 * Masks for both 64 bit elements of the vector are the same.
364 * Trust tcg to produce a good constant loading.
366 gen_gvec_dup64i(get_field(s->fields, v1),
367 generate_byte_mask(i2 & 0xff));
368 } else {
369 TCGv_i64 t = tcg_temp_new_i64();
371 tcg_gen_movi_i64(t, generate_byte_mask(i2 >> 8));
372 write_vec_element_i64(t, get_field(s->fields, v1), 0, ES_64);
373 tcg_gen_movi_i64(t, generate_byte_mask(i2));
374 write_vec_element_i64(t, get_field(s->fields, v1), 1, ES_64);
375 tcg_temp_free_i64(t);
377 return DISAS_NEXT;
380 static DisasJumpType op_vgm(DisasContext *s, DisasOps *o)
382 const uint8_t es = get_field(s->fields, m4);
383 const uint8_t bits = NUM_VEC_ELEMENT_BITS(es);
384 const uint8_t i2 = get_field(s->fields, i2) & (bits - 1);
385 const uint8_t i3 = get_field(s->fields, i3) & (bits - 1);
386 uint64_t mask = 0;
387 int i;
389 if (es > ES_64) {
390 gen_program_exception(s, PGM_SPECIFICATION);
391 return DISAS_NORETURN;
394 /* generate the mask - take care of wrapping */
395 for (i = i2; ; i = (i + 1) % bits) {
396 mask |= 1ull << (bits - i - 1);
397 if (i == i3) {
398 break;
402 gen_gvec_dupi(es, get_field(s->fields, v1), mask);
403 return DISAS_NEXT;
406 static DisasJumpType op_vl(DisasContext *s, DisasOps *o)
408 TCGv_i64 t0 = tcg_temp_new_i64();
409 TCGv_i64 t1 = tcg_temp_new_i64();
411 tcg_gen_qemu_ld_i64(t0, o->addr1, get_mem_index(s), MO_TEQ);
412 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
413 tcg_gen_qemu_ld_i64(t1, o->addr1, get_mem_index(s), MO_TEQ);
414 write_vec_element_i64(t0, get_field(s->fields, v1), 0, ES_64);
415 write_vec_element_i64(t1, get_field(s->fields, v1), 1, ES_64);
416 tcg_temp_free(t0);
417 tcg_temp_free(t1);
418 return DISAS_NEXT;
421 static DisasJumpType op_vlr(DisasContext *s, DisasOps *o)
423 gen_gvec_mov(get_field(s->fields, v1), get_field(s->fields, v2));
424 return DISAS_NEXT;
427 static DisasJumpType op_vlrep(DisasContext *s, DisasOps *o)
429 const uint8_t es = get_field(s->fields, m3);
430 TCGv_i64 tmp;
432 if (es > ES_64) {
433 gen_program_exception(s, PGM_SPECIFICATION);
434 return DISAS_NORETURN;
437 tmp = tcg_temp_new_i64();
438 tcg_gen_qemu_ld_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
439 gen_gvec_dup_i64(es, get_field(s->fields, v1), tmp);
440 tcg_temp_free_i64(tmp);
441 return DISAS_NEXT;
444 static DisasJumpType op_vle(DisasContext *s, DisasOps *o)
446 const uint8_t es = s->insn->data;
447 const uint8_t enr = get_field(s->fields, m3);
448 TCGv_i64 tmp;
450 if (!valid_vec_element(enr, es)) {
451 gen_program_exception(s, PGM_SPECIFICATION);
452 return DISAS_NORETURN;
455 tmp = tcg_temp_new_i64();
456 tcg_gen_qemu_ld_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
457 write_vec_element_i64(tmp, get_field(s->fields, v1), enr, es);
458 tcg_temp_free_i64(tmp);
459 return DISAS_NEXT;
462 static DisasJumpType op_vlei(DisasContext *s, DisasOps *o)
464 const uint8_t es = s->insn->data;
465 const uint8_t enr = get_field(s->fields, m3);
466 TCGv_i64 tmp;
468 if (!valid_vec_element(enr, es)) {
469 gen_program_exception(s, PGM_SPECIFICATION);
470 return DISAS_NORETURN;
473 tmp = tcg_const_i64((int16_t)get_field(s->fields, i2));
474 write_vec_element_i64(tmp, get_field(s->fields, v1), enr, es);
475 tcg_temp_free_i64(tmp);
476 return DISAS_NEXT;
479 static DisasJumpType op_vlgv(DisasContext *s, DisasOps *o)
481 const uint8_t es = get_field(s->fields, m4);
482 TCGv_ptr ptr;
484 if (es > ES_64) {
485 gen_program_exception(s, PGM_SPECIFICATION);
486 return DISAS_NORETURN;
489 /* fast path if we don't need the register content */
490 if (!get_field(s->fields, b2)) {
491 uint8_t enr = get_field(s->fields, d2) & (NUM_VEC_ELEMENTS(es) - 1);
493 read_vec_element_i64(o->out, get_field(s->fields, v3), enr, es);
494 return DISAS_NEXT;
497 ptr = tcg_temp_new_ptr();
498 get_vec_element_ptr_i64(ptr, get_field(s->fields, v3), o->addr1, es);
499 switch (es) {
500 case ES_8:
501 tcg_gen_ld8u_i64(o->out, ptr, 0);
502 break;
503 case ES_16:
504 tcg_gen_ld16u_i64(o->out, ptr, 0);
505 break;
506 case ES_32:
507 tcg_gen_ld32u_i64(o->out, ptr, 0);
508 break;
509 case ES_64:
510 tcg_gen_ld_i64(o->out, ptr, 0);
511 break;
512 default:
513 g_assert_not_reached();
515 tcg_temp_free_ptr(ptr);
517 return DISAS_NEXT;
520 static DisasJumpType op_vllez(DisasContext *s, DisasOps *o)
522 uint8_t es = get_field(s->fields, m3);
523 uint8_t enr;
524 TCGv_i64 t;
526 switch (es) {
527 /* rightmost sub-element of leftmost doubleword */
528 case ES_8:
529 enr = 7;
530 break;
531 case ES_16:
532 enr = 3;
533 break;
534 case ES_32:
535 enr = 1;
536 break;
537 case ES_64:
538 enr = 0;
539 break;
540 /* leftmost sub-element of leftmost doubleword */
541 case 6:
542 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
543 es = ES_32;
544 enr = 0;
545 break;
547 default:
548 /* fallthrough */
549 gen_program_exception(s, PGM_SPECIFICATION);
550 return DISAS_NORETURN;
553 t = tcg_temp_new_i64();
554 tcg_gen_qemu_ld_i64(t, o->addr1, get_mem_index(s), MO_TE | es);
555 zero_vec(get_field(s->fields, v1));
556 write_vec_element_i64(t, get_field(s->fields, v1), enr, es);
557 tcg_temp_free_i64(t);
558 return DISAS_NEXT;
561 static DisasJumpType op_vlm(DisasContext *s, DisasOps *o)
563 const uint8_t v3 = get_field(s->fields, v3);
564 uint8_t v1 = get_field(s->fields, v1);
565 TCGv_i64 t0, t1;
567 if (v3 < v1 || (v3 - v1 + 1) > 16) {
568 gen_program_exception(s, PGM_SPECIFICATION);
569 return DISAS_NORETURN;
573 * Check for possible access exceptions by trying to load the last
574 * element. The first element will be checked first next.
576 t0 = tcg_temp_new_i64();
577 t1 = tcg_temp_new_i64();
578 gen_addi_and_wrap_i64(s, t0, o->addr1, (v3 - v1) * 16 + 8);
579 tcg_gen_qemu_ld_i64(t0, t0, get_mem_index(s), MO_TEQ);
581 for (;; v1++) {
582 tcg_gen_qemu_ld_i64(t1, o->addr1, get_mem_index(s), MO_TEQ);
583 write_vec_element_i64(t1, v1, 0, ES_64);
584 if (v1 == v3) {
585 break;
587 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
588 tcg_gen_qemu_ld_i64(t1, o->addr1, get_mem_index(s), MO_TEQ);
589 write_vec_element_i64(t1, v1, 1, ES_64);
590 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
593 /* Store the last element, loaded first */
594 write_vec_element_i64(t0, v1, 1, ES_64);
596 tcg_temp_free_i64(t0);
597 tcg_temp_free_i64(t1);
598 return DISAS_NEXT;
601 static DisasJumpType op_vlbb(DisasContext *s, DisasOps *o)
603 const int64_t block_size = (1ull << (get_field(s->fields, m3) + 6));
604 const int v1_offs = vec_full_reg_offset(get_field(s->fields, v1));
605 TCGv_ptr a0;
606 TCGv_i64 bytes;
608 if (get_field(s->fields, m3) > 6) {
609 gen_program_exception(s, PGM_SPECIFICATION);
610 return DISAS_NORETURN;
613 bytes = tcg_temp_new_i64();
614 a0 = tcg_temp_new_ptr();
615 /* calculate the number of bytes until the next block boundary */
616 tcg_gen_ori_i64(bytes, o->addr1, -block_size);
617 tcg_gen_neg_i64(bytes, bytes);
619 tcg_gen_addi_ptr(a0, cpu_env, v1_offs);
620 gen_helper_vll(cpu_env, a0, o->addr1, bytes);
621 tcg_temp_free_i64(bytes);
622 tcg_temp_free_ptr(a0);
623 return DISAS_NEXT;
626 static DisasJumpType op_vlvg(DisasContext *s, DisasOps *o)
628 const uint8_t es = get_field(s->fields, m4);
629 TCGv_ptr ptr;
631 if (es > ES_64) {
632 gen_program_exception(s, PGM_SPECIFICATION);
633 return DISAS_NORETURN;
636 /* fast path if we don't need the register content */
637 if (!get_field(s->fields, b2)) {
638 uint8_t enr = get_field(s->fields, d2) & (NUM_VEC_ELEMENTS(es) - 1);
640 write_vec_element_i64(o->in2, get_field(s->fields, v1), enr, es);
641 return DISAS_NEXT;
644 ptr = tcg_temp_new_ptr();
645 get_vec_element_ptr_i64(ptr, get_field(s->fields, v1), o->addr1, es);
646 switch (es) {
647 case ES_8:
648 tcg_gen_st8_i64(o->in2, ptr, 0);
649 break;
650 case ES_16:
651 tcg_gen_st16_i64(o->in2, ptr, 0);
652 break;
653 case ES_32:
654 tcg_gen_st32_i64(o->in2, ptr, 0);
655 break;
656 case ES_64:
657 tcg_gen_st_i64(o->in2, ptr, 0);
658 break;
659 default:
660 g_assert_not_reached();
662 tcg_temp_free_ptr(ptr);
664 return DISAS_NEXT;
667 static DisasJumpType op_vlvgp(DisasContext *s, DisasOps *o)
669 write_vec_element_i64(o->in1, get_field(s->fields, v1), 0, ES_64);
670 write_vec_element_i64(o->in2, get_field(s->fields, v1), 1, ES_64);
671 return DISAS_NEXT;
674 static DisasJumpType op_vll(DisasContext *s, DisasOps *o)
676 const int v1_offs = vec_full_reg_offset(get_field(s->fields, v1));
677 TCGv_ptr a0 = tcg_temp_new_ptr();
679 /* convert highest index into an actual length */
680 tcg_gen_addi_i64(o->in2, o->in2, 1);
681 tcg_gen_addi_ptr(a0, cpu_env, v1_offs);
682 gen_helper_vll(cpu_env, a0, o->addr1, o->in2);
683 tcg_temp_free_ptr(a0);
684 return DISAS_NEXT;
687 static DisasJumpType op_vmr(DisasContext *s, DisasOps *o)
689 const uint8_t v1 = get_field(s->fields, v1);
690 const uint8_t v2 = get_field(s->fields, v2);
691 const uint8_t v3 = get_field(s->fields, v3);
692 const uint8_t es = get_field(s->fields, m4);
693 int dst_idx, src_idx;
694 TCGv_i64 tmp;
696 if (es > ES_64) {
697 gen_program_exception(s, PGM_SPECIFICATION);
698 return DISAS_NORETURN;
701 tmp = tcg_temp_new_i64();
702 if (s->fields->op2 == 0x61) {
703 /* iterate backwards to avoid overwriting data we might need later */
704 for (dst_idx = NUM_VEC_ELEMENTS(es) - 1; dst_idx >= 0; dst_idx--) {
705 src_idx = dst_idx / 2;
706 if (dst_idx % 2 == 0) {
707 read_vec_element_i64(tmp, v2, src_idx, es);
708 } else {
709 read_vec_element_i64(tmp, v3, src_idx, es);
711 write_vec_element_i64(tmp, v1, dst_idx, es);
713 } else {
714 /* iterate forward to avoid overwriting data we might need later */
715 for (dst_idx = 0; dst_idx < NUM_VEC_ELEMENTS(es); dst_idx++) {
716 src_idx = (dst_idx + NUM_VEC_ELEMENTS(es)) / 2;
717 if (dst_idx % 2 == 0) {
718 read_vec_element_i64(tmp, v2, src_idx, es);
719 } else {
720 read_vec_element_i64(tmp, v3, src_idx, es);
722 write_vec_element_i64(tmp, v1, dst_idx, es);
725 tcg_temp_free_i64(tmp);
726 return DISAS_NEXT;
729 static DisasJumpType op_vpk(DisasContext *s, DisasOps *o)
731 const uint8_t v1 = get_field(s->fields, v1);
732 const uint8_t v2 = get_field(s->fields, v2);
733 const uint8_t v3 = get_field(s->fields, v3);
734 const uint8_t es = get_field(s->fields, m4);
735 static gen_helper_gvec_3 * const vpk[3] = {
736 gen_helper_gvec_vpk16,
737 gen_helper_gvec_vpk32,
738 gen_helper_gvec_vpk64,
740 static gen_helper_gvec_3 * const vpks[3] = {
741 gen_helper_gvec_vpks16,
742 gen_helper_gvec_vpks32,
743 gen_helper_gvec_vpks64,
745 static gen_helper_gvec_3_ptr * const vpks_cc[3] = {
746 gen_helper_gvec_vpks_cc16,
747 gen_helper_gvec_vpks_cc32,
748 gen_helper_gvec_vpks_cc64,
750 static gen_helper_gvec_3 * const vpkls[3] = {
751 gen_helper_gvec_vpkls16,
752 gen_helper_gvec_vpkls32,
753 gen_helper_gvec_vpkls64,
755 static gen_helper_gvec_3_ptr * const vpkls_cc[3] = {
756 gen_helper_gvec_vpkls_cc16,
757 gen_helper_gvec_vpkls_cc32,
758 gen_helper_gvec_vpkls_cc64,
761 if (es == ES_8 || es > ES_64) {
762 gen_program_exception(s, PGM_SPECIFICATION);
763 return DISAS_NORETURN;
766 switch (s->fields->op2) {
767 case 0x97:
768 if (get_field(s->fields, m5) & 0x1) {
769 gen_gvec_3_ptr(v1, v2, v3, cpu_env, 0, vpks_cc[es - 1]);
770 set_cc_static(s);
771 } else {
772 gen_gvec_3_ool(v1, v2, v3, 0, vpks[es - 1]);
774 break;
775 case 0x95:
776 if (get_field(s->fields, m5) & 0x1) {
777 gen_gvec_3_ptr(v1, v2, v3, cpu_env, 0, vpkls_cc[es - 1]);
778 set_cc_static(s);
779 } else {
780 gen_gvec_3_ool(v1, v2, v3, 0, vpkls[es - 1]);
782 break;
783 case 0x94:
784 /* If sources and destination dont't overlap -> fast path */
785 if (v1 != v2 && v1 != v3) {
786 const uint8_t src_es = get_field(s->fields, m4);
787 const uint8_t dst_es = src_es - 1;
788 TCGv_i64 tmp = tcg_temp_new_i64();
789 int dst_idx, src_idx;
791 for (dst_idx = 0; dst_idx < NUM_VEC_ELEMENTS(dst_es); dst_idx++) {
792 src_idx = dst_idx;
793 if (src_idx < NUM_VEC_ELEMENTS(src_es)) {
794 read_vec_element_i64(tmp, v2, src_idx, src_es);
795 } else {
796 src_idx -= NUM_VEC_ELEMENTS(src_es);
797 read_vec_element_i64(tmp, v3, src_idx, src_es);
799 write_vec_element_i64(tmp, v1, dst_idx, dst_es);
801 tcg_temp_free_i64(tmp);
802 } else {
803 gen_gvec_3_ool(v1, v2, v3, 0, vpk[es - 1]);
805 break;
806 default:
807 g_assert_not_reached();
809 return DISAS_NEXT;
812 static DisasJumpType op_vperm(DisasContext *s, DisasOps *o)
814 gen_gvec_4_ool(get_field(s->fields, v1), get_field(s->fields, v2),
815 get_field(s->fields, v3), get_field(s->fields, v4),
816 0, gen_helper_gvec_vperm);
817 return DISAS_NEXT;
820 static DisasJumpType op_vpdi(DisasContext *s, DisasOps *o)
822 const uint8_t i2 = extract32(get_field(s->fields, m4), 2, 1);
823 const uint8_t i3 = extract32(get_field(s->fields, m4), 0, 1);
824 TCGv_i64 t0 = tcg_temp_new_i64();
825 TCGv_i64 t1 = tcg_temp_new_i64();
827 read_vec_element_i64(t0, get_field(s->fields, v2), i2, ES_64);
828 read_vec_element_i64(t1, get_field(s->fields, v3), i3, ES_64);
829 write_vec_element_i64(t0, get_field(s->fields, v1), 0, ES_64);
830 write_vec_element_i64(t1, get_field(s->fields, v1), 1, ES_64);
831 tcg_temp_free_i64(t0);
832 tcg_temp_free_i64(t1);
833 return DISAS_NEXT;
836 static DisasJumpType op_vrep(DisasContext *s, DisasOps *o)
838 const uint8_t enr = get_field(s->fields, i2);
839 const uint8_t es = get_field(s->fields, m4);
841 if (es > ES_64 || !valid_vec_element(enr, es)) {
842 gen_program_exception(s, PGM_SPECIFICATION);
843 return DISAS_NORETURN;
846 tcg_gen_gvec_dup_mem(es, vec_full_reg_offset(get_field(s->fields, v1)),
847 vec_reg_offset(get_field(s->fields, v3), enr, es),
848 16, 16);
849 return DISAS_NEXT;
852 static DisasJumpType op_vrepi(DisasContext *s, DisasOps *o)
854 const int64_t data = (int16_t)get_field(s->fields, i2);
855 const uint8_t es = get_field(s->fields, m3);
857 if (es > ES_64) {
858 gen_program_exception(s, PGM_SPECIFICATION);
859 return DISAS_NORETURN;
862 gen_gvec_dupi(es, get_field(s->fields, v1), data);
863 return DISAS_NEXT;
866 static DisasJumpType op_vsce(DisasContext *s, DisasOps *o)
868 const uint8_t es = s->insn->data;
869 const uint8_t enr = get_field(s->fields, m3);
870 TCGv_i64 tmp;
872 if (!valid_vec_element(enr, es)) {
873 gen_program_exception(s, PGM_SPECIFICATION);
874 return DISAS_NORETURN;
877 tmp = tcg_temp_new_i64();
878 read_vec_element_i64(tmp, get_field(s->fields, v2), enr, es);
879 tcg_gen_add_i64(o->addr1, o->addr1, tmp);
880 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 0);
882 read_vec_element_i64(tmp, get_field(s->fields, v1), enr, es);
883 tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
884 tcg_temp_free_i64(tmp);
885 return DISAS_NEXT;
888 static void gen_sel_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b, TCGv_i64 c)
890 TCGv_i64 t = tcg_temp_new_i64();
892 /* bit in c not set -> copy bit from b */
893 tcg_gen_andc_i64(t, b, c);
894 /* bit in c set -> copy bit from a */
895 tcg_gen_and_i64(d, a, c);
896 /* merge the results */
897 tcg_gen_or_i64(d, d, t);
898 tcg_temp_free_i64(t);
901 static void gen_sel_vec(unsigned vece, TCGv_vec d, TCGv_vec a, TCGv_vec b,
902 TCGv_vec c)
904 TCGv_vec t = tcg_temp_new_vec_matching(d);
906 tcg_gen_andc_vec(vece, t, b, c);
907 tcg_gen_and_vec(vece, d, a, c);
908 tcg_gen_or_vec(vece, d, d, t);
909 tcg_temp_free_vec(t);
912 static DisasJumpType op_vsel(DisasContext *s, DisasOps *o)
914 static const GVecGen4 gvec_op = {
915 .fni8 = gen_sel_i64,
916 .fniv = gen_sel_vec,
917 .prefer_i64 = TCG_TARGET_REG_BITS == 64,
920 gen_gvec_4(get_field(s->fields, v1), get_field(s->fields, v2),
921 get_field(s->fields, v3), get_field(s->fields, v4), &gvec_op);
922 return DISAS_NEXT;
925 static DisasJumpType op_vseg(DisasContext *s, DisasOps *o)
927 const uint8_t es = get_field(s->fields, m3);
928 int idx1, idx2;
929 TCGv_i64 tmp;
931 switch (es) {
932 case ES_8:
933 idx1 = 7;
934 idx2 = 15;
935 break;
936 case ES_16:
937 idx1 = 3;
938 idx2 = 7;
939 break;
940 case ES_32:
941 idx1 = 1;
942 idx2 = 3;
943 break;
944 default:
945 gen_program_exception(s, PGM_SPECIFICATION);
946 return DISAS_NORETURN;
949 tmp = tcg_temp_new_i64();
950 read_vec_element_i64(tmp, get_field(s->fields, v2), idx1, es | MO_SIGN);
951 write_vec_element_i64(tmp, get_field(s->fields, v1), 0, ES_64);
952 read_vec_element_i64(tmp, get_field(s->fields, v2), idx2, es | MO_SIGN);
953 write_vec_element_i64(tmp, get_field(s->fields, v1), 1, ES_64);
954 tcg_temp_free_i64(tmp);
955 return DISAS_NEXT;
958 static DisasJumpType op_vst(DisasContext *s, DisasOps *o)
960 TCGv_i64 tmp = tcg_const_i64(16);
962 /* Probe write access before actually modifying memory */
963 gen_helper_probe_write_access(cpu_env, o->addr1, tmp);
965 read_vec_element_i64(tmp, get_field(s->fields, v1), 0, ES_64);
966 tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEQ);
967 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
968 read_vec_element_i64(tmp, get_field(s->fields, v1), 1, ES_64);
969 tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEQ);
970 tcg_temp_free_i64(tmp);
971 return DISAS_NEXT;
974 static DisasJumpType op_vste(DisasContext *s, DisasOps *o)
976 const uint8_t es = s->insn->data;
977 const uint8_t enr = get_field(s->fields, m3);
978 TCGv_i64 tmp;
980 if (!valid_vec_element(enr, es)) {
981 gen_program_exception(s, PGM_SPECIFICATION);
982 return DISAS_NORETURN;
985 tmp = tcg_temp_new_i64();
986 read_vec_element_i64(tmp, get_field(s->fields, v1), enr, es);
987 tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
988 tcg_temp_free_i64(tmp);
989 return DISAS_NEXT;
992 static DisasJumpType op_vstm(DisasContext *s, DisasOps *o)
994 const uint8_t v3 = get_field(s->fields, v3);
995 uint8_t v1 = get_field(s->fields, v1);
996 TCGv_i64 tmp;
998 while (v3 < v1 || (v3 - v1 + 1) > 16) {
999 gen_program_exception(s, PGM_SPECIFICATION);
1000 return DISAS_NORETURN;
1003 /* Probe write access before actually modifying memory */
1004 tmp = tcg_const_i64((v3 - v1 + 1) * 16);
1005 gen_helper_probe_write_access(cpu_env, o->addr1, tmp);
1007 for (;; v1++) {
1008 read_vec_element_i64(tmp, v1, 0, ES_64);
1009 tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEQ);
1010 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
1011 read_vec_element_i64(tmp, v1, 1, ES_64);
1012 tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEQ);
1013 if (v1 == v3) {
1014 break;
1016 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
1018 tcg_temp_free_i64(tmp);
1019 return DISAS_NEXT;
1022 static DisasJumpType op_vstl(DisasContext *s, DisasOps *o)
1024 const int v1_offs = vec_full_reg_offset(get_field(s->fields, v1));
1025 TCGv_ptr a0 = tcg_temp_new_ptr();
1027 /* convert highest index into an actual length */
1028 tcg_gen_addi_i64(o->in2, o->in2, 1);
1029 tcg_gen_addi_ptr(a0, cpu_env, v1_offs);
1030 gen_helper_vstl(cpu_env, a0, o->addr1, o->in2);
1031 tcg_temp_free_ptr(a0);
1032 return DISAS_NEXT;
1035 static DisasJumpType op_vup(DisasContext *s, DisasOps *o)
1037 const bool logical = s->fields->op2 == 0xd4 || s->fields->op2 == 0xd5;
1038 const uint8_t v1 = get_field(s->fields, v1);
1039 const uint8_t v2 = get_field(s->fields, v2);
1040 const uint8_t src_es = get_field(s->fields, m3);
1041 const uint8_t dst_es = src_es + 1;
1042 int dst_idx, src_idx;
1043 TCGv_i64 tmp;
1045 if (src_es > ES_32) {
1046 gen_program_exception(s, PGM_SPECIFICATION);
1047 return DISAS_NORETURN;
1050 tmp = tcg_temp_new_i64();
1051 if (s->fields->op2 == 0xd7 || s->fields->op2 == 0xd5) {
1052 /* iterate backwards to avoid overwriting data we might need later */
1053 for (dst_idx = NUM_VEC_ELEMENTS(dst_es) - 1; dst_idx >= 0; dst_idx--) {
1054 src_idx = dst_idx;
1055 read_vec_element_i64(tmp, v2, src_idx,
1056 src_es | (logical ? 0 : MO_SIGN));
1057 write_vec_element_i64(tmp, v1, dst_idx, dst_es);
1060 } else {
1061 /* iterate forward to avoid overwriting data we might need later */
1062 for (dst_idx = 0; dst_idx < NUM_VEC_ELEMENTS(dst_es); dst_idx++) {
1063 src_idx = dst_idx + NUM_VEC_ELEMENTS(src_es) / 2;
1064 read_vec_element_i64(tmp, v2, src_idx,
1065 src_es | (logical ? 0 : MO_SIGN));
1066 write_vec_element_i64(tmp, v1, dst_idx, dst_es);
1069 tcg_temp_free_i64(tmp);
1070 return DISAS_NEXT;
1073 static DisasJumpType op_va(DisasContext *s, DisasOps *o)
1075 const uint8_t es = get_field(s->fields, m4);
1077 if (es > ES_128) {
1078 gen_program_exception(s, PGM_SPECIFICATION);
1079 return DISAS_NORETURN;
1080 } else if (es == ES_128) {
1081 gen_gvec128_3_i64(tcg_gen_add2_i64, get_field(s->fields, v1),
1082 get_field(s->fields, v2), get_field(s->fields, v3));
1083 return DISAS_NEXT;
1085 gen_gvec_fn_3(add, es, get_field(s->fields, v1), get_field(s->fields, v2),
1086 get_field(s->fields, v3));
1087 return DISAS_NEXT;
1090 static void gen_acc(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b, uint8_t es)
1092 const uint8_t msb_bit_nr = NUM_VEC_ELEMENT_BITS(es) - 1;
1093 TCGv_i64 msb_mask = tcg_const_i64(dup_const(es, 1ull << msb_bit_nr));
1094 TCGv_i64 t1 = tcg_temp_new_i64();
1095 TCGv_i64 t2 = tcg_temp_new_i64();
1096 TCGv_i64 t3 = tcg_temp_new_i64();
1098 /* Calculate the carry into the MSB, ignoring the old MSBs */
1099 tcg_gen_andc_i64(t1, a, msb_mask);
1100 tcg_gen_andc_i64(t2, b, msb_mask);
1101 tcg_gen_add_i64(t1, t1, t2);
1102 /* Calculate the MSB without any carry into it */
1103 tcg_gen_xor_i64(t3, a, b);
1104 /* Calculate the carry out of the MSB in the MSB bit position */
1105 tcg_gen_and_i64(d, a, b);
1106 tcg_gen_and_i64(t1, t1, t3);
1107 tcg_gen_or_i64(d, d, t1);
1108 /* Isolate and shift the carry into position */
1109 tcg_gen_and_i64(d, d, msb_mask);
1110 tcg_gen_shri_i64(d, d, msb_bit_nr);
1112 tcg_temp_free_i64(t1);
1113 tcg_temp_free_i64(t2);
1114 tcg_temp_free_i64(t3);
1117 static void gen_acc8_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
1119 gen_acc(d, a, b, ES_8);
1122 static void gen_acc16_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
1124 gen_acc(d, a, b, ES_16);
1127 static void gen_acc_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
1129 TCGv_i32 t = tcg_temp_new_i32();
1131 tcg_gen_add_i32(t, a, b);
1132 tcg_gen_setcond_i32(TCG_COND_LTU, d, t, b);
1133 tcg_temp_free_i32(t);
1136 static void gen_acc_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
1138 TCGv_i64 t = tcg_temp_new_i64();
1140 tcg_gen_add_i64(t, a, b);
1141 tcg_gen_setcond_i64(TCG_COND_LTU, d, t, b);
1142 tcg_temp_free_i64(t);
1145 static void gen_acc2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al,
1146 TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh)
1148 TCGv_i64 th = tcg_temp_new_i64();
1149 TCGv_i64 tl = tcg_temp_new_i64();
1150 TCGv_i64 zero = tcg_const_i64(0);
1152 tcg_gen_add2_i64(tl, th, al, zero, bl, zero);
1153 tcg_gen_add2_i64(tl, th, th, zero, ah, zero);
1154 tcg_gen_add2_i64(tl, dl, tl, th, bh, zero);
1155 tcg_gen_mov_i64(dh, zero);
1157 tcg_temp_free_i64(th);
1158 tcg_temp_free_i64(tl);
1159 tcg_temp_free_i64(zero);
1162 static DisasJumpType op_vacc(DisasContext *s, DisasOps *o)
1164 const uint8_t es = get_field(s->fields, m4);
1165 static const GVecGen3 g[4] = {
1166 { .fni8 = gen_acc8_i64, },
1167 { .fni8 = gen_acc16_i64, },
1168 { .fni4 = gen_acc_i32, },
1169 { .fni8 = gen_acc_i64, },
1172 if (es > ES_128) {
1173 gen_program_exception(s, PGM_SPECIFICATION);
1174 return DISAS_NORETURN;
1175 } else if (es == ES_128) {
1176 gen_gvec128_3_i64(gen_acc2_i64, get_field(s->fields, v1),
1177 get_field(s->fields, v2), get_field(s->fields, v3));
1178 return DISAS_NEXT;
1180 gen_gvec_3(get_field(s->fields, v1), get_field(s->fields, v2),
1181 get_field(s->fields, v3), &g[es]);
1182 return DISAS_NEXT;
1185 static void gen_ac2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
1186 TCGv_i64 bl, TCGv_i64 bh, TCGv_i64 cl, TCGv_i64 ch)
1188 TCGv_i64 tl = tcg_temp_new_i64();
1189 TCGv_i64 th = tcg_const_i64(0);
1191 /* extract the carry only */
1192 tcg_gen_extract_i64(tl, cl, 0, 1);
1193 tcg_gen_add2_i64(dl, dh, al, ah, bl, bh);
1194 tcg_gen_add2_i64(dl, dh, dl, dh, tl, th);
1196 tcg_temp_free_i64(tl);
1197 tcg_temp_free_i64(th);
1200 static DisasJumpType op_vac(DisasContext *s, DisasOps *o)
1202 if (get_field(s->fields, m5) != ES_128) {
1203 gen_program_exception(s, PGM_SPECIFICATION);
1204 return DISAS_NORETURN;
1207 gen_gvec128_4_i64(gen_ac2_i64, get_field(s->fields, v1),
1208 get_field(s->fields, v2), get_field(s->fields, v3),
1209 get_field(s->fields, v4));
1210 return DISAS_NEXT;
1213 static void gen_accc2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
1214 TCGv_i64 bl, TCGv_i64 bh, TCGv_i64 cl, TCGv_i64 ch)
1216 TCGv_i64 tl = tcg_temp_new_i64();
1217 TCGv_i64 th = tcg_temp_new_i64();
1218 TCGv_i64 zero = tcg_const_i64(0);
1220 tcg_gen_andi_i64(tl, cl, 1);
1221 tcg_gen_add2_i64(tl, th, tl, zero, al, zero);
1222 tcg_gen_add2_i64(tl, th, tl, th, bl, zero);
1223 tcg_gen_add2_i64(tl, th, th, zero, ah, zero);
1224 tcg_gen_add2_i64(tl, dl, tl, th, bh, zero);
1225 tcg_gen_mov_i64(dh, zero);
1227 tcg_temp_free_i64(tl);
1228 tcg_temp_free_i64(th);
1229 tcg_temp_free_i64(zero);
1232 static DisasJumpType op_vaccc(DisasContext *s, DisasOps *o)
1234 if (get_field(s->fields, m5) != ES_128) {
1235 gen_program_exception(s, PGM_SPECIFICATION);
1236 return DISAS_NORETURN;
1239 gen_gvec128_4_i64(gen_accc2_i64, get_field(s->fields, v1),
1240 get_field(s->fields, v2), get_field(s->fields, v3),
1241 get_field(s->fields, v4));
1242 return DISAS_NEXT;
1245 static DisasJumpType op_vn(DisasContext *s, DisasOps *o)
1247 gen_gvec_fn_3(and, ES_8, get_field(s->fields, v1), get_field(s->fields, v2),
1248 get_field(s->fields, v3));
1249 return DISAS_NEXT;
1252 static DisasJumpType op_vnc(DisasContext *s, DisasOps *o)
1254 gen_gvec_fn_3(andc, ES_8, get_field(s->fields, v1),
1255 get_field(s->fields, v2), get_field(s->fields, v3));
1256 return DISAS_NEXT;
1259 static void gen_avg_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
1261 TCGv_i64 t0 = tcg_temp_new_i64();
1262 TCGv_i64 t1 = tcg_temp_new_i64();
1264 tcg_gen_ext_i32_i64(t0, a);
1265 tcg_gen_ext_i32_i64(t1, b);
1266 tcg_gen_add_i64(t0, t0, t1);
1267 tcg_gen_addi_i64(t0, t0, 1);
1268 tcg_gen_shri_i64(t0, t0, 1);
1269 tcg_gen_extrl_i64_i32(d, t0);
1271 tcg_temp_free(t0);
1272 tcg_temp_free(t1);
1275 static void gen_avg_i64(TCGv_i64 dl, TCGv_i64 al, TCGv_i64 bl)
1277 TCGv_i64 dh = tcg_temp_new_i64();
1278 TCGv_i64 ah = tcg_temp_new_i64();
1279 TCGv_i64 bh = tcg_temp_new_i64();
1281 /* extending the sign by one bit is sufficient */
1282 tcg_gen_extract_i64(ah, al, 63, 1);
1283 tcg_gen_extract_i64(bh, bl, 63, 1);
1284 tcg_gen_add2_i64(dl, dh, al, ah, bl, bh);
1285 gen_addi2_i64(dl, dh, dl, dh, 1);
1286 tcg_gen_extract2_i64(dl, dl, dh, 1);
1288 tcg_temp_free_i64(dh);
1289 tcg_temp_free_i64(ah);
1290 tcg_temp_free_i64(bh);
1293 static DisasJumpType op_vavg(DisasContext *s, DisasOps *o)
1295 const uint8_t es = get_field(s->fields, m4);
1296 static const GVecGen3 g[4] = {
1297 { .fno = gen_helper_gvec_vavg8, },
1298 { .fno = gen_helper_gvec_vavg16, },
1299 { .fni4 = gen_avg_i32, },
1300 { .fni8 = gen_avg_i64, },
1303 if (es > ES_64) {
1304 gen_program_exception(s, PGM_SPECIFICATION);
1305 return DISAS_NORETURN;
1307 gen_gvec_3(get_field(s->fields, v1), get_field(s->fields, v2),
1308 get_field(s->fields, v3), &g[es]);
1309 return DISAS_NEXT;
1312 static void gen_avgl_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
1314 TCGv_i64 t0 = tcg_temp_new_i64();
1315 TCGv_i64 t1 = tcg_temp_new_i64();
1317 tcg_gen_extu_i32_i64(t0, a);
1318 tcg_gen_extu_i32_i64(t1, b);
1319 tcg_gen_add_i64(t0, t0, t1);
1320 tcg_gen_addi_i64(t0, t0, 1);
1321 tcg_gen_shri_i64(t0, t0, 1);
1322 tcg_gen_extrl_i64_i32(d, t0);
1324 tcg_temp_free(t0);
1325 tcg_temp_free(t1);
1328 static void gen_avgl_i64(TCGv_i64 dl, TCGv_i64 al, TCGv_i64 bl)
1330 TCGv_i64 dh = tcg_temp_new_i64();
1331 TCGv_i64 zero = tcg_const_i64(0);
1333 tcg_gen_add2_i64(dl, dh, al, zero, bl, zero);
1334 gen_addi2_i64(dl, dh, dl, dh, 1);
1335 tcg_gen_extract2_i64(dl, dl, dh, 1);
1337 tcg_temp_free_i64(dh);
1338 tcg_temp_free_i64(zero);
1341 static DisasJumpType op_vavgl(DisasContext *s, DisasOps *o)
1343 const uint8_t es = get_field(s->fields, m4);
1344 static const GVecGen3 g[4] = {
1345 { .fno = gen_helper_gvec_vavgl8, },
1346 { .fno = gen_helper_gvec_vavgl16, },
1347 { .fni4 = gen_avgl_i32, },
1348 { .fni8 = gen_avgl_i64, },
1351 if (es > ES_64) {
1352 gen_program_exception(s, PGM_SPECIFICATION);
1353 return DISAS_NORETURN;
1355 gen_gvec_3(get_field(s->fields, v1), get_field(s->fields, v2),
1356 get_field(s->fields, v3), &g[es]);
1357 return DISAS_NEXT;
1360 static DisasJumpType op_vcksm(DisasContext *s, DisasOps *o)
1362 TCGv_i32 tmp = tcg_temp_new_i32();
1363 TCGv_i32 sum = tcg_temp_new_i32();
1364 int i;
1366 read_vec_element_i32(sum, get_field(s->fields, v3), 1, ES_32);
1367 for (i = 0; i < 4; i++) {
1368 read_vec_element_i32(tmp, get_field(s->fields, v2), i, ES_32);
1369 tcg_gen_add2_i32(tmp, sum, sum, sum, tmp, tmp);
1371 zero_vec(get_field(s->fields, v1));
1372 write_vec_element_i32(sum, get_field(s->fields, v1), 1, ES_32);
1374 tcg_temp_free_i32(tmp);
1375 tcg_temp_free_i32(sum);
1376 return DISAS_NEXT;
1379 static DisasJumpType op_vec(DisasContext *s, DisasOps *o)
1381 uint8_t es = get_field(s->fields, m3);
1382 const uint8_t enr = NUM_VEC_ELEMENTS(es) / 2 - 1;
1384 if (es > ES_64) {
1385 gen_program_exception(s, PGM_SPECIFICATION);
1386 return DISAS_NORETURN;
1388 if (s->fields->op2 == 0xdb) {
1389 es |= MO_SIGN;
1392 o->in1 = tcg_temp_new_i64();
1393 o->in2 = tcg_temp_new_i64();
1394 read_vec_element_i64(o->in1, get_field(s->fields, v1), enr, es);
1395 read_vec_element_i64(o->in2, get_field(s->fields, v2), enr, es);
1396 return DISAS_NEXT;
1399 static DisasJumpType op_vc(DisasContext *s, DisasOps *o)
1401 const uint8_t es = get_field(s->fields, m4);
1402 TCGCond cond = s->insn->data;
1404 if (es > ES_64) {
1405 gen_program_exception(s, PGM_SPECIFICATION);
1406 return DISAS_NORETURN;
1409 tcg_gen_gvec_cmp(cond, es,
1410 vec_full_reg_offset(get_field(s->fields, v1)),
1411 vec_full_reg_offset(get_field(s->fields, v2)),
1412 vec_full_reg_offset(get_field(s->fields, v3)), 16, 16);
1413 if (get_field(s->fields, m5) & 0x1) {
1414 TCGv_i64 low = tcg_temp_new_i64();
1415 TCGv_i64 high = tcg_temp_new_i64();
1417 read_vec_element_i64(high, get_field(s->fields, v1), 0, ES_64);
1418 read_vec_element_i64(low, get_field(s->fields, v1), 1, ES_64);
1419 gen_op_update2_cc_i64(s, CC_OP_VC, low, high);
1421 tcg_temp_free_i64(low);
1422 tcg_temp_free_i64(high);
1424 return DISAS_NEXT;
1427 static void gen_clz_i32(TCGv_i32 d, TCGv_i32 a)
1429 tcg_gen_clzi_i32(d, a, 32);
1432 static void gen_clz_i64(TCGv_i64 d, TCGv_i64 a)
1434 tcg_gen_clzi_i64(d, a, 64);
1437 static DisasJumpType op_vclz(DisasContext *s, DisasOps *o)
1439 const uint8_t es = get_field(s->fields, m3);
1440 static const GVecGen2 g[4] = {
1441 { .fno = gen_helper_gvec_vclz8, },
1442 { .fno = gen_helper_gvec_vclz16, },
1443 { .fni4 = gen_clz_i32, },
1444 { .fni8 = gen_clz_i64, },
1447 if (es > ES_64) {
1448 gen_program_exception(s, PGM_SPECIFICATION);
1449 return DISAS_NORETURN;
1451 gen_gvec_2(get_field(s->fields, v1), get_field(s->fields, v2), &g[es]);
1452 return DISAS_NEXT;
1455 static void gen_ctz_i32(TCGv_i32 d, TCGv_i32 a)
1457 tcg_gen_ctzi_i32(d, a, 32);
1460 static void gen_ctz_i64(TCGv_i64 d, TCGv_i64 a)
1462 tcg_gen_ctzi_i64(d, a, 64);
1465 static DisasJumpType op_vctz(DisasContext *s, DisasOps *o)
1467 const uint8_t es = get_field(s->fields, m3);
1468 static const GVecGen2 g[4] = {
1469 { .fno = gen_helper_gvec_vctz8, },
1470 { .fno = gen_helper_gvec_vctz16, },
1471 { .fni4 = gen_ctz_i32, },
1472 { .fni8 = gen_ctz_i64, },
1475 if (es > ES_64) {
1476 gen_program_exception(s, PGM_SPECIFICATION);
1477 return DISAS_NORETURN;
1479 gen_gvec_2(get_field(s->fields, v1), get_field(s->fields, v2), &g[es]);
1480 return DISAS_NEXT;
1483 static DisasJumpType op_vx(DisasContext *s, DisasOps *o)
1485 gen_gvec_fn_3(xor, ES_8, get_field(s->fields, v1), get_field(s->fields, v2),
1486 get_field(s->fields, v3));
1487 return DISAS_NEXT;
1490 static DisasJumpType op_vgfm(DisasContext *s, DisasOps *o)
1492 const uint8_t es = get_field(s->fields, m4);
1493 static const GVecGen3 g[4] = {
1494 { .fno = gen_helper_gvec_vgfm8, },
1495 { .fno = gen_helper_gvec_vgfm16, },
1496 { .fno = gen_helper_gvec_vgfm32, },
1497 { .fno = gen_helper_gvec_vgfm64, },
1500 if (es > ES_64) {
1501 gen_program_exception(s, PGM_SPECIFICATION);
1502 return DISAS_NORETURN;
1504 gen_gvec_3(get_field(s->fields, v1), get_field(s->fields, v2),
1505 get_field(s->fields, v3), &g[es]);
1506 return DISAS_NEXT;
1509 static DisasJumpType op_vgfma(DisasContext *s, DisasOps *o)
1511 const uint8_t es = get_field(s->fields, m5);
1512 static const GVecGen4 g[4] = {
1513 { .fno = gen_helper_gvec_vgfma8, },
1514 { .fno = gen_helper_gvec_vgfma16, },
1515 { .fno = gen_helper_gvec_vgfma32, },
1516 { .fno = gen_helper_gvec_vgfma64, },
1519 if (es > ES_64) {
1520 gen_program_exception(s, PGM_SPECIFICATION);
1521 return DISAS_NORETURN;
1523 gen_gvec_4(get_field(s->fields, v1), get_field(s->fields, v2),
1524 get_field(s->fields, v3), get_field(s->fields, v4), &g[es]);
1525 return DISAS_NEXT;
1528 static DisasJumpType op_vlc(DisasContext *s, DisasOps *o)
1530 const uint8_t es = get_field(s->fields, m3);
1532 if (es > ES_64) {
1533 gen_program_exception(s, PGM_SPECIFICATION);
1534 return DISAS_NORETURN;
1537 gen_gvec_fn_2(neg, es, get_field(s->fields, v1), get_field(s->fields, v2));
1538 return DISAS_NEXT;
1541 static DisasJumpType op_vlp(DisasContext *s, DisasOps *o)
1543 const uint8_t es = get_field(s->fields, m3);
1545 if (es > ES_64) {
1546 gen_program_exception(s, PGM_SPECIFICATION);
1547 return DISAS_NORETURN;
1550 gen_gvec_fn_2(abs, es, get_field(s->fields, v1), get_field(s->fields, v2));
1551 return DISAS_NEXT;
1554 static DisasJumpType op_vmx(DisasContext *s, DisasOps *o)
1556 const uint8_t v1 = get_field(s->fields, v1);
1557 const uint8_t v2 = get_field(s->fields, v2);
1558 const uint8_t v3 = get_field(s->fields, v3);
1559 const uint8_t es = get_field(s->fields, m4);
1561 if (es > ES_64) {
1562 gen_program_exception(s, PGM_SPECIFICATION);
1563 return DISAS_NORETURN;
1566 switch (s->fields->op2) {
1567 case 0xff:
1568 gen_gvec_fn_3(smax, es, v1, v2, v3);
1569 break;
1570 case 0xfd:
1571 gen_gvec_fn_3(umax, es, v1, v2, v3);
1572 break;
1573 case 0xfe:
1574 gen_gvec_fn_3(smin, es, v1, v2, v3);
1575 break;
1576 case 0xfc:
1577 gen_gvec_fn_3(umin, es, v1, v2, v3);
1578 break;
1579 default:
1580 g_assert_not_reached();
1582 return DISAS_NEXT;
1585 static void gen_mal_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b, TCGv_i32 c)
1587 TCGv_i32 t0 = tcg_temp_new_i32();
1589 tcg_gen_mul_i32(t0, a, b);
1590 tcg_gen_add_i32(d, t0, c);
1592 tcg_temp_free_i32(t0);
1595 static void gen_mah_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b, TCGv_i32 c)
1597 TCGv_i64 t0 = tcg_temp_new_i64();
1598 TCGv_i64 t1 = tcg_temp_new_i64();
1599 TCGv_i64 t2 = tcg_temp_new_i64();
1601 tcg_gen_ext_i32_i64(t0, a);
1602 tcg_gen_ext_i32_i64(t1, b);
1603 tcg_gen_ext_i32_i64(t2, c);
1604 tcg_gen_mul_i64(t0, t0, t1);
1605 tcg_gen_add_i64(t0, t0, t2);
1606 tcg_gen_extrh_i64_i32(d, t0);
1608 tcg_temp_free(t0);
1609 tcg_temp_free(t1);
1610 tcg_temp_free(t2);
1613 static void gen_malh_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b, TCGv_i32 c)
1615 TCGv_i64 t0 = tcg_temp_new_i64();
1616 TCGv_i64 t1 = tcg_temp_new_i64();
1617 TCGv_i64 t2 = tcg_temp_new_i64();
1619 tcg_gen_extu_i32_i64(t0, a);
1620 tcg_gen_extu_i32_i64(t1, b);
1621 tcg_gen_extu_i32_i64(t2, c);
1622 tcg_gen_mul_i64(t0, t0, t1);
1623 tcg_gen_add_i64(t0, t0, t2);
1624 tcg_gen_extrh_i64_i32(d, t0);
1626 tcg_temp_free(t0);
1627 tcg_temp_free(t1);
1628 tcg_temp_free(t2);
1631 static DisasJumpType op_vma(DisasContext *s, DisasOps *o)
1633 const uint8_t es = get_field(s->fields, m5);
1634 static const GVecGen4 g_vmal[3] = {
1635 { .fno = gen_helper_gvec_vmal8, },
1636 { .fno = gen_helper_gvec_vmal16, },
1637 { .fni4 = gen_mal_i32, },
1639 static const GVecGen4 g_vmah[3] = {
1640 { .fno = gen_helper_gvec_vmah8, },
1641 { .fno = gen_helper_gvec_vmah16, },
1642 { .fni4 = gen_mah_i32, },
1644 static const GVecGen4 g_vmalh[3] = {
1645 { .fno = gen_helper_gvec_vmalh8, },
1646 { .fno = gen_helper_gvec_vmalh16, },
1647 { .fni4 = gen_malh_i32, },
1649 static const GVecGen4 g_vmae[3] = {
1650 { .fno = gen_helper_gvec_vmae8, },
1651 { .fno = gen_helper_gvec_vmae16, },
1652 { .fno = gen_helper_gvec_vmae32, },
1654 static const GVecGen4 g_vmale[3] = {
1655 { .fno = gen_helper_gvec_vmale8, },
1656 { .fno = gen_helper_gvec_vmale16, },
1657 { .fno = gen_helper_gvec_vmale32, },
1659 static const GVecGen4 g_vmao[3] = {
1660 { .fno = gen_helper_gvec_vmao8, },
1661 { .fno = gen_helper_gvec_vmao16, },
1662 { .fno = gen_helper_gvec_vmao32, },
1664 static const GVecGen4 g_vmalo[3] = {
1665 { .fno = gen_helper_gvec_vmalo8, },
1666 { .fno = gen_helper_gvec_vmalo16, },
1667 { .fno = gen_helper_gvec_vmalo32, },
1669 const GVecGen4 *fn;
1671 if (es > ES_32) {
1672 gen_program_exception(s, PGM_SPECIFICATION);
1673 return DISAS_NORETURN;
1676 switch (s->fields->op2) {
1677 case 0xaa:
1678 fn = &g_vmal[es];
1679 break;
1680 case 0xab:
1681 fn = &g_vmah[es];
1682 break;
1683 case 0xa9:
1684 fn = &g_vmalh[es];
1685 break;
1686 case 0xae:
1687 fn = &g_vmae[es];
1688 break;
1689 case 0xac:
1690 fn = &g_vmale[es];
1691 break;
1692 case 0xaf:
1693 fn = &g_vmao[es];
1694 break;
1695 case 0xad:
1696 fn = &g_vmalo[es];
1697 break;
1698 default:
1699 g_assert_not_reached();
1702 gen_gvec_4(get_field(s->fields, v1), get_field(s->fields, v2),
1703 get_field(s->fields, v3), get_field(s->fields, v4), fn);
1704 return DISAS_NEXT;
1707 static void gen_mh_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
1709 TCGv_i32 t = tcg_temp_new_i32();
1711 tcg_gen_muls2_i32(t, d, a, b);
1712 tcg_temp_free_i32(t);
1715 static void gen_mlh_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
1717 TCGv_i32 t = tcg_temp_new_i32();
1719 tcg_gen_mulu2_i32(t, d, a, b);
1720 tcg_temp_free_i32(t);
1723 static DisasJumpType op_vm(DisasContext *s, DisasOps *o)
1725 const uint8_t es = get_field(s->fields, m4);
1726 static const GVecGen3 g_vmh[3] = {
1727 { .fno = gen_helper_gvec_vmh8, },
1728 { .fno = gen_helper_gvec_vmh16, },
1729 { .fni4 = gen_mh_i32, },
1731 static const GVecGen3 g_vmlh[3] = {
1732 { .fno = gen_helper_gvec_vmlh8, },
1733 { .fno = gen_helper_gvec_vmlh16, },
1734 { .fni4 = gen_mlh_i32, },
1736 static const GVecGen3 g_vme[3] = {
1737 { .fno = gen_helper_gvec_vme8, },
1738 { .fno = gen_helper_gvec_vme16, },
1739 { .fno = gen_helper_gvec_vme32, },
1741 static const GVecGen3 g_vmle[3] = {
1742 { .fno = gen_helper_gvec_vmle8, },
1743 { .fno = gen_helper_gvec_vmle16, },
1744 { .fno = gen_helper_gvec_vmle32, },
1746 static const GVecGen3 g_vmo[3] = {
1747 { .fno = gen_helper_gvec_vmo8, },
1748 { .fno = gen_helper_gvec_vmo16, },
1749 { .fno = gen_helper_gvec_vmo32, },
1751 static const GVecGen3 g_vmlo[3] = {
1752 { .fno = gen_helper_gvec_vmlo8, },
1753 { .fno = gen_helper_gvec_vmlo16, },
1754 { .fno = gen_helper_gvec_vmlo32, },
1756 const GVecGen3 *fn;
1758 if (es > ES_32) {
1759 gen_program_exception(s, PGM_SPECIFICATION);
1760 return DISAS_NORETURN;
1763 switch (s->fields->op2) {
1764 case 0xa2:
1765 gen_gvec_fn_3(mul, es, get_field(s->fields, v1),
1766 get_field(s->fields, v2), get_field(s->fields, v3));
1767 return DISAS_NEXT;
1768 case 0xa3:
1769 fn = &g_vmh[es];
1770 break;
1771 case 0xa1:
1772 fn = &g_vmlh[es];
1773 break;
1774 case 0xa6:
1775 fn = &g_vme[es];
1776 break;
1777 case 0xa4:
1778 fn = &g_vmle[es];
1779 break;
1780 case 0xa7:
1781 fn = &g_vmo[es];
1782 break;
1783 case 0xa5:
1784 fn = &g_vmlo[es];
1785 break;
1786 default:
1787 g_assert_not_reached();
1790 gen_gvec_3(get_field(s->fields, v1), get_field(s->fields, v2),
1791 get_field(s->fields, v3), fn);
1792 return DISAS_NEXT;
1795 static DisasJumpType op_vnn(DisasContext *s, DisasOps *o)
1797 gen_gvec_fn_3(nand, ES_8, get_field(s->fields, v1),
1798 get_field(s->fields, v2), get_field(s->fields, v3));
1799 return DISAS_NEXT;
1802 static DisasJumpType op_vno(DisasContext *s, DisasOps *o)
1804 gen_gvec_fn_3(nor, ES_8, get_field(s->fields, v1), get_field(s->fields, v2),
1805 get_field(s->fields, v3));
1806 return DISAS_NEXT;
1809 static DisasJumpType op_vnx(DisasContext *s, DisasOps *o)
1811 gen_gvec_fn_3(eqv, ES_8, get_field(s->fields, v1), get_field(s->fields, v2),
1812 get_field(s->fields, v3));
1813 return DISAS_NEXT;
1816 static DisasJumpType op_vo(DisasContext *s, DisasOps *o)
1818 gen_gvec_fn_3(or, ES_8, get_field(s->fields, v1), get_field(s->fields, v2),
1819 get_field(s->fields, v3));
1820 return DISAS_NEXT;
1823 static DisasJumpType op_voc(DisasContext *s, DisasOps *o)
1825 gen_gvec_fn_3(orc, ES_8, get_field(s->fields, v1), get_field(s->fields, v2),
1826 get_field(s->fields, v3));
1827 return DISAS_NEXT;