2 * QEMU TCG support -- s390x vector instruction translation functions
4 * Copyright (C) 2019 Red Hat Inc
7 * David Hildenbrand <david@redhat.com>
9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 * See the COPYING file in the top-level directory.
14 * For most instructions that use the same element size for reads and
15 * writes, we can use real gvec vector expansion, which potantially uses
16 * real host vector instructions. As they only work up to 64 bit elements,
17 * 128 bit elements (vector is a single element) have to be handled
18 * differently. Operations that are too complicated to encode via TCG ops
19 * are handled via gvec ool (out-of-line) handlers.
21 * As soon as instructions use different element sizes for reads and writes
22 * or access elements "out of their element scope" we expand them manually
23 * in fancy loops, as gvec expansion does not deal with actual element
24 * numbers and does also not support access to other elements.
27 * As we only have i32/i64, such elements have to be loaded into two
28 * i64 values and can then be processed e.g. by tcg_gen_add2_i64.
31 * On s390x, the operand size (oprsz) and the maximum size (maxsz) are
32 * always 16 (128 bit). What gvec code calls "vece", s390x calls "es",
33 * a.k.a. "element size". These values nicely map to MO_8 ... MO_64. Only
34 * 128 bit element size has to be treated in a special way (MO_64 + 1).
35 * We will use ES_* instead of MO_* for this reason in this file.
38 * As gvec ool-helpers can currently not return values (besides via
39 * pointers like vectors or cpu_env), whenever we have to set the CC and
40 * can't conclude the value from the result vector, we will directly
41 * set it in "env->cc_op" and mark it as static via set_cc_static()".
42 * Whenever this is done, the helper writes globals (cc_op).
45 #define NUM_VEC_ELEMENT_BYTES(es) (1 << (es))
46 #define NUM_VEC_ELEMENTS(es) (16 / NUM_VEC_ELEMENT_BYTES(es))
47 #define NUM_VEC_ELEMENT_BITS(es) (NUM_VEC_ELEMENT_BYTES(es) * BITS_PER_BYTE)
55 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
,
63 const int offs
= vec_reg_offset(reg
, enr
, memop
& MO_SIZE
);
67 tcg_gen_ld8u_i64(dst
, cpu_env
, offs
);
70 tcg_gen_ld16u_i64(dst
, cpu_env
, offs
);
73 tcg_gen_ld32u_i64(dst
, cpu_env
, offs
);
76 tcg_gen_ld8s_i64(dst
, cpu_env
, offs
);
79 tcg_gen_ld16s_i64(dst
, cpu_env
, offs
);
82 tcg_gen_ld32s_i64(dst
, cpu_env
, offs
);
86 tcg_gen_ld_i64(dst
, cpu_env
, offs
);
89 g_assert_not_reached();
93 static void read_vec_element_i32(TCGv_i32 dst
, uint8_t reg
, uint8_t enr
,
96 const int offs
= vec_reg_offset(reg
, enr
, memop
& MO_SIZE
);
100 tcg_gen_ld8u_i32(dst
, cpu_env
, offs
);
103 tcg_gen_ld16u_i32(dst
, cpu_env
, offs
);
106 tcg_gen_ld8s_i32(dst
, cpu_env
, offs
);
108 case ES_16
| MO_SIGN
:
109 tcg_gen_ld16s_i32(dst
, cpu_env
, offs
);
112 case ES_32
| MO_SIGN
:
113 tcg_gen_ld_i32(dst
, cpu_env
, offs
);
116 g_assert_not_reached();
120 static void write_vec_element_i64(TCGv_i64 src
, int reg
, uint8_t enr
,
123 const int offs
= vec_reg_offset(reg
, enr
, memop
& MO_SIZE
);
127 tcg_gen_st8_i64(src
, cpu_env
, offs
);
130 tcg_gen_st16_i64(src
, cpu_env
, offs
);
133 tcg_gen_st32_i64(src
, cpu_env
, offs
);
136 tcg_gen_st_i64(src
, cpu_env
, offs
);
139 g_assert_not_reached();
143 static void write_vec_element_i32(TCGv_i32 src
, int reg
, uint8_t enr
,
146 const int offs
= vec_reg_offset(reg
, enr
, memop
& MO_SIZE
);
150 tcg_gen_st8_i32(src
, cpu_env
, offs
);
153 tcg_gen_st16_i32(src
, cpu_env
, offs
);
156 tcg_gen_st_i32(src
, cpu_env
, offs
);
159 g_assert_not_reached();
163 static void get_vec_element_ptr_i64(TCGv_ptr ptr
, uint8_t reg
, TCGv_i64 enr
,
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
));
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), \
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), \
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), \
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), \
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
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
,
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
)
290 tcg_gen_gvec_dup8i(vec_full_reg_offset(reg
), 16, 16, c
);
293 tcg_gen_gvec_dup16i(vec_full_reg_offset(reg
), 16, 16, c
);
296 tcg_gen_gvec_dup32i(vec_full_reg_offset(reg
), 16, 16, c
);
299 gen_gvec_dup64i(reg
, c
);
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
,
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
);
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
);
344 static uint64_t generate_byte_mask(uint8_t mask
)
349 for (i
= 0; i
< 8; i
++) {
350 if ((mask
>> i
) & 1) {
351 r
|= 0xffull
<< (i
* 8);
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));
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
);
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);
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);
402 gen_gvec_dupi(es
, get_field(s
->fields
, v1
), mask
);
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
);
421 static DisasJumpType
op_vlr(DisasContext
*s
, DisasOps
*o
)
423 gen_gvec_mov(get_field(s
->fields
, v1
), get_field(s
->fields
, v2
));
427 static DisasJumpType
op_vlrep(DisasContext
*s
, DisasOps
*o
)
429 const uint8_t es
= get_field(s
->fields
, m3
);
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
);
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
);
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
);
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
);
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
);
479 static DisasJumpType
op_vlgv(DisasContext
*s
, DisasOps
*o
)
481 const uint8_t es
= get_field(s
->fields
, m4
);
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
);
497 ptr
= tcg_temp_new_ptr();
498 get_vec_element_ptr_i64(ptr
, get_field(s
->fields
, v3
), o
->addr1
, es
);
501 tcg_gen_ld8u_i64(o
->out
, ptr
, 0);
504 tcg_gen_ld16u_i64(o
->out
, ptr
, 0);
507 tcg_gen_ld32u_i64(o
->out
, ptr
, 0);
510 tcg_gen_ld_i64(o
->out
, ptr
, 0);
513 g_assert_not_reached();
515 tcg_temp_free_ptr(ptr
);
520 static DisasJumpType
op_vllez(DisasContext
*s
, DisasOps
*o
)
522 uint8_t es
= get_field(s
->fields
, m3
);
527 /* rightmost sub-element of leftmost doubleword */
540 /* leftmost sub-element of leftmost doubleword */
542 if (s390_has_feat(S390_FEAT_VECTOR_ENH
)) {
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
);
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
);
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
);
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
);
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
);
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
));
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
);
626 static DisasJumpType
op_vlvg(DisasContext
*s
, DisasOps
*o
)
628 const uint8_t es
= get_field(s
->fields
, m4
);
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
);
644 ptr
= tcg_temp_new_ptr();
645 get_vec_element_ptr_i64(ptr
, get_field(s
->fields
, v1
), o
->addr1
, es
);
648 tcg_gen_st8_i64(o
->in2
, ptr
, 0);
651 tcg_gen_st16_i64(o
->in2
, ptr
, 0);
654 tcg_gen_st32_i64(o
->in2
, ptr
, 0);
657 tcg_gen_st_i64(o
->in2
, ptr
, 0);
660 g_assert_not_reached();
662 tcg_temp_free_ptr(ptr
);
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
);
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
);
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
;
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
);
709 read_vec_element_i64(tmp
, v3
, src_idx
, es
);
711 write_vec_element_i64(tmp
, v1
, dst_idx
, es
);
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
);
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
);
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
) {
768 if (get_field(s
->fields
, m5
) & 0x1) {
769 gen_gvec_3_ptr(v1
, v2
, v3
, cpu_env
, 0, vpks_cc
[es
- 1]);
772 gen_gvec_3_ool(v1
, v2
, v3
, 0, vpks
[es
- 1]);
776 if (get_field(s
->fields
, m5
) & 0x1) {
777 gen_gvec_3_ptr(v1
, v2
, v3
, cpu_env
, 0, vpkls_cc
[es
- 1]);
780 gen_gvec_3_ool(v1
, v2
, v3
, 0, vpkls
[es
- 1]);
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
++) {
793 if (src_idx
< NUM_VEC_ELEMENTS(src_es
)) {
794 read_vec_element_i64(tmp
, v2
, src_idx
, src_es
);
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
);
803 gen_gvec_3_ool(v1
, v2
, v3
, 0, vpk
[es
- 1]);
807 g_assert_not_reached();
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
);
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
);
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
),
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
);
858 gen_program_exception(s
, PGM_SPECIFICATION
);
859 return DISAS_NORETURN
;
862 gen_gvec_dupi(es
, get_field(s
->fields
, v1
), data
);
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
);
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
);
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
,
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
= {
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
);
925 static DisasJumpType
op_vseg(DisasContext
*s
, DisasOps
*o
)
927 const uint8_t es
= get_field(s
->fields
, m3
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
1016 gen_addi_and_wrap_i64(s
, o
->addr1
, o
->addr1
, 8);
1018 tcg_temp_free_i64(tmp
);
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
);
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
;
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
--) {
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
);
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
);
1073 static DisasJumpType
op_va(DisasContext
*s
, DisasOps
*o
)
1075 const uint8_t es
= get_field(s
->fields
, m4
);
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
));
1085 gen_gvec_fn_3(add
, es
, get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
1086 get_field(s
->fields
, v3
));
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
, },
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
));
1180 gen_gvec_3(get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
1181 get_field(s
->fields
, v3
), &g
[es
]);
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
));
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
));
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
));
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
));
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
);
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
, },
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
]);
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
);
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
, },
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
]);
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();
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
);
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;
1385 gen_program_exception(s
, PGM_SPECIFICATION
);
1386 return DISAS_NORETURN
;
1388 if (s
->fields
->op2
== 0xdb) {
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
);
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
;
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
);
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
, },
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
]);
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
, },
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
]);
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
));
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
, },
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
]);
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
, },
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
]);
1528 static DisasJumpType
op_vlc(DisasContext
*s
, DisasOps
*o
)
1530 const uint8_t es
= get_field(s
->fields
, m3
);
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
));
1541 static DisasJumpType
op_vlp(DisasContext
*s
, DisasOps
*o
)
1543 const uint8_t es
= get_field(s
->fields
, m3
);
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
));
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
);
1562 gen_program_exception(s
, PGM_SPECIFICATION
);
1563 return DISAS_NORETURN
;
1566 switch (s
->fields
->op2
) {
1568 gen_gvec_fn_3(smax
, es
, v1
, v2
, v3
);
1571 gen_gvec_fn_3(umax
, es
, v1
, v2
, v3
);
1574 gen_gvec_fn_3(smin
, es
, v1
, v2
, v3
);
1577 gen_gvec_fn_3(umin
, es
, v1
, v2
, v3
);
1580 g_assert_not_reached();
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
);
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
);
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
, },
1672 gen_program_exception(s
, PGM_SPECIFICATION
);
1673 return DISAS_NORETURN
;
1676 switch (s
->fields
->op2
) {
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
);
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
, },
1759 gen_program_exception(s
, PGM_SPECIFICATION
);
1760 return DISAS_NORETURN
;
1763 switch (s
->fields
->op2
) {
1765 gen_gvec_fn_3(mul
, es
, get_field(s
->fields
, v1
),
1766 get_field(s
->fields
, v2
), get_field(s
->fields
, v3
));
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
);
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
));
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
));
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
));
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
));
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
));