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_2s(v1, v2, c, gen) \
189 tcg_gen_gvec_2s(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
191 #define gen_gvec_2i_ool(v1, v2, c, data, fn) \
192 tcg_gen_gvec_2i_ool(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
194 #define gen_gvec_2_ptr(v1, v2, ptr, data, fn) \
195 tcg_gen_gvec_2_ptr(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
196 ptr, 16, 16, data, fn)
197 #define gen_gvec_3(v1, v2, v3, gen) \
198 tcg_gen_gvec_3(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
199 vec_full_reg_offset(v3), 16, 16, gen)
200 #define gen_gvec_3_ool(v1, v2, v3, data, fn) \
201 tcg_gen_gvec_3_ool(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
202 vec_full_reg_offset(v3), 16, 16, data, fn)
203 #define gen_gvec_3_ptr(v1, v2, v3, ptr, data, fn) \
204 tcg_gen_gvec_3_ptr(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
205 vec_full_reg_offset(v3), ptr, 16, 16, data, fn)
206 #define gen_gvec_3i(v1, v2, v3, c, gen) \
207 tcg_gen_gvec_3i(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
208 vec_full_reg_offset(v3), c, 16, 16, gen)
209 #define gen_gvec_4(v1, v2, v3, v4, gen) \
210 tcg_gen_gvec_4(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
211 vec_full_reg_offset(v3), vec_full_reg_offset(v4), \
213 #define gen_gvec_4_ool(v1, v2, v3, v4, data, fn) \
214 tcg_gen_gvec_4_ool(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
215 vec_full_reg_offset(v3), vec_full_reg_offset(v4), \
217 #define gen_gvec_dup_i64(es, v1, c) \
218 tcg_gen_gvec_dup_i64(es, vec_full_reg_offset(v1), 16, 16, c)
219 #define gen_gvec_mov(v1, v2) \
220 tcg_gen_gvec_mov(0, vec_full_reg_offset(v1), vec_full_reg_offset(v2), 16, \
222 #define gen_gvec_dup64i(v1, c) \
223 tcg_gen_gvec_dup64i(vec_full_reg_offset(v1), 16, 16, c)
224 #define gen_gvec_fn_2(fn, es, v1, v2) \
225 tcg_gen_gvec_##fn(es, vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
227 #define gen_gvec_fn_2i(fn, es, v1, v2, c) \
228 tcg_gen_gvec_##fn(es, vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
230 #define gen_gvec_fn_2s(fn, es, v1, v2, s) \
231 tcg_gen_gvec_##fn(es, vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
233 #define gen_gvec_fn_3(fn, es, v1, v2, v3) \
234 tcg_gen_gvec_##fn(es, vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
235 vec_full_reg_offset(v3), 16, 16)
238 * Helper to carry out a 128 bit vector computation using 2 i64 values per
241 typedef void (*gen_gvec128_3_i64_fn
)(TCGv_i64 dl
, TCGv_i64 dh
, TCGv_i64 al
,
242 TCGv_i64 ah
, TCGv_i64 bl
, TCGv_i64 bh
);
243 static void gen_gvec128_3_i64(gen_gvec128_3_i64_fn fn
, uint8_t d
, uint8_t a
,
246 TCGv_i64 dh
= tcg_temp_new_i64();
247 TCGv_i64 dl
= tcg_temp_new_i64();
248 TCGv_i64 ah
= tcg_temp_new_i64();
249 TCGv_i64 al
= tcg_temp_new_i64();
250 TCGv_i64 bh
= tcg_temp_new_i64();
251 TCGv_i64 bl
= tcg_temp_new_i64();
253 read_vec_element_i64(ah
, a
, 0, ES_64
);
254 read_vec_element_i64(al
, a
, 1, ES_64
);
255 read_vec_element_i64(bh
, b
, 0, ES_64
);
256 read_vec_element_i64(bl
, b
, 1, ES_64
);
257 fn(dl
, dh
, al
, ah
, bl
, bh
);
258 write_vec_element_i64(dh
, d
, 0, ES_64
);
259 write_vec_element_i64(dl
, d
, 1, ES_64
);
261 tcg_temp_free_i64(dh
);
262 tcg_temp_free_i64(dl
);
263 tcg_temp_free_i64(ah
);
264 tcg_temp_free_i64(al
);
265 tcg_temp_free_i64(bh
);
266 tcg_temp_free_i64(bl
);
269 typedef void (*gen_gvec128_4_i64_fn
)(TCGv_i64 dl
, TCGv_i64 dh
, TCGv_i64 al
,
270 TCGv_i64 ah
, TCGv_i64 bl
, TCGv_i64 bh
,
271 TCGv_i64 cl
, TCGv_i64 ch
);
272 static void gen_gvec128_4_i64(gen_gvec128_4_i64_fn fn
, uint8_t d
, uint8_t a
,
273 uint8_t b
, uint8_t c
)
275 TCGv_i64 dh
= tcg_temp_new_i64();
276 TCGv_i64 dl
= tcg_temp_new_i64();
277 TCGv_i64 ah
= tcg_temp_new_i64();
278 TCGv_i64 al
= tcg_temp_new_i64();
279 TCGv_i64 bh
= tcg_temp_new_i64();
280 TCGv_i64 bl
= tcg_temp_new_i64();
281 TCGv_i64 ch
= tcg_temp_new_i64();
282 TCGv_i64 cl
= tcg_temp_new_i64();
284 read_vec_element_i64(ah
, a
, 0, ES_64
);
285 read_vec_element_i64(al
, a
, 1, ES_64
);
286 read_vec_element_i64(bh
, b
, 0, ES_64
);
287 read_vec_element_i64(bl
, b
, 1, ES_64
);
288 read_vec_element_i64(ch
, c
, 0, ES_64
);
289 read_vec_element_i64(cl
, c
, 1, ES_64
);
290 fn(dl
, dh
, al
, ah
, bl
, bh
, cl
, ch
);
291 write_vec_element_i64(dh
, d
, 0, ES_64
);
292 write_vec_element_i64(dl
, d
, 1, ES_64
);
294 tcg_temp_free_i64(dh
);
295 tcg_temp_free_i64(dl
);
296 tcg_temp_free_i64(ah
);
297 tcg_temp_free_i64(al
);
298 tcg_temp_free_i64(bh
);
299 tcg_temp_free_i64(bl
);
300 tcg_temp_free_i64(ch
);
301 tcg_temp_free_i64(cl
);
304 static void gen_gvec_dupi(uint8_t es
, uint8_t reg
, uint64_t c
)
308 tcg_gen_gvec_dup8i(vec_full_reg_offset(reg
), 16, 16, c
);
311 tcg_gen_gvec_dup16i(vec_full_reg_offset(reg
), 16, 16, c
);
314 tcg_gen_gvec_dup32i(vec_full_reg_offset(reg
), 16, 16, c
);
317 gen_gvec_dup64i(reg
, c
);
320 g_assert_not_reached();
324 static void zero_vec(uint8_t reg
)
326 tcg_gen_gvec_dup8i(vec_full_reg_offset(reg
), 16, 16, 0);
329 static void gen_addi2_i64(TCGv_i64 dl
, TCGv_i64 dh
, TCGv_i64 al
, TCGv_i64 ah
,
332 TCGv_i64 bl
= tcg_const_i64(b
);
333 TCGv_i64 bh
= tcg_const_i64(0);
335 tcg_gen_add2_i64(dl
, dh
, al
, ah
, bl
, bh
);
336 tcg_temp_free_i64(bl
);
337 tcg_temp_free_i64(bh
);
340 static DisasJumpType
op_vge(DisasContext
*s
, DisasOps
*o
)
342 const uint8_t es
= s
->insn
->data
;
343 const uint8_t enr
= get_field(s
->fields
, m3
);
346 if (!valid_vec_element(enr
, es
)) {
347 gen_program_exception(s
, PGM_SPECIFICATION
);
348 return DISAS_NORETURN
;
351 tmp
= tcg_temp_new_i64();
352 read_vec_element_i64(tmp
, get_field(s
->fields
, v2
), enr
, es
);
353 tcg_gen_add_i64(o
->addr1
, o
->addr1
, tmp
);
354 gen_addi_and_wrap_i64(s
, o
->addr1
, o
->addr1
, 0);
356 tcg_gen_qemu_ld_i64(tmp
, o
->addr1
, get_mem_index(s
), MO_TE
| es
);
357 write_vec_element_i64(tmp
, get_field(s
->fields
, v1
), enr
, es
);
358 tcg_temp_free_i64(tmp
);
362 static uint64_t generate_byte_mask(uint8_t mask
)
367 for (i
= 0; i
< 8; i
++) {
368 if ((mask
>> i
) & 1) {
369 r
|= 0xffull
<< (i
* 8);
375 static DisasJumpType
op_vgbm(DisasContext
*s
, DisasOps
*o
)
377 const uint16_t i2
= get_field(s
->fields
, i2
);
379 if (i2
== (i2
& 0xff) * 0x0101) {
381 * Masks for both 64 bit elements of the vector are the same.
382 * Trust tcg to produce a good constant loading.
384 gen_gvec_dup64i(get_field(s
->fields
, v1
),
385 generate_byte_mask(i2
& 0xff));
387 TCGv_i64 t
= tcg_temp_new_i64();
389 tcg_gen_movi_i64(t
, generate_byte_mask(i2
>> 8));
390 write_vec_element_i64(t
, get_field(s
->fields
, v1
), 0, ES_64
);
391 tcg_gen_movi_i64(t
, generate_byte_mask(i2
));
392 write_vec_element_i64(t
, get_field(s
->fields
, v1
), 1, ES_64
);
393 tcg_temp_free_i64(t
);
398 static DisasJumpType
op_vgm(DisasContext
*s
, DisasOps
*o
)
400 const uint8_t es
= get_field(s
->fields
, m4
);
401 const uint8_t bits
= NUM_VEC_ELEMENT_BITS(es
);
402 const uint8_t i2
= get_field(s
->fields
, i2
) & (bits
- 1);
403 const uint8_t i3
= get_field(s
->fields
, i3
) & (bits
- 1);
408 gen_program_exception(s
, PGM_SPECIFICATION
);
409 return DISAS_NORETURN
;
412 /* generate the mask - take care of wrapping */
413 for (i
= i2
; ; i
= (i
+ 1) % bits
) {
414 mask
|= 1ull << (bits
- i
- 1);
420 gen_gvec_dupi(es
, get_field(s
->fields
, v1
), mask
);
424 static DisasJumpType
op_vl(DisasContext
*s
, DisasOps
*o
)
426 TCGv_i64 t0
= tcg_temp_new_i64();
427 TCGv_i64 t1
= tcg_temp_new_i64();
429 tcg_gen_qemu_ld_i64(t0
, o
->addr1
, get_mem_index(s
), MO_TEQ
);
430 gen_addi_and_wrap_i64(s
, o
->addr1
, o
->addr1
, 8);
431 tcg_gen_qemu_ld_i64(t1
, o
->addr1
, get_mem_index(s
), MO_TEQ
);
432 write_vec_element_i64(t0
, get_field(s
->fields
, v1
), 0, ES_64
);
433 write_vec_element_i64(t1
, get_field(s
->fields
, v1
), 1, ES_64
);
439 static DisasJumpType
op_vlr(DisasContext
*s
, DisasOps
*o
)
441 gen_gvec_mov(get_field(s
->fields
, v1
), get_field(s
->fields
, v2
));
445 static DisasJumpType
op_vlrep(DisasContext
*s
, DisasOps
*o
)
447 const uint8_t es
= get_field(s
->fields
, m3
);
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 gen_gvec_dup_i64(es
, get_field(s
->fields
, v1
), tmp
);
458 tcg_temp_free_i64(tmp
);
462 static DisasJumpType
op_vle(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_temp_new_i64();
474 tcg_gen_qemu_ld_i64(tmp
, o
->addr1
, get_mem_index(s
), MO_TE
| es
);
475 write_vec_element_i64(tmp
, get_field(s
->fields
, v1
), enr
, es
);
476 tcg_temp_free_i64(tmp
);
480 static DisasJumpType
op_vlei(DisasContext
*s
, DisasOps
*o
)
482 const uint8_t es
= s
->insn
->data
;
483 const uint8_t enr
= get_field(s
->fields
, m3
);
486 if (!valid_vec_element(enr
, es
)) {
487 gen_program_exception(s
, PGM_SPECIFICATION
);
488 return DISAS_NORETURN
;
491 tmp
= tcg_const_i64((int16_t)get_field(s
->fields
, i2
));
492 write_vec_element_i64(tmp
, get_field(s
->fields
, v1
), enr
, es
);
493 tcg_temp_free_i64(tmp
);
497 static DisasJumpType
op_vlgv(DisasContext
*s
, DisasOps
*o
)
499 const uint8_t es
= get_field(s
->fields
, m4
);
503 gen_program_exception(s
, PGM_SPECIFICATION
);
504 return DISAS_NORETURN
;
507 /* fast path if we don't need the register content */
508 if (!get_field(s
->fields
, b2
)) {
509 uint8_t enr
= get_field(s
->fields
, d2
) & (NUM_VEC_ELEMENTS(es
) - 1);
511 read_vec_element_i64(o
->out
, get_field(s
->fields
, v3
), enr
, es
);
515 ptr
= tcg_temp_new_ptr();
516 get_vec_element_ptr_i64(ptr
, get_field(s
->fields
, v3
), o
->addr1
, es
);
519 tcg_gen_ld8u_i64(o
->out
, ptr
, 0);
522 tcg_gen_ld16u_i64(o
->out
, ptr
, 0);
525 tcg_gen_ld32u_i64(o
->out
, ptr
, 0);
528 tcg_gen_ld_i64(o
->out
, ptr
, 0);
531 g_assert_not_reached();
533 tcg_temp_free_ptr(ptr
);
538 static DisasJumpType
op_vllez(DisasContext
*s
, DisasOps
*o
)
540 uint8_t es
= get_field(s
->fields
, m3
);
545 /* rightmost sub-element of leftmost doubleword */
558 /* leftmost sub-element of leftmost doubleword */
560 if (s390_has_feat(S390_FEAT_VECTOR_ENH
)) {
567 gen_program_exception(s
, PGM_SPECIFICATION
);
568 return DISAS_NORETURN
;
571 t
= tcg_temp_new_i64();
572 tcg_gen_qemu_ld_i64(t
, o
->addr1
, get_mem_index(s
), MO_TE
| es
);
573 zero_vec(get_field(s
->fields
, v1
));
574 write_vec_element_i64(t
, get_field(s
->fields
, v1
), enr
, es
);
575 tcg_temp_free_i64(t
);
579 static DisasJumpType
op_vlm(DisasContext
*s
, DisasOps
*o
)
581 const uint8_t v3
= get_field(s
->fields
, v3
);
582 uint8_t v1
= get_field(s
->fields
, v1
);
585 if (v3
< v1
|| (v3
- v1
+ 1) > 16) {
586 gen_program_exception(s
, PGM_SPECIFICATION
);
587 return DISAS_NORETURN
;
591 * Check for possible access exceptions by trying to load the last
592 * element. The first element will be checked first next.
594 t0
= tcg_temp_new_i64();
595 t1
= tcg_temp_new_i64();
596 gen_addi_and_wrap_i64(s
, t0
, o
->addr1
, (v3
- v1
) * 16 + 8);
597 tcg_gen_qemu_ld_i64(t0
, t0
, get_mem_index(s
), MO_TEQ
);
600 tcg_gen_qemu_ld_i64(t1
, o
->addr1
, get_mem_index(s
), MO_TEQ
);
601 write_vec_element_i64(t1
, v1
, 0, ES_64
);
605 gen_addi_and_wrap_i64(s
, o
->addr1
, o
->addr1
, 8);
606 tcg_gen_qemu_ld_i64(t1
, o
->addr1
, get_mem_index(s
), MO_TEQ
);
607 write_vec_element_i64(t1
, v1
, 1, ES_64
);
608 gen_addi_and_wrap_i64(s
, o
->addr1
, o
->addr1
, 8);
611 /* Store the last element, loaded first */
612 write_vec_element_i64(t0
, v1
, 1, ES_64
);
614 tcg_temp_free_i64(t0
);
615 tcg_temp_free_i64(t1
);
619 static DisasJumpType
op_vlbb(DisasContext
*s
, DisasOps
*o
)
621 const int64_t block_size
= (1ull << (get_field(s
->fields
, m3
) + 6));
622 const int v1_offs
= vec_full_reg_offset(get_field(s
->fields
, v1
));
626 if (get_field(s
->fields
, m3
) > 6) {
627 gen_program_exception(s
, PGM_SPECIFICATION
);
628 return DISAS_NORETURN
;
631 bytes
= tcg_temp_new_i64();
632 a0
= tcg_temp_new_ptr();
633 /* calculate the number of bytes until the next block boundary */
634 tcg_gen_ori_i64(bytes
, o
->addr1
, -block_size
);
635 tcg_gen_neg_i64(bytes
, bytes
);
637 tcg_gen_addi_ptr(a0
, cpu_env
, v1_offs
);
638 gen_helper_vll(cpu_env
, a0
, o
->addr1
, bytes
);
639 tcg_temp_free_i64(bytes
);
640 tcg_temp_free_ptr(a0
);
644 static DisasJumpType
op_vlvg(DisasContext
*s
, DisasOps
*o
)
646 const uint8_t es
= get_field(s
->fields
, m4
);
650 gen_program_exception(s
, PGM_SPECIFICATION
);
651 return DISAS_NORETURN
;
654 /* fast path if we don't need the register content */
655 if (!get_field(s
->fields
, b2
)) {
656 uint8_t enr
= get_field(s
->fields
, d2
) & (NUM_VEC_ELEMENTS(es
) - 1);
658 write_vec_element_i64(o
->in2
, get_field(s
->fields
, v1
), enr
, es
);
662 ptr
= tcg_temp_new_ptr();
663 get_vec_element_ptr_i64(ptr
, get_field(s
->fields
, v1
), o
->addr1
, es
);
666 tcg_gen_st8_i64(o
->in2
, ptr
, 0);
669 tcg_gen_st16_i64(o
->in2
, ptr
, 0);
672 tcg_gen_st32_i64(o
->in2
, ptr
, 0);
675 tcg_gen_st_i64(o
->in2
, ptr
, 0);
678 g_assert_not_reached();
680 tcg_temp_free_ptr(ptr
);
685 static DisasJumpType
op_vlvgp(DisasContext
*s
, DisasOps
*o
)
687 write_vec_element_i64(o
->in1
, get_field(s
->fields
, v1
), 0, ES_64
);
688 write_vec_element_i64(o
->in2
, get_field(s
->fields
, v1
), 1, ES_64
);
692 static DisasJumpType
op_vll(DisasContext
*s
, DisasOps
*o
)
694 const int v1_offs
= vec_full_reg_offset(get_field(s
->fields
, v1
));
695 TCGv_ptr a0
= tcg_temp_new_ptr();
697 /* convert highest index into an actual length */
698 tcg_gen_addi_i64(o
->in2
, o
->in2
, 1);
699 tcg_gen_addi_ptr(a0
, cpu_env
, v1_offs
);
700 gen_helper_vll(cpu_env
, a0
, o
->addr1
, o
->in2
);
701 tcg_temp_free_ptr(a0
);
705 static DisasJumpType
op_vmr(DisasContext
*s
, DisasOps
*o
)
707 const uint8_t v1
= get_field(s
->fields
, v1
);
708 const uint8_t v2
= get_field(s
->fields
, v2
);
709 const uint8_t v3
= get_field(s
->fields
, v3
);
710 const uint8_t es
= get_field(s
->fields
, m4
);
711 int dst_idx
, src_idx
;
715 gen_program_exception(s
, PGM_SPECIFICATION
);
716 return DISAS_NORETURN
;
719 tmp
= tcg_temp_new_i64();
720 if (s
->fields
->op2
== 0x61) {
721 /* iterate backwards to avoid overwriting data we might need later */
722 for (dst_idx
= NUM_VEC_ELEMENTS(es
) - 1; dst_idx
>= 0; dst_idx
--) {
723 src_idx
= dst_idx
/ 2;
724 if (dst_idx
% 2 == 0) {
725 read_vec_element_i64(tmp
, v2
, src_idx
, es
);
727 read_vec_element_i64(tmp
, v3
, src_idx
, es
);
729 write_vec_element_i64(tmp
, v1
, dst_idx
, es
);
732 /* iterate forward to avoid overwriting data we might need later */
733 for (dst_idx
= 0; dst_idx
< NUM_VEC_ELEMENTS(es
); dst_idx
++) {
734 src_idx
= (dst_idx
+ NUM_VEC_ELEMENTS(es
)) / 2;
735 if (dst_idx
% 2 == 0) {
736 read_vec_element_i64(tmp
, v2
, src_idx
, es
);
738 read_vec_element_i64(tmp
, v3
, src_idx
, es
);
740 write_vec_element_i64(tmp
, v1
, dst_idx
, es
);
743 tcg_temp_free_i64(tmp
);
747 static DisasJumpType
op_vpk(DisasContext
*s
, DisasOps
*o
)
749 const uint8_t v1
= get_field(s
->fields
, v1
);
750 const uint8_t v2
= get_field(s
->fields
, v2
);
751 const uint8_t v3
= get_field(s
->fields
, v3
);
752 const uint8_t es
= get_field(s
->fields
, m4
);
753 static gen_helper_gvec_3
* const vpk
[3] = {
754 gen_helper_gvec_vpk16
,
755 gen_helper_gvec_vpk32
,
756 gen_helper_gvec_vpk64
,
758 static gen_helper_gvec_3
* const vpks
[3] = {
759 gen_helper_gvec_vpks16
,
760 gen_helper_gvec_vpks32
,
761 gen_helper_gvec_vpks64
,
763 static gen_helper_gvec_3_ptr
* const vpks_cc
[3] = {
764 gen_helper_gvec_vpks_cc16
,
765 gen_helper_gvec_vpks_cc32
,
766 gen_helper_gvec_vpks_cc64
,
768 static gen_helper_gvec_3
* const vpkls
[3] = {
769 gen_helper_gvec_vpkls16
,
770 gen_helper_gvec_vpkls32
,
771 gen_helper_gvec_vpkls64
,
773 static gen_helper_gvec_3_ptr
* const vpkls_cc
[3] = {
774 gen_helper_gvec_vpkls_cc16
,
775 gen_helper_gvec_vpkls_cc32
,
776 gen_helper_gvec_vpkls_cc64
,
779 if (es
== ES_8
|| es
> ES_64
) {
780 gen_program_exception(s
, PGM_SPECIFICATION
);
781 return DISAS_NORETURN
;
784 switch (s
->fields
->op2
) {
786 if (get_field(s
->fields
, m5
) & 0x1) {
787 gen_gvec_3_ptr(v1
, v2
, v3
, cpu_env
, 0, vpks_cc
[es
- 1]);
790 gen_gvec_3_ool(v1
, v2
, v3
, 0, vpks
[es
- 1]);
794 if (get_field(s
->fields
, m5
) & 0x1) {
795 gen_gvec_3_ptr(v1
, v2
, v3
, cpu_env
, 0, vpkls_cc
[es
- 1]);
798 gen_gvec_3_ool(v1
, v2
, v3
, 0, vpkls
[es
- 1]);
802 /* If sources and destination dont't overlap -> fast path */
803 if (v1
!= v2
&& v1
!= v3
) {
804 const uint8_t src_es
= get_field(s
->fields
, m4
);
805 const uint8_t dst_es
= src_es
- 1;
806 TCGv_i64 tmp
= tcg_temp_new_i64();
807 int dst_idx
, src_idx
;
809 for (dst_idx
= 0; dst_idx
< NUM_VEC_ELEMENTS(dst_es
); dst_idx
++) {
811 if (src_idx
< NUM_VEC_ELEMENTS(src_es
)) {
812 read_vec_element_i64(tmp
, v2
, src_idx
, src_es
);
814 src_idx
-= NUM_VEC_ELEMENTS(src_es
);
815 read_vec_element_i64(tmp
, v3
, src_idx
, src_es
);
817 write_vec_element_i64(tmp
, v1
, dst_idx
, dst_es
);
819 tcg_temp_free_i64(tmp
);
821 gen_gvec_3_ool(v1
, v2
, v3
, 0, vpk
[es
- 1]);
825 g_assert_not_reached();
830 static DisasJumpType
op_vperm(DisasContext
*s
, DisasOps
*o
)
832 gen_gvec_4_ool(get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
833 get_field(s
->fields
, v3
), get_field(s
->fields
, v4
),
834 0, gen_helper_gvec_vperm
);
838 static DisasJumpType
op_vpdi(DisasContext
*s
, DisasOps
*o
)
840 const uint8_t i2
= extract32(get_field(s
->fields
, m4
), 2, 1);
841 const uint8_t i3
= extract32(get_field(s
->fields
, m4
), 0, 1);
842 TCGv_i64 t0
= tcg_temp_new_i64();
843 TCGv_i64 t1
= tcg_temp_new_i64();
845 read_vec_element_i64(t0
, get_field(s
->fields
, v2
), i2
, ES_64
);
846 read_vec_element_i64(t1
, get_field(s
->fields
, v3
), i3
, ES_64
);
847 write_vec_element_i64(t0
, get_field(s
->fields
, v1
), 0, ES_64
);
848 write_vec_element_i64(t1
, get_field(s
->fields
, v1
), 1, ES_64
);
849 tcg_temp_free_i64(t0
);
850 tcg_temp_free_i64(t1
);
854 static DisasJumpType
op_vrep(DisasContext
*s
, DisasOps
*o
)
856 const uint8_t enr
= get_field(s
->fields
, i2
);
857 const uint8_t es
= get_field(s
->fields
, m4
);
859 if (es
> ES_64
|| !valid_vec_element(enr
, es
)) {
860 gen_program_exception(s
, PGM_SPECIFICATION
);
861 return DISAS_NORETURN
;
864 tcg_gen_gvec_dup_mem(es
, vec_full_reg_offset(get_field(s
->fields
, v1
)),
865 vec_reg_offset(get_field(s
->fields
, v3
), enr
, es
),
870 static DisasJumpType
op_vrepi(DisasContext
*s
, DisasOps
*o
)
872 const int64_t data
= (int16_t)get_field(s
->fields
, i2
);
873 const uint8_t es
= get_field(s
->fields
, m3
);
876 gen_program_exception(s
, PGM_SPECIFICATION
);
877 return DISAS_NORETURN
;
880 gen_gvec_dupi(es
, get_field(s
->fields
, v1
), data
);
884 static DisasJumpType
op_vsce(DisasContext
*s
, DisasOps
*o
)
886 const uint8_t es
= s
->insn
->data
;
887 const uint8_t enr
= get_field(s
->fields
, m3
);
890 if (!valid_vec_element(enr
, es
)) {
891 gen_program_exception(s
, PGM_SPECIFICATION
);
892 return DISAS_NORETURN
;
895 tmp
= tcg_temp_new_i64();
896 read_vec_element_i64(tmp
, get_field(s
->fields
, v2
), enr
, es
);
897 tcg_gen_add_i64(o
->addr1
, o
->addr1
, tmp
);
898 gen_addi_and_wrap_i64(s
, o
->addr1
, o
->addr1
, 0);
900 read_vec_element_i64(tmp
, get_field(s
->fields
, v1
), enr
, es
);
901 tcg_gen_qemu_st_i64(tmp
, o
->addr1
, get_mem_index(s
), MO_TE
| es
);
902 tcg_temp_free_i64(tmp
);
906 static void gen_sel_i64(TCGv_i64 d
, TCGv_i64 a
, TCGv_i64 b
, TCGv_i64 c
)
908 TCGv_i64 t
= tcg_temp_new_i64();
910 /* bit in c not set -> copy bit from b */
911 tcg_gen_andc_i64(t
, b
, c
);
912 /* bit in c set -> copy bit from a */
913 tcg_gen_and_i64(d
, a
, c
);
914 /* merge the results */
915 tcg_gen_or_i64(d
, d
, t
);
916 tcg_temp_free_i64(t
);
919 static void gen_sel_vec(unsigned vece
, TCGv_vec d
, TCGv_vec a
, TCGv_vec b
,
922 TCGv_vec t
= tcg_temp_new_vec_matching(d
);
924 tcg_gen_andc_vec(vece
, t
, b
, c
);
925 tcg_gen_and_vec(vece
, d
, a
, c
);
926 tcg_gen_or_vec(vece
, d
, d
, t
);
927 tcg_temp_free_vec(t
);
930 static DisasJumpType
op_vsel(DisasContext
*s
, DisasOps
*o
)
932 static const GVecGen4 gvec_op
= {
935 .prefer_i64
= TCG_TARGET_REG_BITS
== 64,
938 gen_gvec_4(get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
939 get_field(s
->fields
, v3
), get_field(s
->fields
, v4
), &gvec_op
);
943 static DisasJumpType
op_vseg(DisasContext
*s
, DisasOps
*o
)
945 const uint8_t es
= get_field(s
->fields
, m3
);
963 gen_program_exception(s
, PGM_SPECIFICATION
);
964 return DISAS_NORETURN
;
967 tmp
= tcg_temp_new_i64();
968 read_vec_element_i64(tmp
, get_field(s
->fields
, v2
), idx1
, es
| MO_SIGN
);
969 write_vec_element_i64(tmp
, get_field(s
->fields
, v1
), 0, ES_64
);
970 read_vec_element_i64(tmp
, get_field(s
->fields
, v2
), idx2
, es
| MO_SIGN
);
971 write_vec_element_i64(tmp
, get_field(s
->fields
, v1
), 1, ES_64
);
972 tcg_temp_free_i64(tmp
);
976 static DisasJumpType
op_vst(DisasContext
*s
, DisasOps
*o
)
978 TCGv_i64 tmp
= tcg_const_i64(16);
980 /* Probe write access before actually modifying memory */
981 gen_helper_probe_write_access(cpu_env
, o
->addr1
, tmp
);
983 read_vec_element_i64(tmp
, get_field(s
->fields
, v1
), 0, ES_64
);
984 tcg_gen_qemu_st_i64(tmp
, o
->addr1
, get_mem_index(s
), MO_TEQ
);
985 gen_addi_and_wrap_i64(s
, o
->addr1
, o
->addr1
, 8);
986 read_vec_element_i64(tmp
, get_field(s
->fields
, v1
), 1, ES_64
);
987 tcg_gen_qemu_st_i64(tmp
, o
->addr1
, get_mem_index(s
), MO_TEQ
);
988 tcg_temp_free_i64(tmp
);
992 static DisasJumpType
op_vste(DisasContext
*s
, DisasOps
*o
)
994 const uint8_t es
= s
->insn
->data
;
995 const uint8_t enr
= get_field(s
->fields
, m3
);
998 if (!valid_vec_element(enr
, es
)) {
999 gen_program_exception(s
, PGM_SPECIFICATION
);
1000 return DISAS_NORETURN
;
1003 tmp
= tcg_temp_new_i64();
1004 read_vec_element_i64(tmp
, get_field(s
->fields
, v1
), enr
, es
);
1005 tcg_gen_qemu_st_i64(tmp
, o
->addr1
, get_mem_index(s
), MO_TE
| es
);
1006 tcg_temp_free_i64(tmp
);
1010 static DisasJumpType
op_vstm(DisasContext
*s
, DisasOps
*o
)
1012 const uint8_t v3
= get_field(s
->fields
, v3
);
1013 uint8_t v1
= get_field(s
->fields
, v1
);
1016 while (v3
< v1
|| (v3
- v1
+ 1) > 16) {
1017 gen_program_exception(s
, PGM_SPECIFICATION
);
1018 return DISAS_NORETURN
;
1021 /* Probe write access before actually modifying memory */
1022 tmp
= tcg_const_i64((v3
- v1
+ 1) * 16);
1023 gen_helper_probe_write_access(cpu_env
, o
->addr1
, tmp
);
1026 read_vec_element_i64(tmp
, v1
, 0, ES_64
);
1027 tcg_gen_qemu_st_i64(tmp
, o
->addr1
, get_mem_index(s
), MO_TEQ
);
1028 gen_addi_and_wrap_i64(s
, o
->addr1
, o
->addr1
, 8);
1029 read_vec_element_i64(tmp
, v1
, 1, ES_64
);
1030 tcg_gen_qemu_st_i64(tmp
, o
->addr1
, get_mem_index(s
), MO_TEQ
);
1034 gen_addi_and_wrap_i64(s
, o
->addr1
, o
->addr1
, 8);
1036 tcg_temp_free_i64(tmp
);
1040 static DisasJumpType
op_vstl(DisasContext
*s
, DisasOps
*o
)
1042 const int v1_offs
= vec_full_reg_offset(get_field(s
->fields
, v1
));
1043 TCGv_ptr a0
= tcg_temp_new_ptr();
1045 /* convert highest index into an actual length */
1046 tcg_gen_addi_i64(o
->in2
, o
->in2
, 1);
1047 tcg_gen_addi_ptr(a0
, cpu_env
, v1_offs
);
1048 gen_helper_vstl(cpu_env
, a0
, o
->addr1
, o
->in2
);
1049 tcg_temp_free_ptr(a0
);
1053 static DisasJumpType
op_vup(DisasContext
*s
, DisasOps
*o
)
1055 const bool logical
= s
->fields
->op2
== 0xd4 || s
->fields
->op2
== 0xd5;
1056 const uint8_t v1
= get_field(s
->fields
, v1
);
1057 const uint8_t v2
= get_field(s
->fields
, v2
);
1058 const uint8_t src_es
= get_field(s
->fields
, m3
);
1059 const uint8_t dst_es
= src_es
+ 1;
1060 int dst_idx
, src_idx
;
1063 if (src_es
> ES_32
) {
1064 gen_program_exception(s
, PGM_SPECIFICATION
);
1065 return DISAS_NORETURN
;
1068 tmp
= tcg_temp_new_i64();
1069 if (s
->fields
->op2
== 0xd7 || s
->fields
->op2
== 0xd5) {
1070 /* iterate backwards to avoid overwriting data we might need later */
1071 for (dst_idx
= NUM_VEC_ELEMENTS(dst_es
) - 1; dst_idx
>= 0; dst_idx
--) {
1073 read_vec_element_i64(tmp
, v2
, src_idx
,
1074 src_es
| (logical
? 0 : MO_SIGN
));
1075 write_vec_element_i64(tmp
, v1
, dst_idx
, dst_es
);
1079 /* iterate forward to avoid overwriting data we might need later */
1080 for (dst_idx
= 0; dst_idx
< NUM_VEC_ELEMENTS(dst_es
); dst_idx
++) {
1081 src_idx
= dst_idx
+ NUM_VEC_ELEMENTS(src_es
) / 2;
1082 read_vec_element_i64(tmp
, v2
, src_idx
,
1083 src_es
| (logical
? 0 : MO_SIGN
));
1084 write_vec_element_i64(tmp
, v1
, dst_idx
, dst_es
);
1087 tcg_temp_free_i64(tmp
);
1091 static DisasJumpType
op_va(DisasContext
*s
, DisasOps
*o
)
1093 const uint8_t es
= get_field(s
->fields
, m4
);
1096 gen_program_exception(s
, PGM_SPECIFICATION
);
1097 return DISAS_NORETURN
;
1098 } else if (es
== ES_128
) {
1099 gen_gvec128_3_i64(tcg_gen_add2_i64
, get_field(s
->fields
, v1
),
1100 get_field(s
->fields
, v2
), get_field(s
->fields
, v3
));
1103 gen_gvec_fn_3(add
, es
, get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
1104 get_field(s
->fields
, v3
));
1108 static void gen_acc(TCGv_i64 d
, TCGv_i64 a
, TCGv_i64 b
, uint8_t es
)
1110 const uint8_t msb_bit_nr
= NUM_VEC_ELEMENT_BITS(es
) - 1;
1111 TCGv_i64 msb_mask
= tcg_const_i64(dup_const(es
, 1ull << msb_bit_nr
));
1112 TCGv_i64 t1
= tcg_temp_new_i64();
1113 TCGv_i64 t2
= tcg_temp_new_i64();
1114 TCGv_i64 t3
= tcg_temp_new_i64();
1116 /* Calculate the carry into the MSB, ignoring the old MSBs */
1117 tcg_gen_andc_i64(t1
, a
, msb_mask
);
1118 tcg_gen_andc_i64(t2
, b
, msb_mask
);
1119 tcg_gen_add_i64(t1
, t1
, t2
);
1120 /* Calculate the MSB without any carry into it */
1121 tcg_gen_xor_i64(t3
, a
, b
);
1122 /* Calculate the carry out of the MSB in the MSB bit position */
1123 tcg_gen_and_i64(d
, a
, b
);
1124 tcg_gen_and_i64(t1
, t1
, t3
);
1125 tcg_gen_or_i64(d
, d
, t1
);
1126 /* Isolate and shift the carry into position */
1127 tcg_gen_and_i64(d
, d
, msb_mask
);
1128 tcg_gen_shri_i64(d
, d
, msb_bit_nr
);
1130 tcg_temp_free_i64(t1
);
1131 tcg_temp_free_i64(t2
);
1132 tcg_temp_free_i64(t3
);
1135 static void gen_acc8_i64(TCGv_i64 d
, TCGv_i64 a
, TCGv_i64 b
)
1137 gen_acc(d
, a
, b
, ES_8
);
1140 static void gen_acc16_i64(TCGv_i64 d
, TCGv_i64 a
, TCGv_i64 b
)
1142 gen_acc(d
, a
, b
, ES_16
);
1145 static void gen_acc_i32(TCGv_i32 d
, TCGv_i32 a
, TCGv_i32 b
)
1147 TCGv_i32 t
= tcg_temp_new_i32();
1149 tcg_gen_add_i32(t
, a
, b
);
1150 tcg_gen_setcond_i32(TCG_COND_LTU
, d
, t
, b
);
1151 tcg_temp_free_i32(t
);
1154 static void gen_acc_i64(TCGv_i64 d
, TCGv_i64 a
, TCGv_i64 b
)
1156 TCGv_i64 t
= tcg_temp_new_i64();
1158 tcg_gen_add_i64(t
, a
, b
);
1159 tcg_gen_setcond_i64(TCG_COND_LTU
, d
, t
, b
);
1160 tcg_temp_free_i64(t
);
1163 static void gen_acc2_i64(TCGv_i64 dl
, TCGv_i64 dh
, TCGv_i64 al
,
1164 TCGv_i64 ah
, TCGv_i64 bl
, TCGv_i64 bh
)
1166 TCGv_i64 th
= tcg_temp_new_i64();
1167 TCGv_i64 tl
= tcg_temp_new_i64();
1168 TCGv_i64 zero
= tcg_const_i64(0);
1170 tcg_gen_add2_i64(tl
, th
, al
, zero
, bl
, zero
);
1171 tcg_gen_add2_i64(tl
, th
, th
, zero
, ah
, zero
);
1172 tcg_gen_add2_i64(tl
, dl
, tl
, th
, bh
, zero
);
1173 tcg_gen_mov_i64(dh
, zero
);
1175 tcg_temp_free_i64(th
);
1176 tcg_temp_free_i64(tl
);
1177 tcg_temp_free_i64(zero
);
1180 static DisasJumpType
op_vacc(DisasContext
*s
, DisasOps
*o
)
1182 const uint8_t es
= get_field(s
->fields
, m4
);
1183 static const GVecGen3 g
[4] = {
1184 { .fni8
= gen_acc8_i64
, },
1185 { .fni8
= gen_acc16_i64
, },
1186 { .fni4
= gen_acc_i32
, },
1187 { .fni8
= gen_acc_i64
, },
1191 gen_program_exception(s
, PGM_SPECIFICATION
);
1192 return DISAS_NORETURN
;
1193 } else if (es
== ES_128
) {
1194 gen_gvec128_3_i64(gen_acc2_i64
, get_field(s
->fields
, v1
),
1195 get_field(s
->fields
, v2
), get_field(s
->fields
, v3
));
1198 gen_gvec_3(get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
1199 get_field(s
->fields
, v3
), &g
[es
]);
1203 static void gen_ac2_i64(TCGv_i64 dl
, TCGv_i64 dh
, TCGv_i64 al
, TCGv_i64 ah
,
1204 TCGv_i64 bl
, TCGv_i64 bh
, TCGv_i64 cl
, TCGv_i64 ch
)
1206 TCGv_i64 tl
= tcg_temp_new_i64();
1207 TCGv_i64 th
= tcg_const_i64(0);
1209 /* extract the carry only */
1210 tcg_gen_extract_i64(tl
, cl
, 0, 1);
1211 tcg_gen_add2_i64(dl
, dh
, al
, ah
, bl
, bh
);
1212 tcg_gen_add2_i64(dl
, dh
, dl
, dh
, tl
, th
);
1214 tcg_temp_free_i64(tl
);
1215 tcg_temp_free_i64(th
);
1218 static DisasJumpType
op_vac(DisasContext
*s
, DisasOps
*o
)
1220 if (get_field(s
->fields
, m5
) != ES_128
) {
1221 gen_program_exception(s
, PGM_SPECIFICATION
);
1222 return DISAS_NORETURN
;
1225 gen_gvec128_4_i64(gen_ac2_i64
, get_field(s
->fields
, v1
),
1226 get_field(s
->fields
, v2
), get_field(s
->fields
, v3
),
1227 get_field(s
->fields
, v4
));
1231 static void gen_accc2_i64(TCGv_i64 dl
, TCGv_i64 dh
, TCGv_i64 al
, TCGv_i64 ah
,
1232 TCGv_i64 bl
, TCGv_i64 bh
, TCGv_i64 cl
, TCGv_i64 ch
)
1234 TCGv_i64 tl
= tcg_temp_new_i64();
1235 TCGv_i64 th
= tcg_temp_new_i64();
1236 TCGv_i64 zero
= tcg_const_i64(0);
1238 tcg_gen_andi_i64(tl
, cl
, 1);
1239 tcg_gen_add2_i64(tl
, th
, tl
, zero
, al
, zero
);
1240 tcg_gen_add2_i64(tl
, th
, tl
, th
, bl
, zero
);
1241 tcg_gen_add2_i64(tl
, th
, th
, zero
, ah
, zero
);
1242 tcg_gen_add2_i64(tl
, dl
, tl
, th
, bh
, zero
);
1243 tcg_gen_mov_i64(dh
, zero
);
1245 tcg_temp_free_i64(tl
);
1246 tcg_temp_free_i64(th
);
1247 tcg_temp_free_i64(zero
);
1250 static DisasJumpType
op_vaccc(DisasContext
*s
, DisasOps
*o
)
1252 if (get_field(s
->fields
, m5
) != ES_128
) {
1253 gen_program_exception(s
, PGM_SPECIFICATION
);
1254 return DISAS_NORETURN
;
1257 gen_gvec128_4_i64(gen_accc2_i64
, get_field(s
->fields
, v1
),
1258 get_field(s
->fields
, v2
), get_field(s
->fields
, v3
),
1259 get_field(s
->fields
, v4
));
1263 static DisasJumpType
op_vn(DisasContext
*s
, DisasOps
*o
)
1265 gen_gvec_fn_3(and, ES_8
, get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
1266 get_field(s
->fields
, v3
));
1270 static DisasJumpType
op_vnc(DisasContext
*s
, DisasOps
*o
)
1272 gen_gvec_fn_3(andc
, ES_8
, get_field(s
->fields
, v1
),
1273 get_field(s
->fields
, v2
), get_field(s
->fields
, v3
));
1277 static void gen_avg_i32(TCGv_i32 d
, TCGv_i32 a
, TCGv_i32 b
)
1279 TCGv_i64 t0
= tcg_temp_new_i64();
1280 TCGv_i64 t1
= tcg_temp_new_i64();
1282 tcg_gen_ext_i32_i64(t0
, a
);
1283 tcg_gen_ext_i32_i64(t1
, b
);
1284 tcg_gen_add_i64(t0
, t0
, t1
);
1285 tcg_gen_addi_i64(t0
, t0
, 1);
1286 tcg_gen_shri_i64(t0
, t0
, 1);
1287 tcg_gen_extrl_i64_i32(d
, t0
);
1293 static void gen_avg_i64(TCGv_i64 dl
, TCGv_i64 al
, TCGv_i64 bl
)
1295 TCGv_i64 dh
= tcg_temp_new_i64();
1296 TCGv_i64 ah
= tcg_temp_new_i64();
1297 TCGv_i64 bh
= tcg_temp_new_i64();
1299 /* extending the sign by one bit is sufficient */
1300 tcg_gen_extract_i64(ah
, al
, 63, 1);
1301 tcg_gen_extract_i64(bh
, bl
, 63, 1);
1302 tcg_gen_add2_i64(dl
, dh
, al
, ah
, bl
, bh
);
1303 gen_addi2_i64(dl
, dh
, dl
, dh
, 1);
1304 tcg_gen_extract2_i64(dl
, dl
, dh
, 1);
1306 tcg_temp_free_i64(dh
);
1307 tcg_temp_free_i64(ah
);
1308 tcg_temp_free_i64(bh
);
1311 static DisasJumpType
op_vavg(DisasContext
*s
, DisasOps
*o
)
1313 const uint8_t es
= get_field(s
->fields
, m4
);
1314 static const GVecGen3 g
[4] = {
1315 { .fno
= gen_helper_gvec_vavg8
, },
1316 { .fno
= gen_helper_gvec_vavg16
, },
1317 { .fni4
= gen_avg_i32
, },
1318 { .fni8
= gen_avg_i64
, },
1322 gen_program_exception(s
, PGM_SPECIFICATION
);
1323 return DISAS_NORETURN
;
1325 gen_gvec_3(get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
1326 get_field(s
->fields
, v3
), &g
[es
]);
1330 static void gen_avgl_i32(TCGv_i32 d
, TCGv_i32 a
, TCGv_i32 b
)
1332 TCGv_i64 t0
= tcg_temp_new_i64();
1333 TCGv_i64 t1
= tcg_temp_new_i64();
1335 tcg_gen_extu_i32_i64(t0
, a
);
1336 tcg_gen_extu_i32_i64(t1
, b
);
1337 tcg_gen_add_i64(t0
, t0
, t1
);
1338 tcg_gen_addi_i64(t0
, t0
, 1);
1339 tcg_gen_shri_i64(t0
, t0
, 1);
1340 tcg_gen_extrl_i64_i32(d
, t0
);
1346 static void gen_avgl_i64(TCGv_i64 dl
, TCGv_i64 al
, TCGv_i64 bl
)
1348 TCGv_i64 dh
= tcg_temp_new_i64();
1349 TCGv_i64 zero
= tcg_const_i64(0);
1351 tcg_gen_add2_i64(dl
, dh
, al
, zero
, bl
, zero
);
1352 gen_addi2_i64(dl
, dh
, dl
, dh
, 1);
1353 tcg_gen_extract2_i64(dl
, dl
, dh
, 1);
1355 tcg_temp_free_i64(dh
);
1356 tcg_temp_free_i64(zero
);
1359 static DisasJumpType
op_vavgl(DisasContext
*s
, DisasOps
*o
)
1361 const uint8_t es
= get_field(s
->fields
, m4
);
1362 static const GVecGen3 g
[4] = {
1363 { .fno
= gen_helper_gvec_vavgl8
, },
1364 { .fno
= gen_helper_gvec_vavgl16
, },
1365 { .fni4
= gen_avgl_i32
, },
1366 { .fni8
= gen_avgl_i64
, },
1370 gen_program_exception(s
, PGM_SPECIFICATION
);
1371 return DISAS_NORETURN
;
1373 gen_gvec_3(get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
1374 get_field(s
->fields
, v3
), &g
[es
]);
1378 static DisasJumpType
op_vcksm(DisasContext
*s
, DisasOps
*o
)
1380 TCGv_i32 tmp
= tcg_temp_new_i32();
1381 TCGv_i32 sum
= tcg_temp_new_i32();
1384 read_vec_element_i32(sum
, get_field(s
->fields
, v3
), 1, ES_32
);
1385 for (i
= 0; i
< 4; i
++) {
1386 read_vec_element_i32(tmp
, get_field(s
->fields
, v2
), i
, ES_32
);
1387 tcg_gen_add2_i32(tmp
, sum
, sum
, sum
, tmp
, tmp
);
1389 zero_vec(get_field(s
->fields
, v1
));
1390 write_vec_element_i32(sum
, get_field(s
->fields
, v1
), 1, ES_32
);
1392 tcg_temp_free_i32(tmp
);
1393 tcg_temp_free_i32(sum
);
1397 static DisasJumpType
op_vec(DisasContext
*s
, DisasOps
*o
)
1399 uint8_t es
= get_field(s
->fields
, m3
);
1400 const uint8_t enr
= NUM_VEC_ELEMENTS(es
) / 2 - 1;
1403 gen_program_exception(s
, PGM_SPECIFICATION
);
1404 return DISAS_NORETURN
;
1406 if (s
->fields
->op2
== 0xdb) {
1410 o
->in1
= tcg_temp_new_i64();
1411 o
->in2
= tcg_temp_new_i64();
1412 read_vec_element_i64(o
->in1
, get_field(s
->fields
, v1
), enr
, es
);
1413 read_vec_element_i64(o
->in2
, get_field(s
->fields
, v2
), enr
, es
);
1417 static DisasJumpType
op_vc(DisasContext
*s
, DisasOps
*o
)
1419 const uint8_t es
= get_field(s
->fields
, m4
);
1420 TCGCond cond
= s
->insn
->data
;
1423 gen_program_exception(s
, PGM_SPECIFICATION
);
1424 return DISAS_NORETURN
;
1427 tcg_gen_gvec_cmp(cond
, es
,
1428 vec_full_reg_offset(get_field(s
->fields
, v1
)),
1429 vec_full_reg_offset(get_field(s
->fields
, v2
)),
1430 vec_full_reg_offset(get_field(s
->fields
, v3
)), 16, 16);
1431 if (get_field(s
->fields
, m5
) & 0x1) {
1432 TCGv_i64 low
= tcg_temp_new_i64();
1433 TCGv_i64 high
= tcg_temp_new_i64();
1435 read_vec_element_i64(high
, get_field(s
->fields
, v1
), 0, ES_64
);
1436 read_vec_element_i64(low
, get_field(s
->fields
, v1
), 1, ES_64
);
1437 gen_op_update2_cc_i64(s
, CC_OP_VC
, low
, high
);
1439 tcg_temp_free_i64(low
);
1440 tcg_temp_free_i64(high
);
1445 static void gen_clz_i32(TCGv_i32 d
, TCGv_i32 a
)
1447 tcg_gen_clzi_i32(d
, a
, 32);
1450 static void gen_clz_i64(TCGv_i64 d
, TCGv_i64 a
)
1452 tcg_gen_clzi_i64(d
, a
, 64);
1455 static DisasJumpType
op_vclz(DisasContext
*s
, DisasOps
*o
)
1457 const uint8_t es
= get_field(s
->fields
, m3
);
1458 static const GVecGen2 g
[4] = {
1459 { .fno
= gen_helper_gvec_vclz8
, },
1460 { .fno
= gen_helper_gvec_vclz16
, },
1461 { .fni4
= gen_clz_i32
, },
1462 { .fni8
= gen_clz_i64
, },
1466 gen_program_exception(s
, PGM_SPECIFICATION
);
1467 return DISAS_NORETURN
;
1469 gen_gvec_2(get_field(s
->fields
, v1
), get_field(s
->fields
, v2
), &g
[es
]);
1473 static void gen_ctz_i32(TCGv_i32 d
, TCGv_i32 a
)
1475 tcg_gen_ctzi_i32(d
, a
, 32);
1478 static void gen_ctz_i64(TCGv_i64 d
, TCGv_i64 a
)
1480 tcg_gen_ctzi_i64(d
, a
, 64);
1483 static DisasJumpType
op_vctz(DisasContext
*s
, DisasOps
*o
)
1485 const uint8_t es
= get_field(s
->fields
, m3
);
1486 static const GVecGen2 g
[4] = {
1487 { .fno
= gen_helper_gvec_vctz8
, },
1488 { .fno
= gen_helper_gvec_vctz16
, },
1489 { .fni4
= gen_ctz_i32
, },
1490 { .fni8
= gen_ctz_i64
, },
1494 gen_program_exception(s
, PGM_SPECIFICATION
);
1495 return DISAS_NORETURN
;
1497 gen_gvec_2(get_field(s
->fields
, v1
), get_field(s
->fields
, v2
), &g
[es
]);
1501 static DisasJumpType
op_vx(DisasContext
*s
, DisasOps
*o
)
1503 gen_gvec_fn_3(xor, ES_8
, get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
1504 get_field(s
->fields
, v3
));
1508 static DisasJumpType
op_vgfm(DisasContext
*s
, DisasOps
*o
)
1510 const uint8_t es
= get_field(s
->fields
, m4
);
1511 static const GVecGen3 g
[4] = {
1512 { .fno
= gen_helper_gvec_vgfm8
, },
1513 { .fno
= gen_helper_gvec_vgfm16
, },
1514 { .fno
= gen_helper_gvec_vgfm32
, },
1515 { .fno
= gen_helper_gvec_vgfm64
, },
1519 gen_program_exception(s
, PGM_SPECIFICATION
);
1520 return DISAS_NORETURN
;
1522 gen_gvec_3(get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
1523 get_field(s
->fields
, v3
), &g
[es
]);
1527 static DisasJumpType
op_vgfma(DisasContext
*s
, DisasOps
*o
)
1529 const uint8_t es
= get_field(s
->fields
, m5
);
1530 static const GVecGen4 g
[4] = {
1531 { .fno
= gen_helper_gvec_vgfma8
, },
1532 { .fno
= gen_helper_gvec_vgfma16
, },
1533 { .fno
= gen_helper_gvec_vgfma32
, },
1534 { .fno
= gen_helper_gvec_vgfma64
, },
1538 gen_program_exception(s
, PGM_SPECIFICATION
);
1539 return DISAS_NORETURN
;
1541 gen_gvec_4(get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
1542 get_field(s
->fields
, v3
), get_field(s
->fields
, v4
), &g
[es
]);
1546 static DisasJumpType
op_vlc(DisasContext
*s
, DisasOps
*o
)
1548 const uint8_t es
= get_field(s
->fields
, m3
);
1551 gen_program_exception(s
, PGM_SPECIFICATION
);
1552 return DISAS_NORETURN
;
1555 gen_gvec_fn_2(neg
, es
, get_field(s
->fields
, v1
), get_field(s
->fields
, v2
));
1559 static DisasJumpType
op_vlp(DisasContext
*s
, DisasOps
*o
)
1561 const uint8_t es
= get_field(s
->fields
, m3
);
1564 gen_program_exception(s
, PGM_SPECIFICATION
);
1565 return DISAS_NORETURN
;
1568 gen_gvec_fn_2(abs
, es
, get_field(s
->fields
, v1
), get_field(s
->fields
, v2
));
1572 static DisasJumpType
op_vmx(DisasContext
*s
, DisasOps
*o
)
1574 const uint8_t v1
= get_field(s
->fields
, v1
);
1575 const uint8_t v2
= get_field(s
->fields
, v2
);
1576 const uint8_t v3
= get_field(s
->fields
, v3
);
1577 const uint8_t es
= get_field(s
->fields
, m4
);
1580 gen_program_exception(s
, PGM_SPECIFICATION
);
1581 return DISAS_NORETURN
;
1584 switch (s
->fields
->op2
) {
1586 gen_gvec_fn_3(smax
, es
, v1
, v2
, v3
);
1589 gen_gvec_fn_3(umax
, es
, v1
, v2
, v3
);
1592 gen_gvec_fn_3(smin
, es
, v1
, v2
, v3
);
1595 gen_gvec_fn_3(umin
, es
, v1
, v2
, v3
);
1598 g_assert_not_reached();
1603 static void gen_mal_i32(TCGv_i32 d
, TCGv_i32 a
, TCGv_i32 b
, TCGv_i32 c
)
1605 TCGv_i32 t0
= tcg_temp_new_i32();
1607 tcg_gen_mul_i32(t0
, a
, b
);
1608 tcg_gen_add_i32(d
, t0
, c
);
1610 tcg_temp_free_i32(t0
);
1613 static void gen_mah_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_ext_i32_i64(t0
, a
);
1620 tcg_gen_ext_i32_i64(t1
, b
);
1621 tcg_gen_ext_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 void gen_malh_i32(TCGv_i32 d
, TCGv_i32 a
, TCGv_i32 b
, TCGv_i32 c
)
1633 TCGv_i64 t0
= tcg_temp_new_i64();
1634 TCGv_i64 t1
= tcg_temp_new_i64();
1635 TCGv_i64 t2
= tcg_temp_new_i64();
1637 tcg_gen_extu_i32_i64(t0
, a
);
1638 tcg_gen_extu_i32_i64(t1
, b
);
1639 tcg_gen_extu_i32_i64(t2
, c
);
1640 tcg_gen_mul_i64(t0
, t0
, t1
);
1641 tcg_gen_add_i64(t0
, t0
, t2
);
1642 tcg_gen_extrh_i64_i32(d
, t0
);
1649 static DisasJumpType
op_vma(DisasContext
*s
, DisasOps
*o
)
1651 const uint8_t es
= get_field(s
->fields
, m5
);
1652 static const GVecGen4 g_vmal
[3] = {
1653 { .fno
= gen_helper_gvec_vmal8
, },
1654 { .fno
= gen_helper_gvec_vmal16
, },
1655 { .fni4
= gen_mal_i32
, },
1657 static const GVecGen4 g_vmah
[3] = {
1658 { .fno
= gen_helper_gvec_vmah8
, },
1659 { .fno
= gen_helper_gvec_vmah16
, },
1660 { .fni4
= gen_mah_i32
, },
1662 static const GVecGen4 g_vmalh
[3] = {
1663 { .fno
= gen_helper_gvec_vmalh8
, },
1664 { .fno
= gen_helper_gvec_vmalh16
, },
1665 { .fni4
= gen_malh_i32
, },
1667 static const GVecGen4 g_vmae
[3] = {
1668 { .fno
= gen_helper_gvec_vmae8
, },
1669 { .fno
= gen_helper_gvec_vmae16
, },
1670 { .fno
= gen_helper_gvec_vmae32
, },
1672 static const GVecGen4 g_vmale
[3] = {
1673 { .fno
= gen_helper_gvec_vmale8
, },
1674 { .fno
= gen_helper_gvec_vmale16
, },
1675 { .fno
= gen_helper_gvec_vmale32
, },
1677 static const GVecGen4 g_vmao
[3] = {
1678 { .fno
= gen_helper_gvec_vmao8
, },
1679 { .fno
= gen_helper_gvec_vmao16
, },
1680 { .fno
= gen_helper_gvec_vmao32
, },
1682 static const GVecGen4 g_vmalo
[3] = {
1683 { .fno
= gen_helper_gvec_vmalo8
, },
1684 { .fno
= gen_helper_gvec_vmalo16
, },
1685 { .fno
= gen_helper_gvec_vmalo32
, },
1690 gen_program_exception(s
, PGM_SPECIFICATION
);
1691 return DISAS_NORETURN
;
1694 switch (s
->fields
->op2
) {
1717 g_assert_not_reached();
1720 gen_gvec_4(get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
1721 get_field(s
->fields
, v3
), get_field(s
->fields
, v4
), fn
);
1725 static void gen_mh_i32(TCGv_i32 d
, TCGv_i32 a
, TCGv_i32 b
)
1727 TCGv_i32 t
= tcg_temp_new_i32();
1729 tcg_gen_muls2_i32(t
, d
, a
, b
);
1730 tcg_temp_free_i32(t
);
1733 static void gen_mlh_i32(TCGv_i32 d
, TCGv_i32 a
, TCGv_i32 b
)
1735 TCGv_i32 t
= tcg_temp_new_i32();
1737 tcg_gen_mulu2_i32(t
, d
, a
, b
);
1738 tcg_temp_free_i32(t
);
1741 static DisasJumpType
op_vm(DisasContext
*s
, DisasOps
*o
)
1743 const uint8_t es
= get_field(s
->fields
, m4
);
1744 static const GVecGen3 g_vmh
[3] = {
1745 { .fno
= gen_helper_gvec_vmh8
, },
1746 { .fno
= gen_helper_gvec_vmh16
, },
1747 { .fni4
= gen_mh_i32
, },
1749 static const GVecGen3 g_vmlh
[3] = {
1750 { .fno
= gen_helper_gvec_vmlh8
, },
1751 { .fno
= gen_helper_gvec_vmlh16
, },
1752 { .fni4
= gen_mlh_i32
, },
1754 static const GVecGen3 g_vme
[3] = {
1755 { .fno
= gen_helper_gvec_vme8
, },
1756 { .fno
= gen_helper_gvec_vme16
, },
1757 { .fno
= gen_helper_gvec_vme32
, },
1759 static const GVecGen3 g_vmle
[3] = {
1760 { .fno
= gen_helper_gvec_vmle8
, },
1761 { .fno
= gen_helper_gvec_vmle16
, },
1762 { .fno
= gen_helper_gvec_vmle32
, },
1764 static const GVecGen3 g_vmo
[3] = {
1765 { .fno
= gen_helper_gvec_vmo8
, },
1766 { .fno
= gen_helper_gvec_vmo16
, },
1767 { .fno
= gen_helper_gvec_vmo32
, },
1769 static const GVecGen3 g_vmlo
[3] = {
1770 { .fno
= gen_helper_gvec_vmlo8
, },
1771 { .fno
= gen_helper_gvec_vmlo16
, },
1772 { .fno
= gen_helper_gvec_vmlo32
, },
1777 gen_program_exception(s
, PGM_SPECIFICATION
);
1778 return DISAS_NORETURN
;
1781 switch (s
->fields
->op2
) {
1783 gen_gvec_fn_3(mul
, es
, get_field(s
->fields
, v1
),
1784 get_field(s
->fields
, v2
), get_field(s
->fields
, v3
));
1805 g_assert_not_reached();
1808 gen_gvec_3(get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
1809 get_field(s
->fields
, v3
), fn
);
1813 static DisasJumpType
op_vnn(DisasContext
*s
, DisasOps
*o
)
1815 gen_gvec_fn_3(nand
, ES_8
, get_field(s
->fields
, v1
),
1816 get_field(s
->fields
, v2
), get_field(s
->fields
, v3
));
1820 static DisasJumpType
op_vno(DisasContext
*s
, DisasOps
*o
)
1822 gen_gvec_fn_3(nor
, ES_8
, get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
1823 get_field(s
->fields
, v3
));
1827 static DisasJumpType
op_vnx(DisasContext
*s
, DisasOps
*o
)
1829 gen_gvec_fn_3(eqv
, ES_8
, get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
1830 get_field(s
->fields
, v3
));
1834 static DisasJumpType
op_vo(DisasContext
*s
, DisasOps
*o
)
1836 gen_gvec_fn_3(or, ES_8
, get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
1837 get_field(s
->fields
, v3
));
1841 static DisasJumpType
op_voc(DisasContext
*s
, DisasOps
*o
)
1843 gen_gvec_fn_3(orc
, ES_8
, get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
1844 get_field(s
->fields
, v3
));
1848 static DisasJumpType
op_vpopct(DisasContext
*s
, DisasOps
*o
)
1850 const uint8_t es
= get_field(s
->fields
, m3
);
1851 static const GVecGen2 g
[4] = {
1852 { .fno
= gen_helper_gvec_vpopct8
, },
1853 { .fno
= gen_helper_gvec_vpopct16
, },
1854 { .fni4
= tcg_gen_ctpop_i32
, },
1855 { .fni8
= tcg_gen_ctpop_i64
, },
1858 if (es
> ES_64
|| (es
!= ES_8
&& !s390_has_feat(S390_FEAT_VECTOR_ENH
))) {
1859 gen_program_exception(s
, PGM_SPECIFICATION
);
1860 return DISAS_NORETURN
;
1863 gen_gvec_2(get_field(s
->fields
, v1
), get_field(s
->fields
, v2
), &g
[es
]);
1867 static void gen_rll_i32(TCGv_i32 d
, TCGv_i32 a
, TCGv_i32 b
)
1869 TCGv_i32 t0
= tcg_temp_new_i32();
1871 tcg_gen_andi_i32(t0
, b
, 31);
1872 tcg_gen_rotl_i32(d
, a
, t0
);
1873 tcg_temp_free_i32(t0
);
1876 static void gen_rll_i64(TCGv_i64 d
, TCGv_i64 a
, TCGv_i64 b
)
1878 TCGv_i64 t0
= tcg_temp_new_i64();
1880 tcg_gen_andi_i64(t0
, b
, 63);
1881 tcg_gen_rotl_i64(d
, a
, t0
);
1882 tcg_temp_free_i64(t0
);
1885 static DisasJumpType
op_verllv(DisasContext
*s
, DisasOps
*o
)
1887 const uint8_t es
= get_field(s
->fields
, m4
);
1888 static const GVecGen3 g
[4] = {
1889 { .fno
= gen_helper_gvec_verllv8
, },
1890 { .fno
= gen_helper_gvec_verllv16
, },
1891 { .fni4
= gen_rll_i32
, },
1892 { .fni8
= gen_rll_i64
, },
1896 gen_program_exception(s
, PGM_SPECIFICATION
);
1897 return DISAS_NORETURN
;
1900 gen_gvec_3(get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
1901 get_field(s
->fields
, v3
), &g
[es
]);
1905 static DisasJumpType
op_verll(DisasContext
*s
, DisasOps
*o
)
1907 const uint8_t es
= get_field(s
->fields
, m4
);
1908 static const GVecGen2s g
[4] = {
1909 { .fno
= gen_helper_gvec_verll8
, },
1910 { .fno
= gen_helper_gvec_verll16
, },
1911 { .fni4
= gen_rll_i32
, },
1912 { .fni8
= gen_rll_i64
, },
1916 gen_program_exception(s
, PGM_SPECIFICATION
);
1917 return DISAS_NORETURN
;
1919 gen_gvec_2s(get_field(s
->fields
, v1
), get_field(s
->fields
, v3
), o
->addr1
,
1924 static void gen_rim_i32(TCGv_i32 d
, TCGv_i32 a
, TCGv_i32 b
, int32_t c
)
1926 TCGv_i32 t
= tcg_temp_new_i32();
1928 tcg_gen_rotli_i32(t
, a
, c
& 31);
1929 tcg_gen_and_i32(t
, t
, b
);
1930 tcg_gen_andc_i32(d
, d
, b
);
1931 tcg_gen_or_i32(d
, d
, t
);
1933 tcg_temp_free_i32(t
);
1936 static void gen_rim_i64(TCGv_i64 d
, TCGv_i64 a
, TCGv_i64 b
, int64_t c
)
1938 TCGv_i64 t
= tcg_temp_new_i64();
1940 tcg_gen_rotli_i64(t
, a
, c
& 63);
1941 tcg_gen_and_i64(t
, t
, b
);
1942 tcg_gen_andc_i64(d
, d
, b
);
1943 tcg_gen_or_i64(d
, d
, t
);
1945 tcg_temp_free_i64(t
);
1948 static DisasJumpType
op_verim(DisasContext
*s
, DisasOps
*o
)
1950 const uint8_t es
= get_field(s
->fields
, m5
);
1951 const uint8_t i4
= get_field(s
->fields
, i4
) &
1952 (NUM_VEC_ELEMENT_BITS(es
) - 1);
1953 static const GVecGen3i g
[4] = {
1954 { .fno
= gen_helper_gvec_verim8
, },
1955 { .fno
= gen_helper_gvec_verim16
, },
1956 { .fni4
= gen_rim_i32
,
1957 .load_dest
= true, },
1958 { .fni8
= gen_rim_i64
,
1959 .load_dest
= true, },
1963 gen_program_exception(s
, PGM_SPECIFICATION
);
1964 return DISAS_NORETURN
;
1967 gen_gvec_3i(get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
1968 get_field(s
->fields
, v3
), i4
, &g
[es
]);
1972 static DisasJumpType
op_vesv(DisasContext
*s
, DisasOps
*o
)
1974 const uint8_t es
= get_field(s
->fields
, m4
);
1975 const uint8_t v1
= get_field(s
->fields
, v1
);
1976 const uint8_t v2
= get_field(s
->fields
, v2
);
1977 const uint8_t v3
= get_field(s
->fields
, v3
);
1980 gen_program_exception(s
, PGM_SPECIFICATION
);
1981 return DISAS_NORETURN
;
1984 switch (s
->fields
->op2
) {
1986 gen_gvec_fn_3(shlv
, es
, v1
, v2
, v3
);
1989 gen_gvec_fn_3(sarv
, es
, v1
, v2
, v3
);
1992 gen_gvec_fn_3(shrv
, es
, v1
, v2
, v3
);
1995 g_assert_not_reached();
2000 static DisasJumpType
op_ves(DisasContext
*s
, DisasOps
*o
)
2002 const uint8_t es
= get_field(s
->fields
, m4
);
2003 const uint8_t d2
= get_field(s
->fields
, d2
) &
2004 (NUM_VEC_ELEMENT_BITS(es
) - 1);
2005 const uint8_t v1
= get_field(s
->fields
, v1
);
2006 const uint8_t v3
= get_field(s
->fields
, v3
);
2010 gen_program_exception(s
, PGM_SPECIFICATION
);
2011 return DISAS_NORETURN
;
2014 if (likely(!get_field(s
->fields
, b2
))) {
2015 switch (s
->fields
->op2
) {
2017 gen_gvec_fn_2i(shli
, es
, v1
, v3
, d2
);
2020 gen_gvec_fn_2i(sari
, es
, v1
, v3
, d2
);
2023 gen_gvec_fn_2i(shri
, es
, v1
, v3
, d2
);
2026 g_assert_not_reached();
2029 shift
= tcg_temp_new_i32();
2030 tcg_gen_extrl_i64_i32(shift
, o
->addr1
);
2031 tcg_gen_andi_i32(shift
, shift
, NUM_VEC_ELEMENT_BITS(es
) - 1);
2032 switch (s
->fields
->op2
) {
2034 gen_gvec_fn_2s(shls
, es
, v1
, v3
, shift
);
2037 gen_gvec_fn_2s(sars
, es
, v1
, v3
, shift
);
2040 gen_gvec_fn_2s(shrs
, es
, v1
, v3
, shift
);
2043 g_assert_not_reached();
2045 tcg_temp_free_i32(shift
);
2050 static DisasJumpType
op_vsl(DisasContext
*s
, DisasOps
*o
)
2052 TCGv_i64 shift
= tcg_temp_new_i64();
2054 read_vec_element_i64(shift
, get_field(s
->fields
, v3
), 7, ES_8
);
2055 if (s
->fields
->op2
== 0x74) {
2056 tcg_gen_andi_i64(shift
, shift
, 0x7);
2058 tcg_gen_andi_i64(shift
, shift
, 0x78);
2061 gen_gvec_2i_ool(get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
2062 shift
, 0, gen_helper_gvec_vsl
);
2063 tcg_temp_free_i64(shift
);
2067 static DisasJumpType
op_vsldb(DisasContext
*s
, DisasOps
*o
)
2069 const uint8_t i4
= get_field(s
->fields
, i4
) & 0xf;
2070 const int left_shift
= (i4
& 7) * 8;
2071 const int right_shift
= 64 - left_shift
;
2072 TCGv_i64 t0
= tcg_temp_new_i64();
2073 TCGv_i64 t1
= tcg_temp_new_i64();
2074 TCGv_i64 t2
= tcg_temp_new_i64();
2076 if ((i4
& 8) == 0) {
2077 read_vec_element_i64(t0
, get_field(s
->fields
, v2
), 0, ES_64
);
2078 read_vec_element_i64(t1
, get_field(s
->fields
, v2
), 1, ES_64
);
2079 read_vec_element_i64(t2
, get_field(s
->fields
, v3
), 0, ES_64
);
2081 read_vec_element_i64(t0
, get_field(s
->fields
, v2
), 1, ES_64
);
2082 read_vec_element_i64(t1
, get_field(s
->fields
, v3
), 0, ES_64
);
2083 read_vec_element_i64(t2
, get_field(s
->fields
, v3
), 1, ES_64
);
2085 tcg_gen_extract2_i64(t0
, t1
, t0
, right_shift
);
2086 tcg_gen_extract2_i64(t1
, t2
, t1
, right_shift
);
2087 write_vec_element_i64(t0
, get_field(s
->fields
, v1
), 0, ES_64
);
2088 write_vec_element_i64(t1
, get_field(s
->fields
, v1
), 1, ES_64
);
2096 static DisasJumpType
op_vsra(DisasContext
*s
, DisasOps
*o
)
2098 TCGv_i64 shift
= tcg_temp_new_i64();
2100 read_vec_element_i64(shift
, get_field(s
->fields
, v3
), 7, ES_8
);
2101 if (s
->fields
->op2
== 0x7e) {
2102 tcg_gen_andi_i64(shift
, shift
, 0x7);
2104 tcg_gen_andi_i64(shift
, shift
, 0x78);
2107 gen_gvec_2i_ool(get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
2108 shift
, 0, gen_helper_gvec_vsra
);
2109 tcg_temp_free_i64(shift
);
2113 static DisasJumpType
op_vsrl(DisasContext
*s
, DisasOps
*o
)
2115 TCGv_i64 shift
= tcg_temp_new_i64();
2117 read_vec_element_i64(shift
, get_field(s
->fields
, v3
), 7, ES_8
);
2118 if (s
->fields
->op2
== 0x7c) {
2119 tcg_gen_andi_i64(shift
, shift
, 0x7);
2121 tcg_gen_andi_i64(shift
, shift
, 0x78);
2124 gen_gvec_2i_ool(get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
2125 shift
, 0, gen_helper_gvec_vsrl
);
2126 tcg_temp_free_i64(shift
);
2130 static DisasJumpType
op_vs(DisasContext
*s
, DisasOps
*o
)
2132 const uint8_t es
= get_field(s
->fields
, m4
);
2135 gen_program_exception(s
, PGM_SPECIFICATION
);
2136 return DISAS_NORETURN
;
2137 } else if (es
== ES_128
) {
2138 gen_gvec128_3_i64(tcg_gen_sub2_i64
, get_field(s
->fields
, v1
),
2139 get_field(s
->fields
, v2
), get_field(s
->fields
, v3
));
2142 gen_gvec_fn_3(sub
, es
, get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
2143 get_field(s
->fields
, v3
));
2147 static void gen_scbi_i32(TCGv_i32 d
, TCGv_i32 a
, TCGv_i32 b
)
2149 tcg_gen_setcond_i32(TCG_COND_LTU
, d
, a
, b
);
2152 static void gen_scbi_i64(TCGv_i64 d
, TCGv_i64 a
, TCGv_i64 b
)
2154 tcg_gen_setcond_i64(TCG_COND_LTU
, d
, a
, b
);
2157 static void gen_scbi2_i64(TCGv_i64 dl
, TCGv_i64 dh
, TCGv_i64 al
,
2158 TCGv_i64 ah
, TCGv_i64 bl
, TCGv_i64 bh
)
2160 TCGv_i64 th
= tcg_temp_new_i64();
2161 TCGv_i64 tl
= tcg_temp_new_i64();
2162 TCGv_i64 zero
= tcg_const_i64(0);
2164 tcg_gen_sub2_i64(tl
, th
, al
, zero
, bl
, zero
);
2165 tcg_gen_andi_i64(th
, th
, 1);
2166 tcg_gen_sub2_i64(tl
, th
, ah
, zero
, th
, zero
);
2167 tcg_gen_sub2_i64(tl
, th
, tl
, th
, bh
, zero
);
2168 tcg_gen_andi_i64(dl
, th
, 1);
2169 tcg_gen_mov_i64(dh
, zero
);
2171 tcg_temp_free_i64(th
);
2172 tcg_temp_free_i64(tl
);
2173 tcg_temp_free_i64(zero
);
2176 static DisasJumpType
op_vscbi(DisasContext
*s
, DisasOps
*o
)
2178 const uint8_t es
= get_field(s
->fields
, m4
);
2179 static const GVecGen3 g
[4] = {
2180 { .fno
= gen_helper_gvec_vscbi8
, },
2181 { .fno
= gen_helper_gvec_vscbi16
, },
2182 { .fni4
= gen_scbi_i32
, },
2183 { .fni8
= gen_scbi_i64
, },
2187 gen_program_exception(s
, PGM_SPECIFICATION
);
2188 return DISAS_NORETURN
;
2189 } else if (es
== ES_128
) {
2190 gen_gvec128_3_i64(gen_scbi2_i64
, get_field(s
->fields
, v1
),
2191 get_field(s
->fields
, v2
), get_field(s
->fields
, v3
));
2194 gen_gvec_3(get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
2195 get_field(s
->fields
, v3
), &g
[es
]);
2199 static void gen_sbi2_i64(TCGv_i64 dl
, TCGv_i64 dh
, TCGv_i64 al
, TCGv_i64 ah
,
2200 TCGv_i64 bl
, TCGv_i64 bh
, TCGv_i64 cl
, TCGv_i64 ch
)
2202 TCGv_i64 tl
= tcg_temp_new_i64();
2203 TCGv_i64 zero
= tcg_const_i64(0);
2205 tcg_gen_andi_i64(tl
, cl
, 1);
2206 tcg_gen_sub2_i64(dl
, dh
, al
, ah
, bl
, bh
);
2207 tcg_gen_sub2_i64(dl
, dh
, dl
, dh
, tl
, zero
);
2208 tcg_temp_free_i64(tl
);
2209 tcg_temp_free_i64(zero
);
2212 static DisasJumpType
op_vsbi(DisasContext
*s
, DisasOps
*o
)
2214 if (get_field(s
->fields
, m5
) != ES_128
) {
2215 gen_program_exception(s
, PGM_SPECIFICATION
);
2216 return DISAS_NORETURN
;
2219 gen_gvec128_4_i64(gen_sbi2_i64
, get_field(s
->fields
, v1
),
2220 get_field(s
->fields
, v2
), get_field(s
->fields
, v3
),
2221 get_field(s
->fields
, v4
));
2225 static void gen_sbcbi2_i64(TCGv_i64 dl
, TCGv_i64 dh
, TCGv_i64 al
, TCGv_i64 ah
,
2226 TCGv_i64 bl
, TCGv_i64 bh
, TCGv_i64 cl
, TCGv_i64 ch
)
2228 TCGv_i64 th
= tcg_temp_new_i64();
2229 TCGv_i64 tl
= tcg_temp_new_i64();
2230 TCGv_i64 zero
= tcg_const_i64(0);
2232 tcg_gen_andi_i64(tl
, cl
, 1);
2233 tcg_gen_sub2_i64(tl
, th
, al
, zero
, tl
, zero
);
2234 tcg_gen_sub2_i64(tl
, th
, tl
, th
, bl
, zero
);
2235 tcg_gen_andi_i64(th
, th
, 1);
2236 tcg_gen_sub2_i64(tl
, th
, ah
, zero
, th
, zero
);
2237 tcg_gen_sub2_i64(tl
, th
, tl
, th
, bh
, zero
);
2238 tcg_gen_andi_i64(dl
, th
, 1);
2239 tcg_gen_mov_i64(dh
, zero
);
2241 tcg_temp_free_i64(tl
);
2242 tcg_temp_free_i64(th
);
2243 tcg_temp_free_i64(zero
);
2246 static DisasJumpType
op_vsbcbi(DisasContext
*s
, DisasOps
*o
)
2248 if (get_field(s
->fields
, m5
) != ES_128
) {
2249 gen_program_exception(s
, PGM_SPECIFICATION
);
2250 return DISAS_NORETURN
;
2253 gen_gvec128_4_i64(gen_sbcbi2_i64
, get_field(s
->fields
, v1
),
2254 get_field(s
->fields
, v2
), get_field(s
->fields
, v3
),
2255 get_field(s
->fields
, v4
));
2259 static DisasJumpType
op_vsumg(DisasContext
*s
, DisasOps
*o
)
2261 const uint8_t es
= get_field(s
->fields
, m4
);
2265 if (es
== ES_8
|| es
> ES_32
) {
2266 gen_program_exception(s
, PGM_SPECIFICATION
);
2267 return DISAS_NORETURN
;
2270 sum
= tcg_temp_new_i64();
2271 tmp
= tcg_temp_new_i64();
2272 for (dst_idx
= 0; dst_idx
< 2; dst_idx
++) {
2273 uint8_t idx
= dst_idx
* NUM_VEC_ELEMENTS(es
) / 2;
2274 const uint8_t max_idx
= idx
+ NUM_VEC_ELEMENTS(es
) / 2 - 1;
2276 read_vec_element_i64(sum
, get_field(s
->fields
, v3
), max_idx
, es
);
2277 for (; idx
<= max_idx
; idx
++) {
2278 read_vec_element_i64(tmp
, get_field(s
->fields
, v2
), idx
, es
);
2279 tcg_gen_add_i64(sum
, sum
, tmp
);
2281 write_vec_element_i64(sum
, get_field(s
->fields
, v1
), dst_idx
, ES_64
);
2283 tcg_temp_free_i64(sum
);
2284 tcg_temp_free_i64(tmp
);
2288 static DisasJumpType
op_vsumq(DisasContext
*s
, DisasOps
*o
)
2290 const uint8_t es
= get_field(s
->fields
, m4
);
2291 const uint8_t max_idx
= NUM_VEC_ELEMENTS(es
) - 1;
2292 TCGv_i64 sumh
, suml
, zero
, tmpl
;
2295 if (es
< ES_32
|| es
> ES_64
) {
2296 gen_program_exception(s
, PGM_SPECIFICATION
);
2297 return DISAS_NORETURN
;
2300 sumh
= tcg_const_i64(0);
2301 suml
= tcg_temp_new_i64();
2302 zero
= tcg_const_i64(0);
2303 tmpl
= tcg_temp_new_i64();
2305 read_vec_element_i64(suml
, get_field(s
->fields
, v3
), max_idx
, es
);
2306 for (idx
= 0; idx
<= max_idx
; idx
++) {
2307 read_vec_element_i64(tmpl
, get_field(s
->fields
, v2
), idx
, es
);
2308 tcg_gen_add2_i64(suml
, sumh
, suml
, sumh
, tmpl
, zero
);
2310 write_vec_element_i64(sumh
, get_field(s
->fields
, v1
), 0, ES_64
);
2311 write_vec_element_i64(suml
, get_field(s
->fields
, v1
), 1, ES_64
);
2313 tcg_temp_free_i64(sumh
);
2314 tcg_temp_free_i64(suml
);
2315 tcg_temp_free_i64(zero
);
2316 tcg_temp_free_i64(tmpl
);
2320 static DisasJumpType
op_vsum(DisasContext
*s
, DisasOps
*o
)
2322 const uint8_t es
= get_field(s
->fields
, m4
);
2327 gen_program_exception(s
, PGM_SPECIFICATION
);
2328 return DISAS_NORETURN
;
2331 sum
= tcg_temp_new_i32();
2332 tmp
= tcg_temp_new_i32();
2333 for (dst_idx
= 0; dst_idx
< 4; dst_idx
++) {
2334 uint8_t idx
= dst_idx
* NUM_VEC_ELEMENTS(es
) / 4;
2335 const uint8_t max_idx
= idx
+ NUM_VEC_ELEMENTS(es
) / 4 - 1;
2337 read_vec_element_i32(sum
, get_field(s
->fields
, v3
), max_idx
, es
);
2338 for (; idx
<= max_idx
; idx
++) {
2339 read_vec_element_i32(tmp
, get_field(s
->fields
, v2
), idx
, es
);
2340 tcg_gen_add_i32(sum
, sum
, tmp
);
2342 write_vec_element_i32(sum
, get_field(s
->fields
, v1
), dst_idx
, ES_32
);
2344 tcg_temp_free_i32(sum
);
2345 tcg_temp_free_i32(tmp
);
2349 static DisasJumpType
op_vtm(DisasContext
*s
, DisasOps
*o
)
2351 gen_gvec_2_ptr(get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
2352 cpu_env
, 0, gen_helper_gvec_vtm
);
2357 static DisasJumpType
op_vfae(DisasContext
*s
, DisasOps
*o
)
2359 const uint8_t es
= get_field(s
->fields
, m4
);
2360 const uint8_t m5
= get_field(s
->fields
, m5
);
2361 static gen_helper_gvec_3
* const g
[3] = {
2362 gen_helper_gvec_vfae8
,
2363 gen_helper_gvec_vfae16
,
2364 gen_helper_gvec_vfae32
,
2366 static gen_helper_gvec_3_ptr
* const g_cc
[3] = {
2367 gen_helper_gvec_vfae_cc8
,
2368 gen_helper_gvec_vfae_cc16
,
2369 gen_helper_gvec_vfae_cc32
,
2372 gen_program_exception(s
, PGM_SPECIFICATION
);
2373 return DISAS_NORETURN
;
2376 if (extract32(m5
, 0, 1)) {
2377 gen_gvec_3_ptr(get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
2378 get_field(s
->fields
, v3
), cpu_env
, m5
, g_cc
[es
]);
2381 gen_gvec_3_ool(get_field(s
->fields
, v1
), get_field(s
->fields
, v2
),
2382 get_field(s
->fields
, v3
), m5
, g
[es
]);