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_3(v1, v2, v3, gen) \
186 tcg_gen_gvec_3(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
187 vec_full_reg_offset(v3), 16, 16, gen)
188 #define gen_gvec_3_ool(v1, v2, v3, data, fn) \
189 tcg_gen_gvec_3_ool(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
190 vec_full_reg_offset(v3), 16, 16, data, fn)
191 #define gen_gvec_3_ptr(v1, v2, v3, ptr, data, fn) \
192 tcg_gen_gvec_3_ptr(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
193 vec_full_reg_offset(v3), ptr, 16, 16, data, fn)
194 #define gen_gvec_4(v1, v2, v3, v4, gen) \
195 tcg_gen_gvec_4(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
196 vec_full_reg_offset(v3), vec_full_reg_offset(v4), \
198 #define gen_gvec_4_ool(v1, v2, v3, v4, data, fn) \
199 tcg_gen_gvec_4_ool(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
200 vec_full_reg_offset(v3), vec_full_reg_offset(v4), \
202 #define gen_gvec_dup_i64(es, v1, c) \
203 tcg_gen_gvec_dup_i64(es, vec_full_reg_offset(v1), 16, 16, c)
204 #define gen_gvec_mov(v1, v2) \
205 tcg_gen_gvec_mov(0, vec_full_reg_offset(v1), vec_full_reg_offset(v2), 16, \
207 #define gen_gvec_dup64i(v1, c) \
208 tcg_gen_gvec_dup64i(vec_full_reg_offset(v1), 16, 16, c)
209 #define gen_gvec_fn_3(fn, es, v1, v2, v3) \
210 tcg_gen_gvec_##fn(es, vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
211 vec_full_reg_offset(v3), 16, 16)
214 * Helper to carry out a 128 bit vector computation using 2 i64 values per
217 typedef void (*gen_gvec128_3_i64_fn
)(TCGv_i64 dl
, TCGv_i64 dh
, TCGv_i64 al
,
218 TCGv_i64 ah
, TCGv_i64 bl
, TCGv_i64 bh
);
219 static void gen_gvec128_3_i64(gen_gvec128_3_i64_fn fn
, uint8_t d
, uint8_t a
,
222 TCGv_i64 dh
= tcg_temp_new_i64();
223 TCGv_i64 dl
= tcg_temp_new_i64();
224 TCGv_i64 ah
= tcg_temp_new_i64();
225 TCGv_i64 al
= tcg_temp_new_i64();
226 TCGv_i64 bh
= tcg_temp_new_i64();
227 TCGv_i64 bl
= tcg_temp_new_i64();
229 read_vec_element_i64(ah
, a
, 0, ES_64
);
230 read_vec_element_i64(al
, a
, 1, ES_64
);
231 read_vec_element_i64(bh
, b
, 0, ES_64
);
232 read_vec_element_i64(bl
, b
, 1, ES_64
);
233 fn(dl
, dh
, al
, ah
, bl
, bh
);
234 write_vec_element_i64(dh
, d
, 0, ES_64
);
235 write_vec_element_i64(dl
, d
, 1, ES_64
);
237 tcg_temp_free_i64(dh
);
238 tcg_temp_free_i64(dl
);
239 tcg_temp_free_i64(ah
);
240 tcg_temp_free_i64(al
);
241 tcg_temp_free_i64(bh
);
242 tcg_temp_free_i64(bl
);
245 typedef void (*gen_gvec128_4_i64_fn
)(TCGv_i64 dl
, TCGv_i64 dh
, TCGv_i64 al
,
246 TCGv_i64 ah
, TCGv_i64 bl
, TCGv_i64 bh
,
247 TCGv_i64 cl
, TCGv_i64 ch
);
248 static void gen_gvec128_4_i64(gen_gvec128_4_i64_fn fn
, uint8_t d
, uint8_t a
,
249 uint8_t b
, uint8_t c
)
251 TCGv_i64 dh
= tcg_temp_new_i64();
252 TCGv_i64 dl
= tcg_temp_new_i64();
253 TCGv_i64 ah
= tcg_temp_new_i64();
254 TCGv_i64 al
= tcg_temp_new_i64();
255 TCGv_i64 bh
= tcg_temp_new_i64();
256 TCGv_i64 bl
= tcg_temp_new_i64();
257 TCGv_i64 ch
= tcg_temp_new_i64();
258 TCGv_i64 cl
= tcg_temp_new_i64();
260 read_vec_element_i64(ah
, a
, 0, ES_64
);
261 read_vec_element_i64(al
, a
, 1, ES_64
);
262 read_vec_element_i64(bh
, b
, 0, ES_64
);
263 read_vec_element_i64(bl
, b
, 1, ES_64
);
264 read_vec_element_i64(ch
, c
, 0, ES_64
);
265 read_vec_element_i64(cl
, c
, 1, ES_64
);
266 fn(dl
, dh
, al
, ah
, bl
, bh
, cl
, ch
);
267 write_vec_element_i64(dh
, d
, 0, ES_64
);
268 write_vec_element_i64(dl
, d
, 1, ES_64
);
270 tcg_temp_free_i64(dh
);
271 tcg_temp_free_i64(dl
);
272 tcg_temp_free_i64(ah
);
273 tcg_temp_free_i64(al
);
274 tcg_temp_free_i64(bh
);
275 tcg_temp_free_i64(bl
);
276 tcg_temp_free_i64(ch
);
277 tcg_temp_free_i64(cl
);
280 static void gen_gvec_dupi(uint8_t es
, uint8_t reg
, uint64_t c
)
284 tcg_gen_gvec_dup8i(vec_full_reg_offset(reg
), 16, 16, c
);
287 tcg_gen_gvec_dup16i(vec_full_reg_offset(reg
), 16, 16, c
);
290 tcg_gen_gvec_dup32i(vec_full_reg_offset(reg
), 16, 16, c
);
293 gen_gvec_dup64i(reg
, c
);
296 g_assert_not_reached();
300 static void zero_vec(uint8_t reg
)
302 tcg_gen_gvec_dup8i(vec_full_reg_offset(reg
), 16, 16, 0);
305 static void gen_addi2_i64(TCGv_i64 dl
, TCGv_i64 dh
, TCGv_i64 al
, TCGv_i64 ah
,
308 TCGv_i64 bl
= tcg_const_i64(b
);
309 TCGv_i64 bh
= tcg_const_i64(0);
311 tcg_gen_add2_i64(dl
, dh
, al
, ah
, bl
, bh
);
312 tcg_temp_free_i64(bl
);
313 tcg_temp_free_i64(bh
);
316 static DisasJumpType
op_vge(DisasContext
*s
, DisasOps
*o
)
318 const uint8_t es
= s
->insn
->data
;
319 const uint8_t enr
= get_field(s
->fields
, m3
);
322 if (!valid_vec_element(enr
, es
)) {
323 gen_program_exception(s
, PGM_SPECIFICATION
);
324 return DISAS_NORETURN
;
327 tmp
= tcg_temp_new_i64();
328 read_vec_element_i64(tmp
, get_field(s
->fields
, v2
), enr
, es
);
329 tcg_gen_add_i64(o
->addr1
, o
->addr1
, tmp
);
330 gen_addi_and_wrap_i64(s
, o
->addr1
, o
->addr1
, 0);
332 tcg_gen_qemu_ld_i64(tmp
, o
->addr1
, get_mem_index(s
), MO_TE
| es
);
333 write_vec_element_i64(tmp
, get_field(s
->fields
, v1
), enr
, es
);
334 tcg_temp_free_i64(tmp
);
338 static uint64_t generate_byte_mask(uint8_t mask
)
343 for (i
= 0; i
< 8; i
++) {
344 if ((mask
>> i
) & 1) {
345 r
|= 0xffull
<< (i
* 8);
351 static DisasJumpType
op_vgbm(DisasContext
*s
, DisasOps
*o
)
353 const uint16_t i2
= get_field(s
->fields
, i2
);
355 if (i2
== (i2
& 0xff) * 0x0101) {
357 * Masks for both 64 bit elements of the vector are the same.
358 * Trust tcg to produce a good constant loading.
360 gen_gvec_dup64i(get_field(s
->fields
, v1
),
361 generate_byte_mask(i2
& 0xff));
363 TCGv_i64 t
= tcg_temp_new_i64();
365 tcg_gen_movi_i64(t
, generate_byte_mask(i2
>> 8));
366 write_vec_element_i64(t
, get_field(s
->fields
, v1
), 0, ES_64
);
367 tcg_gen_movi_i64(t
, generate_byte_mask(i2
));
368 write_vec_element_i64(t
, get_field(s
->fields
, v1
), 1, ES_64
);
369 tcg_temp_free_i64(t
);
374 static DisasJumpType
op_vgm(DisasContext
*s
, DisasOps
*o
)
376 const uint8_t es
= get_field(s
->fields
, m4
);
377 const uint8_t bits
= NUM_VEC_ELEMENT_BITS(es
);
378 const uint8_t i2
= get_field(s
->fields
, i2
) & (bits
- 1);
379 const uint8_t i3
= get_field(s
->fields
, i3
) & (bits
- 1);
384 gen_program_exception(s
, PGM_SPECIFICATION
);
385 return DISAS_NORETURN
;
388 /* generate the mask - take care of wrapping */
389 for (i
= i2
; ; i
= (i
+ 1) % bits
) {
390 mask
|= 1ull << (bits
- i
- 1);
396 gen_gvec_dupi(es
, get_field(s
->fields
, v1
), mask
);
400 static DisasJumpType
op_vl(DisasContext
*s
, DisasOps
*o
)
402 TCGv_i64 t0
= tcg_temp_new_i64();
403 TCGv_i64 t1
= tcg_temp_new_i64();
405 tcg_gen_qemu_ld_i64(t0
, o
->addr1
, get_mem_index(s
), MO_TEQ
);
406 gen_addi_and_wrap_i64(s
, o
->addr1
, o
->addr1
, 8);
407 tcg_gen_qemu_ld_i64(t1
, o
->addr1
, get_mem_index(s
), MO_TEQ
);
408 write_vec_element_i64(t0
, get_field(s
->fields
, v1
), 0, ES_64
);
409 write_vec_element_i64(t1
, get_field(s
->fields
, v1
), 1, ES_64
);
415 static DisasJumpType
op_vlr(DisasContext
*s
, DisasOps
*o
)
417 gen_gvec_mov(get_field(s
->fields
, v1
), get_field(s
->fields
, v2
));
421 static DisasJumpType
op_vlrep(DisasContext
*s
, DisasOps
*o
)
423 const uint8_t es
= get_field(s
->fields
, m3
);
427 gen_program_exception(s
, PGM_SPECIFICATION
);
428 return DISAS_NORETURN
;
431 tmp
= tcg_temp_new_i64();
432 tcg_gen_qemu_ld_i64(tmp
, o
->addr1
, get_mem_index(s
), MO_TE
| es
);
433 gen_gvec_dup_i64(es
, get_field(s
->fields
, v1
), tmp
);
434 tcg_temp_free_i64(tmp
);
438 static DisasJumpType
op_vle(DisasContext
*s
, DisasOps
*o
)
440 const uint8_t es
= s
->insn
->data
;
441 const uint8_t enr
= get_field(s
->fields
, m3
);
444 if (!valid_vec_element(enr
, es
)) {
445 gen_program_exception(s
, PGM_SPECIFICATION
);
446 return DISAS_NORETURN
;
449 tmp
= tcg_temp_new_i64();
450 tcg_gen_qemu_ld_i64(tmp
, o
->addr1
, get_mem_index(s
), MO_TE
| es
);
451 write_vec_element_i64(tmp
, get_field(s
->fields
, v1
), enr
, es
);
452 tcg_temp_free_i64(tmp
);
456 static DisasJumpType
op_vlei(DisasContext
*s
, DisasOps
*o
)
458 const uint8_t es
= s
->insn
->data
;
459 const uint8_t enr
= get_field(s
->fields
, m3
);
462 if (!valid_vec_element(enr
, es
)) {
463 gen_program_exception(s
, PGM_SPECIFICATION
);
464 return DISAS_NORETURN
;
467 tmp
= tcg_const_i64((int16_t)get_field(s
->fields
, i2
));
468 write_vec_element_i64(tmp
, get_field(s
->fields
, v1
), enr
, es
);
469 tcg_temp_free_i64(tmp
);
473 static DisasJumpType
op_vlgv(DisasContext
*s
, DisasOps
*o
)
475 const uint8_t es
= get_field(s
->fields
, m4
);
479 gen_program_exception(s
, PGM_SPECIFICATION
);
480 return DISAS_NORETURN
;
483 /* fast path if we don't need the register content */
484 if (!get_field(s
->fields
, b2
)) {
485 uint8_t enr
= get_field(s
->fields
, d2
) & (NUM_VEC_ELEMENTS(es
) - 1);
487 read_vec_element_i64(o
->out
, get_field(s
->fields
, v3
), enr
, es
);
491 ptr
= tcg_temp_new_ptr();
492 get_vec_element_ptr_i64(ptr
, get_field(s
->fields
, v3
), o
->addr1
, es
);
495 tcg_gen_ld8u_i64(o
->out
, ptr
, 0);
498 tcg_gen_ld16u_i64(o
->out
, ptr
, 0);
501 tcg_gen_ld32u_i64(o
->out
, ptr
, 0);
504 tcg_gen_ld_i64(o
->out
, ptr
, 0);
507 g_assert_not_reached();
509 tcg_temp_free_ptr(ptr
);
514 static DisasJumpType
op_vllez(DisasContext
*s
, DisasOps
*o
)
516 uint8_t es
= get_field(s
->fields
, m3
);
521 /* rightmost sub-element of leftmost doubleword */
534 /* leftmost sub-element of leftmost doubleword */
536 if (s390_has_feat(S390_FEAT_VECTOR_ENH
)) {
543 gen_program_exception(s
, PGM_SPECIFICATION
);
544 return DISAS_NORETURN
;
547 t
= tcg_temp_new_i64();
548 tcg_gen_qemu_ld_i64(t
, o
->addr1
, get_mem_index(s
), MO_TE
| es
);
549 zero_vec(get_field(s
->fields
, v1
));
550 write_vec_element_i64(t
, get_field(s
->fields
, v1
), enr
, es
);
551 tcg_temp_free_i64(t
);
555 static DisasJumpType
op_vlm(DisasContext
*s
, DisasOps
*o
)
557 const uint8_t v3
= get_field(s
->fields
, v3
);
558 uint8_t v1
= get_field(s
->fields
, v1
);
561 if (v3
< v1
|| (v3
- v1
+ 1) > 16) {
562 gen_program_exception(s
, PGM_SPECIFICATION
);
563 return DISAS_NORETURN
;
567 * Check for possible access exceptions by trying to load the last
568 * element. The first element will be checked first next.
570 t0
= tcg_temp_new_i64();
571 t1
= tcg_temp_new_i64();
572 gen_addi_and_wrap_i64(s
, t0
, o
->addr1
, (v3
- v1
) * 16 + 8);
573 tcg_gen_qemu_ld_i64(t0
, t0
, get_mem_index(s
), MO_TEQ
);
576 tcg_gen_qemu_ld_i64(t1
, o
->addr1
, get_mem_index(s
), MO_TEQ
);
577 write_vec_element_i64(t1
, v1
, 0, ES_64
);
581 gen_addi_and_wrap_i64(s
, o
->addr1
, o
->addr1
, 8);
582 tcg_gen_qemu_ld_i64(t1
, o
->addr1
, get_mem_index(s
), MO_TEQ
);
583 write_vec_element_i64(t1
, v1
, 1, ES_64
);
584 gen_addi_and_wrap_i64(s
, o
->addr1
, o
->addr1
, 8);
587 /* Store the last element, loaded first */
588 write_vec_element_i64(t0
, v1
, 1, ES_64
);
590 tcg_temp_free_i64(t0
);
591 tcg_temp_free_i64(t1
);
595 static DisasJumpType
op_vlbb(DisasContext
*s
, DisasOps
*o
)
597 const int64_t block_size
= (1ull << (get_field(s
->fields
, m3
) + 6));
598 const int v1_offs
= vec_full_reg_offset(get_field(s
->fields
, v1
));
602 if (get_field(s
->fields
, m3
) > 6) {
603 gen_program_exception(s
, PGM_SPECIFICATION
);
604 return DISAS_NORETURN
;
607 bytes
= tcg_temp_new_i64();
608 a0
= tcg_temp_new_ptr();
609 /* calculate the number of bytes until the next block boundary */
610 tcg_gen_ori_i64(bytes
, o
->addr1
, -block_size
);
611 tcg_gen_neg_i64(bytes
, bytes
);
613 tcg_gen_addi_ptr(a0
, cpu_env
, v1_offs
);
614 gen_helper_vll(cpu_env
, a0
, o
->addr1
, bytes
);
615 tcg_temp_free_i64(bytes
);
616 tcg_temp_free_ptr(a0
);
620 static DisasJumpType
op_vlvg(DisasContext
*s
, DisasOps
*o
)
622 const uint8_t es
= get_field(s
->fields
, m4
);
626 gen_program_exception(s
, PGM_SPECIFICATION
);
627 return DISAS_NORETURN
;
630 /* fast path if we don't need the register content */
631 if (!get_field(s
->fields
, b2
)) {
632 uint8_t enr
= get_field(s
->fields
, d2
) & (NUM_VEC_ELEMENTS(es
) - 1);
634 write_vec_element_i64(o
->in2
, get_field(s
->fields
, v1
), enr
, es
);
638 ptr
= tcg_temp_new_ptr();
639 get_vec_element_ptr_i64(ptr
, get_field(s
->fields
, v1
), o
->addr1
, es
);
642 tcg_gen_st8_i64(o
->in2
, ptr
, 0);
645 tcg_gen_st16_i64(o
->in2
, ptr
, 0);
648 tcg_gen_st32_i64(o
->in2
, ptr
, 0);
651 tcg_gen_st_i64(o
->in2
, ptr
, 0);
654 g_assert_not_reached();
656 tcg_temp_free_ptr(ptr
);
661 static DisasJumpType
op_vlvgp(DisasContext
*s
, DisasOps
*o
)
663 write_vec_element_i64(o
->in1
, get_field(s
->fields
, v1
), 0, ES_64
);
664 write_vec_element_i64(o
->in2
, get_field(s
->fields
, v1
), 1, ES_64
);
668 static DisasJumpType
op_vll(DisasContext
*s
, DisasOps
*o
)
670 const int v1_offs
= vec_full_reg_offset(get_field(s
->fields
, v1
));
671 TCGv_ptr a0
= tcg_temp_new_ptr();
673 /* convert highest index into an actual length */
674 tcg_gen_addi_i64(o
->in2
, o
->in2
, 1);
675 tcg_gen_addi_ptr(a0
, cpu_env
, v1_offs
);
676 gen_helper_vll(cpu_env
, a0
, o
->addr1
, o
->in2
);
677 tcg_temp_free_ptr(a0
);
681 static DisasJumpType
op_vmr(DisasContext
*s
, DisasOps
*o
)
683 const uint8_t v1
= get_field(s
->fields
, v1
);
684 const uint8_t v2
= get_field(s
->fields
, v2
);
685 const uint8_t v3
= get_field(s
->fields
, v3
);
686 const uint8_t es
= get_field(s
->fields
, m4
);
687 int dst_idx
, src_idx
;
691 gen_program_exception(s
, PGM_SPECIFICATION
);
692 return DISAS_NORETURN
;
695 tmp
= tcg_temp_new_i64();
696 if (s
->fields
->op2
== 0x61) {
697 /* iterate backwards to avoid overwriting data we might need later */
698 for (dst_idx
= NUM_VEC_ELEMENTS(es
) - 1; dst_idx
>= 0; dst_idx
--) {
699 src_idx
= dst_idx
/ 2;
700 if (dst_idx
% 2 == 0) {
701 read_vec_element_i64(tmp
, v2
, src_idx
, es
);
703 read_vec_element_i64(tmp
, v3
, src_idx
, es
);
705 write_vec_element_i64(tmp
, v1
, dst_idx
, es
);
708 /* iterate forward to avoid overwriting data we might need later */
709 for (dst_idx
= 0; dst_idx
< NUM_VEC_ELEMENTS(es
); dst_idx
++) {
710 src_idx
= (dst_idx
+ NUM_VEC_ELEMENTS(es
)) / 2;
711 if (dst_idx
% 2 == 0) {
712 read_vec_element_i64(tmp
, v2
, src_idx
, es
);
714 read_vec_element_i64(tmp
, v3
, src_idx
, es
);
716 write_vec_element_i64(tmp
, v1
, dst_idx
, es
);
719 tcg_temp_free_i64(tmp
);
723 static DisasJumpType
op_vpk(DisasContext
*s
, DisasOps
*o
)
725 const uint8_t v1
= get_field(s
->fields
, v1
);
726 const uint8_t v2
= get_field(s
->fields
, v2
);
727 const uint8_t v3
= get_field(s
->fields
, v3
);
728 const uint8_t es
= get_field(s
->fields
, m4
);
729 static gen_helper_gvec_3
* const vpk
[3] = {
730 gen_helper_gvec_vpk16
,
731 gen_helper_gvec_vpk32
,
732 gen_helper_gvec_vpk64
,
734 static gen_helper_gvec_3
* const vpks
[3] = {
735 gen_helper_gvec_vpks16
,
736 gen_helper_gvec_vpks32
,
737 gen_helper_gvec_vpks64
,
739 static gen_helper_gvec_3_ptr
* const vpks_cc
[3] = {
740 gen_helper_gvec_vpks_cc16
,
741 gen_helper_gvec_vpks_cc32
,
742 gen_helper_gvec_vpks_cc64
,
744 static gen_helper_gvec_3
* const vpkls
[3] = {
745 gen_helper_gvec_vpkls16
,
746 gen_helper_gvec_vpkls32
,
747 gen_helper_gvec_vpkls64
,
749 static gen_helper_gvec_3_ptr
* const vpkls_cc
[3] = {
750 gen_helper_gvec_vpkls_cc16
,
751 gen_helper_gvec_vpkls_cc32
,
752 gen_helper_gvec_vpkls_cc64
,
755 if (es
== ES_8
|| es
> ES_64
) {
756 gen_program_exception(s
, PGM_SPECIFICATION
);
757 return DISAS_NORETURN
;
760 switch (s
->fields
->op2
) {
762 if (get_field(s
->fields
, m5
) & 0x1) {
763 gen_gvec_3_ptr(v1
, v2
, v3
, cpu_env
, 0, vpks_cc
[es
- 1]);
766 gen_gvec_3_ool(v1
, v2
, v3
, 0, vpks
[es
- 1]);
770 if (get_field(s
->fields
, m5
) & 0x1) {
771 gen_gvec_3_ptr(v1
, v2
, v3
, cpu_env
, 0, vpkls_cc
[es
- 1]);
774 gen_gvec_3_ool(v1
, v2
, v3
, 0, vpkls
[es
- 1]);
778 /* If sources and destination dont't overlap -> fast path */
779 if (v1
!= v2
&& v1
!= v3
) {
780 const uint8_t src_es
= get_field(s
->fields
, m4
);
781 const uint8_t dst_es
= src_es
- 1;
782 TCGv_i64 tmp
= tcg_temp_new_i64();
783 int dst_idx
, src_idx
;
785 for (dst_idx
= 0; dst_idx
< NUM_VEC_ELEMENTS(dst_es
); dst_idx
++) {
787 if (src_idx
< NUM_VEC_ELEMENTS(src_es
)) {
788 read_vec_element_i64(tmp
, v2
, src_idx
, src_es
);
790 src_idx
-= NUM_VEC_ELEMENTS(src_es
);
791 read_vec_element_i64(tmp
, v3
, src_idx
, src_es
);
793 write_vec_element_i64(tmp
, v1
, dst_idx
, dst_es
);
795 tcg_temp_free_i64(tmp
);
797 gen_gvec_3_ool(v1
, v2
, v3
, 0, vpk
[es
- 1]);
801 g_assert_not_reached();
806 static DisasJumpType
op_vperm(DisasContext
*s
, DisasOps
*o
)
808 gen_gvec_4_ool(get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
809 get_field(s
->fields
, v3
), get_field(s
->fields
, v4
),
810 0, gen_helper_gvec_vperm
);
814 static DisasJumpType
op_vpdi(DisasContext
*s
, DisasOps
*o
)
816 const uint8_t i2
= extract32(get_field(s
->fields
, m4
), 2, 1);
817 const uint8_t i3
= extract32(get_field(s
->fields
, m4
), 0, 1);
818 TCGv_i64 t0
= tcg_temp_new_i64();
819 TCGv_i64 t1
= tcg_temp_new_i64();
821 read_vec_element_i64(t0
, get_field(s
->fields
, v2
), i2
, ES_64
);
822 read_vec_element_i64(t1
, get_field(s
->fields
, v3
), i3
, ES_64
);
823 write_vec_element_i64(t0
, get_field(s
->fields
, v1
), 0, ES_64
);
824 write_vec_element_i64(t1
, get_field(s
->fields
, v1
), 1, ES_64
);
825 tcg_temp_free_i64(t0
);
826 tcg_temp_free_i64(t1
);
830 static DisasJumpType
op_vrep(DisasContext
*s
, DisasOps
*o
)
832 const uint8_t enr
= get_field(s
->fields
, i2
);
833 const uint8_t es
= get_field(s
->fields
, m4
);
835 if (es
> ES_64
|| !valid_vec_element(enr
, es
)) {
836 gen_program_exception(s
, PGM_SPECIFICATION
);
837 return DISAS_NORETURN
;
840 tcg_gen_gvec_dup_mem(es
, vec_full_reg_offset(get_field(s
->fields
, v1
)),
841 vec_reg_offset(get_field(s
->fields
, v3
), enr
, es
),
846 static DisasJumpType
op_vrepi(DisasContext
*s
, DisasOps
*o
)
848 const int64_t data
= (int16_t)get_field(s
->fields
, i2
);
849 const uint8_t es
= get_field(s
->fields
, m3
);
852 gen_program_exception(s
, PGM_SPECIFICATION
);
853 return DISAS_NORETURN
;
856 gen_gvec_dupi(es
, get_field(s
->fields
, v1
), data
);
860 static DisasJumpType
op_vsce(DisasContext
*s
, DisasOps
*o
)
862 const uint8_t es
= s
->insn
->data
;
863 const uint8_t enr
= get_field(s
->fields
, m3
);
866 if (!valid_vec_element(enr
, es
)) {
867 gen_program_exception(s
, PGM_SPECIFICATION
);
868 return DISAS_NORETURN
;
871 tmp
= tcg_temp_new_i64();
872 read_vec_element_i64(tmp
, get_field(s
->fields
, v2
), enr
, es
);
873 tcg_gen_add_i64(o
->addr1
, o
->addr1
, tmp
);
874 gen_addi_and_wrap_i64(s
, o
->addr1
, o
->addr1
, 0);
876 read_vec_element_i64(tmp
, get_field(s
->fields
, v1
), enr
, es
);
877 tcg_gen_qemu_st_i64(tmp
, o
->addr1
, get_mem_index(s
), MO_TE
| es
);
878 tcg_temp_free_i64(tmp
);
882 static void gen_sel_i64(TCGv_i64 d
, TCGv_i64 a
, TCGv_i64 b
, TCGv_i64 c
)
884 TCGv_i64 t
= tcg_temp_new_i64();
886 /* bit in c not set -> copy bit from b */
887 tcg_gen_andc_i64(t
, b
, c
);
888 /* bit in c set -> copy bit from a */
889 tcg_gen_and_i64(d
, a
, c
);
890 /* merge the results */
891 tcg_gen_or_i64(d
, d
, t
);
892 tcg_temp_free_i64(t
);
895 static void gen_sel_vec(unsigned vece
, TCGv_vec d
, TCGv_vec a
, TCGv_vec b
,
898 TCGv_vec t
= tcg_temp_new_vec_matching(d
);
900 tcg_gen_andc_vec(vece
, t
, b
, c
);
901 tcg_gen_and_vec(vece
, d
, a
, c
);
902 tcg_gen_or_vec(vece
, d
, d
, t
);
903 tcg_temp_free_vec(t
);
906 static DisasJumpType
op_vsel(DisasContext
*s
, DisasOps
*o
)
908 static const GVecGen4 gvec_op
= {
911 .prefer_i64
= TCG_TARGET_REG_BITS
== 64,
914 gen_gvec_4(get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
915 get_field(s
->fields
, v3
), get_field(s
->fields
, v4
), &gvec_op
);
919 static DisasJumpType
op_vseg(DisasContext
*s
, DisasOps
*o
)
921 const uint8_t es
= get_field(s
->fields
, m3
);
939 gen_program_exception(s
, PGM_SPECIFICATION
);
940 return DISAS_NORETURN
;
943 tmp
= tcg_temp_new_i64();
944 read_vec_element_i64(tmp
, get_field(s
->fields
, v2
), idx1
, es
| MO_SIGN
);
945 write_vec_element_i64(tmp
, get_field(s
->fields
, v1
), 0, ES_64
);
946 read_vec_element_i64(tmp
, get_field(s
->fields
, v2
), idx2
, es
| MO_SIGN
);
947 write_vec_element_i64(tmp
, get_field(s
->fields
, v1
), 1, ES_64
);
948 tcg_temp_free_i64(tmp
);
952 static DisasJumpType
op_vst(DisasContext
*s
, DisasOps
*o
)
954 TCGv_i64 tmp
= tcg_const_i64(16);
956 /* Probe write access before actually modifying memory */
957 gen_helper_probe_write_access(cpu_env
, o
->addr1
, tmp
);
959 read_vec_element_i64(tmp
, get_field(s
->fields
, v1
), 0, ES_64
);
960 tcg_gen_qemu_st_i64(tmp
, o
->addr1
, get_mem_index(s
), MO_TEQ
);
961 gen_addi_and_wrap_i64(s
, o
->addr1
, o
->addr1
, 8);
962 read_vec_element_i64(tmp
, get_field(s
->fields
, v1
), 1, ES_64
);
963 tcg_gen_qemu_st_i64(tmp
, o
->addr1
, get_mem_index(s
), MO_TEQ
);
964 tcg_temp_free_i64(tmp
);
968 static DisasJumpType
op_vste(DisasContext
*s
, DisasOps
*o
)
970 const uint8_t es
= s
->insn
->data
;
971 const uint8_t enr
= get_field(s
->fields
, m3
);
974 if (!valid_vec_element(enr
, es
)) {
975 gen_program_exception(s
, PGM_SPECIFICATION
);
976 return DISAS_NORETURN
;
979 tmp
= tcg_temp_new_i64();
980 read_vec_element_i64(tmp
, get_field(s
->fields
, v1
), enr
, es
);
981 tcg_gen_qemu_st_i64(tmp
, o
->addr1
, get_mem_index(s
), MO_TE
| es
);
982 tcg_temp_free_i64(tmp
);
986 static DisasJumpType
op_vstm(DisasContext
*s
, DisasOps
*o
)
988 const uint8_t v3
= get_field(s
->fields
, v3
);
989 uint8_t v1
= get_field(s
->fields
, v1
);
992 while (v3
< v1
|| (v3
- v1
+ 1) > 16) {
993 gen_program_exception(s
, PGM_SPECIFICATION
);
994 return DISAS_NORETURN
;
997 /* Probe write access before actually modifying memory */
998 tmp
= tcg_const_i64((v3
- v1
+ 1) * 16);
999 gen_helper_probe_write_access(cpu_env
, o
->addr1
, tmp
);
1002 read_vec_element_i64(tmp
, v1
, 0, ES_64
);
1003 tcg_gen_qemu_st_i64(tmp
, o
->addr1
, get_mem_index(s
), MO_TEQ
);
1004 gen_addi_and_wrap_i64(s
, o
->addr1
, o
->addr1
, 8);
1005 read_vec_element_i64(tmp
, v1
, 1, ES_64
);
1006 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);
1012 tcg_temp_free_i64(tmp
);
1016 static DisasJumpType
op_vstl(DisasContext
*s
, DisasOps
*o
)
1018 const int v1_offs
= vec_full_reg_offset(get_field(s
->fields
, v1
));
1019 TCGv_ptr a0
= tcg_temp_new_ptr();
1021 /* convert highest index into an actual length */
1022 tcg_gen_addi_i64(o
->in2
, o
->in2
, 1);
1023 tcg_gen_addi_ptr(a0
, cpu_env
, v1_offs
);
1024 gen_helper_vstl(cpu_env
, a0
, o
->addr1
, o
->in2
);
1025 tcg_temp_free_ptr(a0
);
1029 static DisasJumpType
op_vup(DisasContext
*s
, DisasOps
*o
)
1031 const bool logical
= s
->fields
->op2
== 0xd4 || s
->fields
->op2
== 0xd5;
1032 const uint8_t v1
= get_field(s
->fields
, v1
);
1033 const uint8_t v2
= get_field(s
->fields
, v2
);
1034 const uint8_t src_es
= get_field(s
->fields
, m3
);
1035 const uint8_t dst_es
= src_es
+ 1;
1036 int dst_idx
, src_idx
;
1039 if (src_es
> ES_32
) {
1040 gen_program_exception(s
, PGM_SPECIFICATION
);
1041 return DISAS_NORETURN
;
1044 tmp
= tcg_temp_new_i64();
1045 if (s
->fields
->op2
== 0xd7 || s
->fields
->op2
== 0xd5) {
1046 /* iterate backwards to avoid overwriting data we might need later */
1047 for (dst_idx
= NUM_VEC_ELEMENTS(dst_es
) - 1; dst_idx
>= 0; dst_idx
--) {
1049 read_vec_element_i64(tmp
, v2
, src_idx
,
1050 src_es
| (logical
? 0 : MO_SIGN
));
1051 write_vec_element_i64(tmp
, v1
, dst_idx
, dst_es
);
1055 /* iterate forward to avoid overwriting data we might need later */
1056 for (dst_idx
= 0; dst_idx
< NUM_VEC_ELEMENTS(dst_es
); dst_idx
++) {
1057 src_idx
= dst_idx
+ NUM_VEC_ELEMENTS(src_es
) / 2;
1058 read_vec_element_i64(tmp
, v2
, src_idx
,
1059 src_es
| (logical
? 0 : MO_SIGN
));
1060 write_vec_element_i64(tmp
, v1
, dst_idx
, dst_es
);
1063 tcg_temp_free_i64(tmp
);
1067 static DisasJumpType
op_va(DisasContext
*s
, DisasOps
*o
)
1069 const uint8_t es
= get_field(s
->fields
, m4
);
1072 gen_program_exception(s
, PGM_SPECIFICATION
);
1073 return DISAS_NORETURN
;
1074 } else if (es
== ES_128
) {
1075 gen_gvec128_3_i64(tcg_gen_add2_i64
, get_field(s
->fields
, v1
),
1076 get_field(s
->fields
, v2
), get_field(s
->fields
, v3
));
1079 gen_gvec_fn_3(add
, es
, get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
1080 get_field(s
->fields
, v3
));
1084 static void gen_acc(TCGv_i64 d
, TCGv_i64 a
, TCGv_i64 b
, uint8_t es
)
1086 const uint8_t msb_bit_nr
= NUM_VEC_ELEMENT_BITS(es
) - 1;
1087 TCGv_i64 msb_mask
= tcg_const_i64(dup_const(es
, 1ull << msb_bit_nr
));
1088 TCGv_i64 t1
= tcg_temp_new_i64();
1089 TCGv_i64 t2
= tcg_temp_new_i64();
1090 TCGv_i64 t3
= tcg_temp_new_i64();
1092 /* Calculate the carry into the MSB, ignoring the old MSBs */
1093 tcg_gen_andc_i64(t1
, a
, msb_mask
);
1094 tcg_gen_andc_i64(t2
, b
, msb_mask
);
1095 tcg_gen_add_i64(t1
, t1
, t2
);
1096 /* Calculate the MSB without any carry into it */
1097 tcg_gen_xor_i64(t3
, a
, b
);
1098 /* Calculate the carry out of the MSB in the MSB bit position */
1099 tcg_gen_and_i64(d
, a
, b
);
1100 tcg_gen_and_i64(t1
, t1
, t3
);
1101 tcg_gen_or_i64(d
, d
, t1
);
1102 /* Isolate and shift the carry into position */
1103 tcg_gen_and_i64(d
, d
, msb_mask
);
1104 tcg_gen_shri_i64(d
, d
, msb_bit_nr
);
1106 tcg_temp_free_i64(t1
);
1107 tcg_temp_free_i64(t2
);
1108 tcg_temp_free_i64(t3
);
1111 static void gen_acc8_i64(TCGv_i64 d
, TCGv_i64 a
, TCGv_i64 b
)
1113 gen_acc(d
, a
, b
, ES_8
);
1116 static void gen_acc16_i64(TCGv_i64 d
, TCGv_i64 a
, TCGv_i64 b
)
1118 gen_acc(d
, a
, b
, ES_16
);
1121 static void gen_acc_i32(TCGv_i32 d
, TCGv_i32 a
, TCGv_i32 b
)
1123 TCGv_i32 t
= tcg_temp_new_i32();
1125 tcg_gen_add_i32(t
, a
, b
);
1126 tcg_gen_setcond_i32(TCG_COND_LTU
, d
, t
, b
);
1127 tcg_temp_free_i32(t
);
1130 static void gen_acc_i64(TCGv_i64 d
, TCGv_i64 a
, TCGv_i64 b
)
1132 TCGv_i64 t
= tcg_temp_new_i64();
1134 tcg_gen_add_i64(t
, a
, b
);
1135 tcg_gen_setcond_i64(TCG_COND_LTU
, d
, t
, b
);
1136 tcg_temp_free_i64(t
);
1139 static void gen_acc2_i64(TCGv_i64 dl
, TCGv_i64 dh
, TCGv_i64 al
,
1140 TCGv_i64 ah
, TCGv_i64 bl
, TCGv_i64 bh
)
1142 TCGv_i64 th
= tcg_temp_new_i64();
1143 TCGv_i64 tl
= tcg_temp_new_i64();
1144 TCGv_i64 zero
= tcg_const_i64(0);
1146 tcg_gen_add2_i64(tl
, th
, al
, zero
, bl
, zero
);
1147 tcg_gen_add2_i64(tl
, th
, th
, zero
, ah
, zero
);
1148 tcg_gen_add2_i64(tl
, dl
, tl
, th
, bh
, zero
);
1149 tcg_gen_mov_i64(dh
, zero
);
1151 tcg_temp_free_i64(th
);
1152 tcg_temp_free_i64(tl
);
1153 tcg_temp_free_i64(zero
);
1156 static DisasJumpType
op_vacc(DisasContext
*s
, DisasOps
*o
)
1158 const uint8_t es
= get_field(s
->fields
, m4
);
1159 static const GVecGen3 g
[4] = {
1160 { .fni8
= gen_acc8_i64
, },
1161 { .fni8
= gen_acc16_i64
, },
1162 { .fni4
= gen_acc_i32
, },
1163 { .fni8
= gen_acc_i64
, },
1167 gen_program_exception(s
, PGM_SPECIFICATION
);
1168 return DISAS_NORETURN
;
1169 } else if (es
== ES_128
) {
1170 gen_gvec128_3_i64(gen_acc2_i64
, get_field(s
->fields
, v1
),
1171 get_field(s
->fields
, v2
), get_field(s
->fields
, v3
));
1174 gen_gvec_3(get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
1175 get_field(s
->fields
, v3
), &g
[es
]);
1179 static void gen_ac2_i64(TCGv_i64 dl
, TCGv_i64 dh
, TCGv_i64 al
, TCGv_i64 ah
,
1180 TCGv_i64 bl
, TCGv_i64 bh
, TCGv_i64 cl
, TCGv_i64 ch
)
1182 TCGv_i64 tl
= tcg_temp_new_i64();
1183 TCGv_i64 th
= tcg_const_i64(0);
1185 /* extract the carry only */
1186 tcg_gen_extract_i64(tl
, cl
, 0, 1);
1187 tcg_gen_add2_i64(dl
, dh
, al
, ah
, bl
, bh
);
1188 tcg_gen_add2_i64(dl
, dh
, dl
, dh
, tl
, th
);
1190 tcg_temp_free_i64(tl
);
1191 tcg_temp_free_i64(th
);
1194 static DisasJumpType
op_vac(DisasContext
*s
, DisasOps
*o
)
1196 if (get_field(s
->fields
, m5
) != ES_128
) {
1197 gen_program_exception(s
, PGM_SPECIFICATION
);
1198 return DISAS_NORETURN
;
1201 gen_gvec128_4_i64(gen_ac2_i64
, get_field(s
->fields
, v1
),
1202 get_field(s
->fields
, v2
), get_field(s
->fields
, v3
),
1203 get_field(s
->fields
, v4
));
1207 static void gen_accc2_i64(TCGv_i64 dl
, TCGv_i64 dh
, TCGv_i64 al
, TCGv_i64 ah
,
1208 TCGv_i64 bl
, TCGv_i64 bh
, TCGv_i64 cl
, TCGv_i64 ch
)
1210 TCGv_i64 tl
= tcg_temp_new_i64();
1211 TCGv_i64 th
= tcg_temp_new_i64();
1212 TCGv_i64 zero
= tcg_const_i64(0);
1214 tcg_gen_andi_i64(tl
, cl
, 1);
1215 tcg_gen_add2_i64(tl
, th
, tl
, zero
, al
, zero
);
1216 tcg_gen_add2_i64(tl
, th
, tl
, th
, bl
, zero
);
1217 tcg_gen_add2_i64(tl
, th
, th
, zero
, ah
, zero
);
1218 tcg_gen_add2_i64(tl
, dl
, tl
, th
, bh
, zero
);
1219 tcg_gen_mov_i64(dh
, zero
);
1221 tcg_temp_free_i64(tl
);
1222 tcg_temp_free_i64(th
);
1223 tcg_temp_free_i64(zero
);
1226 static DisasJumpType
op_vaccc(DisasContext
*s
, DisasOps
*o
)
1228 if (get_field(s
->fields
, m5
) != ES_128
) {
1229 gen_program_exception(s
, PGM_SPECIFICATION
);
1230 return DISAS_NORETURN
;
1233 gen_gvec128_4_i64(gen_accc2_i64
, get_field(s
->fields
, v1
),
1234 get_field(s
->fields
, v2
), get_field(s
->fields
, v3
),
1235 get_field(s
->fields
, v4
));
1239 static DisasJumpType
op_vn(DisasContext
*s
, DisasOps
*o
)
1241 gen_gvec_fn_3(and, ES_8
, get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
1242 get_field(s
->fields
, v3
));
1246 static DisasJumpType
op_vnc(DisasContext
*s
, DisasOps
*o
)
1248 gen_gvec_fn_3(andc
, ES_8
, get_field(s
->fields
, v1
),
1249 get_field(s
->fields
, v2
), get_field(s
->fields
, v3
));
1253 static void gen_avg_i32(TCGv_i32 d
, TCGv_i32 a
, TCGv_i32 b
)
1255 TCGv_i64 t0
= tcg_temp_new_i64();
1256 TCGv_i64 t1
= tcg_temp_new_i64();
1258 tcg_gen_ext_i32_i64(t0
, a
);
1259 tcg_gen_ext_i32_i64(t1
, b
);
1260 tcg_gen_add_i64(t0
, t0
, t1
);
1261 tcg_gen_addi_i64(t0
, t0
, 1);
1262 tcg_gen_shri_i64(t0
, t0
, 1);
1263 tcg_gen_extrl_i64_i32(d
, t0
);
1269 static void gen_avg_i64(TCGv_i64 dl
, TCGv_i64 al
, TCGv_i64 bl
)
1271 TCGv_i64 dh
= tcg_temp_new_i64();
1272 TCGv_i64 ah
= tcg_temp_new_i64();
1273 TCGv_i64 bh
= tcg_temp_new_i64();
1275 /* extending the sign by one bit is sufficient */
1276 tcg_gen_extract_i64(ah
, al
, 63, 1);
1277 tcg_gen_extract_i64(bh
, bl
, 63, 1);
1278 tcg_gen_add2_i64(dl
, dh
, al
, ah
, bl
, bh
);
1279 gen_addi2_i64(dl
, dh
, dl
, dh
, 1);
1280 tcg_gen_extract2_i64(dl
, dl
, dh
, 1);
1282 tcg_temp_free_i64(dh
);
1283 tcg_temp_free_i64(ah
);
1284 tcg_temp_free_i64(bh
);
1287 static DisasJumpType
op_vavg(DisasContext
*s
, DisasOps
*o
)
1289 const uint8_t es
= get_field(s
->fields
, m4
);
1290 static const GVecGen3 g
[4] = {
1291 { .fno
= gen_helper_gvec_vavg8
, },
1292 { .fno
= gen_helper_gvec_vavg16
, },
1293 { .fni4
= gen_avg_i32
, },
1294 { .fni8
= gen_avg_i64
, },
1298 gen_program_exception(s
, PGM_SPECIFICATION
);
1299 return DISAS_NORETURN
;
1301 gen_gvec_3(get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
1302 get_field(s
->fields
, v3
), &g
[es
]);
1306 static void gen_avgl_i32(TCGv_i32 d
, TCGv_i32 a
, TCGv_i32 b
)
1308 TCGv_i64 t0
= tcg_temp_new_i64();
1309 TCGv_i64 t1
= tcg_temp_new_i64();
1311 tcg_gen_extu_i32_i64(t0
, a
);
1312 tcg_gen_extu_i32_i64(t1
, b
);
1313 tcg_gen_add_i64(t0
, t0
, t1
);
1314 tcg_gen_addi_i64(t0
, t0
, 1);
1315 tcg_gen_shri_i64(t0
, t0
, 1);
1316 tcg_gen_extrl_i64_i32(d
, t0
);
1322 static void gen_avgl_i64(TCGv_i64 dl
, TCGv_i64 al
, TCGv_i64 bl
)
1324 TCGv_i64 dh
= tcg_temp_new_i64();
1325 TCGv_i64 zero
= tcg_const_i64(0);
1327 tcg_gen_add2_i64(dl
, dh
, al
, zero
, bl
, zero
);
1328 gen_addi2_i64(dl
, dh
, dl
, dh
, 1);
1329 tcg_gen_extract2_i64(dl
, dl
, dh
, 1);
1331 tcg_temp_free_i64(dh
);
1332 tcg_temp_free_i64(zero
);
1335 static DisasJumpType
op_vavgl(DisasContext
*s
, DisasOps
*o
)
1337 const uint8_t es
= get_field(s
->fields
, m4
);
1338 static const GVecGen3 g
[4] = {
1339 { .fno
= gen_helper_gvec_vavgl8
, },
1340 { .fno
= gen_helper_gvec_vavgl16
, },
1341 { .fni4
= gen_avgl_i32
, },
1342 { .fni8
= gen_avgl_i64
, },
1346 gen_program_exception(s
, PGM_SPECIFICATION
);
1347 return DISAS_NORETURN
;
1349 gen_gvec_3(get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
1350 get_field(s
->fields
, v3
), &g
[es
]);
1354 static DisasJumpType
op_vcksm(DisasContext
*s
, DisasOps
*o
)
1356 TCGv_i32 tmp
= tcg_temp_new_i32();
1357 TCGv_i32 sum
= tcg_temp_new_i32();
1360 read_vec_element_i32(sum
, get_field(s
->fields
, v3
), 1, ES_32
);
1361 for (i
= 0; i
< 4; i
++) {
1362 read_vec_element_i32(tmp
, get_field(s
->fields
, v2
), i
, ES_32
);
1363 tcg_gen_add2_i32(tmp
, sum
, sum
, sum
, tmp
, tmp
);
1365 zero_vec(get_field(s
->fields
, v1
));
1366 write_vec_element_i32(sum
, get_field(s
->fields
, v1
), 1, ES_32
);
1368 tcg_temp_free_i32(tmp
);
1369 tcg_temp_free_i32(sum
);