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