]> git.proxmox.com Git - mirror_qemu.git/blob - target/s390x/tcg/translate_vx.c.inc
iotests: Add mirror-ready-cancel-error test
[mirror_qemu.git] / target / s390x / tcg / translate_vx.c.inc
1 /*
2 * QEMU TCG support -- s390x vector instruction translation functions
3 *
4 * Copyright (C) 2019 Red Hat Inc
5 *
6 * Authors:
7 * David Hildenbrand <david@redhat.com>
8 *
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.
11 */
12
13 /*
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.
20 *
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.
25 *
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.
29 *
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.
36 *
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).
43 */
44
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)
48
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
54
55 /* Floating-Point Format */
56 #define FPF_SHORT 2
57 #define FPF_LONG 3
58 #define FPF_EXT 4
59
60 static inline bool valid_vec_element(uint8_t enr, MemOp es)
61 {
62 return !(enr & ~(NUM_VEC_ELEMENTS(es) - 1));
63 }
64
65 static void read_vec_element_i64(TCGv_i64 dst, uint8_t reg, uint8_t enr,
66 MemOp memop)
67 {
68 const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE);
69
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();
95 }
96 }
97
98 static void read_vec_element_i32(TCGv_i32 dst, uint8_t reg, uint8_t enr,
99 MemOp memop)
100 {
101 const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE);
102
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();
122 }
123 }
124
125 static void write_vec_element_i64(TCGv_i64 src, int reg, uint8_t enr,
126 MemOp memop)
127 {
128 const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE);
129
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();
145 }
146 }
147
148 static void write_vec_element_i32(TCGv_i32 src, int reg, uint8_t enr,
149 MemOp memop)
150 {
151 const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE);
152
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();
165 }
166 }
167
168 static void get_vec_element_ptr_i64(TCGv_ptr ptr, uint8_t reg, TCGv_i64 enr,
169 uint8_t es)
170 {
171 TCGv_i64 tmp = tcg_temp_new_i64();
172
173 /* mask off invalid parts from the element nr */
174 tcg_gen_andi_i64(tmp, enr, NUM_VEC_ELEMENTS(es) - 1);
175
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));
182
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);
186
187 tcg_temp_free_i64(tmp);
188 }
189
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), 16, 16, c, 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, \
233 16)
234 #define gen_gvec_dup_imm(es, v1, c) \
235 tcg_gen_gvec_dup_imm(es, 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)
248 #define gen_gvec_fn_4(fn, es, v1, v2, v3, v4) \
249 tcg_gen_gvec_##fn(es, vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
250 vec_full_reg_offset(v3), vec_full_reg_offset(v4), 16, 16)
251
252 /*
253 * Helper to carry out a 128 bit vector computation using 2 i64 values per
254 * vector.
255 */
256 typedef void (*gen_gvec128_3_i64_fn)(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al,
257 TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh);
258 static void gen_gvec128_3_i64(gen_gvec128_3_i64_fn fn, uint8_t d, uint8_t a,
259 uint8_t b)
260 {
261 TCGv_i64 dh = tcg_temp_new_i64();
262 TCGv_i64 dl = tcg_temp_new_i64();
263 TCGv_i64 ah = tcg_temp_new_i64();
264 TCGv_i64 al = tcg_temp_new_i64();
265 TCGv_i64 bh = tcg_temp_new_i64();
266 TCGv_i64 bl = tcg_temp_new_i64();
267
268 read_vec_element_i64(ah, a, 0, ES_64);
269 read_vec_element_i64(al, a, 1, ES_64);
270 read_vec_element_i64(bh, b, 0, ES_64);
271 read_vec_element_i64(bl, b, 1, ES_64);
272 fn(dl, dh, al, ah, bl, bh);
273 write_vec_element_i64(dh, d, 0, ES_64);
274 write_vec_element_i64(dl, d, 1, ES_64);
275
276 tcg_temp_free_i64(dh);
277 tcg_temp_free_i64(dl);
278 tcg_temp_free_i64(ah);
279 tcg_temp_free_i64(al);
280 tcg_temp_free_i64(bh);
281 tcg_temp_free_i64(bl);
282 }
283
284 typedef void (*gen_gvec128_4_i64_fn)(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al,
285 TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh,
286 TCGv_i64 cl, TCGv_i64 ch);
287 static void gen_gvec128_4_i64(gen_gvec128_4_i64_fn fn, uint8_t d, uint8_t a,
288 uint8_t b, uint8_t c)
289 {
290 TCGv_i64 dh = tcg_temp_new_i64();
291 TCGv_i64 dl = tcg_temp_new_i64();
292 TCGv_i64 ah = tcg_temp_new_i64();
293 TCGv_i64 al = tcg_temp_new_i64();
294 TCGv_i64 bh = tcg_temp_new_i64();
295 TCGv_i64 bl = tcg_temp_new_i64();
296 TCGv_i64 ch = tcg_temp_new_i64();
297 TCGv_i64 cl = tcg_temp_new_i64();
298
299 read_vec_element_i64(ah, a, 0, ES_64);
300 read_vec_element_i64(al, a, 1, ES_64);
301 read_vec_element_i64(bh, b, 0, ES_64);
302 read_vec_element_i64(bl, b, 1, ES_64);
303 read_vec_element_i64(ch, c, 0, ES_64);
304 read_vec_element_i64(cl, c, 1, ES_64);
305 fn(dl, dh, al, ah, bl, bh, cl, ch);
306 write_vec_element_i64(dh, d, 0, ES_64);
307 write_vec_element_i64(dl, d, 1, ES_64);
308
309 tcg_temp_free_i64(dh);
310 tcg_temp_free_i64(dl);
311 tcg_temp_free_i64(ah);
312 tcg_temp_free_i64(al);
313 tcg_temp_free_i64(bh);
314 tcg_temp_free_i64(bl);
315 tcg_temp_free_i64(ch);
316 tcg_temp_free_i64(cl);
317 }
318
319 static void gen_addi2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
320 uint64_t b)
321 {
322 TCGv_i64 bl = tcg_const_i64(b);
323 TCGv_i64 bh = tcg_const_i64(0);
324
325 tcg_gen_add2_i64(dl, dh, al, ah, bl, bh);
326 tcg_temp_free_i64(bl);
327 tcg_temp_free_i64(bh);
328 }
329
330 static DisasJumpType op_vbperm(DisasContext *s, DisasOps *o)
331 {
332 gen_gvec_3_ool(get_field(s, v1), get_field(s, v2), get_field(s, v3), 0,
333 gen_helper_gvec_vbperm);
334
335 return DISAS_NEXT;
336 }
337
338 static DisasJumpType op_vge(DisasContext *s, DisasOps *o)
339 {
340 const uint8_t es = s->insn->data;
341 const uint8_t enr = get_field(s, m3);
342 TCGv_i64 tmp;
343
344 if (!valid_vec_element(enr, es)) {
345 gen_program_exception(s, PGM_SPECIFICATION);
346 return DISAS_NORETURN;
347 }
348
349 tmp = tcg_temp_new_i64();
350 read_vec_element_i64(tmp, get_field(s, v2), enr, es);
351 tcg_gen_add_i64(o->addr1, o->addr1, tmp);
352 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 0);
353
354 tcg_gen_qemu_ld_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
355 write_vec_element_i64(tmp, get_field(s, v1), enr, es);
356 tcg_temp_free_i64(tmp);
357 return DISAS_NEXT;
358 }
359
360 static uint64_t generate_byte_mask(uint8_t mask)
361 {
362 uint64_t r = 0;
363 int i;
364
365 for (i = 0; i < 8; i++) {
366 if ((mask >> i) & 1) {
367 r |= 0xffull << (i * 8);
368 }
369 }
370 return r;
371 }
372
373 static DisasJumpType op_vgbm(DisasContext *s, DisasOps *o)
374 {
375 const uint16_t i2 = get_field(s, i2);
376
377 if (i2 == (i2 & 0xff) * 0x0101) {
378 /*
379 * Masks for both 64 bit elements of the vector are the same.
380 * Trust tcg to produce a good constant loading.
381 */
382 gen_gvec_dup_imm(ES_64, get_field(s, v1),
383 generate_byte_mask(i2 & 0xff));
384 } else {
385 TCGv_i64 t = tcg_temp_new_i64();
386
387 tcg_gen_movi_i64(t, generate_byte_mask(i2 >> 8));
388 write_vec_element_i64(t, get_field(s, v1), 0, ES_64);
389 tcg_gen_movi_i64(t, generate_byte_mask(i2));
390 write_vec_element_i64(t, get_field(s, v1), 1, ES_64);
391 tcg_temp_free_i64(t);
392 }
393 return DISAS_NEXT;
394 }
395
396 static DisasJumpType op_vgm(DisasContext *s, DisasOps *o)
397 {
398 const uint8_t es = get_field(s, m4);
399 const uint8_t bits = NUM_VEC_ELEMENT_BITS(es);
400 const uint8_t i2 = get_field(s, i2) & (bits - 1);
401 const uint8_t i3 = get_field(s, i3) & (bits - 1);
402 uint64_t mask = 0;
403 int i;
404
405 if (es > ES_64) {
406 gen_program_exception(s, PGM_SPECIFICATION);
407 return DISAS_NORETURN;
408 }
409
410 /* generate the mask - take care of wrapping */
411 for (i = i2; ; i = (i + 1) % bits) {
412 mask |= 1ull << (bits - i - 1);
413 if (i == i3) {
414 break;
415 }
416 }
417
418 gen_gvec_dup_imm(es, get_field(s, v1), mask);
419 return DISAS_NEXT;
420 }
421
422 static DisasJumpType op_vl(DisasContext *s, DisasOps *o)
423 {
424 TCGv_i64 t0 = tcg_temp_new_i64();
425 TCGv_i64 t1 = tcg_temp_new_i64();
426
427 tcg_gen_qemu_ld_i64(t0, o->addr1, get_mem_index(s), MO_TEQ);
428 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
429 tcg_gen_qemu_ld_i64(t1, o->addr1, get_mem_index(s), MO_TEQ);
430 write_vec_element_i64(t0, get_field(s, v1), 0, ES_64);
431 write_vec_element_i64(t1, get_field(s, v1), 1, ES_64);
432 tcg_temp_free(t0);
433 tcg_temp_free(t1);
434 return DISAS_NEXT;
435 }
436
437 static DisasJumpType op_vlr(DisasContext *s, DisasOps *o)
438 {
439 gen_gvec_mov(get_field(s, v1), get_field(s, v2));
440 return DISAS_NEXT;
441 }
442
443 static DisasJumpType op_vlrep(DisasContext *s, DisasOps *o)
444 {
445 const uint8_t es = get_field(s, m3);
446 TCGv_i64 tmp;
447
448 if (es > ES_64) {
449 gen_program_exception(s, PGM_SPECIFICATION);
450 return DISAS_NORETURN;
451 }
452
453 tmp = tcg_temp_new_i64();
454 tcg_gen_qemu_ld_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
455 gen_gvec_dup_i64(es, get_field(s, v1), tmp);
456 tcg_temp_free_i64(tmp);
457 return DISAS_NEXT;
458 }
459
460 static DisasJumpType op_vle(DisasContext *s, DisasOps *o)
461 {
462 const uint8_t es = s->insn->data;
463 const uint8_t enr = get_field(s, m3);
464 TCGv_i64 tmp;
465
466 if (!valid_vec_element(enr, es)) {
467 gen_program_exception(s, PGM_SPECIFICATION);
468 return DISAS_NORETURN;
469 }
470
471 tmp = tcg_temp_new_i64();
472 tcg_gen_qemu_ld_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
473 write_vec_element_i64(tmp, get_field(s, v1), enr, es);
474 tcg_temp_free_i64(tmp);
475 return DISAS_NEXT;
476 }
477
478 static DisasJumpType op_vlei(DisasContext *s, DisasOps *o)
479 {
480 const uint8_t es = s->insn->data;
481 const uint8_t enr = get_field(s, m3);
482 TCGv_i64 tmp;
483
484 if (!valid_vec_element(enr, es)) {
485 gen_program_exception(s, PGM_SPECIFICATION);
486 return DISAS_NORETURN;
487 }
488
489 tmp = tcg_const_i64((int16_t)get_field(s, i2));
490 write_vec_element_i64(tmp, get_field(s, v1), enr, es);
491 tcg_temp_free_i64(tmp);
492 return DISAS_NEXT;
493 }
494
495 static DisasJumpType op_vlgv(DisasContext *s, DisasOps *o)
496 {
497 const uint8_t es = get_field(s, m4);
498 TCGv_ptr ptr;
499
500 if (es > ES_64) {
501 gen_program_exception(s, PGM_SPECIFICATION);
502 return DISAS_NORETURN;
503 }
504
505 /* fast path if we don't need the register content */
506 if (!get_field(s, b2)) {
507 uint8_t enr = get_field(s, d2) & (NUM_VEC_ELEMENTS(es) - 1);
508
509 read_vec_element_i64(o->out, get_field(s, v3), enr, es);
510 return DISAS_NEXT;
511 }
512
513 ptr = tcg_temp_new_ptr();
514 get_vec_element_ptr_i64(ptr, get_field(s, v3), o->addr1, es);
515 switch (es) {
516 case ES_8:
517 tcg_gen_ld8u_i64(o->out, ptr, 0);
518 break;
519 case ES_16:
520 tcg_gen_ld16u_i64(o->out, ptr, 0);
521 break;
522 case ES_32:
523 tcg_gen_ld32u_i64(o->out, ptr, 0);
524 break;
525 case ES_64:
526 tcg_gen_ld_i64(o->out, ptr, 0);
527 break;
528 default:
529 g_assert_not_reached();
530 }
531 tcg_temp_free_ptr(ptr);
532
533 return DISAS_NEXT;
534 }
535
536 static DisasJumpType op_vllez(DisasContext *s, DisasOps *o)
537 {
538 uint8_t es = get_field(s, m3);
539 uint8_t enr;
540 TCGv_i64 t;
541
542 switch (es) {
543 /* rightmost sub-element of leftmost doubleword */
544 case ES_8:
545 enr = 7;
546 break;
547 case ES_16:
548 enr = 3;
549 break;
550 case ES_32:
551 enr = 1;
552 break;
553 case ES_64:
554 enr = 0;
555 break;
556 /* leftmost sub-element of leftmost doubleword */
557 case 6:
558 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
559 es = ES_32;
560 enr = 0;
561 break;
562 }
563 /* fallthrough */
564 default:
565 gen_program_exception(s, PGM_SPECIFICATION);
566 return DISAS_NORETURN;
567 }
568
569 t = tcg_temp_new_i64();
570 tcg_gen_qemu_ld_i64(t, o->addr1, get_mem_index(s), MO_TE | es);
571 gen_gvec_dup_imm(es, get_field(s, v1), 0);
572 write_vec_element_i64(t, get_field(s, v1), enr, es);
573 tcg_temp_free_i64(t);
574 return DISAS_NEXT;
575 }
576
577 static DisasJumpType op_vlm(DisasContext *s, DisasOps *o)
578 {
579 const uint8_t v3 = get_field(s, v3);
580 uint8_t v1 = get_field(s, v1);
581 TCGv_i64 t0, t1;
582
583 if (v3 < v1 || (v3 - v1 + 1) > 16) {
584 gen_program_exception(s, PGM_SPECIFICATION);
585 return DISAS_NORETURN;
586 }
587
588 /*
589 * Check for possible access exceptions by trying to load the last
590 * element. The first element will be checked first next.
591 */
592 t0 = tcg_temp_new_i64();
593 t1 = tcg_temp_new_i64();
594 gen_addi_and_wrap_i64(s, t0, o->addr1, (v3 - v1) * 16 + 8);
595 tcg_gen_qemu_ld_i64(t0, t0, get_mem_index(s), MO_TEQ);
596
597 for (;; v1++) {
598 tcg_gen_qemu_ld_i64(t1, o->addr1, get_mem_index(s), MO_TEQ);
599 write_vec_element_i64(t1, v1, 0, ES_64);
600 if (v1 == v3) {
601 break;
602 }
603 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
604 tcg_gen_qemu_ld_i64(t1, o->addr1, get_mem_index(s), MO_TEQ);
605 write_vec_element_i64(t1, v1, 1, ES_64);
606 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
607 }
608
609 /* Store the last element, loaded first */
610 write_vec_element_i64(t0, v1, 1, ES_64);
611
612 tcg_temp_free_i64(t0);
613 tcg_temp_free_i64(t1);
614 return DISAS_NEXT;
615 }
616
617 static DisasJumpType op_vlbb(DisasContext *s, DisasOps *o)
618 {
619 const int64_t block_size = (1ull << (get_field(s, m3) + 6));
620 const int v1_offs = vec_full_reg_offset(get_field(s, v1));
621 TCGv_ptr a0;
622 TCGv_i64 bytes;
623
624 if (get_field(s, m3) > 6) {
625 gen_program_exception(s, PGM_SPECIFICATION);
626 return DISAS_NORETURN;
627 }
628
629 bytes = tcg_temp_new_i64();
630 a0 = tcg_temp_new_ptr();
631 /* calculate the number of bytes until the next block boundary */
632 tcg_gen_ori_i64(bytes, o->addr1, -block_size);
633 tcg_gen_neg_i64(bytes, bytes);
634
635 tcg_gen_addi_ptr(a0, cpu_env, v1_offs);
636 gen_helper_vll(cpu_env, a0, o->addr1, bytes);
637 tcg_temp_free_i64(bytes);
638 tcg_temp_free_ptr(a0);
639 return DISAS_NEXT;
640 }
641
642 static DisasJumpType op_vlvg(DisasContext *s, DisasOps *o)
643 {
644 const uint8_t es = get_field(s, m4);
645 TCGv_ptr ptr;
646
647 if (es > ES_64) {
648 gen_program_exception(s, PGM_SPECIFICATION);
649 return DISAS_NORETURN;
650 }
651
652 /* fast path if we don't need the register content */
653 if (!get_field(s, b2)) {
654 uint8_t enr = get_field(s, d2) & (NUM_VEC_ELEMENTS(es) - 1);
655
656 write_vec_element_i64(o->in2, get_field(s, v1), enr, es);
657 return DISAS_NEXT;
658 }
659
660 ptr = tcg_temp_new_ptr();
661 get_vec_element_ptr_i64(ptr, get_field(s, v1), o->addr1, es);
662 switch (es) {
663 case ES_8:
664 tcg_gen_st8_i64(o->in2, ptr, 0);
665 break;
666 case ES_16:
667 tcg_gen_st16_i64(o->in2, ptr, 0);
668 break;
669 case ES_32:
670 tcg_gen_st32_i64(o->in2, ptr, 0);
671 break;
672 case ES_64:
673 tcg_gen_st_i64(o->in2, ptr, 0);
674 break;
675 default:
676 g_assert_not_reached();
677 }
678 tcg_temp_free_ptr(ptr);
679
680 return DISAS_NEXT;
681 }
682
683 static DisasJumpType op_vlvgp(DisasContext *s, DisasOps *o)
684 {
685 write_vec_element_i64(o->in1, get_field(s, v1), 0, ES_64);
686 write_vec_element_i64(o->in2, get_field(s, v1), 1, ES_64);
687 return DISAS_NEXT;
688 }
689
690 static DisasJumpType op_vll(DisasContext *s, DisasOps *o)
691 {
692 const int v1_offs = vec_full_reg_offset(get_field(s, v1));
693 TCGv_ptr a0 = tcg_temp_new_ptr();
694
695 /* convert highest index into an actual length */
696 tcg_gen_addi_i64(o->in2, o->in2, 1);
697 tcg_gen_addi_ptr(a0, cpu_env, v1_offs);
698 gen_helper_vll(cpu_env, a0, o->addr1, o->in2);
699 tcg_temp_free_ptr(a0);
700 return DISAS_NEXT;
701 }
702
703 static DisasJumpType op_vmr(DisasContext *s, DisasOps *o)
704 {
705 const uint8_t v1 = get_field(s, v1);
706 const uint8_t v2 = get_field(s, v2);
707 const uint8_t v3 = get_field(s, v3);
708 const uint8_t es = get_field(s, m4);
709 int dst_idx, src_idx;
710 TCGv_i64 tmp;
711
712 if (es > ES_64) {
713 gen_program_exception(s, PGM_SPECIFICATION);
714 return DISAS_NORETURN;
715 }
716
717 tmp = tcg_temp_new_i64();
718 if (s->fields.op2 == 0x61) {
719 /* iterate backwards to avoid overwriting data we might need later */
720 for (dst_idx = NUM_VEC_ELEMENTS(es) - 1; dst_idx >= 0; dst_idx--) {
721 src_idx = dst_idx / 2;
722 if (dst_idx % 2 == 0) {
723 read_vec_element_i64(tmp, v2, src_idx, es);
724 } else {
725 read_vec_element_i64(tmp, v3, src_idx, es);
726 }
727 write_vec_element_i64(tmp, v1, dst_idx, es);
728 }
729 } else {
730 /* iterate forward to avoid overwriting data we might need later */
731 for (dst_idx = 0; dst_idx < NUM_VEC_ELEMENTS(es); dst_idx++) {
732 src_idx = (dst_idx + NUM_VEC_ELEMENTS(es)) / 2;
733 if (dst_idx % 2 == 0) {
734 read_vec_element_i64(tmp, v2, src_idx, es);
735 } else {
736 read_vec_element_i64(tmp, v3, src_idx, es);
737 }
738 write_vec_element_i64(tmp, v1, dst_idx, es);
739 }
740 }
741 tcg_temp_free_i64(tmp);
742 return DISAS_NEXT;
743 }
744
745 static DisasJumpType op_vpk(DisasContext *s, DisasOps *o)
746 {
747 const uint8_t v1 = get_field(s, v1);
748 const uint8_t v2 = get_field(s, v2);
749 const uint8_t v3 = get_field(s, v3);
750 const uint8_t es = get_field(s, m4);
751 static gen_helper_gvec_3 * const vpk[3] = {
752 gen_helper_gvec_vpk16,
753 gen_helper_gvec_vpk32,
754 gen_helper_gvec_vpk64,
755 };
756 static gen_helper_gvec_3 * const vpks[3] = {
757 gen_helper_gvec_vpks16,
758 gen_helper_gvec_vpks32,
759 gen_helper_gvec_vpks64,
760 };
761 static gen_helper_gvec_3_ptr * const vpks_cc[3] = {
762 gen_helper_gvec_vpks_cc16,
763 gen_helper_gvec_vpks_cc32,
764 gen_helper_gvec_vpks_cc64,
765 };
766 static gen_helper_gvec_3 * const vpkls[3] = {
767 gen_helper_gvec_vpkls16,
768 gen_helper_gvec_vpkls32,
769 gen_helper_gvec_vpkls64,
770 };
771 static gen_helper_gvec_3_ptr * const vpkls_cc[3] = {
772 gen_helper_gvec_vpkls_cc16,
773 gen_helper_gvec_vpkls_cc32,
774 gen_helper_gvec_vpkls_cc64,
775 };
776
777 if (es == ES_8 || es > ES_64) {
778 gen_program_exception(s, PGM_SPECIFICATION);
779 return DISAS_NORETURN;
780 }
781
782 switch (s->fields.op2) {
783 case 0x97:
784 if (get_field(s, m5) & 0x1) {
785 gen_gvec_3_ptr(v1, v2, v3, cpu_env, 0, vpks_cc[es - 1]);
786 set_cc_static(s);
787 } else {
788 gen_gvec_3_ool(v1, v2, v3, 0, vpks[es - 1]);
789 }
790 break;
791 case 0x95:
792 if (get_field(s, m5) & 0x1) {
793 gen_gvec_3_ptr(v1, v2, v3, cpu_env, 0, vpkls_cc[es - 1]);
794 set_cc_static(s);
795 } else {
796 gen_gvec_3_ool(v1, v2, v3, 0, vpkls[es - 1]);
797 }
798 break;
799 case 0x94:
800 /* If sources and destination dont't overlap -> fast path */
801 if (v1 != v2 && v1 != v3) {
802 const uint8_t src_es = get_field(s, m4);
803 const uint8_t dst_es = src_es - 1;
804 TCGv_i64 tmp = tcg_temp_new_i64();
805 int dst_idx, src_idx;
806
807 for (dst_idx = 0; dst_idx < NUM_VEC_ELEMENTS(dst_es); dst_idx++) {
808 src_idx = dst_idx;
809 if (src_idx < NUM_VEC_ELEMENTS(src_es)) {
810 read_vec_element_i64(tmp, v2, src_idx, src_es);
811 } else {
812 src_idx -= NUM_VEC_ELEMENTS(src_es);
813 read_vec_element_i64(tmp, v3, src_idx, src_es);
814 }
815 write_vec_element_i64(tmp, v1, dst_idx, dst_es);
816 }
817 tcg_temp_free_i64(tmp);
818 } else {
819 gen_gvec_3_ool(v1, v2, v3, 0, vpk[es - 1]);
820 }
821 break;
822 default:
823 g_assert_not_reached();
824 }
825 return DISAS_NEXT;
826 }
827
828 static DisasJumpType op_vperm(DisasContext *s, DisasOps *o)
829 {
830 gen_gvec_4_ool(get_field(s, v1), get_field(s, v2),
831 get_field(s, v3), get_field(s, v4),
832 0, gen_helper_gvec_vperm);
833 return DISAS_NEXT;
834 }
835
836 static DisasJumpType op_vpdi(DisasContext *s, DisasOps *o)
837 {
838 const uint8_t i2 = extract32(get_field(s, m4), 2, 1);
839 const uint8_t i3 = extract32(get_field(s, m4), 0, 1);
840 TCGv_i64 t0 = tcg_temp_new_i64();
841 TCGv_i64 t1 = tcg_temp_new_i64();
842
843 read_vec_element_i64(t0, get_field(s, v2), i2, ES_64);
844 read_vec_element_i64(t1, get_field(s, v3), i3, ES_64);
845 write_vec_element_i64(t0, get_field(s, v1), 0, ES_64);
846 write_vec_element_i64(t1, get_field(s, v1), 1, ES_64);
847 tcg_temp_free_i64(t0);
848 tcg_temp_free_i64(t1);
849 return DISAS_NEXT;
850 }
851
852 static DisasJumpType op_vrep(DisasContext *s, DisasOps *o)
853 {
854 const uint8_t enr = get_field(s, i2);
855 const uint8_t es = get_field(s, m4);
856
857 if (es > ES_64 || !valid_vec_element(enr, es)) {
858 gen_program_exception(s, PGM_SPECIFICATION);
859 return DISAS_NORETURN;
860 }
861
862 tcg_gen_gvec_dup_mem(es, vec_full_reg_offset(get_field(s, v1)),
863 vec_reg_offset(get_field(s, v3), enr, es),
864 16, 16);
865 return DISAS_NEXT;
866 }
867
868 static DisasJumpType op_vrepi(DisasContext *s, DisasOps *o)
869 {
870 const int64_t data = (int16_t)get_field(s, i2);
871 const uint8_t es = get_field(s, m3);
872
873 if (es > ES_64) {
874 gen_program_exception(s, PGM_SPECIFICATION);
875 return DISAS_NORETURN;
876 }
877
878 gen_gvec_dup_imm(es, get_field(s, v1), data);
879 return DISAS_NEXT;
880 }
881
882 static DisasJumpType op_vsce(DisasContext *s, DisasOps *o)
883 {
884 const uint8_t es = s->insn->data;
885 const uint8_t enr = get_field(s, m3);
886 TCGv_i64 tmp;
887
888 if (!valid_vec_element(enr, es)) {
889 gen_program_exception(s, PGM_SPECIFICATION);
890 return DISAS_NORETURN;
891 }
892
893 tmp = tcg_temp_new_i64();
894 read_vec_element_i64(tmp, get_field(s, v2), enr, es);
895 tcg_gen_add_i64(o->addr1, o->addr1, tmp);
896 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 0);
897
898 read_vec_element_i64(tmp, get_field(s, v1), enr, es);
899 tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
900 tcg_temp_free_i64(tmp);
901 return DISAS_NEXT;
902 }
903
904 static DisasJumpType op_vsel(DisasContext *s, DisasOps *o)
905 {
906 gen_gvec_fn_4(bitsel, ES_8, get_field(s, v1),
907 get_field(s, v4), get_field(s, v2),
908 get_field(s, v3));
909 return DISAS_NEXT;
910 }
911
912 static DisasJumpType op_vseg(DisasContext *s, DisasOps *o)
913 {
914 const uint8_t es = get_field(s, m3);
915 int idx1, idx2;
916 TCGv_i64 tmp;
917
918 switch (es) {
919 case ES_8:
920 idx1 = 7;
921 idx2 = 15;
922 break;
923 case ES_16:
924 idx1 = 3;
925 idx2 = 7;
926 break;
927 case ES_32:
928 idx1 = 1;
929 idx2 = 3;
930 break;
931 default:
932 gen_program_exception(s, PGM_SPECIFICATION);
933 return DISAS_NORETURN;
934 }
935
936 tmp = tcg_temp_new_i64();
937 read_vec_element_i64(tmp, get_field(s, v2), idx1, es | MO_SIGN);
938 write_vec_element_i64(tmp, get_field(s, v1), 0, ES_64);
939 read_vec_element_i64(tmp, get_field(s, v2), idx2, es | MO_SIGN);
940 write_vec_element_i64(tmp, get_field(s, v1), 1, ES_64);
941 tcg_temp_free_i64(tmp);
942 return DISAS_NEXT;
943 }
944
945 static DisasJumpType op_vst(DisasContext *s, DisasOps *o)
946 {
947 TCGv_i64 tmp = tcg_const_i64(16);
948
949 /* Probe write access before actually modifying memory */
950 gen_helper_probe_write_access(cpu_env, o->addr1, tmp);
951
952 read_vec_element_i64(tmp, get_field(s, v1), 0, ES_64);
953 tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEQ);
954 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
955 read_vec_element_i64(tmp, get_field(s, v1), 1, ES_64);
956 tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEQ);
957 tcg_temp_free_i64(tmp);
958 return DISAS_NEXT;
959 }
960
961 static DisasJumpType op_vste(DisasContext *s, DisasOps *o)
962 {
963 const uint8_t es = s->insn->data;
964 const uint8_t enr = get_field(s, m3);
965 TCGv_i64 tmp;
966
967 if (!valid_vec_element(enr, es)) {
968 gen_program_exception(s, PGM_SPECIFICATION);
969 return DISAS_NORETURN;
970 }
971
972 tmp = tcg_temp_new_i64();
973 read_vec_element_i64(tmp, get_field(s, v1), enr, es);
974 tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
975 tcg_temp_free_i64(tmp);
976 return DISAS_NEXT;
977 }
978
979 static DisasJumpType op_vstm(DisasContext *s, DisasOps *o)
980 {
981 const uint8_t v3 = get_field(s, v3);
982 uint8_t v1 = get_field(s, v1);
983 TCGv_i64 tmp;
984
985 while (v3 < v1 || (v3 - v1 + 1) > 16) {
986 gen_program_exception(s, PGM_SPECIFICATION);
987 return DISAS_NORETURN;
988 }
989
990 /* Probe write access before actually modifying memory */
991 tmp = tcg_const_i64((v3 - v1 + 1) * 16);
992 gen_helper_probe_write_access(cpu_env, o->addr1, tmp);
993
994 for (;; v1++) {
995 read_vec_element_i64(tmp, 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, v1, 1, ES_64);
999 tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEQ);
1000 if (v1 == v3) {
1001 break;
1002 }
1003 gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
1004 }
1005 tcg_temp_free_i64(tmp);
1006 return DISAS_NEXT;
1007 }
1008
1009 static DisasJumpType op_vstl(DisasContext *s, DisasOps *o)
1010 {
1011 const int v1_offs = vec_full_reg_offset(get_field(s, v1));
1012 TCGv_ptr a0 = tcg_temp_new_ptr();
1013
1014 /* convert highest index into an actual length */
1015 tcg_gen_addi_i64(o->in2, o->in2, 1);
1016 tcg_gen_addi_ptr(a0, cpu_env, v1_offs);
1017 gen_helper_vstl(cpu_env, a0, o->addr1, o->in2);
1018 tcg_temp_free_ptr(a0);
1019 return DISAS_NEXT;
1020 }
1021
1022 static DisasJumpType op_vup(DisasContext *s, DisasOps *o)
1023 {
1024 const bool logical = s->fields.op2 == 0xd4 || s->fields.op2 == 0xd5;
1025 const uint8_t v1 = get_field(s, v1);
1026 const uint8_t v2 = get_field(s, v2);
1027 const uint8_t src_es = get_field(s, m3);
1028 const uint8_t dst_es = src_es + 1;
1029 int dst_idx, src_idx;
1030 TCGv_i64 tmp;
1031
1032 if (src_es > ES_32) {
1033 gen_program_exception(s, PGM_SPECIFICATION);
1034 return DISAS_NORETURN;
1035 }
1036
1037 tmp = tcg_temp_new_i64();
1038 if (s->fields.op2 == 0xd7 || s->fields.op2 == 0xd5) {
1039 /* iterate backwards to avoid overwriting data we might need later */
1040 for (dst_idx = NUM_VEC_ELEMENTS(dst_es) - 1; dst_idx >= 0; dst_idx--) {
1041 src_idx = dst_idx;
1042 read_vec_element_i64(tmp, v2, src_idx,
1043 src_es | (logical ? 0 : MO_SIGN));
1044 write_vec_element_i64(tmp, v1, dst_idx, dst_es);
1045 }
1046
1047 } else {
1048 /* iterate forward to avoid overwriting data we might need later */
1049 for (dst_idx = 0; dst_idx < NUM_VEC_ELEMENTS(dst_es); dst_idx++) {
1050 src_idx = dst_idx + NUM_VEC_ELEMENTS(src_es) / 2;
1051 read_vec_element_i64(tmp, v2, src_idx,
1052 src_es | (logical ? 0 : MO_SIGN));
1053 write_vec_element_i64(tmp, v1, dst_idx, dst_es);
1054 }
1055 }
1056 tcg_temp_free_i64(tmp);
1057 return DISAS_NEXT;
1058 }
1059
1060 static DisasJumpType op_va(DisasContext *s, DisasOps *o)
1061 {
1062 const uint8_t es = get_field(s, m4);
1063
1064 if (es > ES_128) {
1065 gen_program_exception(s, PGM_SPECIFICATION);
1066 return DISAS_NORETURN;
1067 } else if (es == ES_128) {
1068 gen_gvec128_3_i64(tcg_gen_add2_i64, get_field(s, v1),
1069 get_field(s, v2), get_field(s, v3));
1070 return DISAS_NEXT;
1071 }
1072 gen_gvec_fn_3(add, es, get_field(s, v1), get_field(s, v2),
1073 get_field(s, v3));
1074 return DISAS_NEXT;
1075 }
1076
1077 static void gen_acc(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b, uint8_t es)
1078 {
1079 const uint8_t msb_bit_nr = NUM_VEC_ELEMENT_BITS(es) - 1;
1080 TCGv_i64 msb_mask = tcg_const_i64(dup_const(es, 1ull << msb_bit_nr));
1081 TCGv_i64 t1 = tcg_temp_new_i64();
1082 TCGv_i64 t2 = tcg_temp_new_i64();
1083 TCGv_i64 t3 = tcg_temp_new_i64();
1084
1085 /* Calculate the carry into the MSB, ignoring the old MSBs */
1086 tcg_gen_andc_i64(t1, a, msb_mask);
1087 tcg_gen_andc_i64(t2, b, msb_mask);
1088 tcg_gen_add_i64(t1, t1, t2);
1089 /* Calculate the MSB without any carry into it */
1090 tcg_gen_xor_i64(t3, a, b);
1091 /* Calculate the carry out of the MSB in the MSB bit position */
1092 tcg_gen_and_i64(d, a, b);
1093 tcg_gen_and_i64(t1, t1, t3);
1094 tcg_gen_or_i64(d, d, t1);
1095 /* Isolate and shift the carry into position */
1096 tcg_gen_and_i64(d, d, msb_mask);
1097 tcg_gen_shri_i64(d, d, msb_bit_nr);
1098
1099 tcg_temp_free_i64(t1);
1100 tcg_temp_free_i64(t2);
1101 tcg_temp_free_i64(t3);
1102 }
1103
1104 static void gen_acc8_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
1105 {
1106 gen_acc(d, a, b, ES_8);
1107 }
1108
1109 static void gen_acc16_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
1110 {
1111 gen_acc(d, a, b, ES_16);
1112 }
1113
1114 static void gen_acc_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
1115 {
1116 TCGv_i32 t = tcg_temp_new_i32();
1117
1118 tcg_gen_add_i32(t, a, b);
1119 tcg_gen_setcond_i32(TCG_COND_LTU, d, t, b);
1120 tcg_temp_free_i32(t);
1121 }
1122
1123 static void gen_acc_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
1124 {
1125 TCGv_i64 t = tcg_temp_new_i64();
1126
1127 tcg_gen_add_i64(t, a, b);
1128 tcg_gen_setcond_i64(TCG_COND_LTU, d, t, b);
1129 tcg_temp_free_i64(t);
1130 }
1131
1132 static void gen_acc2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al,
1133 TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh)
1134 {
1135 TCGv_i64 th = tcg_temp_new_i64();
1136 TCGv_i64 tl = tcg_temp_new_i64();
1137 TCGv_i64 zero = tcg_const_i64(0);
1138
1139 tcg_gen_add2_i64(tl, th, al, zero, bl, zero);
1140 tcg_gen_add2_i64(tl, th, th, zero, ah, zero);
1141 tcg_gen_add2_i64(tl, dl, tl, th, bh, zero);
1142 tcg_gen_mov_i64(dh, zero);
1143
1144 tcg_temp_free_i64(th);
1145 tcg_temp_free_i64(tl);
1146 tcg_temp_free_i64(zero);
1147 }
1148
1149 static DisasJumpType op_vacc(DisasContext *s, DisasOps *o)
1150 {
1151 const uint8_t es = get_field(s, m4);
1152 static const GVecGen3 g[4] = {
1153 { .fni8 = gen_acc8_i64, },
1154 { .fni8 = gen_acc16_i64, },
1155 { .fni4 = gen_acc_i32, },
1156 { .fni8 = gen_acc_i64, },
1157 };
1158
1159 if (es > ES_128) {
1160 gen_program_exception(s, PGM_SPECIFICATION);
1161 return DISAS_NORETURN;
1162 } else if (es == ES_128) {
1163 gen_gvec128_3_i64(gen_acc2_i64, get_field(s, v1),
1164 get_field(s, v2), get_field(s, v3));
1165 return DISAS_NEXT;
1166 }
1167 gen_gvec_3(get_field(s, v1), get_field(s, v2),
1168 get_field(s, v3), &g[es]);
1169 return DISAS_NEXT;
1170 }
1171
1172 static void gen_ac2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
1173 TCGv_i64 bl, TCGv_i64 bh, TCGv_i64 cl, TCGv_i64 ch)
1174 {
1175 TCGv_i64 tl = tcg_temp_new_i64();
1176 TCGv_i64 th = tcg_const_i64(0);
1177
1178 /* extract the carry only */
1179 tcg_gen_extract_i64(tl, cl, 0, 1);
1180 tcg_gen_add2_i64(dl, dh, al, ah, bl, bh);
1181 tcg_gen_add2_i64(dl, dh, dl, dh, tl, th);
1182
1183 tcg_temp_free_i64(tl);
1184 tcg_temp_free_i64(th);
1185 }
1186
1187 static DisasJumpType op_vac(DisasContext *s, DisasOps *o)
1188 {
1189 if (get_field(s, m5) != ES_128) {
1190 gen_program_exception(s, PGM_SPECIFICATION);
1191 return DISAS_NORETURN;
1192 }
1193
1194 gen_gvec128_4_i64(gen_ac2_i64, get_field(s, v1),
1195 get_field(s, v2), get_field(s, v3),
1196 get_field(s, v4));
1197 return DISAS_NEXT;
1198 }
1199
1200 static void gen_accc2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
1201 TCGv_i64 bl, TCGv_i64 bh, TCGv_i64 cl, TCGv_i64 ch)
1202 {
1203 TCGv_i64 tl = tcg_temp_new_i64();
1204 TCGv_i64 th = tcg_temp_new_i64();
1205 TCGv_i64 zero = tcg_const_i64(0);
1206
1207 tcg_gen_andi_i64(tl, cl, 1);
1208 tcg_gen_add2_i64(tl, th, tl, zero, al, zero);
1209 tcg_gen_add2_i64(tl, th, tl, th, bl, zero);
1210 tcg_gen_add2_i64(tl, th, th, zero, ah, zero);
1211 tcg_gen_add2_i64(tl, dl, tl, th, bh, zero);
1212 tcg_gen_mov_i64(dh, zero);
1213
1214 tcg_temp_free_i64(tl);
1215 tcg_temp_free_i64(th);
1216 tcg_temp_free_i64(zero);
1217 }
1218
1219 static DisasJumpType op_vaccc(DisasContext *s, DisasOps *o)
1220 {
1221 if (get_field(s, m5) != ES_128) {
1222 gen_program_exception(s, PGM_SPECIFICATION);
1223 return DISAS_NORETURN;
1224 }
1225
1226 gen_gvec128_4_i64(gen_accc2_i64, get_field(s, v1),
1227 get_field(s, v2), get_field(s, v3),
1228 get_field(s, v4));
1229 return DISAS_NEXT;
1230 }
1231
1232 static DisasJumpType op_vn(DisasContext *s, DisasOps *o)
1233 {
1234 gen_gvec_fn_3(and, ES_8, get_field(s, v1), get_field(s, v2),
1235 get_field(s, v3));
1236 return DISAS_NEXT;
1237 }
1238
1239 static DisasJumpType op_vnc(DisasContext *s, DisasOps *o)
1240 {
1241 gen_gvec_fn_3(andc, ES_8, get_field(s, v1),
1242 get_field(s, v2), get_field(s, v3));
1243 return DISAS_NEXT;
1244 }
1245
1246 static void gen_avg_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
1247 {
1248 TCGv_i64 t0 = tcg_temp_new_i64();
1249 TCGv_i64 t1 = tcg_temp_new_i64();
1250
1251 tcg_gen_ext_i32_i64(t0, a);
1252 tcg_gen_ext_i32_i64(t1, b);
1253 tcg_gen_add_i64(t0, t0, t1);
1254 tcg_gen_addi_i64(t0, t0, 1);
1255 tcg_gen_shri_i64(t0, t0, 1);
1256 tcg_gen_extrl_i64_i32(d, t0);
1257
1258 tcg_temp_free(t0);
1259 tcg_temp_free(t1);
1260 }
1261
1262 static void gen_avg_i64(TCGv_i64 dl, TCGv_i64 al, TCGv_i64 bl)
1263 {
1264 TCGv_i64 dh = tcg_temp_new_i64();
1265 TCGv_i64 ah = tcg_temp_new_i64();
1266 TCGv_i64 bh = tcg_temp_new_i64();
1267
1268 /* extending the sign by one bit is sufficient */
1269 tcg_gen_extract_i64(ah, al, 63, 1);
1270 tcg_gen_extract_i64(bh, bl, 63, 1);
1271 tcg_gen_add2_i64(dl, dh, al, ah, bl, bh);
1272 gen_addi2_i64(dl, dh, dl, dh, 1);
1273 tcg_gen_extract2_i64(dl, dl, dh, 1);
1274
1275 tcg_temp_free_i64(dh);
1276 tcg_temp_free_i64(ah);
1277 tcg_temp_free_i64(bh);
1278 }
1279
1280 static DisasJumpType op_vavg(DisasContext *s, DisasOps *o)
1281 {
1282 const uint8_t es = get_field(s, m4);
1283 static const GVecGen3 g[4] = {
1284 { .fno = gen_helper_gvec_vavg8, },
1285 { .fno = gen_helper_gvec_vavg16, },
1286 { .fni4 = gen_avg_i32, },
1287 { .fni8 = gen_avg_i64, },
1288 };
1289
1290 if (es > ES_64) {
1291 gen_program_exception(s, PGM_SPECIFICATION);
1292 return DISAS_NORETURN;
1293 }
1294 gen_gvec_3(get_field(s, v1), get_field(s, v2),
1295 get_field(s, v3), &g[es]);
1296 return DISAS_NEXT;
1297 }
1298
1299 static void gen_avgl_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
1300 {
1301 TCGv_i64 t0 = tcg_temp_new_i64();
1302 TCGv_i64 t1 = tcg_temp_new_i64();
1303
1304 tcg_gen_extu_i32_i64(t0, a);
1305 tcg_gen_extu_i32_i64(t1, b);
1306 tcg_gen_add_i64(t0, t0, t1);
1307 tcg_gen_addi_i64(t0, t0, 1);
1308 tcg_gen_shri_i64(t0, t0, 1);
1309 tcg_gen_extrl_i64_i32(d, t0);
1310
1311 tcg_temp_free(t0);
1312 tcg_temp_free(t1);
1313 }
1314
1315 static void gen_avgl_i64(TCGv_i64 dl, TCGv_i64 al, TCGv_i64 bl)
1316 {
1317 TCGv_i64 dh = tcg_temp_new_i64();
1318 TCGv_i64 zero = tcg_const_i64(0);
1319
1320 tcg_gen_add2_i64(dl, dh, al, zero, bl, zero);
1321 gen_addi2_i64(dl, dh, dl, dh, 1);
1322 tcg_gen_extract2_i64(dl, dl, dh, 1);
1323
1324 tcg_temp_free_i64(dh);
1325 tcg_temp_free_i64(zero);
1326 }
1327
1328 static DisasJumpType op_vavgl(DisasContext *s, DisasOps *o)
1329 {
1330 const uint8_t es = get_field(s, m4);
1331 static const GVecGen3 g[4] = {
1332 { .fno = gen_helper_gvec_vavgl8, },
1333 { .fno = gen_helper_gvec_vavgl16, },
1334 { .fni4 = gen_avgl_i32, },
1335 { .fni8 = gen_avgl_i64, },
1336 };
1337
1338 if (es > ES_64) {
1339 gen_program_exception(s, PGM_SPECIFICATION);
1340 return DISAS_NORETURN;
1341 }
1342 gen_gvec_3(get_field(s, v1), get_field(s, v2),
1343 get_field(s, v3), &g[es]);
1344 return DISAS_NEXT;
1345 }
1346
1347 static DisasJumpType op_vcksm(DisasContext *s, DisasOps *o)
1348 {
1349 TCGv_i32 tmp = tcg_temp_new_i32();
1350 TCGv_i32 sum = tcg_temp_new_i32();
1351 int i;
1352
1353 read_vec_element_i32(sum, get_field(s, v3), 1, ES_32);
1354 for (i = 0; i < 4; i++) {
1355 read_vec_element_i32(tmp, get_field(s, v2), i, ES_32);
1356 tcg_gen_add2_i32(tmp, sum, sum, sum, tmp, tmp);
1357 }
1358 gen_gvec_dup_imm(ES_32, get_field(s, v1), 0);
1359 write_vec_element_i32(sum, get_field(s, v1), 1, ES_32);
1360
1361 tcg_temp_free_i32(tmp);
1362 tcg_temp_free_i32(sum);
1363 return DISAS_NEXT;
1364 }
1365
1366 static DisasJumpType op_vec(DisasContext *s, DisasOps *o)
1367 {
1368 uint8_t es = get_field(s, m3);
1369 const uint8_t enr = NUM_VEC_ELEMENTS(es) / 2 - 1;
1370
1371 if (es > ES_64) {
1372 gen_program_exception(s, PGM_SPECIFICATION);
1373 return DISAS_NORETURN;
1374 }
1375 if (s->fields.op2 == 0xdb) {
1376 es |= MO_SIGN;
1377 }
1378
1379 o->in1 = tcg_temp_new_i64();
1380 o->in2 = tcg_temp_new_i64();
1381 read_vec_element_i64(o->in1, get_field(s, v1), enr, es);
1382 read_vec_element_i64(o->in2, get_field(s, v2), enr, es);
1383 return DISAS_NEXT;
1384 }
1385
1386 static DisasJumpType op_vc(DisasContext *s, DisasOps *o)
1387 {
1388 const uint8_t es = get_field(s, m4);
1389 TCGCond cond = s->insn->data;
1390
1391 if (es > ES_64) {
1392 gen_program_exception(s, PGM_SPECIFICATION);
1393 return DISAS_NORETURN;
1394 }
1395
1396 tcg_gen_gvec_cmp(cond, es,
1397 vec_full_reg_offset(get_field(s, v1)),
1398 vec_full_reg_offset(get_field(s, v2)),
1399 vec_full_reg_offset(get_field(s, v3)), 16, 16);
1400 if (get_field(s, m5) & 0x1) {
1401 TCGv_i64 low = tcg_temp_new_i64();
1402 TCGv_i64 high = tcg_temp_new_i64();
1403
1404 read_vec_element_i64(high, get_field(s, v1), 0, ES_64);
1405 read_vec_element_i64(low, get_field(s, v1), 1, ES_64);
1406 gen_op_update2_cc_i64(s, CC_OP_VC, low, high);
1407
1408 tcg_temp_free_i64(low);
1409 tcg_temp_free_i64(high);
1410 }
1411 return DISAS_NEXT;
1412 }
1413
1414 static void gen_clz_i32(TCGv_i32 d, TCGv_i32 a)
1415 {
1416 tcg_gen_clzi_i32(d, a, 32);
1417 }
1418
1419 static void gen_clz_i64(TCGv_i64 d, TCGv_i64 a)
1420 {
1421 tcg_gen_clzi_i64(d, a, 64);
1422 }
1423
1424 static DisasJumpType op_vclz(DisasContext *s, DisasOps *o)
1425 {
1426 const uint8_t es = get_field(s, m3);
1427 static const GVecGen2 g[4] = {
1428 { .fno = gen_helper_gvec_vclz8, },
1429 { .fno = gen_helper_gvec_vclz16, },
1430 { .fni4 = gen_clz_i32, },
1431 { .fni8 = gen_clz_i64, },
1432 };
1433
1434 if (es > ES_64) {
1435 gen_program_exception(s, PGM_SPECIFICATION);
1436 return DISAS_NORETURN;
1437 }
1438 gen_gvec_2(get_field(s, v1), get_field(s, v2), &g[es]);
1439 return DISAS_NEXT;
1440 }
1441
1442 static void gen_ctz_i32(TCGv_i32 d, TCGv_i32 a)
1443 {
1444 tcg_gen_ctzi_i32(d, a, 32);
1445 }
1446
1447 static void gen_ctz_i64(TCGv_i64 d, TCGv_i64 a)
1448 {
1449 tcg_gen_ctzi_i64(d, a, 64);
1450 }
1451
1452 static DisasJumpType op_vctz(DisasContext *s, DisasOps *o)
1453 {
1454 const uint8_t es = get_field(s, m3);
1455 static const GVecGen2 g[4] = {
1456 { .fno = gen_helper_gvec_vctz8, },
1457 { .fno = gen_helper_gvec_vctz16, },
1458 { .fni4 = gen_ctz_i32, },
1459 { .fni8 = gen_ctz_i64, },
1460 };
1461
1462 if (es > ES_64) {
1463 gen_program_exception(s, PGM_SPECIFICATION);
1464 return DISAS_NORETURN;
1465 }
1466 gen_gvec_2(get_field(s, v1), get_field(s, v2), &g[es]);
1467 return DISAS_NEXT;
1468 }
1469
1470 static DisasJumpType op_vx(DisasContext *s, DisasOps *o)
1471 {
1472 gen_gvec_fn_3(xor, ES_8, get_field(s, v1), get_field(s, v2),
1473 get_field(s, v3));
1474 return DISAS_NEXT;
1475 }
1476
1477 static DisasJumpType op_vgfm(DisasContext *s, DisasOps *o)
1478 {
1479 const uint8_t es = get_field(s, m4);
1480 static const GVecGen3 g[4] = {
1481 { .fno = gen_helper_gvec_vgfm8, },
1482 { .fno = gen_helper_gvec_vgfm16, },
1483 { .fno = gen_helper_gvec_vgfm32, },
1484 { .fno = gen_helper_gvec_vgfm64, },
1485 };
1486
1487 if (es > ES_64) {
1488 gen_program_exception(s, PGM_SPECIFICATION);
1489 return DISAS_NORETURN;
1490 }
1491 gen_gvec_3(get_field(s, v1), get_field(s, v2),
1492 get_field(s, v3), &g[es]);
1493 return DISAS_NEXT;
1494 }
1495
1496 static DisasJumpType op_vgfma(DisasContext *s, DisasOps *o)
1497 {
1498 const uint8_t es = get_field(s, m5);
1499 static const GVecGen4 g[4] = {
1500 { .fno = gen_helper_gvec_vgfma8, },
1501 { .fno = gen_helper_gvec_vgfma16, },
1502 { .fno = gen_helper_gvec_vgfma32, },
1503 { .fno = gen_helper_gvec_vgfma64, },
1504 };
1505
1506 if (es > ES_64) {
1507 gen_program_exception(s, PGM_SPECIFICATION);
1508 return DISAS_NORETURN;
1509 }
1510 gen_gvec_4(get_field(s, v1), get_field(s, v2),
1511 get_field(s, v3), get_field(s, v4), &g[es]);
1512 return DISAS_NEXT;
1513 }
1514
1515 static DisasJumpType op_vlc(DisasContext *s, DisasOps *o)
1516 {
1517 const uint8_t es = get_field(s, m3);
1518
1519 if (es > ES_64) {
1520 gen_program_exception(s, PGM_SPECIFICATION);
1521 return DISAS_NORETURN;
1522 }
1523
1524 gen_gvec_fn_2(neg, es, get_field(s, v1), get_field(s, v2));
1525 return DISAS_NEXT;
1526 }
1527
1528 static DisasJumpType op_vlp(DisasContext *s, DisasOps *o)
1529 {
1530 const uint8_t es = get_field(s, m3);
1531
1532 if (es > ES_64) {
1533 gen_program_exception(s, PGM_SPECIFICATION);
1534 return DISAS_NORETURN;
1535 }
1536
1537 gen_gvec_fn_2(abs, es, get_field(s, v1), get_field(s, v2));
1538 return DISAS_NEXT;
1539 }
1540
1541 static DisasJumpType op_vmx(DisasContext *s, DisasOps *o)
1542 {
1543 const uint8_t v1 = get_field(s, v1);
1544 const uint8_t v2 = get_field(s, v2);
1545 const uint8_t v3 = get_field(s, v3);
1546 const uint8_t es = get_field(s, m4);
1547
1548 if (es > ES_64) {
1549 gen_program_exception(s, PGM_SPECIFICATION);
1550 return DISAS_NORETURN;
1551 }
1552
1553 switch (s->fields.op2) {
1554 case 0xff:
1555 gen_gvec_fn_3(smax, es, v1, v2, v3);
1556 break;
1557 case 0xfd:
1558 gen_gvec_fn_3(umax, es, v1, v2, v3);
1559 break;
1560 case 0xfe:
1561 gen_gvec_fn_3(smin, es, v1, v2, v3);
1562 break;
1563 case 0xfc:
1564 gen_gvec_fn_3(umin, es, v1, v2, v3);
1565 break;
1566 default:
1567 g_assert_not_reached();
1568 }
1569 return DISAS_NEXT;
1570 }
1571
1572 static void gen_mal_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b, TCGv_i32 c)
1573 {
1574 TCGv_i32 t0 = tcg_temp_new_i32();
1575
1576 tcg_gen_mul_i32(t0, a, b);
1577 tcg_gen_add_i32(d, t0, c);
1578
1579 tcg_temp_free_i32(t0);
1580 }
1581
1582 static void gen_mah_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b, TCGv_i32 c)
1583 {
1584 TCGv_i64 t0 = tcg_temp_new_i64();
1585 TCGv_i64 t1 = tcg_temp_new_i64();
1586 TCGv_i64 t2 = tcg_temp_new_i64();
1587
1588 tcg_gen_ext_i32_i64(t0, a);
1589 tcg_gen_ext_i32_i64(t1, b);
1590 tcg_gen_ext_i32_i64(t2, c);
1591 tcg_gen_mul_i64(t0, t0, t1);
1592 tcg_gen_add_i64(t0, t0, t2);
1593 tcg_gen_extrh_i64_i32(d, t0);
1594
1595 tcg_temp_free(t0);
1596 tcg_temp_free(t1);
1597 tcg_temp_free(t2);
1598 }
1599
1600 static void gen_malh_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b, TCGv_i32 c)
1601 {
1602 TCGv_i64 t0 = tcg_temp_new_i64();
1603 TCGv_i64 t1 = tcg_temp_new_i64();
1604 TCGv_i64 t2 = tcg_temp_new_i64();
1605
1606 tcg_gen_extu_i32_i64(t0, a);
1607 tcg_gen_extu_i32_i64(t1, b);
1608 tcg_gen_extu_i32_i64(t2, c);
1609 tcg_gen_mul_i64(t0, t0, t1);
1610 tcg_gen_add_i64(t0, t0, t2);
1611 tcg_gen_extrh_i64_i32(d, t0);
1612
1613 tcg_temp_free(t0);
1614 tcg_temp_free(t1);
1615 tcg_temp_free(t2);
1616 }
1617
1618 static DisasJumpType op_vma(DisasContext *s, DisasOps *o)
1619 {
1620 const uint8_t es = get_field(s, m5);
1621 static const GVecGen4 g_vmal[3] = {
1622 { .fno = gen_helper_gvec_vmal8, },
1623 { .fno = gen_helper_gvec_vmal16, },
1624 { .fni4 = gen_mal_i32, },
1625 };
1626 static const GVecGen4 g_vmah[3] = {
1627 { .fno = gen_helper_gvec_vmah8, },
1628 { .fno = gen_helper_gvec_vmah16, },
1629 { .fni4 = gen_mah_i32, },
1630 };
1631 static const GVecGen4 g_vmalh[3] = {
1632 { .fno = gen_helper_gvec_vmalh8, },
1633 { .fno = gen_helper_gvec_vmalh16, },
1634 { .fni4 = gen_malh_i32, },
1635 };
1636 static const GVecGen4 g_vmae[3] = {
1637 { .fno = gen_helper_gvec_vmae8, },
1638 { .fno = gen_helper_gvec_vmae16, },
1639 { .fno = gen_helper_gvec_vmae32, },
1640 };
1641 static const GVecGen4 g_vmale[3] = {
1642 { .fno = gen_helper_gvec_vmale8, },
1643 { .fno = gen_helper_gvec_vmale16, },
1644 { .fno = gen_helper_gvec_vmale32, },
1645 };
1646 static const GVecGen4 g_vmao[3] = {
1647 { .fno = gen_helper_gvec_vmao8, },
1648 { .fno = gen_helper_gvec_vmao16, },
1649 { .fno = gen_helper_gvec_vmao32, },
1650 };
1651 static const GVecGen4 g_vmalo[3] = {
1652 { .fno = gen_helper_gvec_vmalo8, },
1653 { .fno = gen_helper_gvec_vmalo16, },
1654 { .fno = gen_helper_gvec_vmalo32, },
1655 };
1656 const GVecGen4 *fn;
1657
1658 if (es > ES_32) {
1659 gen_program_exception(s, PGM_SPECIFICATION);
1660 return DISAS_NORETURN;
1661 }
1662
1663 switch (s->fields.op2) {
1664 case 0xaa:
1665 fn = &g_vmal[es];
1666 break;
1667 case 0xab:
1668 fn = &g_vmah[es];
1669 break;
1670 case 0xa9:
1671 fn = &g_vmalh[es];
1672 break;
1673 case 0xae:
1674 fn = &g_vmae[es];
1675 break;
1676 case 0xac:
1677 fn = &g_vmale[es];
1678 break;
1679 case 0xaf:
1680 fn = &g_vmao[es];
1681 break;
1682 case 0xad:
1683 fn = &g_vmalo[es];
1684 break;
1685 default:
1686 g_assert_not_reached();
1687 }
1688
1689 gen_gvec_4(get_field(s, v1), get_field(s, v2),
1690 get_field(s, v3), get_field(s, v4), fn);
1691 return DISAS_NEXT;
1692 }
1693
1694 static void gen_mh_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
1695 {
1696 TCGv_i32 t = tcg_temp_new_i32();
1697
1698 tcg_gen_muls2_i32(t, d, a, b);
1699 tcg_temp_free_i32(t);
1700 }
1701
1702 static void gen_mlh_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
1703 {
1704 TCGv_i32 t = tcg_temp_new_i32();
1705
1706 tcg_gen_mulu2_i32(t, d, a, b);
1707 tcg_temp_free_i32(t);
1708 }
1709
1710 static DisasJumpType op_vm(DisasContext *s, DisasOps *o)
1711 {
1712 const uint8_t es = get_field(s, m4);
1713 static const GVecGen3 g_vmh[3] = {
1714 { .fno = gen_helper_gvec_vmh8, },
1715 { .fno = gen_helper_gvec_vmh16, },
1716 { .fni4 = gen_mh_i32, },
1717 };
1718 static const GVecGen3 g_vmlh[3] = {
1719 { .fno = gen_helper_gvec_vmlh8, },
1720 { .fno = gen_helper_gvec_vmlh16, },
1721 { .fni4 = gen_mlh_i32, },
1722 };
1723 static const GVecGen3 g_vme[3] = {
1724 { .fno = gen_helper_gvec_vme8, },
1725 { .fno = gen_helper_gvec_vme16, },
1726 { .fno = gen_helper_gvec_vme32, },
1727 };
1728 static const GVecGen3 g_vmle[3] = {
1729 { .fno = gen_helper_gvec_vmle8, },
1730 { .fno = gen_helper_gvec_vmle16, },
1731 { .fno = gen_helper_gvec_vmle32, },
1732 };
1733 static const GVecGen3 g_vmo[3] = {
1734 { .fno = gen_helper_gvec_vmo8, },
1735 { .fno = gen_helper_gvec_vmo16, },
1736 { .fno = gen_helper_gvec_vmo32, },
1737 };
1738 static const GVecGen3 g_vmlo[3] = {
1739 { .fno = gen_helper_gvec_vmlo8, },
1740 { .fno = gen_helper_gvec_vmlo16, },
1741 { .fno = gen_helper_gvec_vmlo32, },
1742 };
1743 const GVecGen3 *fn;
1744
1745 if (es > ES_32) {
1746 gen_program_exception(s, PGM_SPECIFICATION);
1747 return DISAS_NORETURN;
1748 }
1749
1750 switch (s->fields.op2) {
1751 case 0xa2:
1752 gen_gvec_fn_3(mul, es, get_field(s, v1),
1753 get_field(s, v2), get_field(s, v3));
1754 return DISAS_NEXT;
1755 case 0xa3:
1756 fn = &g_vmh[es];
1757 break;
1758 case 0xa1:
1759 fn = &g_vmlh[es];
1760 break;
1761 case 0xa6:
1762 fn = &g_vme[es];
1763 break;
1764 case 0xa4:
1765 fn = &g_vmle[es];
1766 break;
1767 case 0xa7:
1768 fn = &g_vmo[es];
1769 break;
1770 case 0xa5:
1771 fn = &g_vmlo[es];
1772 break;
1773 default:
1774 g_assert_not_reached();
1775 }
1776
1777 gen_gvec_3(get_field(s, v1), get_field(s, v2),
1778 get_field(s, v3), fn);
1779 return DISAS_NEXT;
1780 }
1781
1782 static DisasJumpType op_vmsl(DisasContext *s, DisasOps *o)
1783 {
1784 TCGv_i64 l1, h1, l2, h2;
1785
1786 if (get_field(s, m5) != ES_64) {
1787 gen_program_exception(s, PGM_SPECIFICATION);
1788 return DISAS_NORETURN;
1789 }
1790
1791 l1 = tcg_temp_new_i64();
1792 h1 = tcg_temp_new_i64();
1793 l2 = tcg_temp_new_i64();
1794 h2 = tcg_temp_new_i64();
1795
1796 /* Multipy both even elements from v2 and v3 */
1797 read_vec_element_i64(l1, get_field(s, v2), 0, ES_64);
1798 read_vec_element_i64(h1, get_field(s, v3), 0, ES_64);
1799 tcg_gen_mulu2_i64(l1, h1, l1, h1);
1800 /* Shift result left by one (x2) if requested */
1801 if (extract32(get_field(s, m6), 3, 1)) {
1802 tcg_gen_add2_i64(l1, h1, l1, h1, l1, h1);
1803 }
1804
1805 /* Multipy both odd elements from v2 and v3 */
1806 read_vec_element_i64(l2, get_field(s, v2), 1, ES_64);
1807 read_vec_element_i64(h2, get_field(s, v3), 1, ES_64);
1808 tcg_gen_mulu2_i64(l2, h2, l2, h2);
1809 /* Shift result left by one (x2) if requested */
1810 if (extract32(get_field(s, m6), 2, 1)) {
1811 tcg_gen_add2_i64(l2, h2, l2, h2, l2, h2);
1812 }
1813
1814 /* Add both intermediate results */
1815 tcg_gen_add2_i64(l1, h1, l1, h1, l2, h2);
1816 /* Add whole v4 */
1817 read_vec_element_i64(h2, get_field(s, v4), 0, ES_64);
1818 read_vec_element_i64(l2, get_field(s, v4), 1, ES_64);
1819 tcg_gen_add2_i64(l1, h1, l1, h1, l2, h2);
1820
1821 /* Store final result into v1. */
1822 write_vec_element_i64(h1, get_field(s, v1), 0, ES_64);
1823 write_vec_element_i64(l1, get_field(s, v1), 1, ES_64);
1824
1825 tcg_temp_free_i64(l1);
1826 tcg_temp_free_i64(h1);
1827 tcg_temp_free_i64(l2);
1828 tcg_temp_free_i64(h2);
1829 return DISAS_NEXT;
1830 }
1831
1832 static DisasJumpType op_vnn(DisasContext *s, DisasOps *o)
1833 {
1834 gen_gvec_fn_3(nand, ES_8, get_field(s, v1),
1835 get_field(s, v2), get_field(s, v3));
1836 return DISAS_NEXT;
1837 }
1838
1839 static DisasJumpType op_vno(DisasContext *s, DisasOps *o)
1840 {
1841 gen_gvec_fn_3(nor, ES_8, get_field(s, v1), get_field(s, v2),
1842 get_field(s, v3));
1843 return DISAS_NEXT;
1844 }
1845
1846 static DisasJumpType op_vnx(DisasContext *s, DisasOps *o)
1847 {
1848 gen_gvec_fn_3(eqv, ES_8, get_field(s, v1), get_field(s, v2),
1849 get_field(s, v3));
1850 return DISAS_NEXT;
1851 }
1852
1853 static DisasJumpType op_vo(DisasContext *s, DisasOps *o)
1854 {
1855 gen_gvec_fn_3(or, ES_8, get_field(s, v1), get_field(s, v2),
1856 get_field(s, v3));
1857 return DISAS_NEXT;
1858 }
1859
1860 static DisasJumpType op_voc(DisasContext *s, DisasOps *o)
1861 {
1862 gen_gvec_fn_3(orc, ES_8, get_field(s, v1), get_field(s, v2),
1863 get_field(s, v3));
1864 return DISAS_NEXT;
1865 }
1866
1867 static DisasJumpType op_vpopct(DisasContext *s, DisasOps *o)
1868 {
1869 const uint8_t es = get_field(s, m3);
1870 static const GVecGen2 g[4] = {
1871 { .fno = gen_helper_gvec_vpopct8, },
1872 { .fno = gen_helper_gvec_vpopct16, },
1873 { .fni4 = tcg_gen_ctpop_i32, },
1874 { .fni8 = tcg_gen_ctpop_i64, },
1875 };
1876
1877 if (es > ES_64 || (es != ES_8 && !s390_has_feat(S390_FEAT_VECTOR_ENH))) {
1878 gen_program_exception(s, PGM_SPECIFICATION);
1879 return DISAS_NORETURN;
1880 }
1881
1882 gen_gvec_2(get_field(s, v1), get_field(s, v2), &g[es]);
1883 return DISAS_NEXT;
1884 }
1885
1886 static void gen_rim_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b, int32_t c)
1887 {
1888 TCGv_i32 t = tcg_temp_new_i32();
1889
1890 tcg_gen_rotli_i32(t, a, c & 31);
1891 tcg_gen_and_i32(t, t, b);
1892 tcg_gen_andc_i32(d, d, b);
1893 tcg_gen_or_i32(d, d, t);
1894
1895 tcg_temp_free_i32(t);
1896 }
1897
1898 static void gen_rim_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b, int64_t c)
1899 {
1900 TCGv_i64 t = tcg_temp_new_i64();
1901
1902 tcg_gen_rotli_i64(t, a, c & 63);
1903 tcg_gen_and_i64(t, t, b);
1904 tcg_gen_andc_i64(d, d, b);
1905 tcg_gen_or_i64(d, d, t);
1906
1907 tcg_temp_free_i64(t);
1908 }
1909
1910 static DisasJumpType op_verim(DisasContext *s, DisasOps *o)
1911 {
1912 const uint8_t es = get_field(s, m5);
1913 const uint8_t i4 = get_field(s, i4) &
1914 (NUM_VEC_ELEMENT_BITS(es) - 1);
1915 static const GVecGen3i g[4] = {
1916 { .fno = gen_helper_gvec_verim8, },
1917 { .fno = gen_helper_gvec_verim16, },
1918 { .fni4 = gen_rim_i32,
1919 .load_dest = true, },
1920 { .fni8 = gen_rim_i64,
1921 .load_dest = true, },
1922 };
1923
1924 if (es > ES_64) {
1925 gen_program_exception(s, PGM_SPECIFICATION);
1926 return DISAS_NORETURN;
1927 }
1928
1929 gen_gvec_3i(get_field(s, v1), get_field(s, v2),
1930 get_field(s, v3), i4, &g[es]);
1931 return DISAS_NEXT;
1932 }
1933
1934 static DisasJumpType op_vesv(DisasContext *s, DisasOps *o)
1935 {
1936 const uint8_t es = get_field(s, m4);
1937 const uint8_t v1 = get_field(s, v1);
1938 const uint8_t v2 = get_field(s, v2);
1939 const uint8_t v3 = get_field(s, v3);
1940
1941 if (es > ES_64) {
1942 gen_program_exception(s, PGM_SPECIFICATION);
1943 return DISAS_NORETURN;
1944 }
1945
1946 switch (s->fields.op2) {
1947 case 0x70:
1948 gen_gvec_fn_3(shlv, es, v1, v2, v3);
1949 break;
1950 case 0x73:
1951 gen_gvec_fn_3(rotlv, es, v1, v2, v3);
1952 break;
1953 case 0x7a:
1954 gen_gvec_fn_3(sarv, es, v1, v2, v3);
1955 break;
1956 case 0x78:
1957 gen_gvec_fn_3(shrv, es, v1, v2, v3);
1958 break;
1959 default:
1960 g_assert_not_reached();
1961 }
1962 return DISAS_NEXT;
1963 }
1964
1965 static DisasJumpType op_ves(DisasContext *s, DisasOps *o)
1966 {
1967 const uint8_t es = get_field(s, m4);
1968 const uint8_t d2 = get_field(s, d2) &
1969 (NUM_VEC_ELEMENT_BITS(es) - 1);
1970 const uint8_t v1 = get_field(s, v1);
1971 const uint8_t v3 = get_field(s, v3);
1972 TCGv_i32 shift;
1973
1974 if (es > ES_64) {
1975 gen_program_exception(s, PGM_SPECIFICATION);
1976 return DISAS_NORETURN;
1977 }
1978
1979 if (likely(!get_field(s, b2))) {
1980 switch (s->fields.op2) {
1981 case 0x30:
1982 gen_gvec_fn_2i(shli, es, v1, v3, d2);
1983 break;
1984 case 0x33:
1985 gen_gvec_fn_2i(rotli, es, v1, v3, d2);
1986 break;
1987 case 0x3a:
1988 gen_gvec_fn_2i(sari, es, v1, v3, d2);
1989 break;
1990 case 0x38:
1991 gen_gvec_fn_2i(shri, es, v1, v3, d2);
1992 break;
1993 default:
1994 g_assert_not_reached();
1995 }
1996 } else {
1997 shift = tcg_temp_new_i32();
1998 tcg_gen_extrl_i64_i32(shift, o->addr1);
1999 tcg_gen_andi_i32(shift, shift, NUM_VEC_ELEMENT_BITS(es) - 1);
2000 switch (s->fields.op2) {
2001 case 0x30:
2002 gen_gvec_fn_2s(shls, es, v1, v3, shift);
2003 break;
2004 case 0x33:
2005 gen_gvec_fn_2s(rotls, es, v1, v3, shift);
2006 break;
2007 case 0x3a:
2008 gen_gvec_fn_2s(sars, es, v1, v3, shift);
2009 break;
2010 case 0x38:
2011 gen_gvec_fn_2s(shrs, es, v1, v3, shift);
2012 break;
2013 default:
2014 g_assert_not_reached();
2015 }
2016 tcg_temp_free_i32(shift);
2017 }
2018 return DISAS_NEXT;
2019 }
2020
2021 static DisasJumpType op_vsl(DisasContext *s, DisasOps *o)
2022 {
2023 TCGv_i64 shift = tcg_temp_new_i64();
2024
2025 read_vec_element_i64(shift, get_field(s, v3), 7, ES_8);
2026 if (s->fields.op2 == 0x74) {
2027 tcg_gen_andi_i64(shift, shift, 0x7);
2028 } else {
2029 tcg_gen_andi_i64(shift, shift, 0x78);
2030 }
2031
2032 gen_gvec_2i_ool(get_field(s, v1), get_field(s, v2),
2033 shift, 0, gen_helper_gvec_vsl);
2034 tcg_temp_free_i64(shift);
2035 return DISAS_NEXT;
2036 }
2037
2038 static DisasJumpType op_vsldb(DisasContext *s, DisasOps *o)
2039 {
2040 const uint8_t i4 = get_field(s, i4) & 0xf;
2041 const int left_shift = (i4 & 7) * 8;
2042 const int right_shift = 64 - left_shift;
2043 TCGv_i64 t0 = tcg_temp_new_i64();
2044 TCGv_i64 t1 = tcg_temp_new_i64();
2045 TCGv_i64 t2 = tcg_temp_new_i64();
2046
2047 if ((i4 & 8) == 0) {
2048 read_vec_element_i64(t0, get_field(s, v2), 0, ES_64);
2049 read_vec_element_i64(t1, get_field(s, v2), 1, ES_64);
2050 read_vec_element_i64(t2, get_field(s, v3), 0, ES_64);
2051 } else {
2052 read_vec_element_i64(t0, get_field(s, v2), 1, ES_64);
2053 read_vec_element_i64(t1, get_field(s, v3), 0, ES_64);
2054 read_vec_element_i64(t2, get_field(s, v3), 1, ES_64);
2055 }
2056 tcg_gen_extract2_i64(t0, t1, t0, right_shift);
2057 tcg_gen_extract2_i64(t1, t2, t1, right_shift);
2058 write_vec_element_i64(t0, get_field(s, v1), 0, ES_64);
2059 write_vec_element_i64(t1, get_field(s, v1), 1, ES_64);
2060
2061 tcg_temp_free(t0);
2062 tcg_temp_free(t1);
2063 tcg_temp_free(t2);
2064 return DISAS_NEXT;
2065 }
2066
2067 static DisasJumpType op_vsra(DisasContext *s, DisasOps *o)
2068 {
2069 TCGv_i64 shift = tcg_temp_new_i64();
2070
2071 read_vec_element_i64(shift, get_field(s, v3), 7, ES_8);
2072 if (s->fields.op2 == 0x7e) {
2073 tcg_gen_andi_i64(shift, shift, 0x7);
2074 } else {
2075 tcg_gen_andi_i64(shift, shift, 0x78);
2076 }
2077
2078 gen_gvec_2i_ool(get_field(s, v1), get_field(s, v2),
2079 shift, 0, gen_helper_gvec_vsra);
2080 tcg_temp_free_i64(shift);
2081 return DISAS_NEXT;
2082 }
2083
2084 static DisasJumpType op_vsrl(DisasContext *s, DisasOps *o)
2085 {
2086 TCGv_i64 shift = tcg_temp_new_i64();
2087
2088 read_vec_element_i64(shift, get_field(s, v3), 7, ES_8);
2089 if (s->fields.op2 == 0x7c) {
2090 tcg_gen_andi_i64(shift, shift, 0x7);
2091 } else {
2092 tcg_gen_andi_i64(shift, shift, 0x78);
2093 }
2094
2095 gen_gvec_2i_ool(get_field(s, v1), get_field(s, v2),
2096 shift, 0, gen_helper_gvec_vsrl);
2097 tcg_temp_free_i64(shift);
2098 return DISAS_NEXT;
2099 }
2100
2101 static DisasJumpType op_vs(DisasContext *s, DisasOps *o)
2102 {
2103 const uint8_t es = get_field(s, m4);
2104
2105 if (es > ES_128) {
2106 gen_program_exception(s, PGM_SPECIFICATION);
2107 return DISAS_NORETURN;
2108 } else if (es == ES_128) {
2109 gen_gvec128_3_i64(tcg_gen_sub2_i64, get_field(s, v1),
2110 get_field(s, v2), get_field(s, v3));
2111 return DISAS_NEXT;
2112 }
2113 gen_gvec_fn_3(sub, es, get_field(s, v1), get_field(s, v2),
2114 get_field(s, v3));
2115 return DISAS_NEXT;
2116 }
2117
2118 static void gen_scbi_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
2119 {
2120 tcg_gen_setcond_i32(TCG_COND_GEU, d, a, b);
2121 }
2122
2123 static void gen_scbi_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
2124 {
2125 tcg_gen_setcond_i64(TCG_COND_GEU, d, a, b);
2126 }
2127
2128 static void gen_scbi2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al,
2129 TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh)
2130 {
2131 TCGv_i64 th = tcg_temp_new_i64();
2132 TCGv_i64 tl = tcg_temp_new_i64();
2133 TCGv_i64 zero = tcg_const_i64(0);
2134
2135 tcg_gen_sub2_i64(tl, th, al, zero, bl, zero);
2136 tcg_gen_andi_i64(th, th, 1);
2137 tcg_gen_sub2_i64(tl, th, ah, zero, th, zero);
2138 tcg_gen_sub2_i64(tl, th, tl, th, bh, zero);
2139 /* "invert" the result: -1 -> 0; 0 -> 1 */
2140 tcg_gen_addi_i64(dl, th, 1);
2141 tcg_gen_mov_i64(dh, zero);
2142
2143 tcg_temp_free_i64(th);
2144 tcg_temp_free_i64(tl);
2145 tcg_temp_free_i64(zero);
2146 }
2147
2148 static DisasJumpType op_vscbi(DisasContext *s, DisasOps *o)
2149 {
2150 const uint8_t es = get_field(s, m4);
2151 static const GVecGen3 g[4] = {
2152 { .fno = gen_helper_gvec_vscbi8, },
2153 { .fno = gen_helper_gvec_vscbi16, },
2154 { .fni4 = gen_scbi_i32, },
2155 { .fni8 = gen_scbi_i64, },
2156 };
2157
2158 if (es > ES_128) {
2159 gen_program_exception(s, PGM_SPECIFICATION);
2160 return DISAS_NORETURN;
2161 } else if (es == ES_128) {
2162 gen_gvec128_3_i64(gen_scbi2_i64, get_field(s, v1),
2163 get_field(s, v2), get_field(s, v3));
2164 return DISAS_NEXT;
2165 }
2166 gen_gvec_3(get_field(s, v1), get_field(s, v2),
2167 get_field(s, v3), &g[es]);
2168 return DISAS_NEXT;
2169 }
2170
2171 static void gen_sbi2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
2172 TCGv_i64 bl, TCGv_i64 bh, TCGv_i64 cl, TCGv_i64 ch)
2173 {
2174 TCGv_i64 tl = tcg_temp_new_i64();
2175 TCGv_i64 th = tcg_temp_new_i64();
2176
2177 tcg_gen_not_i64(tl, bl);
2178 tcg_gen_not_i64(th, bh);
2179 gen_ac2_i64(dl, dh, al, ah, tl, th, cl, ch);
2180 tcg_temp_free_i64(tl);
2181 tcg_temp_free_i64(th);
2182 }
2183
2184 static DisasJumpType op_vsbi(DisasContext *s, DisasOps *o)
2185 {
2186 if (get_field(s, m5) != ES_128) {
2187 gen_program_exception(s, PGM_SPECIFICATION);
2188 return DISAS_NORETURN;
2189 }
2190
2191 gen_gvec128_4_i64(gen_sbi2_i64, get_field(s, v1),
2192 get_field(s, v2), get_field(s, v3),
2193 get_field(s, v4));
2194 return DISAS_NEXT;
2195 }
2196
2197 static void gen_sbcbi2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
2198 TCGv_i64 bl, TCGv_i64 bh, TCGv_i64 cl, TCGv_i64 ch)
2199 {
2200 TCGv_i64 th = tcg_temp_new_i64();
2201 TCGv_i64 tl = tcg_temp_new_i64();
2202
2203 tcg_gen_not_i64(tl, bl);
2204 tcg_gen_not_i64(th, bh);
2205 gen_accc2_i64(dl, dh, al, ah, tl, th, cl, ch);
2206
2207 tcg_temp_free_i64(tl);
2208 tcg_temp_free_i64(th);
2209 }
2210
2211 static DisasJumpType op_vsbcbi(DisasContext *s, DisasOps *o)
2212 {
2213 if (get_field(s, m5) != ES_128) {
2214 gen_program_exception(s, PGM_SPECIFICATION);
2215 return DISAS_NORETURN;
2216 }
2217
2218 gen_gvec128_4_i64(gen_sbcbi2_i64, get_field(s, v1),
2219 get_field(s, v2), get_field(s, v3),
2220 get_field(s, v4));
2221 return DISAS_NEXT;
2222 }
2223
2224 static DisasJumpType op_vsumg(DisasContext *s, DisasOps *o)
2225 {
2226 const uint8_t es = get_field(s, m4);
2227 TCGv_i64 sum, tmp;
2228 uint8_t dst_idx;
2229
2230 if (es == ES_8 || es > ES_32) {
2231 gen_program_exception(s, PGM_SPECIFICATION);
2232 return DISAS_NORETURN;
2233 }
2234
2235 sum = tcg_temp_new_i64();
2236 tmp = tcg_temp_new_i64();
2237 for (dst_idx = 0; dst_idx < 2; dst_idx++) {
2238 uint8_t idx = dst_idx * NUM_VEC_ELEMENTS(es) / 2;
2239 const uint8_t max_idx = idx + NUM_VEC_ELEMENTS(es) / 2 - 1;
2240
2241 read_vec_element_i64(sum, get_field(s, v3), max_idx, es);
2242 for (; idx <= max_idx; idx++) {
2243 read_vec_element_i64(tmp, get_field(s, v2), idx, es);
2244 tcg_gen_add_i64(sum, sum, tmp);
2245 }
2246 write_vec_element_i64(sum, get_field(s, v1), dst_idx, ES_64);
2247 }
2248 tcg_temp_free_i64(sum);
2249 tcg_temp_free_i64(tmp);
2250 return DISAS_NEXT;
2251 }
2252
2253 static DisasJumpType op_vsumq(DisasContext *s, DisasOps *o)
2254 {
2255 const uint8_t es = get_field(s, m4);
2256 const uint8_t max_idx = NUM_VEC_ELEMENTS(es) - 1;
2257 TCGv_i64 sumh, suml, zero, tmpl;
2258 uint8_t idx;
2259
2260 if (es < ES_32 || es > ES_64) {
2261 gen_program_exception(s, PGM_SPECIFICATION);
2262 return DISAS_NORETURN;
2263 }
2264
2265 sumh = tcg_const_i64(0);
2266 suml = tcg_temp_new_i64();
2267 zero = tcg_const_i64(0);
2268 tmpl = tcg_temp_new_i64();
2269
2270 read_vec_element_i64(suml, get_field(s, v3), max_idx, es);
2271 for (idx = 0; idx <= max_idx; idx++) {
2272 read_vec_element_i64(tmpl, get_field(s, v2), idx, es);
2273 tcg_gen_add2_i64(suml, sumh, suml, sumh, tmpl, zero);
2274 }
2275 write_vec_element_i64(sumh, get_field(s, v1), 0, ES_64);
2276 write_vec_element_i64(suml, get_field(s, v1), 1, ES_64);
2277
2278 tcg_temp_free_i64(sumh);
2279 tcg_temp_free_i64(suml);
2280 tcg_temp_free_i64(zero);
2281 tcg_temp_free_i64(tmpl);
2282 return DISAS_NEXT;
2283 }
2284
2285 static DisasJumpType op_vsum(DisasContext *s, DisasOps *o)
2286 {
2287 const uint8_t es = get_field(s, m4);
2288 TCGv_i32 sum, tmp;
2289 uint8_t dst_idx;
2290
2291 if (es > ES_16) {
2292 gen_program_exception(s, PGM_SPECIFICATION);
2293 return DISAS_NORETURN;
2294 }
2295
2296 sum = tcg_temp_new_i32();
2297 tmp = tcg_temp_new_i32();
2298 for (dst_idx = 0; dst_idx < 4; dst_idx++) {
2299 uint8_t idx = dst_idx * NUM_VEC_ELEMENTS(es) / 4;
2300 const uint8_t max_idx = idx + NUM_VEC_ELEMENTS(es) / 4 - 1;
2301
2302 read_vec_element_i32(sum, get_field(s, v3), max_idx, es);
2303 for (; idx <= max_idx; idx++) {
2304 read_vec_element_i32(tmp, get_field(s, v2), idx, es);
2305 tcg_gen_add_i32(sum, sum, tmp);
2306 }
2307 write_vec_element_i32(sum, get_field(s, v1), dst_idx, ES_32);
2308 }
2309 tcg_temp_free_i32(sum);
2310 tcg_temp_free_i32(tmp);
2311 return DISAS_NEXT;
2312 }
2313
2314 static DisasJumpType op_vtm(DisasContext *s, DisasOps *o)
2315 {
2316 gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2),
2317 cpu_env, 0, gen_helper_gvec_vtm);
2318 set_cc_static(s);
2319 return DISAS_NEXT;
2320 }
2321
2322 static DisasJumpType op_vfae(DisasContext *s, DisasOps *o)
2323 {
2324 const uint8_t es = get_field(s, m4);
2325 const uint8_t m5 = get_field(s, m5);
2326 static gen_helper_gvec_3 * const g[3] = {
2327 gen_helper_gvec_vfae8,
2328 gen_helper_gvec_vfae16,
2329 gen_helper_gvec_vfae32,
2330 };
2331 static gen_helper_gvec_3_ptr * const g_cc[3] = {
2332 gen_helper_gvec_vfae_cc8,
2333 gen_helper_gvec_vfae_cc16,
2334 gen_helper_gvec_vfae_cc32,
2335 };
2336 if (es > ES_32) {
2337 gen_program_exception(s, PGM_SPECIFICATION);
2338 return DISAS_NORETURN;
2339 }
2340
2341 if (extract32(m5, 0, 1)) {
2342 gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2),
2343 get_field(s, v3), cpu_env, m5, g_cc[es]);
2344 set_cc_static(s);
2345 } else {
2346 gen_gvec_3_ool(get_field(s, v1), get_field(s, v2),
2347 get_field(s, v3), m5, g[es]);
2348 }
2349 return DISAS_NEXT;
2350 }
2351
2352 static DisasJumpType op_vfee(DisasContext *s, DisasOps *o)
2353 {
2354 const uint8_t es = get_field(s, m4);
2355 const uint8_t m5 = get_field(s, m5);
2356 static gen_helper_gvec_3 * const g[3] = {
2357 gen_helper_gvec_vfee8,
2358 gen_helper_gvec_vfee16,
2359 gen_helper_gvec_vfee32,
2360 };
2361 static gen_helper_gvec_3_ptr * const g_cc[3] = {
2362 gen_helper_gvec_vfee_cc8,
2363 gen_helper_gvec_vfee_cc16,
2364 gen_helper_gvec_vfee_cc32,
2365 };
2366
2367 if (es > ES_32 || m5 & ~0x3) {
2368 gen_program_exception(s, PGM_SPECIFICATION);
2369 return DISAS_NORETURN;
2370 }
2371
2372 if (extract32(m5, 0, 1)) {
2373 gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2),
2374 get_field(s, v3), cpu_env, m5, g_cc[es]);
2375 set_cc_static(s);
2376 } else {
2377 gen_gvec_3_ool(get_field(s, v1), get_field(s, v2),
2378 get_field(s, v3), m5, g[es]);
2379 }
2380 return DISAS_NEXT;
2381 }
2382
2383 static DisasJumpType op_vfene(DisasContext *s, DisasOps *o)
2384 {
2385 const uint8_t es = get_field(s, m4);
2386 const uint8_t m5 = get_field(s, m5);
2387 static gen_helper_gvec_3 * const g[3] = {
2388 gen_helper_gvec_vfene8,
2389 gen_helper_gvec_vfene16,
2390 gen_helper_gvec_vfene32,
2391 };
2392 static gen_helper_gvec_3_ptr * const g_cc[3] = {
2393 gen_helper_gvec_vfene_cc8,
2394 gen_helper_gvec_vfene_cc16,
2395 gen_helper_gvec_vfene_cc32,
2396 };
2397
2398 if (es > ES_32 || m5 & ~0x3) {
2399 gen_program_exception(s, PGM_SPECIFICATION);
2400 return DISAS_NORETURN;
2401 }
2402
2403 if (extract32(m5, 0, 1)) {
2404 gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2),
2405 get_field(s, v3), cpu_env, m5, g_cc[es]);
2406 set_cc_static(s);
2407 } else {
2408 gen_gvec_3_ool(get_field(s, v1), get_field(s, v2),
2409 get_field(s, v3), m5, g[es]);
2410 }
2411 return DISAS_NEXT;
2412 }
2413
2414 static DisasJumpType op_vistr(DisasContext *s, DisasOps *o)
2415 {
2416 const uint8_t es = get_field(s, m4);
2417 const uint8_t m5 = get_field(s, m5);
2418 static gen_helper_gvec_2 * const g[3] = {
2419 gen_helper_gvec_vistr8,
2420 gen_helper_gvec_vistr16,
2421 gen_helper_gvec_vistr32,
2422 };
2423 static gen_helper_gvec_2_ptr * const g_cc[3] = {
2424 gen_helper_gvec_vistr_cc8,
2425 gen_helper_gvec_vistr_cc16,
2426 gen_helper_gvec_vistr_cc32,
2427 };
2428
2429 if (es > ES_32 || m5 & ~0x1) {
2430 gen_program_exception(s, PGM_SPECIFICATION);
2431 return DISAS_NORETURN;
2432 }
2433
2434 if (extract32(m5, 0, 1)) {
2435 gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2),
2436 cpu_env, 0, g_cc[es]);
2437 set_cc_static(s);
2438 } else {
2439 gen_gvec_2_ool(get_field(s, v1), get_field(s, v2), 0,
2440 g[es]);
2441 }
2442 return DISAS_NEXT;
2443 }
2444
2445 static DisasJumpType op_vstrc(DisasContext *s, DisasOps *o)
2446 {
2447 const uint8_t es = get_field(s, m5);
2448 const uint8_t m6 = get_field(s, m6);
2449 static gen_helper_gvec_4 * const g[3] = {
2450 gen_helper_gvec_vstrc8,
2451 gen_helper_gvec_vstrc16,
2452 gen_helper_gvec_vstrc32,
2453 };
2454 static gen_helper_gvec_4 * const g_rt[3] = {
2455 gen_helper_gvec_vstrc_rt8,
2456 gen_helper_gvec_vstrc_rt16,
2457 gen_helper_gvec_vstrc_rt32,
2458 };
2459 static gen_helper_gvec_4_ptr * const g_cc[3] = {
2460 gen_helper_gvec_vstrc_cc8,
2461 gen_helper_gvec_vstrc_cc16,
2462 gen_helper_gvec_vstrc_cc32,
2463 };
2464 static gen_helper_gvec_4_ptr * const g_cc_rt[3] = {
2465 gen_helper_gvec_vstrc_cc_rt8,
2466 gen_helper_gvec_vstrc_cc_rt16,
2467 gen_helper_gvec_vstrc_cc_rt32,
2468 };
2469
2470 if (es > ES_32) {
2471 gen_program_exception(s, PGM_SPECIFICATION);
2472 return DISAS_NORETURN;
2473 }
2474
2475 if (extract32(m6, 0, 1)) {
2476 if (extract32(m6, 2, 1)) {
2477 gen_gvec_4_ptr(get_field(s, v1), get_field(s, v2),
2478 get_field(s, v3), get_field(s, v4),
2479 cpu_env, m6, g_cc_rt[es]);
2480 } else {
2481 gen_gvec_4_ptr(get_field(s, v1), get_field(s, v2),
2482 get_field(s, v3), get_field(s, v4),
2483 cpu_env, m6, g_cc[es]);
2484 }
2485 set_cc_static(s);
2486 } else {
2487 if (extract32(m6, 2, 1)) {
2488 gen_gvec_4_ool(get_field(s, v1), get_field(s, v2),
2489 get_field(s, v3), get_field(s, v4),
2490 m6, g_rt[es]);
2491 } else {
2492 gen_gvec_4_ool(get_field(s, v1), get_field(s, v2),
2493 get_field(s, v3), get_field(s, v4),
2494 m6, g[es]);
2495 }
2496 }
2497 return DISAS_NEXT;
2498 }
2499
2500 static DisasJumpType op_vfa(DisasContext *s, DisasOps *o)
2501 {
2502 const uint8_t fpf = get_field(s, m4);
2503 const uint8_t m5 = get_field(s, m5);
2504 gen_helper_gvec_3_ptr *fn = NULL;
2505
2506 switch (s->fields.op2) {
2507 case 0xe3:
2508 switch (fpf) {
2509 case FPF_SHORT:
2510 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
2511 fn = gen_helper_gvec_vfa32;
2512 }
2513 break;
2514 case FPF_LONG:
2515 fn = gen_helper_gvec_vfa64;
2516 break;
2517 case FPF_EXT:
2518 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
2519 fn = gen_helper_gvec_vfa128;
2520 }
2521 break;
2522 default:
2523 break;
2524 }
2525 break;
2526 case 0xe5:
2527 switch (fpf) {
2528 case FPF_SHORT:
2529 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
2530 fn = gen_helper_gvec_vfd32;
2531 }
2532 break;
2533 case FPF_LONG:
2534 fn = gen_helper_gvec_vfd64;
2535 break;
2536 case FPF_EXT:
2537 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
2538 fn = gen_helper_gvec_vfd128;
2539 }
2540 break;
2541 default:
2542 break;
2543 }
2544 break;
2545 case 0xe7:
2546 switch (fpf) {
2547 case FPF_SHORT:
2548 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
2549 fn = gen_helper_gvec_vfm32;
2550 }
2551 break;
2552 case FPF_LONG:
2553 fn = gen_helper_gvec_vfm64;
2554 break;
2555 case FPF_EXT:
2556 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
2557 fn = gen_helper_gvec_vfm128;
2558 }
2559 break;
2560 default:
2561 break;
2562 }
2563 break;
2564 case 0xe2:
2565 switch (fpf) {
2566 case FPF_SHORT:
2567 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
2568 fn = gen_helper_gvec_vfs32;
2569 }
2570 break;
2571 case FPF_LONG:
2572 fn = gen_helper_gvec_vfs64;
2573 break;
2574 case FPF_EXT:
2575 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
2576 fn = gen_helper_gvec_vfs128;
2577 }
2578 break;
2579 default:
2580 break;
2581 }
2582 break;
2583 default:
2584 g_assert_not_reached();
2585 }
2586
2587 if (!fn || extract32(m5, 0, 3)) {
2588 gen_program_exception(s, PGM_SPECIFICATION);
2589 return DISAS_NORETURN;
2590 }
2591
2592 gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2),
2593 get_field(s, v3), cpu_env, m5, fn);
2594 return DISAS_NEXT;
2595 }
2596
2597 static DisasJumpType op_wfc(DisasContext *s, DisasOps *o)
2598 {
2599 const uint8_t fpf = get_field(s, m3);
2600 const uint8_t m4 = get_field(s, m4);
2601 gen_helper_gvec_2_ptr *fn = NULL;
2602
2603 switch (fpf) {
2604 case FPF_SHORT:
2605 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
2606 fn = gen_helper_gvec_wfk32;
2607 if (s->fields.op2 == 0xcb) {
2608 fn = gen_helper_gvec_wfc32;
2609 }
2610 }
2611 break;
2612 case FPF_LONG:
2613 fn = gen_helper_gvec_wfk64;
2614 if (s->fields.op2 == 0xcb) {
2615 fn = gen_helper_gvec_wfc64;
2616 }
2617 break;
2618 case FPF_EXT:
2619 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
2620 fn = gen_helper_gvec_wfk128;
2621 if (s->fields.op2 == 0xcb) {
2622 fn = gen_helper_gvec_wfc128;
2623 }
2624 }
2625 break;
2626 default:
2627 break;
2628 };
2629
2630 if (!fn || m4) {
2631 gen_program_exception(s, PGM_SPECIFICATION);
2632 return DISAS_NORETURN;
2633 }
2634
2635 gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, 0, fn);
2636 set_cc_static(s);
2637 return DISAS_NEXT;
2638 }
2639
2640 static DisasJumpType op_vfc(DisasContext *s, DisasOps *o)
2641 {
2642 const uint8_t fpf = get_field(s, m4);
2643 const uint8_t m5 = get_field(s, m5);
2644 const uint8_t m6 = get_field(s, m6);
2645 const bool cs = extract32(m6, 0, 1);
2646 const bool sq = extract32(m5, 2, 1);
2647 gen_helper_gvec_3_ptr *fn = NULL;
2648
2649 switch (s->fields.op2) {
2650 case 0xe8:
2651 switch (fpf) {
2652 case FPF_SHORT:
2653 fn = cs ? gen_helper_gvec_vfce32_cc : gen_helper_gvec_vfce32;
2654 break;
2655 case FPF_LONG:
2656 fn = cs ? gen_helper_gvec_vfce64_cc : gen_helper_gvec_vfce64;
2657 break;
2658 case FPF_EXT:
2659 fn = cs ? gen_helper_gvec_vfce128_cc : gen_helper_gvec_vfce128;
2660 break;
2661 default:
2662 break;
2663 }
2664 break;
2665 case 0xeb:
2666 switch (fpf) {
2667 case FPF_SHORT:
2668 fn = cs ? gen_helper_gvec_vfch32_cc : gen_helper_gvec_vfch32;
2669 break;
2670 case FPF_LONG:
2671 fn = cs ? gen_helper_gvec_vfch64_cc : gen_helper_gvec_vfch64;
2672 break;
2673 case FPF_EXT:
2674 fn = cs ? gen_helper_gvec_vfch128_cc : gen_helper_gvec_vfch128;
2675 break;
2676 default:
2677 break;
2678 }
2679 break;
2680 case 0xea:
2681 switch (fpf) {
2682 case FPF_SHORT:
2683 fn = cs ? gen_helper_gvec_vfche32_cc : gen_helper_gvec_vfche32;
2684 break;
2685 case FPF_LONG:
2686 fn = cs ? gen_helper_gvec_vfche64_cc : gen_helper_gvec_vfche64;
2687 break;
2688 case FPF_EXT:
2689 fn = cs ? gen_helper_gvec_vfche128_cc : gen_helper_gvec_vfche128;
2690 break;
2691 default:
2692 break;
2693 }
2694 break;
2695 default:
2696 g_assert_not_reached();
2697 }
2698
2699 if (!fn || extract32(m5, 0, 2) || extract32(m6, 1, 3) ||
2700 (!s390_has_feat(S390_FEAT_VECTOR_ENH) && (fpf != FPF_LONG || sq))) {
2701 gen_program_exception(s, PGM_SPECIFICATION);
2702 return DISAS_NORETURN;
2703 }
2704
2705 gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2), get_field(s, v3),
2706 cpu_env, m5, fn);
2707 if (cs) {
2708 set_cc_static(s);
2709 }
2710 return DISAS_NEXT;
2711 }
2712
2713 static DisasJumpType op_vcdg(DisasContext *s, DisasOps *o)
2714 {
2715 const uint8_t fpf = get_field(s, m3);
2716 const uint8_t m4 = get_field(s, m4);
2717 const uint8_t erm = get_field(s, m5);
2718 gen_helper_gvec_2_ptr *fn = NULL;
2719
2720
2721 switch (s->fields.op2) {
2722 case 0xc3:
2723 if (fpf == FPF_LONG) {
2724 fn = gen_helper_gvec_vcdg64;
2725 }
2726 break;
2727 case 0xc1:
2728 if (fpf == FPF_LONG) {
2729 fn = gen_helper_gvec_vcdlg64;
2730 }
2731 break;
2732 case 0xc2:
2733 if (fpf == FPF_LONG) {
2734 fn = gen_helper_gvec_vcgd64;
2735 }
2736 break;
2737 case 0xc0:
2738 if (fpf == FPF_LONG) {
2739 fn = gen_helper_gvec_vclgd64;
2740 }
2741 break;
2742 case 0xc7:
2743 switch (fpf) {
2744 case FPF_SHORT:
2745 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
2746 fn = gen_helper_gvec_vfi32;
2747 }
2748 break;
2749 case FPF_LONG:
2750 fn = gen_helper_gvec_vfi64;
2751 break;
2752 case FPF_EXT:
2753 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
2754 fn = gen_helper_gvec_vfi128;
2755 }
2756 break;
2757 default:
2758 break;
2759 }
2760 break;
2761 case 0xc5:
2762 switch (fpf) {
2763 case FPF_LONG:
2764 fn = gen_helper_gvec_vflr64;
2765 break;
2766 case FPF_EXT:
2767 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
2768 fn = gen_helper_gvec_vflr128;
2769 }
2770 break;
2771 default:
2772 break;
2773 }
2774 break;
2775 default:
2776 g_assert_not_reached();
2777 }
2778
2779 if (!fn || extract32(m4, 0, 2) || erm > 7 || erm == 2) {
2780 gen_program_exception(s, PGM_SPECIFICATION);
2781 return DISAS_NORETURN;
2782 }
2783
2784 gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env,
2785 deposit32(m4, 4, 4, erm), fn);
2786 return DISAS_NEXT;
2787 }
2788
2789 static DisasJumpType op_vfll(DisasContext *s, DisasOps *o)
2790 {
2791 const uint8_t fpf = get_field(s, m3);
2792 const uint8_t m4 = get_field(s, m4);
2793 gen_helper_gvec_2_ptr *fn = NULL;
2794
2795 switch (fpf) {
2796 case FPF_SHORT:
2797 fn = gen_helper_gvec_vfll32;
2798 break;
2799 case FPF_LONG:
2800 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
2801 fn = gen_helper_gvec_vfll64;
2802 }
2803 break;
2804 default:
2805 break;
2806 }
2807
2808 if (!fn || extract32(m4, 0, 3)) {
2809 gen_program_exception(s, PGM_SPECIFICATION);
2810 return DISAS_NORETURN;
2811 }
2812
2813 gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, m4, fn);
2814 return DISAS_NEXT;
2815 }
2816
2817 static DisasJumpType op_vfmax(DisasContext *s, DisasOps *o)
2818 {
2819 const uint8_t fpf = get_field(s, m4);
2820 const uint8_t m6 = get_field(s, m6);
2821 const uint8_t m5 = get_field(s, m5);
2822 gen_helper_gvec_3_ptr *fn;
2823
2824 if (m6 == 5 || m6 == 6 || m6 == 7 || m6 > 13) {
2825 gen_program_exception(s, PGM_SPECIFICATION);
2826 return DISAS_NORETURN;
2827 }
2828
2829 switch (fpf) {
2830 case FPF_SHORT:
2831 if (s->fields.op2 == 0xef) {
2832 fn = gen_helper_gvec_vfmax32;
2833 } else {
2834 fn = gen_helper_gvec_vfmin32;
2835 }
2836 break;
2837 case FPF_LONG:
2838 if (s->fields.op2 == 0xef) {
2839 fn = gen_helper_gvec_vfmax64;
2840 } else {
2841 fn = gen_helper_gvec_vfmin64;
2842 }
2843 break;
2844 case FPF_EXT:
2845 if (s->fields.op2 == 0xef) {
2846 fn = gen_helper_gvec_vfmax128;
2847 } else {
2848 fn = gen_helper_gvec_vfmin128;
2849 }
2850 break;
2851 default:
2852 gen_program_exception(s, PGM_SPECIFICATION);
2853 return DISAS_NORETURN;
2854 }
2855
2856 gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2), get_field(s, v3),
2857 cpu_env, deposit32(m5, 4, 4, m6), fn);
2858 return DISAS_NEXT;
2859 }
2860
2861 static DisasJumpType op_vfma(DisasContext *s, DisasOps *o)
2862 {
2863 const uint8_t m5 = get_field(s, m5);
2864 const uint8_t fpf = get_field(s, m6);
2865 gen_helper_gvec_4_ptr *fn = NULL;
2866
2867 switch (s->fields.op2) {
2868 case 0x8f:
2869 switch (fpf) {
2870 case FPF_SHORT:
2871 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
2872 fn = gen_helper_gvec_vfma32;
2873 }
2874 break;
2875 case FPF_LONG:
2876 fn = gen_helper_gvec_vfma64;
2877 break;
2878 case FPF_EXT:
2879 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
2880 fn = gen_helper_gvec_vfma128;
2881 }
2882 break;
2883 default:
2884 break;
2885 }
2886 break;
2887 case 0x8e:
2888 switch (fpf) {
2889 case FPF_SHORT:
2890 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
2891 fn = gen_helper_gvec_vfms32;
2892 }
2893 break;
2894 case FPF_LONG:
2895 fn = gen_helper_gvec_vfms64;
2896 break;
2897 case FPF_EXT:
2898 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
2899 fn = gen_helper_gvec_vfms128;
2900 }
2901 break;
2902 default:
2903 break;
2904 }
2905 break;
2906 case 0x9f:
2907 switch (fpf) {
2908 case FPF_SHORT:
2909 fn = gen_helper_gvec_vfnma32;
2910 break;
2911 case FPF_LONG:
2912 fn = gen_helper_gvec_vfnma64;
2913 break;
2914 case FPF_EXT:
2915 fn = gen_helper_gvec_vfnma128;
2916 break;
2917 default:
2918 break;
2919 }
2920 break;
2921 case 0x9e:
2922 switch (fpf) {
2923 case FPF_SHORT:
2924 fn = gen_helper_gvec_vfnms32;
2925 break;
2926 case FPF_LONG:
2927 fn = gen_helper_gvec_vfnms64;
2928 break;
2929 case FPF_EXT:
2930 fn = gen_helper_gvec_vfnms128;
2931 break;
2932 default:
2933 break;
2934 }
2935 break;
2936 default:
2937 g_assert_not_reached();
2938 }
2939
2940 if (!fn || extract32(m5, 0, 3)) {
2941 gen_program_exception(s, PGM_SPECIFICATION);
2942 return DISAS_NORETURN;
2943 }
2944
2945 gen_gvec_4_ptr(get_field(s, v1), get_field(s, v2),
2946 get_field(s, v3), get_field(s, v4), cpu_env, m5, fn);
2947 return DISAS_NEXT;
2948 }
2949
2950 static DisasJumpType op_vfpso(DisasContext *s, DisasOps *o)
2951 {
2952 const uint8_t v1 = get_field(s, v1);
2953 const uint8_t v2 = get_field(s, v2);
2954 const uint8_t fpf = get_field(s, m3);
2955 const uint8_t m4 = get_field(s, m4);
2956 const uint8_t m5 = get_field(s, m5);
2957 const bool se = extract32(m4, 3, 1);
2958 TCGv_i64 tmp;
2959
2960 if ((fpf != FPF_LONG && !s390_has_feat(S390_FEAT_VECTOR_ENH)) ||
2961 extract32(m4, 0, 3) || m5 > 2) {
2962 gen_program_exception(s, PGM_SPECIFICATION);
2963 return DISAS_NORETURN;
2964 }
2965
2966 switch (fpf) {
2967 case FPF_SHORT:
2968 if (!se) {
2969 switch (m5) {
2970 case 0:
2971 /* sign bit is inverted (complement) */
2972 gen_gvec_fn_2i(xori, ES_32, v1, v2, 1ull << 31);
2973 break;
2974 case 1:
2975 /* sign bit is set to one (negative) */
2976 gen_gvec_fn_2i(ori, ES_32, v1, v2, 1ull << 31);
2977 break;
2978 case 2:
2979 /* sign bit is set to zero (positive) */
2980 gen_gvec_fn_2i(andi, ES_32, v1, v2, (1ull << 31) - 1);
2981 break;
2982 }
2983 return DISAS_NEXT;
2984 }
2985 break;
2986 case FPF_LONG:
2987 if (!se) {
2988 switch (m5) {
2989 case 0:
2990 /* sign bit is inverted (complement) */
2991 gen_gvec_fn_2i(xori, ES_64, v1, v2, 1ull << 63);
2992 break;
2993 case 1:
2994 /* sign bit is set to one (negative) */
2995 gen_gvec_fn_2i(ori, ES_64, v1, v2, 1ull << 63);
2996 break;
2997 case 2:
2998 /* sign bit is set to zero (positive) */
2999 gen_gvec_fn_2i(andi, ES_64, v1, v2, (1ull << 63) - 1);
3000 break;
3001 }
3002 return DISAS_NEXT;
3003 }
3004 break;
3005 case FPF_EXT:
3006 /* Only a single element. */
3007 break;
3008 default:
3009 gen_program_exception(s, PGM_SPECIFICATION);
3010 return DISAS_NORETURN;
3011 }
3012
3013 /* With a single element, we are only interested in bit 0. */
3014 tmp = tcg_temp_new_i64();
3015 read_vec_element_i64(tmp, v2, 0, ES_64);
3016 switch (m5) {
3017 case 0:
3018 /* sign bit is inverted (complement) */
3019 tcg_gen_xori_i64(tmp, tmp, 1ull << 63);
3020 break;
3021 case 1:
3022 /* sign bit is set to one (negative) */
3023 tcg_gen_ori_i64(tmp, tmp, 1ull << 63);
3024 break;
3025 case 2:
3026 /* sign bit is set to zero (positive) */
3027 tcg_gen_andi_i64(tmp, tmp, (1ull << 63) - 1);
3028 break;
3029 }
3030 write_vec_element_i64(tmp, v1, 0, ES_64);
3031
3032 if (fpf == FPF_EXT) {
3033 read_vec_element_i64(tmp, v2, 1, ES_64);
3034 write_vec_element_i64(tmp, v1, 1, ES_64);
3035 }
3036
3037 tcg_temp_free_i64(tmp);
3038
3039 return DISAS_NEXT;
3040 }
3041
3042 static DisasJumpType op_vfsq(DisasContext *s, DisasOps *o)
3043 {
3044 const uint8_t fpf = get_field(s, m3);
3045 const uint8_t m4 = get_field(s, m4);
3046 gen_helper_gvec_2_ptr *fn = NULL;
3047
3048 switch (fpf) {
3049 case FPF_SHORT:
3050 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
3051 fn = gen_helper_gvec_vfsq32;
3052 }
3053 break;
3054 case FPF_LONG:
3055 fn = gen_helper_gvec_vfsq64;
3056 break;
3057 case FPF_EXT:
3058 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
3059 fn = gen_helper_gvec_vfsq128;
3060 }
3061 break;
3062 default:
3063 break;
3064 }
3065
3066 if (!fn || extract32(m4, 0, 3)) {
3067 gen_program_exception(s, PGM_SPECIFICATION);
3068 return DISAS_NORETURN;
3069 }
3070
3071 gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, m4, fn);
3072 return DISAS_NEXT;
3073 }
3074
3075 static DisasJumpType op_vftci(DisasContext *s, DisasOps *o)
3076 {
3077 const uint16_t i3 = get_field(s, i3);
3078 const uint8_t fpf = get_field(s, m4);
3079 const uint8_t m5 = get_field(s, m5);
3080 gen_helper_gvec_2_ptr *fn = NULL;
3081
3082 switch (fpf) {
3083 case FPF_SHORT:
3084 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
3085 fn = gen_helper_gvec_vftci32;
3086 }
3087 break;
3088 case FPF_LONG:
3089 fn = gen_helper_gvec_vftci64;
3090 break;
3091 case FPF_EXT:
3092 if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
3093 fn = gen_helper_gvec_vftci128;
3094 }
3095 break;
3096 default:
3097 break;
3098 }
3099
3100 if (!fn || extract32(m5, 0, 3)) {
3101 gen_program_exception(s, PGM_SPECIFICATION);
3102 return DISAS_NORETURN;
3103 }
3104
3105 gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env,
3106 deposit32(m5, 4, 12, i3), fn);
3107 set_cc_static(s);
3108 return DISAS_NEXT;
3109 }