s390x/tcg: Implement VECTOR FP COMPARE (EQUAL|HIGH|HIGH OR EQUAL)
[qemu/ar7.git] / target / s390x / translate_vx.inc.c
blob5571a71e1a480cc821f52621791e0c5e85d7b898
1 /*
2 * QEMU TCG support -- s390x vector instruction translation functions
4 * Copyright (C) 2019 Red Hat Inc
6 * Authors:
7 * David Hildenbrand <david@redhat.com>
9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 * See the COPYING file in the top-level directory.
14 * For most instructions that use the same element size for reads and
15 * writes, we can use real gvec vector expansion, which potantially uses
16 * real host vector instructions. As they only work up to 64 bit elements,
17 * 128 bit elements (vector is a single element) have to be handled
18 * differently. Operations that are too complicated to encode via TCG ops
19 * are handled via gvec ool (out-of-line) handlers.
21 * As soon as instructions use different element sizes for reads and writes
22 * or access elements "out of their element scope" we expand them manually
23 * in fancy loops, as gvec expansion does not deal with actual element
24 * numbers and does also not support access to other elements.
26 * 128 bit elements:
27 * As we only have i32/i64, such elements have to be loaded into two
28 * i64 values and can then be processed e.g. by tcg_gen_add2_i64.
30 * Sizes:
31 * On s390x, the operand size (oprsz) and the maximum size (maxsz) are
32 * always 16 (128 bit). What gvec code calls "vece", s390x calls "es",
33 * a.k.a. "element size". These values nicely map to MO_8 ... MO_64. Only
34 * 128 bit element size has to be treated in a special way (MO_64 + 1).
35 * We will use ES_* instead of MO_* for this reason in this file.
37 * CC handling:
38 * As gvec ool-helpers can currently not return values (besides via
39 * pointers like vectors or cpu_env), whenever we have to set the CC and
40 * can't conclude the value from the result vector, we will directly
41 * set it in "env->cc_op" and mark it as static via set_cc_static()".
42 * Whenever this is done, the helper writes globals (cc_op).
45 #define NUM_VEC_ELEMENT_BYTES(es) (1 << (es))
46 #define NUM_VEC_ELEMENTS(es) (16 / NUM_VEC_ELEMENT_BYTES(es))
47 #define NUM_VEC_ELEMENT_BITS(es) (NUM_VEC_ELEMENT_BYTES(es) * BITS_PER_BYTE)
49 #define ES_8 MO_8
50 #define ES_16 MO_16
51 #define ES_32 MO_32
52 #define ES_64 MO_64
53 #define ES_128 4
55 /* Floating-Point Format */
56 #define FPF_SHORT 2
57 #define FPF_LONG 3
58 #define FPF_EXT 4
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,
66 TCGMemOp memop)
68 const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE);
70 switch (memop) {
71 case ES_8:
72 tcg_gen_ld8u_i64(dst, cpu_env, offs);
73 break;
74 case ES_16:
75 tcg_gen_ld16u_i64(dst, cpu_env, offs);
76 break;
77 case ES_32:
78 tcg_gen_ld32u_i64(dst, cpu_env, offs);
79 break;
80 case ES_8 | MO_SIGN:
81 tcg_gen_ld8s_i64(dst, cpu_env, offs);
82 break;
83 case ES_16 | MO_SIGN:
84 tcg_gen_ld16s_i64(dst, cpu_env, offs);
85 break;
86 case ES_32 | MO_SIGN:
87 tcg_gen_ld32s_i64(dst, cpu_env, offs);
88 break;
89 case ES_64:
90 case ES_64 | MO_SIGN:
91 tcg_gen_ld_i64(dst, cpu_env, offs);
92 break;
93 default:
94 g_assert_not_reached();
98 static void read_vec_element_i32(TCGv_i32 dst, uint8_t reg, uint8_t enr,
99 TCGMemOp memop)
101 const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE);
103 switch (memop) {
104 case ES_8:
105 tcg_gen_ld8u_i32(dst, cpu_env, offs);
106 break;
107 case ES_16:
108 tcg_gen_ld16u_i32(dst, cpu_env, offs);
109 break;
110 case ES_8 | MO_SIGN:
111 tcg_gen_ld8s_i32(dst, cpu_env, offs);
112 break;
113 case ES_16 | MO_SIGN:
114 tcg_gen_ld16s_i32(dst, cpu_env, offs);
115 break;
116 case ES_32:
117 case ES_32 | MO_SIGN:
118 tcg_gen_ld_i32(dst, cpu_env, offs);
119 break;
120 default:
121 g_assert_not_reached();
125 static void write_vec_element_i64(TCGv_i64 src, int reg, uint8_t enr,
126 TCGMemOp memop)
128 const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE);
130 switch (memop) {
131 case ES_8:
132 tcg_gen_st8_i64(src, cpu_env, offs);
133 break;
134 case ES_16:
135 tcg_gen_st16_i64(src, cpu_env, offs);
136 break;
137 case ES_32:
138 tcg_gen_st32_i64(src, cpu_env, offs);
139 break;
140 case ES_64:
141 tcg_gen_st_i64(src, cpu_env, offs);
142 break;
143 default:
144 g_assert_not_reached();
148 static void write_vec_element_i32(TCGv_i32 src, int reg, uint8_t enr,
149 TCGMemOp memop)
151 const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE);
153 switch (memop) {
154 case ES_8:
155 tcg_gen_st8_i32(src, cpu_env, offs);
156 break;
157 case ES_16:
158 tcg_gen_st16_i32(src, cpu_env, offs);
159 break;
160 case ES_32:
161 tcg_gen_st_i32(src, cpu_env, offs);
162 break;
163 default:
164 g_assert_not_reached();
168 static void get_vec_element_ptr_i64(TCGv_ptr ptr, uint8_t reg, TCGv_i64 enr,
169 uint8_t es)
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));
180 #endif
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), \
192 16, 16, gen)
193 #define gen_gvec_2s(v1, v2, c, gen) \
194 tcg_gen_gvec_2s(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
195 16, 16, c, gen)
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), \
198 16, 16, data, fn)
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), \
201 c, 16, 16, data, fn)
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), \
220 16, 16, gen)
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), \
224 16, 16, data, fn)
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), \
238 16, 16)
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), \
241 c, 16, 16)
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), \
244 s, 16, 16)
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
251 * vector.
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,
256 uint8_t b)
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)
318 switch (es) {
319 case ES_8:
320 tcg_gen_gvec_dup8i(vec_full_reg_offset(reg), 16, 16, c);
321 break;
322 case ES_16:
323 tcg_gen_gvec_dup16i(vec_full_reg_offset(reg), 16, 16, c);
324 break;
325 case ES_32:
326 tcg_gen_gvec_dup32i(vec_full_reg_offset(reg), 16, 16, c);
327 break;
328 case ES_64:
329 gen_gvec_dup64i(reg, c);
330 break;
331 default:
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,
342 uint64_t b)
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);
356 TCGv_i64 tmp;
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);
371 return DISAS_NEXT;
374 static uint64_t generate_byte_mask(uint8_t mask)
376 uint64_t r = 0;
377 int i;
379 for (i = 0; i < 8; i++) {
380 if ((mask >> i) & 1) {
381 r |= 0xffull << (i * 8);
384 return r;
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));
398 } else {
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);
407 return DISAS_NEXT;
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);
416 uint64_t mask = 0;
417 int i;
419 if (es > ES_64) {
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);
427 if (i == i3) {
428 break;
432 gen_gvec_dupi(es, get_field(s->fields, v1), mask);
433 return DISAS_NEXT;
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);
446 tcg_temp_free(t0);
447 tcg_temp_free(t1);
448 return DISAS_NEXT;
451 static DisasJumpType op_vlr(DisasContext *s, DisasOps *o)
453 gen_gvec_mov(get_field(s->fields, v1), get_field(s->fields, v2));
454 return DISAS_NEXT;
457 static DisasJumpType op_vlrep(DisasContext *s, DisasOps *o)
459 const uint8_t es = get_field(s->fields, m3);
460 TCGv_i64 tmp;
462 if (es > ES_64) {
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);
471 return DISAS_NEXT;
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);
478 TCGv_i64 tmp;
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);
489 return DISAS_NEXT;
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);
496 TCGv_i64 tmp;
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);
506 return DISAS_NEXT;
509 static DisasJumpType op_vlgv(DisasContext *s, DisasOps *o)
511 const uint8_t es = get_field(s->fields, m4);
512 TCGv_ptr ptr;
514 if (es > ES_64) {
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);
524 return DISAS_NEXT;
527 ptr = tcg_temp_new_ptr();
528 get_vec_element_ptr_i64(ptr, get_field(s->fields, v3), o->addr1, es);
529 switch (es) {
530 case ES_8:
531 tcg_gen_ld8u_i64(o->out, ptr, 0);
532 break;
533 case ES_16:
534 tcg_gen_ld16u_i64(o->out, ptr, 0);
535 break;
536 case ES_32:
537 tcg_gen_ld32u_i64(o->out, ptr, 0);
538 break;
539 case ES_64:
540 tcg_gen_ld_i64(o->out, ptr, 0);
541 break;
542 default:
543 g_assert_not_reached();
545 tcg_temp_free_ptr(ptr);
547 return DISAS_NEXT;
550 static DisasJumpType op_vllez(DisasContext *s, DisasOps *o)
552 uint8_t es = get_field(s->fields, m3);
553 uint8_t enr;
554 TCGv_i64 t;
556 switch (es) {
557 /* rightmost sub-element of leftmost doubleword */
558 case ES_8:
559 enr = 7;
560 break;
561 case ES_16:
562 enr = 3;
563 break;
564 case ES_32:
565 enr = 1;
566 break;
567 case ES_64:
568 enr = 0;
569 break;
570 /* leftmost sub-element of leftmost doubleword */
571 case 6:
572 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
573 es = ES_32;
574 enr = 0;
575 break;
577 default:
578 /* fallthrough */
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);
588 return DISAS_NEXT;
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);
595 TCGv_i64 t0, t1;
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);
611 for (;; v1++) {
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);
614 if (v1 == v3) {
615 break;
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);
628 return DISAS_NEXT;
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));
635 TCGv_ptr a0;
636 TCGv_i64 bytes;
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);
653 return DISAS_NEXT;
656 static DisasJumpType op_vlvg(DisasContext *s, DisasOps *o)
658 const uint8_t es = get_field(s->fields, m4);
659 TCGv_ptr ptr;
661 if (es > ES_64) {
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);
671 return DISAS_NEXT;
674 ptr = tcg_temp_new_ptr();
675 get_vec_element_ptr_i64(ptr, get_field(s->fields, v1), o->addr1, es);
676 switch (es) {
677 case ES_8:
678 tcg_gen_st8_i64(o->in2, ptr, 0);
679 break;
680 case ES_16:
681 tcg_gen_st16_i64(o->in2, ptr, 0);
682 break;
683 case ES_32:
684 tcg_gen_st32_i64(o->in2, ptr, 0);
685 break;
686 case ES_64:
687 tcg_gen_st_i64(o->in2, ptr, 0);
688 break;
689 default:
690 g_assert_not_reached();
692 tcg_temp_free_ptr(ptr);
694 return DISAS_NEXT;
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);
701 return DISAS_NEXT;
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);
714 return DISAS_NEXT;
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;
724 TCGv_i64 tmp;
726 if (es > ES_64) {
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);
738 } else {
739 read_vec_element_i64(tmp, v3, src_idx, es);
741 write_vec_element_i64(tmp, v1, dst_idx, es);
743 } else {
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);
749 } else {
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);
756 return DISAS_NEXT;
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) {
797 case 0x97:
798 if (get_field(s->fields, m5) & 0x1) {
799 gen_gvec_3_ptr(v1, v2, v3, cpu_env, 0, vpks_cc[es - 1]);
800 set_cc_static(s);
801 } else {
802 gen_gvec_3_ool(v1, v2, v3, 0, vpks[es - 1]);
804 break;
805 case 0x95:
806 if (get_field(s->fields, m5) & 0x1) {
807 gen_gvec_3_ptr(v1, v2, v3, cpu_env, 0, vpkls_cc[es - 1]);
808 set_cc_static(s);
809 } else {
810 gen_gvec_3_ool(v1, v2, v3, 0, vpkls[es - 1]);
812 break;
813 case 0x94:
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++) {
822 src_idx = dst_idx;
823 if (src_idx < NUM_VEC_ELEMENTS(src_es)) {
824 read_vec_element_i64(tmp, v2, src_idx, src_es);
825 } else {
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);
832 } else {
833 gen_gvec_3_ool(v1, v2, v3, 0, vpk[es - 1]);
835 break;
836 default:
837 g_assert_not_reached();
839 return DISAS_NEXT;
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);
847 return DISAS_NEXT;
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);
863 return DISAS_NEXT;
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),
878 16, 16);
879 return DISAS_NEXT;
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);
887 if (es > ES_64) {
888 gen_program_exception(s, PGM_SPECIFICATION);
889 return DISAS_NORETURN;
892 gen_gvec_dupi(es, get_field(s->fields, v1), data);
893 return DISAS_NEXT;
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);
900 TCGv_i64 tmp;
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);
915 return DISAS_NEXT;
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,
932 TCGv_vec c)
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 = {
945 .fni8 = gen_sel_i64,
946 .fniv = gen_sel_vec,
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);
952 return DISAS_NEXT;
955 static DisasJumpType op_vseg(DisasContext *s, DisasOps *o)
957 const uint8_t es = get_field(s->fields, m3);
958 int idx1, idx2;
959 TCGv_i64 tmp;
961 switch (es) {
962 case ES_8:
963 idx1 = 7;
964 idx2 = 15;
965 break;
966 case ES_16:
967 idx1 = 3;
968 idx2 = 7;
969 break;
970 case ES_32:
971 idx1 = 1;
972 idx2 = 3;
973 break;
974 default:
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);
985 return DISAS_NEXT;
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);
1001 return DISAS_NEXT;
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);
1008 TCGv_i64 tmp;
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);
1019 return DISAS_NEXT;
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);
1026 TCGv_i64 tmp;
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);
1037 for (;; v1++) {
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);
1043 if (v1 == v3) {
1044 break;
1046 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
1048 tcg_temp_free_i64(tmp);
1049 return DISAS_NEXT;
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);
1062 return DISAS_NEXT;
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;
1073 TCGv_i64 tmp;
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--) {
1084 src_idx = 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);
1090 } else {
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);
1100 return DISAS_NEXT;
1103 static DisasJumpType op_va(DisasContext *s, DisasOps *o)
1105 const uint8_t es = get_field(s->fields, m4);
1107 if (es > ES_128) {
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));
1113 return DISAS_NEXT;
1115 gen_gvec_fn_3(add, es, get_field(s->fields, v1), get_field(s->fields, v2),
1116 get_field(s->fields, v3));
1117 return DISAS_NEXT;
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, },
1202 if (es > ES_128) {
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));
1208 return DISAS_NEXT;
1210 gen_gvec_3(get_field(s->fields, v1), get_field(s->fields, v2),
1211 get_field(s->fields, v3), &g[es]);
1212 return DISAS_NEXT;
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));
1240 return DISAS_NEXT;
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));
1272 return DISAS_NEXT;
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));
1279 return DISAS_NEXT;
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));
1286 return DISAS_NEXT;
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);
1301 tcg_temp_free(t0);
1302 tcg_temp_free(t1);
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, },
1333 if (es > ES_64) {
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]);
1339 return DISAS_NEXT;
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);
1354 tcg_temp_free(t0);
1355 tcg_temp_free(t1);
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, },
1381 if (es > ES_64) {
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]);
1387 return DISAS_NEXT;
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();
1394 int i;
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);
1406 return DISAS_NEXT;
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;
1414 if (es > ES_64) {
1415 gen_program_exception(s, PGM_SPECIFICATION);
1416 return DISAS_NORETURN;
1418 if (s->fields->op2 == 0xdb) {
1419 es |= MO_SIGN;
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);
1426 return DISAS_NEXT;
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;
1434 if (es > ES_64) {
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);
1454 return DISAS_NEXT;
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, },
1477 if (es > ES_64) {
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]);
1482 return DISAS_NEXT;
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, },
1505 if (es > ES_64) {
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]);
1510 return DISAS_NEXT;
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));
1517 return DISAS_NEXT;
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, },
1530 if (es > ES_64) {
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]);
1536 return DISAS_NEXT;
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, },
1549 if (es > ES_64) {
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]);
1555 return DISAS_NEXT;
1558 static DisasJumpType op_vlc(DisasContext *s, DisasOps *o)
1560 const uint8_t es = get_field(s->fields, m3);
1562 if (es > ES_64) {
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));
1568 return DISAS_NEXT;
1571 static DisasJumpType op_vlp(DisasContext *s, DisasOps *o)
1573 const uint8_t es = get_field(s->fields, m3);
1575 if (es > ES_64) {
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));
1581 return DISAS_NEXT;
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);
1591 if (es > ES_64) {
1592 gen_program_exception(s, PGM_SPECIFICATION);
1593 return DISAS_NORETURN;
1596 switch (s->fields->op2) {
1597 case 0xff:
1598 gen_gvec_fn_3(smax, es, v1, v2, v3);
1599 break;
1600 case 0xfd:
1601 gen_gvec_fn_3(umax, es, v1, v2, v3);
1602 break;
1603 case 0xfe:
1604 gen_gvec_fn_3(smin, es, v1, v2, v3);
1605 break;
1606 case 0xfc:
1607 gen_gvec_fn_3(umin, es, v1, v2, v3);
1608 break;
1609 default:
1610 g_assert_not_reached();
1612 return DISAS_NEXT;
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);
1638 tcg_temp_free(t0);
1639 tcg_temp_free(t1);
1640 tcg_temp_free(t2);
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);
1656 tcg_temp_free(t0);
1657 tcg_temp_free(t1);
1658 tcg_temp_free(t2);
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, },
1699 const GVecGen4 *fn;
1701 if (es > ES_32) {
1702 gen_program_exception(s, PGM_SPECIFICATION);
1703 return DISAS_NORETURN;
1706 switch (s->fields->op2) {
1707 case 0xaa:
1708 fn = &g_vmal[es];
1709 break;
1710 case 0xab:
1711 fn = &g_vmah[es];
1712 break;
1713 case 0xa9:
1714 fn = &g_vmalh[es];
1715 break;
1716 case 0xae:
1717 fn = &g_vmae[es];
1718 break;
1719 case 0xac:
1720 fn = &g_vmale[es];
1721 break;
1722 case 0xaf:
1723 fn = &g_vmao[es];
1724 break;
1725 case 0xad:
1726 fn = &g_vmalo[es];
1727 break;
1728 default:
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);
1734 return DISAS_NEXT;
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, },
1786 const GVecGen3 *fn;
1788 if (es > ES_32) {
1789 gen_program_exception(s, PGM_SPECIFICATION);
1790 return DISAS_NORETURN;
1793 switch (s->fields->op2) {
1794 case 0xa2:
1795 gen_gvec_fn_3(mul, es, get_field(s->fields, v1),
1796 get_field(s->fields, v2), get_field(s->fields, v3));
1797 return DISAS_NEXT;
1798 case 0xa3:
1799 fn = &g_vmh[es];
1800 break;
1801 case 0xa1:
1802 fn = &g_vmlh[es];
1803 break;
1804 case 0xa6:
1805 fn = &g_vme[es];
1806 break;
1807 case 0xa4:
1808 fn = &g_vmle[es];
1809 break;
1810 case 0xa7:
1811 fn = &g_vmo[es];
1812 break;
1813 case 0xa5:
1814 fn = &g_vmlo[es];
1815 break;
1816 default:
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);
1822 return DISAS_NEXT;
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));
1829 return DISAS_NEXT;
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));
1836 return DISAS_NEXT;
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));
1843 return DISAS_NEXT;
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));
1850 return DISAS_NEXT;
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));
1857 return DISAS_NEXT;
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]);
1876 return DISAS_NEXT;
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, },
1907 if (es > ES_64) {
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]);
1914 return DISAS_NEXT;
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, },
1927 if (es > ES_64) {
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,
1932 &g[es]);
1933 return DISAS_NEXT;
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, },
1974 if (es > ES_64) {
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]);
1981 return DISAS_NEXT;
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);
1991 if (es > ES_64) {
1992 gen_program_exception(s, PGM_SPECIFICATION);
1993 return DISAS_NORETURN;
1996 switch (s->fields->op2) {
1997 case 0x70:
1998 gen_gvec_fn_3(shlv, es, v1, v2, v3);
1999 break;
2000 case 0x7a:
2001 gen_gvec_fn_3(sarv, es, v1, v2, v3);
2002 break;
2003 case 0x78:
2004 gen_gvec_fn_3(shrv, es, v1, v2, v3);
2005 break;
2006 default:
2007 g_assert_not_reached();
2009 return DISAS_NEXT;
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);
2019 TCGv_i32 shift;
2021 if (es > ES_64) {
2022 gen_program_exception(s, PGM_SPECIFICATION);
2023 return DISAS_NORETURN;
2026 if (likely(!get_field(s->fields, b2))) {
2027 switch (s->fields->op2) {
2028 case 0x30:
2029 gen_gvec_fn_2i(shli, es, v1, v3, d2);
2030 break;
2031 case 0x3a:
2032 gen_gvec_fn_2i(sari, es, v1, v3, d2);
2033 break;
2034 case 0x38:
2035 gen_gvec_fn_2i(shri, es, v1, v3, d2);
2036 break;
2037 default:
2038 g_assert_not_reached();
2040 } else {
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) {
2045 case 0x30:
2046 gen_gvec_fn_2s(shls, es, v1, v3, shift);
2047 break;
2048 case 0x3a:
2049 gen_gvec_fn_2s(sars, es, v1, v3, shift);
2050 break;
2051 case 0x38:
2052 gen_gvec_fn_2s(shrs, es, v1, v3, shift);
2053 break;
2054 default:
2055 g_assert_not_reached();
2057 tcg_temp_free_i32(shift);
2059 return DISAS_NEXT;
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);
2069 } else {
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);
2076 return DISAS_NEXT;
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);
2092 } else {
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);
2102 tcg_temp_free(t0);
2103 tcg_temp_free(t1);
2104 tcg_temp_free(t2);
2105 return DISAS_NEXT;
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);
2115 } else {
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);
2122 return DISAS_NEXT;
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);
2132 } else {
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);
2139 return DISAS_NEXT;
2142 static DisasJumpType op_vs(DisasContext *s, DisasOps *o)
2144 const uint8_t es = get_field(s->fields, m4);
2146 if (es > ES_128) {
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));
2152 return DISAS_NEXT;
2154 gen_gvec_fn_3(sub, es, get_field(s->fields, v1), get_field(s->fields, v2),
2155 get_field(s->fields, v3));
2156 return DISAS_NEXT;
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, },
2198 if (es > ES_128) {
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));
2204 return DISAS_NEXT;
2206 gen_gvec_3(get_field(s->fields, v1), get_field(s->fields, v2),
2207 get_field(s->fields, v3), &g[es]);
2208 return DISAS_NEXT;
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));
2234 return DISAS_NEXT;
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));
2268 return DISAS_NEXT;
2271 static DisasJumpType op_vsumg(DisasContext *s, DisasOps *o)
2273 const uint8_t es = get_field(s->fields, m4);
2274 TCGv_i64 sum, tmp;
2275 uint8_t dst_idx;
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);
2297 return DISAS_NEXT;
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;
2305 uint8_t idx;
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);
2329 return DISAS_NEXT;
2332 static DisasJumpType op_vsum(DisasContext *s, DisasOps *o)
2334 const uint8_t es = get_field(s->fields, m4);
2335 TCGv_i32 sum, tmp;
2336 uint8_t dst_idx;
2338 if (es > ES_16) {
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);
2358 return DISAS_NEXT;
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);
2365 set_cc_static(s);
2366 return DISAS_NEXT;
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,
2383 if (es > ES_32) {
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]);
2391 set_cc_static(s);
2392 } else {
2393 gen_gvec_3_ool(get_field(s->fields, v1), get_field(s->fields, v2),
2394 get_field(s->fields, v3), m5, g[es]);
2396 return DISAS_NEXT;
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]);
2422 set_cc_static(s);
2423 } else {
2424 gen_gvec_3_ool(get_field(s->fields, v1), get_field(s->fields, v2),
2425 get_field(s->fields, v3), m5, g[es]);
2427 return DISAS_NEXT;
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]);
2453 set_cc_static(s);
2454 } else {
2455 gen_gvec_3_ool(get_field(s->fields, v1), get_field(s->fields, v2),
2456 get_field(s->fields, v3), m5, g[es]);
2458 return DISAS_NEXT;
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]);
2484 set_cc_static(s);
2485 } else {
2486 gen_gvec_2_ool(get_field(s->fields, v1), get_field(s->fields, v2), 0,
2487 g[es]);
2489 return DISAS_NEXT;
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,
2517 if (es > ES_32) {
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]);
2527 } else {
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]);
2532 set_cc_static(s);
2533 } else {
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),
2537 m6, g_rt[es]);
2538 } else {
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),
2541 m6, g[es]);
2544 return DISAS_NEXT;
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) {
2560 case 0xe3:
2561 fn = se ? gen_helper_gvec_vfa64s : gen_helper_gvec_vfa64;
2562 break;
2563 default:
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);
2568 return DISAS_NEXT;
2571 static DisasJumpType op_wfc(DisasContext *s, DisasOps *o)
2573 const uint8_t fpf = get_field(s->fields, m3);
2574 const uint8_t m4 = get_field(s->fields, m4);
2576 if (fpf != FPF_LONG || m4) {
2577 gen_program_exception(s, PGM_SPECIFICATION);
2578 return DISAS_NORETURN;
2581 if (s->fields->op2 == 0xcb) {
2582 gen_gvec_2_ptr(get_field(s->fields, v1), get_field(s->fields, v2),
2583 cpu_env, 0, gen_helper_gvec_wfc64);
2584 } else {
2585 gen_gvec_2_ptr(get_field(s->fields, v1), get_field(s->fields, v2),
2586 cpu_env, 0, gen_helper_gvec_wfk64);
2588 set_cc_static(s);
2589 return DISAS_NEXT;
2592 static DisasJumpType op_vfc(DisasContext *s, DisasOps *o)
2594 const uint8_t fpf = get_field(s->fields, m4);
2595 const uint8_t m5 = get_field(s->fields, m5);
2596 const uint8_t m6 = get_field(s->fields, m6);
2597 const bool se = extract32(m5, 3, 1);
2598 const bool cs = extract32(m6, 0, 1);
2599 gen_helper_gvec_3_ptr *fn;
2601 if (fpf != FPF_LONG || extract32(m5, 0, 3) || extract32(m6, 1, 3)) {
2602 gen_program_exception(s, PGM_SPECIFICATION);
2603 return DISAS_NORETURN;
2606 if (cs) {
2607 switch (s->fields->op2) {
2608 case 0xe8:
2609 fn = se ? gen_helper_gvec_vfce64s_cc : gen_helper_gvec_vfce64_cc;
2610 break;
2611 case 0xeb:
2612 fn = se ? gen_helper_gvec_vfch64s_cc : gen_helper_gvec_vfch64_cc;
2613 break;
2614 case 0xea:
2615 fn = se ? gen_helper_gvec_vfche64s_cc : gen_helper_gvec_vfche64_cc;
2616 break;
2617 default:
2618 g_assert_not_reached();
2620 } else {
2621 switch (s->fields->op2) {
2622 case 0xe8:
2623 fn = se ? gen_helper_gvec_vfce64s : gen_helper_gvec_vfce64;
2624 break;
2625 case 0xeb:
2626 fn = se ? gen_helper_gvec_vfch64s : gen_helper_gvec_vfch64;
2627 break;
2628 case 0xea:
2629 fn = se ? gen_helper_gvec_vfche64s : gen_helper_gvec_vfche64;
2630 break;
2631 default:
2632 g_assert_not_reached();
2635 gen_gvec_3_ptr(get_field(s->fields, v1), get_field(s->fields, v2),
2636 get_field(s->fields, v3), cpu_env, 0, fn);
2637 if (cs) {
2638 set_cc_static(s);
2640 return DISAS_NEXT;