]> Git Repo - qemu.git/blob - target/s390x/translate_vx.c.inc
s390x/tcg: Implement 32/128 bit for VECTOR FP COMPARE *
[qemu.git] / target / s390x / 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 <[email protected]>
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, m4) != 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
2602     if (fpf != FPF_LONG || m4) {
2603         gen_program_exception(s, PGM_SPECIFICATION);
2604         return DISAS_NORETURN;
2605     }
2606
2607     if (s->fields.op2 == 0xcb) {
2608         gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2),
2609                        cpu_env, 0, gen_helper_gvec_wfc64);
2610     } else {
2611         gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2),
2612                        cpu_env, 0, gen_helper_gvec_wfk64);
2613     }
2614     set_cc_static(s);
2615     return DISAS_NEXT;
2616 }
2617
2618 static DisasJumpType op_vfc(DisasContext *s, DisasOps *o)
2619 {
2620     const uint8_t fpf = get_field(s, m4);
2621     const uint8_t m5 = get_field(s, m5);
2622     const uint8_t m6 = get_field(s, m6);
2623     const bool cs = extract32(m6, 0, 1);
2624     const bool sq = extract32(m5, 2, 1);
2625     gen_helper_gvec_3_ptr *fn = NULL;
2626
2627     switch (s->fields.op2) {
2628     case 0xe8:
2629         switch (fpf) {
2630         case FPF_SHORT:
2631             fn = cs ? gen_helper_gvec_vfce32_cc : gen_helper_gvec_vfce32;
2632             break;
2633         case FPF_LONG:
2634             fn = cs ? gen_helper_gvec_vfce64_cc : gen_helper_gvec_vfce64;
2635             break;
2636         case FPF_EXT:
2637             fn = cs ? gen_helper_gvec_vfce128_cc : gen_helper_gvec_vfce128;
2638             break;
2639         default:
2640             break;
2641         }
2642         break;
2643     case 0xeb:
2644         switch (fpf) {
2645         case FPF_SHORT:
2646             fn = cs ? gen_helper_gvec_vfch32_cc : gen_helper_gvec_vfch32;
2647             break;
2648         case FPF_LONG:
2649             fn = cs ? gen_helper_gvec_vfch64_cc : gen_helper_gvec_vfch64;
2650             break;
2651         case FPF_EXT:
2652             fn = cs ? gen_helper_gvec_vfch128_cc : gen_helper_gvec_vfch128;
2653             break;
2654         default:
2655             break;
2656         }
2657         break;
2658     case 0xea:
2659         switch (fpf) {
2660         case FPF_SHORT:
2661             fn = cs ? gen_helper_gvec_vfche32_cc : gen_helper_gvec_vfche32;
2662             break;
2663         case FPF_LONG:
2664             fn = cs ? gen_helper_gvec_vfche64_cc : gen_helper_gvec_vfche64;
2665             break;
2666         case FPF_EXT:
2667             fn = cs ? gen_helper_gvec_vfche128_cc : gen_helper_gvec_vfche128;
2668             break;
2669         default:
2670             break;
2671         }
2672         break;
2673     default:
2674         g_assert_not_reached();
2675     }
2676
2677     if (!fn || extract32(m5, 0, 2) || extract32(m6, 1, 3) ||
2678         (!s390_has_feat(S390_FEAT_VECTOR_ENH) && (fpf != FPF_LONG || sq))) {
2679         gen_program_exception(s, PGM_SPECIFICATION);
2680         return DISAS_NORETURN;
2681     }
2682
2683     gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2), get_field(s, v3),
2684                    cpu_env, m5, fn);
2685     if (cs) {
2686         set_cc_static(s);
2687     }
2688     return DISAS_NEXT;
2689 }
2690
2691 static DisasJumpType op_vcdg(DisasContext *s, DisasOps *o)
2692 {
2693     const uint8_t fpf = get_field(s, m3);
2694     const uint8_t m4 = get_field(s, m4);
2695     const uint8_t erm = get_field(s, m5);
2696     gen_helper_gvec_2_ptr *fn = NULL;
2697
2698
2699     switch (s->fields.op2) {
2700     case 0xc3:
2701         if (fpf == FPF_LONG) {
2702             fn = gen_helper_gvec_vcdg64;
2703         }
2704         break;
2705     case 0xc1:
2706         if (fpf == FPF_LONG) {
2707             fn = gen_helper_gvec_vcdlg64;
2708         }
2709         break;
2710     case 0xc2:
2711         if (fpf == FPF_LONG) {
2712             fn = gen_helper_gvec_vcgd64;
2713         }
2714         break;
2715     case 0xc0:
2716         if (fpf == FPF_LONG) {
2717             fn = gen_helper_gvec_vclgd64;
2718         }
2719         break;
2720     case 0xc7:
2721         switch (fpf) {
2722         case FPF_SHORT:
2723             if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
2724                 fn = gen_helper_gvec_vfi32;
2725             }
2726             break;
2727         case FPF_LONG:
2728             fn = gen_helper_gvec_vfi64;
2729             break;
2730         case FPF_EXT:
2731             if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
2732                 fn = gen_helper_gvec_vfi128;
2733             }
2734             break;
2735         default:
2736             break;
2737         }
2738         break;
2739     case 0xc5:
2740         if (fpf == FPF_LONG) {
2741             fn = gen_helper_gvec_vflr64;
2742         }
2743         break;
2744     default:
2745         g_assert_not_reached();
2746     }
2747
2748     if (!fn || extract32(m4, 0, 2) || erm > 7 || erm == 2) {
2749         gen_program_exception(s, PGM_SPECIFICATION);
2750         return DISAS_NORETURN;
2751     }
2752
2753     gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env,
2754                    deposit32(m4, 4, 4, erm), fn);
2755     return DISAS_NEXT;
2756 }
2757
2758 static DisasJumpType op_vfll(DisasContext *s, DisasOps *o)
2759 {
2760     const uint8_t fpf = get_field(s, m3);
2761     const uint8_t m4 = get_field(s, m4);
2762
2763     if (fpf != FPF_SHORT || extract32(m4, 0, 3)) {
2764         gen_program_exception(s, PGM_SPECIFICATION);
2765         return DISAS_NORETURN;
2766     }
2767
2768     gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env,
2769                    m4, gen_helper_gvec_vfll32);
2770     return DISAS_NEXT;
2771 }
2772
2773 static DisasJumpType op_vfma(DisasContext *s, DisasOps *o)
2774 {
2775     const uint8_t m5 = get_field(s, m5);
2776     const uint8_t fpf = get_field(s, m6);
2777     gen_helper_gvec_4_ptr *fn;
2778
2779     if (fpf != FPF_LONG || extract32(m5, 0, 3)) {
2780         gen_program_exception(s, PGM_SPECIFICATION);
2781         return DISAS_NORETURN;
2782     }
2783
2784     if (s->fields.op2 == 0x8f) {
2785         fn = gen_helper_gvec_vfma64;
2786     } else {
2787         fn = gen_helper_gvec_vfms64;
2788     }
2789     gen_gvec_4_ptr(get_field(s, v1), get_field(s, v2),
2790                    get_field(s, v3), get_field(s, v4), cpu_env, m5, fn);
2791     return DISAS_NEXT;
2792 }
2793
2794 static DisasJumpType op_vfpso(DisasContext *s, DisasOps *o)
2795 {
2796     const uint8_t v1 = get_field(s, v1);
2797     const uint8_t v2 = get_field(s, v2);
2798     const uint8_t fpf = get_field(s, m3);
2799     const uint8_t m4 = get_field(s, m4);
2800     const uint8_t m5 = get_field(s, m5);
2801     TCGv_i64 tmp;
2802
2803     if (fpf != FPF_LONG || extract32(m4, 0, 3) || m5 > 2) {
2804         gen_program_exception(s, PGM_SPECIFICATION);
2805         return DISAS_NORETURN;
2806     }
2807
2808     if (extract32(m4, 3, 1)) {
2809         tmp = tcg_temp_new_i64();
2810         read_vec_element_i64(tmp, v2, 0, ES_64);
2811         switch (m5) {
2812         case 0:
2813             /* sign bit is inverted (complement) */
2814             tcg_gen_xori_i64(tmp, tmp, 1ull << 63);
2815             break;
2816         case 1:
2817             /* sign bit is set to one (negative) */
2818             tcg_gen_ori_i64(tmp, tmp, 1ull << 63);
2819             break;
2820         case 2:
2821             /* sign bit is set to zero (positive) */
2822             tcg_gen_andi_i64(tmp, tmp, (1ull << 63) - 1);
2823             break;
2824         }
2825         write_vec_element_i64(tmp, v1, 0, ES_64);
2826         tcg_temp_free_i64(tmp);
2827     } else {
2828         switch (m5) {
2829         case 0:
2830             /* sign bit is inverted (complement) */
2831             gen_gvec_fn_2i(xori, ES_64, v1, v2, 1ull << 63);
2832             break;
2833         case 1:
2834             /* sign bit is set to one (negative) */
2835             gen_gvec_fn_2i(ori, ES_64, v1, v2, 1ull << 63);
2836             break;
2837         case 2:
2838             /* sign bit is set to zero (positive) */
2839             gen_gvec_fn_2i(andi, ES_64, v1, v2, (1ull << 63) - 1);
2840             break;
2841         }
2842     }
2843     return DISAS_NEXT;
2844 }
2845
2846 static DisasJumpType op_vfsq(DisasContext *s, DisasOps *o)
2847 {
2848     const uint8_t fpf = get_field(s, m3);
2849     const uint8_t m4 = get_field(s, m4);
2850     gen_helper_gvec_2_ptr *fn = NULL;
2851
2852     switch (fpf) {
2853     case FPF_SHORT:
2854         if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
2855             fn = gen_helper_gvec_vfsq32;
2856         }
2857         break;
2858     case FPF_LONG:
2859         fn = gen_helper_gvec_vfsq64;
2860         break;
2861     case FPF_EXT:
2862         if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
2863             fn = gen_helper_gvec_vfsq128;
2864         }
2865         break;
2866     default:
2867         break;
2868     }
2869
2870     if (!fn || extract32(m4, 0, 3)) {
2871         gen_program_exception(s, PGM_SPECIFICATION);
2872         return DISAS_NORETURN;
2873     }
2874
2875     gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, m4, fn);
2876     return DISAS_NEXT;
2877 }
2878
2879 static DisasJumpType op_vftci(DisasContext *s, DisasOps *o)
2880 {
2881     const uint16_t i3 = get_field(s, i3);
2882     const uint8_t fpf = get_field(s, m4);
2883     const uint8_t m5 = get_field(s, m5);
2884
2885     if (fpf != FPF_LONG || extract32(m5, 0, 3)) {
2886         gen_program_exception(s, PGM_SPECIFICATION);
2887         return DISAS_NORETURN;
2888     }
2889
2890     gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env,
2891                    deposit32(m5, 4, 12, i3), gen_helper_gvec_vftci64);
2892     set_cc_static(s);
2893     return DISAS_NEXT;
2894 }
This page took 0.184406 seconds and 4 git commands to generate.