xref: /qemu/target/ppc/translate/vmx-impl.c.inc (revision d84ed5d2)
1/*
2 * translate/vmx-impl.c
3 *
4 * Altivec/VMX translation
5 */
6
7/***                      Altivec vector extension                         ***/
8/* Altivec registers moves */
9
10static inline TCGv_ptr gen_avr_ptr(int reg)
11{
12    TCGv_ptr r = tcg_temp_new_ptr();
13    tcg_gen_addi_ptr(r, tcg_env, avr_full_offset(reg));
14    return r;
15}
16
17static bool trans_LVX(DisasContext *ctx, arg_X *a)
18{
19    TCGv EA;
20    TCGv_i64 avr;
21    REQUIRE_INSNS_FLAGS(ctx, ALTIVEC);
22    REQUIRE_VECTOR(ctx);
23    gen_set_access_type(ctx, ACCESS_INT);
24    avr = tcg_temp_new_i64();
25    EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
26    tcg_gen_andi_tl(EA, EA, ~0xf);
27    /*
28     * We only need to swap high and low halves. gen_qemu_ld64_i64
29     * does necessary 64-bit byteswap already.
30     */
31    gen_qemu_ld64_i64(ctx, avr, EA);
32    set_avr64(a->rt, avr, !ctx->le_mode);
33    tcg_gen_addi_tl(EA, EA, 8);
34    gen_qemu_ld64_i64(ctx, avr, EA);
35    set_avr64(a->rt, avr, ctx->le_mode);
36    return true;
37}
38
39/* As we don't emulate the cache, lvxl is strictly equivalent to lvx */
40QEMU_FLATTEN
41static bool trans_LVXL(DisasContext *ctx, arg_LVXL *a)
42{
43    return trans_LVX(ctx, a);
44}
45
46static bool trans_STVX(DisasContext *ctx, arg_STVX *a)
47{
48    TCGv EA;
49    TCGv_i64 avr;
50    REQUIRE_INSNS_FLAGS(ctx, ALTIVEC);
51    REQUIRE_VECTOR(ctx);
52    gen_set_access_type(ctx, ACCESS_INT);
53    avr = tcg_temp_new_i64();
54    EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
55    tcg_gen_andi_tl(EA, EA, ~0xf);
56    /*
57     * We only need to swap high and low halves. gen_qemu_st64_i64
58     * does necessary 64-bit byteswap already.
59     */
60    get_avr64(avr, a->rt, !ctx->le_mode);
61    gen_qemu_st64_i64(ctx, avr, EA);
62    tcg_gen_addi_tl(EA, EA, 8);
63    get_avr64(avr, a->rt, ctx->le_mode);
64    gen_qemu_st64_i64(ctx, avr, EA);
65    return true;
66}
67
68/* As we don't emulate the cache, stvxl is strictly equivalent to stvx */
69QEMU_FLATTEN
70static bool trans_STVXL(DisasContext *ctx, arg_STVXL *a)
71{
72    return trans_STVX(ctx, a);
73}
74
75static bool do_ldst_ve_X(DisasContext *ctx, arg_X *a, int size,
76                   void (*helper)(TCGv_env, TCGv_ptr, TCGv))
77{
78    TCGv EA;
79    TCGv_ptr vrt;
80    REQUIRE_INSNS_FLAGS(ctx, ALTIVEC);
81    REQUIRE_VECTOR(ctx);
82    gen_set_access_type(ctx, ACCESS_INT);
83    EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
84    if (size > 1) {
85        tcg_gen_andi_tl(EA, EA, ~(size - 1));
86    }
87    vrt = gen_avr_ptr(a->rt);
88    helper(tcg_env, vrt, EA);
89    return true;
90}
91
92TRANS(LVEBX, do_ldst_ve_X, 1, gen_helper_LVEBX);
93TRANS(LVEHX, do_ldst_ve_X, 2, gen_helper_LVEHX);
94TRANS(LVEWX, do_ldst_ve_X, 4, gen_helper_LVEWX);
95
96TRANS(STVEBX, do_ldst_ve_X, 1, gen_helper_STVEBX);
97TRANS(STVEHX, do_ldst_ve_X, 2, gen_helper_STVEHX);
98TRANS(STVEWX, do_ldst_ve_X, 4, gen_helper_STVEWX);
99
100static void gen_mfvscr(DisasContext *ctx)
101{
102    TCGv_i32 t;
103    TCGv_i64 avr;
104    if (unlikely(!ctx->altivec_enabled)) {
105        gen_exception(ctx, POWERPC_EXCP_VPU);
106        return;
107    }
108    avr = tcg_temp_new_i64();
109    tcg_gen_movi_i64(avr, 0);
110    set_avr64(rD(ctx->opcode), avr, true);
111    t = tcg_temp_new_i32();
112    gen_helper_mfvscr(t, tcg_env);
113    tcg_gen_extu_i32_i64(avr, t);
114    set_avr64(rD(ctx->opcode), avr, false);
115}
116
117static void gen_mtvscr(DisasContext *ctx)
118{
119    TCGv_i32 val;
120    int bofs;
121
122    if (unlikely(!ctx->altivec_enabled)) {
123        gen_exception(ctx, POWERPC_EXCP_VPU);
124        return;
125    }
126
127    val = tcg_temp_new_i32();
128    bofs = avr_full_offset(rB(ctx->opcode));
129#if HOST_BIG_ENDIAN
130    bofs += 3 * 4;
131#endif
132
133    tcg_gen_ld_i32(val, tcg_env, bofs);
134    gen_helper_mtvscr(tcg_env, val);
135}
136
137static void gen_vx_vmul10(DisasContext *ctx, bool add_cin, bool ret_carry)
138{
139    TCGv_i64 t0;
140    TCGv_i64 t1;
141    TCGv_i64 t2;
142    TCGv_i64 avr;
143    TCGv_i64 ten, z;
144
145    if (unlikely(!ctx->altivec_enabled)) {
146        gen_exception(ctx, POWERPC_EXCP_VPU);
147        return;
148    }
149
150    t0 = tcg_temp_new_i64();
151    t1 = tcg_temp_new_i64();
152    t2 = tcg_temp_new_i64();
153    avr = tcg_temp_new_i64();
154    ten = tcg_constant_i64(10);
155    z = tcg_constant_i64(0);
156
157    if (add_cin) {
158        get_avr64(avr, rA(ctx->opcode), false);
159        tcg_gen_mulu2_i64(t0, t1, avr, ten);
160        get_avr64(avr, rB(ctx->opcode), false);
161        tcg_gen_andi_i64(t2, avr, 0xF);
162        tcg_gen_add2_i64(avr, t2, t0, t1, t2, z);
163        set_avr64(rD(ctx->opcode), avr, false);
164    } else {
165        get_avr64(avr, rA(ctx->opcode), false);
166        tcg_gen_mulu2_i64(avr, t2, avr, ten);
167        set_avr64(rD(ctx->opcode), avr, false);
168    }
169
170    if (ret_carry) {
171        get_avr64(avr, rA(ctx->opcode), true);
172        tcg_gen_mulu2_i64(t0, t1, avr, ten);
173        tcg_gen_add2_i64(t0, avr, t0, t1, t2, z);
174        set_avr64(rD(ctx->opcode), avr, false);
175        set_avr64(rD(ctx->opcode), z, true);
176    } else {
177        get_avr64(avr, rA(ctx->opcode), true);
178        tcg_gen_mul_i64(t0, avr, ten);
179        tcg_gen_add_i64(avr, t0, t2);
180        set_avr64(rD(ctx->opcode), avr, true);
181    }
182}
183
184#define GEN_VX_VMUL10(name, add_cin, ret_carry)                         \
185    static void glue(gen_, name)(DisasContext *ctx)                     \
186    { gen_vx_vmul10(ctx, add_cin, ret_carry); }
187
188GEN_VX_VMUL10(vmul10uq, 0, 0);
189GEN_VX_VMUL10(vmul10euq, 1, 0);
190GEN_VX_VMUL10(vmul10cuq, 0, 1);
191GEN_VX_VMUL10(vmul10ecuq, 1, 1);
192
193#define GEN_VXFORM_V(name, vece, tcg_op, opc2, opc3)                    \
194static void glue(gen_, name)(DisasContext *ctx)                         \
195{                                                                       \
196    if (unlikely(!ctx->altivec_enabled)) {                              \
197        gen_exception(ctx, POWERPC_EXCP_VPU);                           \
198        return;                                                         \
199    }                                                                   \
200                                                                        \
201    tcg_op(vece,                                                        \
202           avr_full_offset(rD(ctx->opcode)),                            \
203           avr_full_offset(rA(ctx->opcode)),                            \
204           avr_full_offset(rB(ctx->opcode)),                            \
205           16, 16);                                                     \
206}
207
208#define GEN_VXFORM(name, opc2, opc3)                                    \
209static void glue(gen_, name)(DisasContext *ctx)                         \
210{                                                                       \
211    TCGv_ptr ra, rb, rd;                                                \
212    if (unlikely(!ctx->altivec_enabled)) {                              \
213        gen_exception(ctx, POWERPC_EXCP_VPU);                           \
214        return;                                                         \
215    }                                                                   \
216    ra = gen_avr_ptr(rA(ctx->opcode));                                  \
217    rb = gen_avr_ptr(rB(ctx->opcode));                                  \
218    rd = gen_avr_ptr(rD(ctx->opcode));                                  \
219    gen_helper_##name(rd, ra, rb);                                      \
220}
221
222#define GEN_VXFORM_TRANS(name, opc2, opc3)                              \
223static void glue(gen_, name)(DisasContext *ctx)                         \
224{                                                                       \
225    if (unlikely(!ctx->altivec_enabled)) {                              \
226        gen_exception(ctx, POWERPC_EXCP_VPU);                           \
227        return;                                                         \
228    }                                                                   \
229    trans_##name(ctx);                                                  \
230}
231
232#define GEN_VXFORM_ENV(name, opc2, opc3)                                \
233static void glue(gen_, name)(DisasContext *ctx)                         \
234{                                                                       \
235    TCGv_ptr ra, rb, rd;                                                \
236    if (unlikely(!ctx->altivec_enabled)) {                              \
237        gen_exception(ctx, POWERPC_EXCP_VPU);                           \
238        return;                                                         \
239    }                                                                   \
240    ra = gen_avr_ptr(rA(ctx->opcode));                                  \
241    rb = gen_avr_ptr(rB(ctx->opcode));                                  \
242    rd = gen_avr_ptr(rD(ctx->opcode));                                  \
243    gen_helper_##name(tcg_env, rd, ra, rb);                             \
244}
245
246#define GEN_VXFORM3(name, opc2, opc3)                                   \
247static void glue(gen_, name)(DisasContext *ctx)                         \
248{                                                                       \
249    TCGv_ptr ra, rb, rc, rd;                                            \
250    if (unlikely(!ctx->altivec_enabled)) {                              \
251        gen_exception(ctx, POWERPC_EXCP_VPU);                           \
252        return;                                                         \
253    }                                                                   \
254    ra = gen_avr_ptr(rA(ctx->opcode));                                  \
255    rb = gen_avr_ptr(rB(ctx->opcode));                                  \
256    rc = gen_avr_ptr(rC(ctx->opcode));                                  \
257    rd = gen_avr_ptr(rD(ctx->opcode));                                  \
258    gen_helper_##name(rd, ra, rb, rc);                                  \
259}
260
261/*
262 * Support for Altivec instruction pairs that use bit 31 (Rc) as
263 * an opcode bit.  In general, these pairs come from different
264 * versions of the ISA, so we must also support a pair of flags for
265 * each instruction.
266 */
267#define GEN_VXFORM_DUAL(name0, flg0, flg2_0, name1, flg1, flg2_1)          \
268static void glue(gen_, name0##_##name1)(DisasContext *ctx)             \
269{                                                                      \
270    if ((Rc(ctx->opcode) == 0) &&                                      \
271        ((ctx->insns_flags & flg0) || (ctx->insns_flags2 & flg2_0))) { \
272        gen_##name0(ctx);                                              \
273    } else if ((Rc(ctx->opcode) == 1) &&                               \
274        ((ctx->insns_flags & flg1) || (ctx->insns_flags2 & flg2_1))) { \
275        gen_##name1(ctx);                                              \
276    } else {                                                           \
277        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);            \
278    }                                                                  \
279}
280
281/*
282 * We use this macro if one instruction is realized with direct
283 * translation, and second one with helper.
284 */
285#define GEN_VXFORM_TRANS_DUAL(name0, flg0, flg2_0, name1, flg1, flg2_1)\
286static void glue(gen_, name0##_##name1)(DisasContext *ctx)             \
287{                                                                      \
288    if ((Rc(ctx->opcode) == 0) &&                                      \
289        ((ctx->insns_flags & flg0) || (ctx->insns_flags2 & flg2_0))) { \
290        if (unlikely(!ctx->altivec_enabled)) {                         \
291            gen_exception(ctx, POWERPC_EXCP_VPU);                      \
292            return;                                                    \
293        }                                                              \
294        trans_##name0(ctx);                                            \
295    } else if ((Rc(ctx->opcode) == 1) &&                               \
296        ((ctx->insns_flags & flg1) || (ctx->insns_flags2 & flg2_1))) { \
297        gen_##name1(ctx);                                              \
298    } else {                                                           \
299        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);            \
300    }                                                                  \
301}
302
303/* Adds support to provide invalid mask */
304#define GEN_VXFORM_DUAL_EXT(name0, flg0, flg2_0, inval0,                \
305                            name1, flg1, flg2_1, inval1)                \
306static void glue(gen_, name0##_##name1)(DisasContext *ctx)              \
307{                                                                       \
308    if ((Rc(ctx->opcode) == 0) &&                                       \
309        ((ctx->insns_flags & flg0) || (ctx->insns_flags2 & flg2_0)) &&  \
310        !(ctx->opcode & inval0)) {                                      \
311        gen_##name0(ctx);                                               \
312    } else if ((Rc(ctx->opcode) == 1) &&                                \
313               ((ctx->insns_flags & flg1) || (ctx->insns_flags2 & flg2_1)) && \
314               !(ctx->opcode & inval1)) {                               \
315        gen_##name1(ctx);                                               \
316    } else {                                                            \
317        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);             \
318    }                                                                   \
319}
320
321#define GEN_VXFORM_HETRO(name, opc2, opc3)                              \
322static void glue(gen_, name)(DisasContext *ctx)                         \
323{                                                                       \
324    TCGv_ptr rb;                                                        \
325    if (unlikely(!ctx->altivec_enabled)) {                              \
326        gen_exception(ctx, POWERPC_EXCP_VPU);                           \
327        return;                                                         \
328    }                                                                   \
329    rb = gen_avr_ptr(rB(ctx->opcode));                                  \
330    gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], rb); \
331}
332
333GEN_VXFORM_V(vaddubm, MO_8, tcg_gen_gvec_add, 0, 0);
334GEN_VXFORM_DUAL_EXT(vaddubm, PPC_ALTIVEC, PPC_NONE, 0,       \
335                    vmul10cuq, PPC_NONE, PPC2_ISA300, 0x0000F800)
336GEN_VXFORM_V(vadduhm, MO_16, tcg_gen_gvec_add, 0, 1);
337GEN_VXFORM_DUAL(vadduhm, PPC_ALTIVEC, PPC_NONE,  \
338                vmul10ecuq, PPC_NONE, PPC2_ISA300)
339GEN_VXFORM_V(vadduwm, MO_32, tcg_gen_gvec_add, 0, 2);
340GEN_VXFORM_V(vaddudm, MO_64, tcg_gen_gvec_add, 0, 3);
341GEN_VXFORM_V(vsububm, MO_8, tcg_gen_gvec_sub, 0, 16);
342GEN_VXFORM_V(vsubuhm, MO_16, tcg_gen_gvec_sub, 0, 17);
343GEN_VXFORM_V(vsubuwm, MO_32, tcg_gen_gvec_sub, 0, 18);
344GEN_VXFORM_V(vsubudm, MO_64, tcg_gen_gvec_sub, 0, 19);
345GEN_VXFORM(vmrghb, 6, 0);
346GEN_VXFORM(vmrghh, 6, 1);
347GEN_VXFORM(vmrghw, 6, 2);
348GEN_VXFORM(vmrglb, 6, 4);
349GEN_VXFORM(vmrglh, 6, 5);
350GEN_VXFORM(vmrglw, 6, 6);
351
352static void trans_vmrgew(DisasContext *ctx)
353{
354    int VT = rD(ctx->opcode);
355    int VA = rA(ctx->opcode);
356    int VB = rB(ctx->opcode);
357    TCGv_i64 tmp = tcg_temp_new_i64();
358    TCGv_i64 avr = tcg_temp_new_i64();
359
360    get_avr64(avr, VB, true);
361    tcg_gen_shri_i64(tmp, avr, 32);
362    get_avr64(avr, VA, true);
363    tcg_gen_deposit_i64(avr, avr, tmp, 0, 32);
364    set_avr64(VT, avr, true);
365
366    get_avr64(avr, VB, false);
367    tcg_gen_shri_i64(tmp, avr, 32);
368    get_avr64(avr, VA, false);
369    tcg_gen_deposit_i64(avr, avr, tmp, 0, 32);
370    set_avr64(VT, avr, false);
371}
372
373static void trans_vmrgow(DisasContext *ctx)
374{
375    int VT = rD(ctx->opcode);
376    int VA = rA(ctx->opcode);
377    int VB = rB(ctx->opcode);
378    TCGv_i64 t0 = tcg_temp_new_i64();
379    TCGv_i64 t1 = tcg_temp_new_i64();
380    TCGv_i64 avr = tcg_temp_new_i64();
381
382    get_avr64(t0, VB, true);
383    get_avr64(t1, VA, true);
384    tcg_gen_deposit_i64(avr, t0, t1, 32, 32);
385    set_avr64(VT, avr, true);
386
387    get_avr64(t0, VB, false);
388    get_avr64(t1, VA, false);
389    tcg_gen_deposit_i64(avr, t0, t1, 32, 32);
390    set_avr64(VT, avr, false);
391}
392
393/*
394 * lvsl VRT,RA,RB - Load Vector for Shift Left
395 *
396 * Let the EA be the sum (rA|0)+(rB). Let sh=EA[28–31].
397 * Let X be the 32-byte value 0x00 || 0x01 || 0x02 || ... || 0x1E || 0x1F.
398 * Bytes sh:sh+15 of X are placed into vD.
399 */
400static bool trans_LVSL(DisasContext *ctx, arg_LVSL *a)
401{
402    TCGv_i64 result = tcg_temp_new_i64();
403    TCGv_i64 sh = tcg_temp_new_i64();
404    TCGv EA = tcg_temp_new();
405
406    REQUIRE_INSNS_FLAGS(ctx, ALTIVEC);
407    REQUIRE_VECTOR(ctx);
408
409    /* Get sh(from description) by anding EA with 0xf. */
410    EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
411    tcg_gen_extu_tl_i64(sh, EA);
412    tcg_gen_andi_i64(sh, sh, 0xfULL);
413
414    /*
415     * Create bytes sh:sh+7 of X(from description) and place them in
416     * higher doubleword of vD.
417     */
418    tcg_gen_muli_i64(sh, sh, 0x0101010101010101ULL);
419    tcg_gen_addi_i64(result, sh, 0x0001020304050607ull);
420    set_avr64(a->rt, result, true);
421    /*
422     * Create bytes sh+8:sh+15 of X(from description) and place them in
423     * lower doubleword of vD.
424     */
425    tcg_gen_addi_i64(result, sh, 0x08090a0b0c0d0e0fULL);
426    set_avr64(a->rt, result, false);
427    return true;
428}
429
430/*
431 * lvsr VRT,RA,RB - Load Vector for Shift Right
432 *
433 * Let the EA be the sum (rA|0)+(rB). Let sh=EA[28–31].
434 * Let X be the 32-byte value 0x00 || 0x01 || 0x02 || ... || 0x1E || 0x1F.
435 * Bytes (16-sh):(31-sh) of X are placed into vD.
436 */
437static bool trans_LVSR(DisasContext *ctx, arg_LVSR *a)
438{
439    TCGv_i64 result = tcg_temp_new_i64();
440    TCGv_i64 sh = tcg_temp_new_i64();
441    TCGv EA = tcg_temp_new();
442
443    REQUIRE_INSNS_FLAGS(ctx, ALTIVEC);
444    REQUIRE_VECTOR(ctx);
445
446    /* Get sh(from description) by anding EA with 0xf. */
447    EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
448    tcg_gen_extu_tl_i64(sh, EA);
449    tcg_gen_andi_i64(sh, sh, 0xfULL);
450
451    /*
452     * Create bytes (16-sh):(23-sh) of X(from description) and place them in
453     * higher doubleword of vD.
454     */
455    tcg_gen_muli_i64(sh, sh, 0x0101010101010101ULL);
456    tcg_gen_subfi_i64(result, 0x1011121314151617ULL, sh);
457    set_avr64(a->rt, result, true);
458    /*
459     * Create bytes (24-sh):(32-sh) of X(from description) and place them in
460     * lower doubleword of vD.
461     */
462    tcg_gen_subfi_i64(result, 0x18191a1b1c1d1e1fULL, sh);
463    set_avr64(a->rt, result, false);
464    return true;
465}
466
467/*
468 * vsl VRT,VRA,VRB - Vector Shift Left
469 *
470 * Shifting left 128 bit value of vA by value specified in bits 125-127 of vB.
471 * Lowest 3 bits in each byte element of register vB must be identical or
472 * result is undefined.
473 */
474static void trans_vsl(DisasContext *ctx)
475{
476    int VT = rD(ctx->opcode);
477    int VA = rA(ctx->opcode);
478    int VB = rB(ctx->opcode);
479    TCGv_i64 avr = tcg_temp_new_i64();
480    TCGv_i64 sh = tcg_temp_new_i64();
481    TCGv_i64 carry = tcg_temp_new_i64();
482    TCGv_i64 tmp = tcg_temp_new_i64();
483
484    /* Place bits 125-127 of vB in 'sh'. */
485    get_avr64(avr, VB, false);
486    tcg_gen_andi_i64(sh, avr, 0x07ULL);
487
488    /*
489     * Save highest 'sh' bits of lower doubleword element of vA in variable
490     * 'carry' and perform shift on lower doubleword.
491     */
492    get_avr64(avr, VA, false);
493    tcg_gen_subfi_i64(tmp, 32, sh);
494    tcg_gen_shri_i64(carry, avr, 32);
495    tcg_gen_shr_i64(carry, carry, tmp);
496    tcg_gen_shl_i64(avr, avr, sh);
497    set_avr64(VT, avr, false);
498
499    /*
500     * Perform shift on higher doubleword element of vA and replace lowest
501     * 'sh' bits with 'carry'.
502     */
503    get_avr64(avr, VA, true);
504    tcg_gen_shl_i64(avr, avr, sh);
505    tcg_gen_or_i64(avr, avr, carry);
506    set_avr64(VT, avr, true);
507}
508
509/*
510 * vsr VRT,VRA,VRB - Vector Shift Right
511 *
512 * Shifting right 128 bit value of vA by value specified in bits 125-127 of vB.
513 * Lowest 3 bits in each byte element of register vB must be identical or
514 * result is undefined.
515 */
516static void trans_vsr(DisasContext *ctx)
517{
518    int VT = rD(ctx->opcode);
519    int VA = rA(ctx->opcode);
520    int VB = rB(ctx->opcode);
521    TCGv_i64 avr = tcg_temp_new_i64();
522    TCGv_i64 sh = tcg_temp_new_i64();
523    TCGv_i64 carry = tcg_temp_new_i64();
524    TCGv_i64 tmp = tcg_temp_new_i64();
525
526    /* Place bits 125-127 of vB in 'sh'. */
527    get_avr64(avr, VB, false);
528    tcg_gen_andi_i64(sh, avr, 0x07ULL);
529
530    /*
531     * Save lowest 'sh' bits of higher doubleword element of vA in variable
532     * 'carry' and perform shift on higher doubleword.
533     */
534    get_avr64(avr, VA, true);
535    tcg_gen_subfi_i64(tmp, 32, sh);
536    tcg_gen_shli_i64(carry, avr, 32);
537    tcg_gen_shl_i64(carry, carry, tmp);
538    tcg_gen_shr_i64(avr, avr, sh);
539    set_avr64(VT, avr, true);
540    /*
541     * Perform shift on lower doubleword element of vA and replace highest
542     * 'sh' bits with 'carry'.
543     */
544    get_avr64(avr, VA, false);
545    tcg_gen_shr_i64(avr, avr, sh);
546    tcg_gen_or_i64(avr, avr, carry);
547    set_avr64(VT, avr, false);
548}
549
550/*
551 * vgbbd VRT,VRB - Vector Gather Bits by Bytes by Doubleword
552 *
553 * All ith bits (i in range 1 to 8) of each byte of doubleword element in source
554 * register are concatenated and placed into ith byte of appropriate doubleword
555 * element in destination register.
556 *
557 * Following solution is done for both doubleword elements of source register
558 * in parallel, in order to reduce the number of instructions needed(that's why
559 * arrays are used):
560 * First, both doubleword elements of source register vB are placed in
561 * appropriate element of array avr. Bits are gathered in 2x8 iterations(2 for
562 * loops). In first iteration bit 1 of byte 1, bit 2 of byte 2,... bit 8 of
563 * byte 8 are in their final spots so avr[i], i={0,1} can be and-ed with
564 * tcg_mask. For every following iteration, both avr[i] and tcg_mask variables
565 * have to be shifted right for 7 and 8 places, respectively, in order to get
566 * bit 1 of byte 2, bit 2 of byte 3.. bit 7 of byte 8 in their final spots so
567 * shifted avr values(saved in tmp) can be and-ed with new value of tcg_mask...
568 * After first 8 iteration(first loop), all the first bits are in their final
569 * places, all second bits but second bit from eight byte are in their places...
570 * only 1 eight bit from eight byte is in it's place). In second loop we do all
571 * operations symmetrically, in order to get other half of bits in their final
572 * spots. Results for first and second doubleword elements are saved in
573 * result[0] and result[1] respectively. In the end those results are saved in
574 * appropriate doubleword element of destination register vD.
575 */
576static void trans_vgbbd(DisasContext *ctx)
577{
578    int VT = rD(ctx->opcode);
579    int VB = rB(ctx->opcode);
580    TCGv_i64 tmp = tcg_temp_new_i64();
581    uint64_t mask = 0x8040201008040201ULL;
582    int i, j;
583
584    TCGv_i64 result[2];
585    result[0] = tcg_temp_new_i64();
586    result[1] = tcg_temp_new_i64();
587    TCGv_i64 avr[2];
588    avr[0] = tcg_temp_new_i64();
589    avr[1] = tcg_temp_new_i64();
590    TCGv_i64 tcg_mask = tcg_temp_new_i64();
591
592    tcg_gen_movi_i64(tcg_mask, mask);
593    for (j = 0; j < 2; j++) {
594        get_avr64(avr[j], VB, j);
595        tcg_gen_and_i64(result[j], avr[j], tcg_mask);
596    }
597    for (i = 1; i < 8; i++) {
598        tcg_gen_movi_i64(tcg_mask, mask >> (i * 8));
599        for (j = 0; j < 2; j++) {
600            tcg_gen_shri_i64(tmp, avr[j], i * 7);
601            tcg_gen_and_i64(tmp, tmp, tcg_mask);
602            tcg_gen_or_i64(result[j], result[j], tmp);
603        }
604    }
605    for (i = 1; i < 8; i++) {
606        tcg_gen_movi_i64(tcg_mask, mask << (i * 8));
607        for (j = 0; j < 2; j++) {
608            tcg_gen_shli_i64(tmp, avr[j], i * 7);
609            tcg_gen_and_i64(tmp, tmp, tcg_mask);
610            tcg_gen_or_i64(result[j], result[j], tmp);
611        }
612    }
613    for (j = 0; j < 2; j++) {
614        set_avr64(VT, result[j], j);
615    }
616}
617
618/*
619 * vclzw VRT,VRB - Vector Count Leading Zeros Word
620 *
621 * Counting the number of leading zero bits of each word element in source
622 * register and placing result in appropriate word element of destination
623 * register.
624 */
625static void trans_vclzw(DisasContext *ctx)
626{
627    int VT = rD(ctx->opcode);
628    int VB = rB(ctx->opcode);
629    TCGv_i32 tmp = tcg_temp_new_i32();
630    int i;
631
632    /* Perform count for every word element using tcg_gen_clzi_i32. */
633    for (i = 0; i < 4; i++) {
634        tcg_gen_ld_i32(tmp, tcg_env,
635            offsetof(CPUPPCState, vsr[32 + VB].u64[0]) + i * 4);
636        tcg_gen_clzi_i32(tmp, tmp, 32);
637        tcg_gen_st_i32(tmp, tcg_env,
638            offsetof(CPUPPCState, vsr[32 + VT].u64[0]) + i * 4);
639    }
640}
641
642/*
643 * vclzd VRT,VRB - Vector Count Leading Zeros Doubleword
644 *
645 * Counting the number of leading zero bits of each doubleword element in source
646 * register and placing result in appropriate doubleword element of destination
647 * register.
648 */
649static void trans_vclzd(DisasContext *ctx)
650{
651    int VT = rD(ctx->opcode);
652    int VB = rB(ctx->opcode);
653    TCGv_i64 avr = tcg_temp_new_i64();
654
655    /* high doubleword */
656    get_avr64(avr, VB, true);
657    tcg_gen_clzi_i64(avr, avr, 64);
658    set_avr64(VT, avr, true);
659
660    /* low doubleword */
661    get_avr64(avr, VB, false);
662    tcg_gen_clzi_i64(avr, avr, 64);
663    set_avr64(VT, avr, false);
664}
665
666GEN_VXFORM_V(vmuluwm, MO_32, tcg_gen_gvec_mul, 4, 2);
667GEN_VXFORM(vsrv, 2, 28);
668GEN_VXFORM(vslv, 2, 29);
669GEN_VXFORM(vslo, 6, 16);
670GEN_VXFORM(vsro, 6, 17);
671
672static bool do_vector_gvec3_VX(DisasContext *ctx, arg_VX *a, int vece,
673                               void (*gen_gvec)(unsigned, uint32_t, uint32_t,
674                                                uint32_t, uint32_t, uint32_t))
675{
676    REQUIRE_VECTOR(ctx);
677
678    gen_gvec(vece, avr_full_offset(a->vrt), avr_full_offset(a->vra),
679             avr_full_offset(a->vrb), 16, 16);
680
681    return true;
682}
683
684TRANS_FLAGS(ALTIVEC, VSLB, do_vector_gvec3_VX, MO_8, tcg_gen_gvec_shlv);
685TRANS_FLAGS(ALTIVEC, VSLH, do_vector_gvec3_VX, MO_16, tcg_gen_gvec_shlv);
686TRANS_FLAGS(ALTIVEC, VSLW, do_vector_gvec3_VX, MO_32, tcg_gen_gvec_shlv);
687TRANS_FLAGS2(ALTIVEC_207, VSLD, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_shlv);
688
689TRANS_FLAGS(ALTIVEC, VSRB, do_vector_gvec3_VX, MO_8, tcg_gen_gvec_shrv);
690TRANS_FLAGS(ALTIVEC, VSRH, do_vector_gvec3_VX, MO_16, tcg_gen_gvec_shrv);
691TRANS_FLAGS(ALTIVEC, VSRW, do_vector_gvec3_VX, MO_32, tcg_gen_gvec_shrv);
692TRANS_FLAGS2(ALTIVEC_207, VSRD, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_shrv);
693
694TRANS_FLAGS(ALTIVEC, VSRAB, do_vector_gvec3_VX, MO_8, tcg_gen_gvec_sarv);
695TRANS_FLAGS(ALTIVEC, VSRAH, do_vector_gvec3_VX, MO_16, tcg_gen_gvec_sarv);
696TRANS_FLAGS(ALTIVEC, VSRAW, do_vector_gvec3_VX, MO_32, tcg_gen_gvec_sarv);
697TRANS_FLAGS2(ALTIVEC_207, VSRAD, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_sarv);
698
699TRANS_FLAGS(ALTIVEC, VRLB, do_vector_gvec3_VX, MO_8, tcg_gen_gvec_rotlv)
700TRANS_FLAGS(ALTIVEC, VRLH, do_vector_gvec3_VX, MO_16, tcg_gen_gvec_rotlv)
701TRANS_FLAGS(ALTIVEC, VRLW, do_vector_gvec3_VX, MO_32, tcg_gen_gvec_rotlv)
702TRANS_FLAGS2(ALTIVEC_207, VRLD, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_rotlv)
703
704/* Logical operations */
705TRANS_FLAGS(ALTIVEC, VAND, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_and);
706TRANS_FLAGS(ALTIVEC, VANDC, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_andc);
707TRANS_FLAGS(ALTIVEC, VOR, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_or);
708TRANS_FLAGS(ALTIVEC, VXOR, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_xor);
709TRANS_FLAGS(ALTIVEC, VNOR, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_nor);
710TRANS_FLAGS2(ALTIVEC_207, VEQV, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_eqv);
711TRANS_FLAGS2(ALTIVEC_207, VNAND, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_nand);
712TRANS_FLAGS2(ALTIVEC_207, VORC, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_orc);
713
714/* Integer Max/Min operations */
715TRANS_FLAGS(ALTIVEC, VMAXUB, do_vector_gvec3_VX, MO_8, tcg_gen_gvec_umax);
716TRANS_FLAGS(ALTIVEC, VMAXUH, do_vector_gvec3_VX, MO_16, tcg_gen_gvec_umax);
717TRANS_FLAGS(ALTIVEC, VMAXUW, do_vector_gvec3_VX, MO_32, tcg_gen_gvec_umax);
718TRANS_FLAGS2(ALTIVEC_207, VMAXUD, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_umax);
719
720TRANS_FLAGS(ALTIVEC, VMAXSB, do_vector_gvec3_VX, MO_8, tcg_gen_gvec_smax);
721TRANS_FLAGS(ALTIVEC, VMAXSH, do_vector_gvec3_VX, MO_16, tcg_gen_gvec_smax);
722TRANS_FLAGS(ALTIVEC, VMAXSW, do_vector_gvec3_VX, MO_32, tcg_gen_gvec_smax);
723TRANS_FLAGS2(ALTIVEC_207, VMAXSD, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_smax);
724
725TRANS_FLAGS(ALTIVEC, VMINUB, do_vector_gvec3_VX, MO_8, tcg_gen_gvec_umin);
726TRANS_FLAGS(ALTIVEC, VMINUH, do_vector_gvec3_VX, MO_16, tcg_gen_gvec_umin);
727TRANS_FLAGS(ALTIVEC, VMINUW, do_vector_gvec3_VX, MO_32, tcg_gen_gvec_umin);
728TRANS_FLAGS2(ALTIVEC_207, VMINUD, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_umin);
729
730TRANS_FLAGS(ALTIVEC, VMINSB, do_vector_gvec3_VX, MO_8, tcg_gen_gvec_smin);
731TRANS_FLAGS(ALTIVEC, VMINSH, do_vector_gvec3_VX, MO_16, tcg_gen_gvec_smin);
732TRANS_FLAGS(ALTIVEC, VMINSW, do_vector_gvec3_VX, MO_32, tcg_gen_gvec_smin);
733TRANS_FLAGS2(ALTIVEC_207, VMINSD, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_smin);
734
735static TCGv_vec do_vrl_mask_vec(unsigned vece, TCGv_vec vrb)
736{
737    TCGv_vec t0 = tcg_temp_new_vec_matching(vrb),
738             t1 = tcg_temp_new_vec_matching(vrb),
739             t2 = tcg_temp_new_vec_matching(vrb),
740             ones = tcg_constant_vec_matching(vrb, vece, -1);
741
742    /* Extract b and e */
743    tcg_gen_dupi_vec(vece, t2, (8 << vece) - 1);
744
745    tcg_gen_shri_vec(vece, t0, vrb, 16);
746    tcg_gen_and_vec(vece, t0, t0, t2);
747
748    tcg_gen_shri_vec(vece, t1, vrb, 8);
749    tcg_gen_and_vec(vece, t1, t1, t2);
750
751    /* Compare b and e to negate the mask where begin > end */
752    tcg_gen_cmp_vec(TCG_COND_GT, vece, t2, t0, t1);
753
754    /* Create the mask with (~0 >> b) ^ ((~0 >> e) >> 1) */
755    tcg_gen_shrv_vec(vece, t0, ones, t0);
756    tcg_gen_shrv_vec(vece, t1, ones, t1);
757    tcg_gen_shri_vec(vece, t1, t1, 1);
758    tcg_gen_xor_vec(vece, t0, t0, t1);
759
760    /* negate the mask */
761    tcg_gen_xor_vec(vece, t0, t0, t2);
762
763    return t0;
764}
765
766static void gen_vrlnm_vec(unsigned vece, TCGv_vec vrt, TCGv_vec vra,
767                          TCGv_vec vrb)
768{
769    TCGv_vec mask, n = tcg_temp_new_vec_matching(vrt);
770
771    /* Create the mask */
772    mask = do_vrl_mask_vec(vece, vrb);
773
774    /* Extract n */
775    tcg_gen_dupi_vec(vece, n, (8 << vece) - 1);
776    tcg_gen_and_vec(vece, n, vrb, n);
777
778    /* Rotate and mask */
779    tcg_gen_rotlv_vec(vece, vrt, vra, n);
780    tcg_gen_and_vec(vece, vrt, vrt, mask);
781}
782
783static bool do_vrlnm(DisasContext *ctx, arg_VX *a, int vece)
784{
785    static const TCGOpcode vecop_list[] = {
786        INDEX_op_cmp_vec, INDEX_op_rotlv_vec, INDEX_op_sari_vec,
787        INDEX_op_shli_vec, INDEX_op_shri_vec, INDEX_op_shrv_vec, 0
788    };
789    static const GVecGen3 ops[2] = {
790        {
791            .fniv = gen_vrlnm_vec,
792            .fno = gen_helper_VRLWNM,
793            .opt_opc = vecop_list,
794            .load_dest = true,
795            .vece = MO_32
796        },
797        {
798            .fniv = gen_vrlnm_vec,
799            .fno = gen_helper_VRLDNM,
800            .opt_opc = vecop_list,
801            .load_dest = true,
802            .vece = MO_64
803        }
804    };
805
806    REQUIRE_INSNS_FLAGS2(ctx, ISA300);
807    REQUIRE_VSX(ctx);
808
809    tcg_gen_gvec_3(avr_full_offset(a->vrt), avr_full_offset(a->vra),
810                   avr_full_offset(a->vrb), 16, 16, &ops[vece - 2]);
811
812    return true;
813}
814
815TRANS(VRLWNM, do_vrlnm, MO_32)
816TRANS(VRLDNM, do_vrlnm, MO_64)
817
818static void gen_vrlmi_vec(unsigned vece, TCGv_vec vrt, TCGv_vec vra,
819                          TCGv_vec vrb)
820{
821    TCGv_vec mask, n = tcg_temp_new_vec_matching(vrt),
822             tmp = tcg_temp_new_vec_matching(vrt);
823
824    /* Create the mask */
825    mask = do_vrl_mask_vec(vece, vrb);
826
827    /* Extract n */
828    tcg_gen_dupi_vec(vece, n, (8 << vece) - 1);
829    tcg_gen_and_vec(vece, n, vrb, n);
830
831    /* Rotate and insert */
832    tcg_gen_rotlv_vec(vece, tmp, vra, n);
833    tcg_gen_bitsel_vec(vece, vrt, mask, tmp, vrt);
834}
835
836static bool do_vrlmi(DisasContext *ctx, arg_VX *a, int vece)
837{
838    static const TCGOpcode vecop_list[] = {
839        INDEX_op_cmp_vec, INDEX_op_rotlv_vec, INDEX_op_sari_vec,
840        INDEX_op_shli_vec, INDEX_op_shri_vec, INDEX_op_shrv_vec, 0
841    };
842    static const GVecGen3 ops[2] = {
843        {
844            .fniv = gen_vrlmi_vec,
845            .fno = gen_helper_VRLWMI,
846            .opt_opc = vecop_list,
847            .load_dest = true,
848            .vece = MO_32
849        },
850        {
851            .fniv = gen_vrlnm_vec,
852            .fno = gen_helper_VRLDMI,
853            .opt_opc = vecop_list,
854            .load_dest = true,
855            .vece = MO_64
856        }
857    };
858
859    REQUIRE_INSNS_FLAGS2(ctx, ISA300);
860    REQUIRE_VSX(ctx);
861
862    tcg_gen_gvec_3(avr_full_offset(a->vrt), avr_full_offset(a->vra),
863                   avr_full_offset(a->vrb), 16, 16, &ops[vece - 2]);
864
865    return true;
866}
867
868TRANS(VRLWMI, do_vrlmi, MO_32)
869TRANS(VRLDMI, do_vrlmi, MO_64)
870
871static bool do_vector_shift_quad(DisasContext *ctx, arg_VX *a, bool right,
872                                 bool alg)
873{
874    TCGv_i64 hi, lo, t0, t1, n, zero = tcg_constant_i64(0);
875
876    REQUIRE_VECTOR(ctx);
877
878    n = tcg_temp_new_i64();
879    hi = tcg_temp_new_i64();
880    lo = tcg_temp_new_i64();
881    t0 = tcg_temp_new_i64();
882
883    get_avr64(lo, a->vra, false);
884    get_avr64(hi, a->vra, true);
885
886    get_avr64(n, a->vrb, true);
887
888    tcg_gen_andi_i64(t0, n, 64);
889    if (right) {
890        tcg_gen_movcond_i64(TCG_COND_NE, lo, t0, zero, hi, lo);
891        if (alg) {
892            t1 = tcg_temp_new_i64();
893            tcg_gen_sari_i64(t1, lo, 63);
894        } else {
895            t1 = zero;
896        }
897        tcg_gen_movcond_i64(TCG_COND_NE, hi, t0, zero, t1, hi);
898    } else {
899        tcg_gen_movcond_i64(TCG_COND_NE, hi, t0, zero, lo, hi);
900        tcg_gen_movcond_i64(TCG_COND_NE, lo, t0, zero, zero, lo);
901    }
902    tcg_gen_andi_i64(n, n, 0x3F);
903
904    if (right) {
905        if (alg) {
906            tcg_gen_sar_i64(t0, hi, n);
907        } else {
908            tcg_gen_shr_i64(t0, hi, n);
909        }
910    } else {
911        tcg_gen_shl_i64(t0, lo, n);
912    }
913    set_avr64(a->vrt, t0, right);
914
915    if (right) {
916        tcg_gen_shr_i64(lo, lo, n);
917    } else {
918        tcg_gen_shl_i64(hi, hi, n);
919    }
920    tcg_gen_xori_i64(n, n, 63);
921    if (right) {
922        tcg_gen_shl_i64(hi, hi, n);
923        tcg_gen_shli_i64(hi, hi, 1);
924    } else {
925        tcg_gen_shr_i64(lo, lo, n);
926        tcg_gen_shri_i64(lo, lo, 1);
927    }
928    tcg_gen_or_i64(hi, hi, lo);
929    set_avr64(a->vrt, hi, !right);
930    return true;
931}
932
933TRANS_FLAGS2(ISA310, VSLQ, do_vector_shift_quad, false, false);
934TRANS_FLAGS2(ISA310, VSRQ, do_vector_shift_quad, true, false);
935TRANS_FLAGS2(ISA310, VSRAQ, do_vector_shift_quad, true, true);
936
937static void do_vrlq_mask(TCGv_i64 mh, TCGv_i64 ml, TCGv_i64 b, TCGv_i64 e)
938{
939    TCGv_i64 th, tl, t0, t1, zero = tcg_constant_i64(0),
940             ones = tcg_constant_i64(-1);
941
942    th = tcg_temp_new_i64();
943    tl = tcg_temp_new_i64();
944    t0 = tcg_temp_new_i64();
945    t1 = tcg_temp_new_i64();
946
947    /* m = ~0 >> b */
948    tcg_gen_andi_i64(t0, b, 64);
949    tcg_gen_movcond_i64(TCG_COND_NE, t1, t0, zero, zero, ones);
950    tcg_gen_andi_i64(t0, b, 0x3F);
951    tcg_gen_shr_i64(mh, t1, t0);
952    tcg_gen_shr_i64(ml, ones, t0);
953    tcg_gen_xori_i64(t0, t0, 63);
954    tcg_gen_shl_i64(t1, t1, t0);
955    tcg_gen_shli_i64(t1, t1, 1);
956    tcg_gen_or_i64(ml, t1, ml);
957
958    /* t = ~0 >> e */
959    tcg_gen_andi_i64(t0, e, 64);
960    tcg_gen_movcond_i64(TCG_COND_NE, t1, t0, zero, zero, ones);
961    tcg_gen_andi_i64(t0, e, 0x3F);
962    tcg_gen_shr_i64(th, t1, t0);
963    tcg_gen_shr_i64(tl, ones, t0);
964    tcg_gen_xori_i64(t0, t0, 63);
965    tcg_gen_shl_i64(t1, t1, t0);
966    tcg_gen_shli_i64(t1, t1, 1);
967    tcg_gen_or_i64(tl, t1, tl);
968
969    /* t = t >> 1 */
970    tcg_gen_extract2_i64(tl, tl, th, 1);
971    tcg_gen_shri_i64(th, th, 1);
972
973    /* m = m ^ t */
974    tcg_gen_xor_i64(mh, mh, th);
975    tcg_gen_xor_i64(ml, ml, tl);
976
977    /* Negate the mask if begin > end */
978    tcg_gen_movcond_i64(TCG_COND_GT, t0, b, e, ones, zero);
979
980    tcg_gen_xor_i64(mh, mh, t0);
981    tcg_gen_xor_i64(ml, ml, t0);
982}
983
984static bool do_vector_rotl_quad(DisasContext *ctx, arg_VX *a, bool mask,
985                                bool insert)
986{
987    TCGv_i64 ah, al, vrb, n, t0, t1, zero = tcg_constant_i64(0);
988
989    REQUIRE_VECTOR(ctx);
990    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
991
992    ah = tcg_temp_new_i64();
993    al = tcg_temp_new_i64();
994    vrb = tcg_temp_new_i64();
995    n = tcg_temp_new_i64();
996    t0 = tcg_temp_new_i64();
997    t1 = tcg_temp_new_i64();
998
999    get_avr64(ah, a->vra, true);
1000    get_avr64(al, a->vra, false);
1001    get_avr64(vrb, a->vrb, true);
1002
1003    tcg_gen_mov_i64(t0, ah);
1004    tcg_gen_andi_i64(t1, vrb, 64);
1005    tcg_gen_movcond_i64(TCG_COND_NE, ah, t1, zero, al, ah);
1006    tcg_gen_movcond_i64(TCG_COND_NE, al, t1, zero, t0, al);
1007    tcg_gen_andi_i64(n, vrb, 0x3F);
1008
1009    tcg_gen_shl_i64(t0, ah, n);
1010    tcg_gen_shl_i64(t1, al, n);
1011
1012    tcg_gen_xori_i64(n, n, 63);
1013
1014    tcg_gen_shr_i64(al, al, n);
1015    tcg_gen_shri_i64(al, al, 1);
1016    tcg_gen_or_i64(t0, al, t0);
1017
1018    tcg_gen_shr_i64(ah, ah, n);
1019    tcg_gen_shri_i64(ah, ah, 1);
1020    tcg_gen_or_i64(t1, ah, t1);
1021
1022    if (mask || insert) {
1023        tcg_gen_extract_i64(n, vrb, 8, 7);
1024        tcg_gen_extract_i64(vrb, vrb, 16, 7);
1025
1026        do_vrlq_mask(ah, al, vrb, n);
1027
1028        tcg_gen_and_i64(t0, t0, ah);
1029        tcg_gen_and_i64(t1, t1, al);
1030
1031        if (insert) {
1032            get_avr64(n, a->vrt, true);
1033            get_avr64(vrb, a->vrt, false);
1034            tcg_gen_andc_i64(n, n, ah);
1035            tcg_gen_andc_i64(vrb, vrb, al);
1036            tcg_gen_or_i64(t0, t0, n);
1037            tcg_gen_or_i64(t1, t1, vrb);
1038        }
1039    }
1040
1041    set_avr64(a->vrt, t0, true);
1042    set_avr64(a->vrt, t1, false);
1043    return true;
1044}
1045
1046TRANS(VRLQ, do_vector_rotl_quad, false, false)
1047TRANS(VRLQNM, do_vector_rotl_quad, true, false)
1048TRANS(VRLQMI, do_vector_rotl_quad, false, true)
1049
1050#define GEN_VXFORM_SAT(NAME, VECE, NORM, SAT, OPC2, OPC3)               \
1051static void glue(glue(gen_, NAME), _vec)(unsigned vece, TCGv_vec t,     \
1052                                         TCGv_vec sat, TCGv_vec a,      \
1053                                         TCGv_vec b)                    \
1054{                                                                       \
1055    TCGv_vec x = tcg_temp_new_vec_matching(t);                          \
1056    glue(glue(tcg_gen_, NORM), _vec)(VECE, x, a, b);                    \
1057    glue(glue(tcg_gen_, SAT), _vec)(VECE, t, a, b);                     \
1058    tcg_gen_cmp_vec(TCG_COND_NE, VECE, x, x, t);                        \
1059    tcg_gen_or_vec(VECE, sat, sat, x);                                  \
1060}                                                                       \
1061static void glue(gen_, NAME)(DisasContext *ctx)                         \
1062{                                                                       \
1063    static const TCGOpcode vecop_list[] = {                             \
1064        glue(glue(INDEX_op_, NORM), _vec),                              \
1065        glue(glue(INDEX_op_, SAT), _vec),                               \
1066        INDEX_op_cmp_vec, 0                                             \
1067    };                                                                  \
1068    static const GVecGen4 g = {                                         \
1069        .fniv = glue(glue(gen_, NAME), _vec),                           \
1070        .fno = glue(gen_helper_, NAME),                                 \
1071        .opt_opc = vecop_list,                                          \
1072        .write_aofs = true,                                             \
1073        .vece = VECE,                                                   \
1074    };                                                                  \
1075    if (unlikely(!ctx->altivec_enabled)) {                              \
1076        gen_exception(ctx, POWERPC_EXCP_VPU);                           \
1077        return;                                                         \
1078    }                                                                   \
1079    tcg_gen_gvec_4(avr_full_offset(rD(ctx->opcode)),                    \
1080                   offsetof(CPUPPCState, vscr_sat),                     \
1081                   avr_full_offset(rA(ctx->opcode)),                    \
1082                   avr_full_offset(rB(ctx->opcode)),                    \
1083                   16, 16, &g);                                         \
1084}
1085
1086GEN_VXFORM_SAT(vaddubs, MO_8, add, usadd, 0, 8);
1087GEN_VXFORM_DUAL_EXT(vaddubs, PPC_ALTIVEC, PPC_NONE, 0,       \
1088                    vmul10uq, PPC_NONE, PPC2_ISA300, 0x0000F800)
1089GEN_VXFORM_SAT(vadduhs, MO_16, add, usadd, 0, 9);
1090GEN_VXFORM_DUAL(vadduhs, PPC_ALTIVEC, PPC_NONE, \
1091                vmul10euq, PPC_NONE, PPC2_ISA300)
1092GEN_VXFORM_SAT(vadduws, MO_32, add, usadd, 0, 10);
1093GEN_VXFORM_SAT(vaddsbs, MO_8, add, ssadd, 0, 12);
1094GEN_VXFORM_SAT(vaddshs, MO_16, add, ssadd, 0, 13);
1095GEN_VXFORM_SAT(vaddsws, MO_32, add, ssadd, 0, 14);
1096GEN_VXFORM_SAT(vsububs, MO_8, sub, ussub, 0, 24);
1097GEN_VXFORM_SAT(vsubuhs, MO_16, sub, ussub, 0, 25);
1098GEN_VXFORM_SAT(vsubuws, MO_32, sub, ussub, 0, 26);
1099GEN_VXFORM_SAT(vsubsbs, MO_8, sub, sssub, 0, 28);
1100GEN_VXFORM_SAT(vsubshs, MO_16, sub, sssub, 0, 29);
1101GEN_VXFORM_SAT(vsubsws, MO_32, sub, sssub, 0, 30);
1102GEN_VXFORM_TRANS(vsl, 2, 7);
1103GEN_VXFORM_TRANS(vsr, 2, 11);
1104GEN_VXFORM_ENV(vpkuhum, 7, 0);
1105GEN_VXFORM_ENV(vpkuwum, 7, 1);
1106GEN_VXFORM_ENV(vpkudum, 7, 17);
1107GEN_VXFORM_ENV(vpkuhus, 7, 2);
1108GEN_VXFORM_ENV(vpkuwus, 7, 3);
1109GEN_VXFORM_ENV(vpkudus, 7, 19);
1110GEN_VXFORM_ENV(vpkshus, 7, 4);
1111GEN_VXFORM_ENV(vpkswus, 7, 5);
1112GEN_VXFORM_ENV(vpksdus, 7, 21);
1113GEN_VXFORM_ENV(vpkshss, 7, 6);
1114GEN_VXFORM_ENV(vpkswss, 7, 7);
1115GEN_VXFORM_ENV(vpksdss, 7, 23);
1116GEN_VXFORM(vpkpx, 7, 12);
1117GEN_VXFORM_ENV(vsum4ubs, 4, 24);
1118GEN_VXFORM_ENV(vsum4sbs, 4, 28);
1119GEN_VXFORM_ENV(vsum4shs, 4, 25);
1120GEN_VXFORM_ENV(vsum2sws, 4, 26);
1121GEN_VXFORM_ENV(vsumsws, 4, 30);
1122GEN_VXFORM_ENV(vaddfp, 5, 0);
1123GEN_VXFORM_ENV(vsubfp, 5, 1);
1124GEN_VXFORM_ENV(vmaxfp, 5, 16);
1125GEN_VXFORM_ENV(vminfp, 5, 17);
1126GEN_VXFORM_HETRO(vextublx, 6, 24)
1127GEN_VXFORM_HETRO(vextuhlx, 6, 25)
1128GEN_VXFORM_HETRO(vextuwlx, 6, 26)
1129GEN_VXFORM_TRANS_DUAL(vmrgow, PPC_NONE, PPC2_ALTIVEC_207,
1130                vextuwlx, PPC_NONE, PPC2_ISA300)
1131GEN_VXFORM_HETRO(vextubrx, 6, 28)
1132GEN_VXFORM_HETRO(vextuhrx, 6, 29)
1133GEN_VXFORM_HETRO(vextuwrx, 6, 30)
1134GEN_VXFORM_TRANS_DUAL(vmrgew, PPC_NONE, PPC2_ALTIVEC_207,
1135                vextuwrx, PPC_NONE, PPC2_ISA300)
1136
1137#define GEN_VXRFORM1(opname, name, str, opc2, opc3)                     \
1138static void glue(gen_, name)(DisasContext *ctx)                         \
1139    {                                                                   \
1140        TCGv_ptr ra, rb, rd;                                            \
1141        if (unlikely(!ctx->altivec_enabled)) {                          \
1142            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
1143            return;                                                     \
1144        }                                                               \
1145        ra = gen_avr_ptr(rA(ctx->opcode));                              \
1146        rb = gen_avr_ptr(rB(ctx->opcode));                              \
1147        rd = gen_avr_ptr(rD(ctx->opcode));                              \
1148        gen_helper_##opname(tcg_env, rd, ra, rb);                       \
1149    }
1150
1151#define GEN_VXRFORM(name, opc2, opc3)                                \
1152    GEN_VXRFORM1(name, name, #name, opc2, opc3)                      \
1153    GEN_VXRFORM1(name##_dot, name##_, #name ".", opc2, (opc3 | (0x1 << 4)))
1154
1155/*
1156 * Support for Altivec instructions that use bit 31 (Rc) as an opcode
1157 * bit but also use bit 21 as an actual Rc bit.  In general, these pairs
1158 * come from different versions of the ISA, so we must also support a
1159 * pair of flags for each instruction.
1160 */
1161#define GEN_VXRFORM_DUAL(name0, flg0, flg2_0, name1, flg1, flg2_1)     \
1162static void glue(gen_, name0##_##name1)(DisasContext *ctx)             \
1163{                                                                      \
1164    if ((Rc(ctx->opcode) == 0) &&                                      \
1165        ((ctx->insns_flags & flg0) || (ctx->insns_flags2 & flg2_0))) { \
1166        if (Rc21(ctx->opcode) == 0) {                                  \
1167            gen_##name0(ctx);                                          \
1168        } else {                                                       \
1169            gen_##name0##_(ctx);                                       \
1170        }                                                              \
1171    } else if ((Rc(ctx->opcode) == 1) &&                               \
1172        ((ctx->insns_flags & flg1) || (ctx->insns_flags2 & flg2_1))) { \
1173        if (Rc21(ctx->opcode) == 0) {                                  \
1174            gen_##name1(ctx);                                          \
1175        } else {                                                       \
1176            gen_##name1##_(ctx);                                       \
1177        }                                                              \
1178    } else {                                                           \
1179        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);            \
1180    }                                                                  \
1181}
1182
1183static void do_vcmp_rc(int vrt)
1184{
1185    TCGv_i64 tmp, set, clr;
1186
1187    tmp = tcg_temp_new_i64();
1188    set = tcg_temp_new_i64();
1189    clr = tcg_temp_new_i64();
1190
1191    get_avr64(tmp, vrt, true);
1192    tcg_gen_mov_i64(set, tmp);
1193    get_avr64(tmp, vrt, false);
1194    tcg_gen_or_i64(clr, set, tmp);
1195    tcg_gen_and_i64(set, set, tmp);
1196
1197    tcg_gen_setcondi_i64(TCG_COND_EQ, clr, clr, 0);
1198    tcg_gen_shli_i64(clr, clr, 1);
1199
1200    tcg_gen_setcondi_i64(TCG_COND_EQ, set, set, -1);
1201    tcg_gen_shli_i64(set, set, 3);
1202
1203    tcg_gen_or_i64(tmp, set, clr);
1204    tcg_gen_extrl_i64_i32(cpu_crf[6], tmp);
1205}
1206
1207static bool do_vcmp(DisasContext *ctx, arg_VC *a, TCGCond cond, int vece)
1208{
1209    REQUIRE_VECTOR(ctx);
1210
1211    tcg_gen_gvec_cmp(cond, vece, avr_full_offset(a->vrt),
1212                     avr_full_offset(a->vra), avr_full_offset(a->vrb), 16, 16);
1213
1214    if (a->rc) {
1215        do_vcmp_rc(a->vrt);
1216    }
1217
1218    return true;
1219}
1220
1221TRANS_FLAGS(ALTIVEC, VCMPEQUB, do_vcmp, TCG_COND_EQ, MO_8)
1222TRANS_FLAGS(ALTIVEC, VCMPEQUH, do_vcmp, TCG_COND_EQ, MO_16)
1223TRANS_FLAGS(ALTIVEC, VCMPEQUW, do_vcmp, TCG_COND_EQ, MO_32)
1224TRANS_FLAGS2(ALTIVEC_207, VCMPEQUD, do_vcmp, TCG_COND_EQ, MO_64)
1225
1226TRANS_FLAGS(ALTIVEC, VCMPGTSB, do_vcmp, TCG_COND_GT, MO_8)
1227TRANS_FLAGS(ALTIVEC, VCMPGTSH, do_vcmp, TCG_COND_GT, MO_16)
1228TRANS_FLAGS(ALTIVEC, VCMPGTSW, do_vcmp, TCG_COND_GT, MO_32)
1229TRANS_FLAGS2(ALTIVEC_207, VCMPGTSD, do_vcmp, TCG_COND_GT, MO_64)
1230TRANS_FLAGS(ALTIVEC, VCMPGTUB, do_vcmp, TCG_COND_GTU, MO_8)
1231TRANS_FLAGS(ALTIVEC, VCMPGTUH, do_vcmp, TCG_COND_GTU, MO_16)
1232TRANS_FLAGS(ALTIVEC, VCMPGTUW, do_vcmp, TCG_COND_GTU, MO_32)
1233TRANS_FLAGS2(ALTIVEC_207, VCMPGTUD, do_vcmp, TCG_COND_GTU, MO_64)
1234
1235TRANS_FLAGS2(ISA300, VCMPNEB, do_vcmp, TCG_COND_NE, MO_8)
1236TRANS_FLAGS2(ISA300, VCMPNEH, do_vcmp, TCG_COND_NE, MO_16)
1237TRANS_FLAGS2(ISA300, VCMPNEW, do_vcmp, TCG_COND_NE, MO_32)
1238
1239static void gen_vcmpnez_vec(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b)
1240{
1241    TCGv_vec t0, t1, zero;
1242
1243    t0 = tcg_temp_new_vec_matching(t);
1244    t1 = tcg_temp_new_vec_matching(t);
1245    zero = tcg_constant_vec_matching(t, vece, 0);
1246
1247    tcg_gen_cmp_vec(TCG_COND_EQ, vece, t0, a, zero);
1248    tcg_gen_cmp_vec(TCG_COND_EQ, vece, t1, b, zero);
1249    tcg_gen_cmp_vec(TCG_COND_NE, vece, t, a, b);
1250
1251    tcg_gen_or_vec(vece, t, t, t0);
1252    tcg_gen_or_vec(vece, t, t, t1);
1253}
1254
1255static bool do_vcmpnez(DisasContext *ctx, arg_VC *a, int vece)
1256{
1257    static const TCGOpcode vecop_list[] = {
1258        INDEX_op_cmp_vec, 0
1259    };
1260    static const GVecGen3 ops[3] = {
1261        {
1262            .fniv = gen_vcmpnez_vec,
1263            .fno = gen_helper_VCMPNEZB,
1264            .opt_opc = vecop_list,
1265            .vece = MO_8
1266        },
1267        {
1268            .fniv = gen_vcmpnez_vec,
1269            .fno = gen_helper_VCMPNEZH,
1270            .opt_opc = vecop_list,
1271            .vece = MO_16
1272        },
1273        {
1274            .fniv = gen_vcmpnez_vec,
1275            .fno = gen_helper_VCMPNEZW,
1276            .opt_opc = vecop_list,
1277            .vece = MO_32
1278        }
1279    };
1280
1281    REQUIRE_INSNS_FLAGS2(ctx, ISA300);
1282    REQUIRE_VECTOR(ctx);
1283
1284    tcg_gen_gvec_3(avr_full_offset(a->vrt), avr_full_offset(a->vra),
1285                   avr_full_offset(a->vrb), 16, 16, &ops[vece]);
1286
1287    if (a->rc) {
1288        do_vcmp_rc(a->vrt);
1289    }
1290
1291    return true;
1292}
1293
1294TRANS(VCMPNEZB, do_vcmpnez, MO_8)
1295TRANS(VCMPNEZH, do_vcmpnez, MO_16)
1296TRANS(VCMPNEZW, do_vcmpnez, MO_32)
1297
1298static bool trans_VCMPEQUQ(DisasContext *ctx, arg_VC *a)
1299{
1300    TCGv_i64 t0, t1, t2;
1301
1302    t0 = tcg_temp_new_i64();
1303    t1 = tcg_temp_new_i64();
1304    t2 = tcg_temp_new_i64();
1305
1306    get_avr64(t0, a->vra, true);
1307    get_avr64(t1, a->vrb, true);
1308    tcg_gen_xor_i64(t2, t0, t1);
1309
1310    get_avr64(t0, a->vra, false);
1311    get_avr64(t1, a->vrb, false);
1312    tcg_gen_xor_i64(t1, t0, t1);
1313
1314    tcg_gen_or_i64(t1, t1, t2);
1315    tcg_gen_negsetcond_i64(TCG_COND_EQ, t1, t1, tcg_constant_i64(0));
1316
1317    set_avr64(a->vrt, t1, true);
1318    set_avr64(a->vrt, t1, false);
1319
1320    if (a->rc) {
1321        tcg_gen_extrl_i64_i32(cpu_crf[6], t1);
1322        tcg_gen_andi_i32(cpu_crf[6], cpu_crf[6], 0xa);
1323        tcg_gen_xori_i32(cpu_crf[6], cpu_crf[6], 0x2);
1324    }
1325    return true;
1326}
1327
1328static bool do_vcmpgtq(DisasContext *ctx, arg_VC *a, bool sign)
1329{
1330    TCGv_i64 t0, t1, t2;
1331
1332    t0 = tcg_temp_new_i64();
1333    t1 = tcg_temp_new_i64();
1334    t2 = tcg_temp_new_i64();
1335
1336    get_avr64(t0, a->vra, false);
1337    get_avr64(t1, a->vrb, false);
1338    tcg_gen_negsetcond_i64(TCG_COND_GTU, t2, t0, t1);
1339
1340    get_avr64(t0, a->vra, true);
1341    get_avr64(t1, a->vrb, true);
1342    tcg_gen_movcond_i64(TCG_COND_EQ, t2, t0, t1, t2, tcg_constant_i64(0));
1343    tcg_gen_negsetcond_i64(sign ? TCG_COND_GT : TCG_COND_GTU, t1, t0, t1);
1344
1345    tcg_gen_or_i64(t1, t1, t2);
1346
1347    set_avr64(a->vrt, t1, true);
1348    set_avr64(a->vrt, t1, false);
1349
1350    if (a->rc) {
1351        tcg_gen_extrl_i64_i32(cpu_crf[6], t1);
1352        tcg_gen_andi_i32(cpu_crf[6], cpu_crf[6], 0xa);
1353        tcg_gen_xori_i32(cpu_crf[6], cpu_crf[6], 0x2);
1354    }
1355    return true;
1356}
1357
1358TRANS(VCMPGTSQ, do_vcmpgtq, true)
1359TRANS(VCMPGTUQ, do_vcmpgtq, false)
1360
1361static bool do_vcmpq(DisasContext *ctx, arg_VX_bf *a, bool sign)
1362{
1363    TCGv_i64 vra, vrb;
1364    TCGLabel *gt, *lt, *done;
1365
1366    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
1367    REQUIRE_VECTOR(ctx);
1368
1369    vra = tcg_temp_new_i64();
1370    vrb = tcg_temp_new_i64();
1371    gt = gen_new_label();
1372    lt = gen_new_label();
1373    done = gen_new_label();
1374
1375    get_avr64(vra, a->vra, true);
1376    get_avr64(vrb, a->vrb, true);
1377    tcg_gen_brcond_i64((sign ? TCG_COND_GT : TCG_COND_GTU), vra, vrb, gt);
1378    tcg_gen_brcond_i64((sign ? TCG_COND_LT : TCG_COND_LTU), vra, vrb, lt);
1379
1380    get_avr64(vra, a->vra, false);
1381    get_avr64(vrb, a->vrb, false);
1382    tcg_gen_brcond_i64(TCG_COND_GTU, vra, vrb, gt);
1383    tcg_gen_brcond_i64(TCG_COND_LTU, vra, vrb, lt);
1384
1385    tcg_gen_movi_i32(cpu_crf[a->bf], CRF_EQ);
1386    tcg_gen_br(done);
1387
1388    gen_set_label(gt);
1389    tcg_gen_movi_i32(cpu_crf[a->bf], CRF_GT);
1390    tcg_gen_br(done);
1391
1392    gen_set_label(lt);
1393    tcg_gen_movi_i32(cpu_crf[a->bf], CRF_LT);
1394    tcg_gen_br(done);
1395
1396    gen_set_label(done);
1397    return true;
1398}
1399
1400TRANS(VCMPSQ, do_vcmpq, true)
1401TRANS(VCMPUQ, do_vcmpq, false)
1402
1403GEN_VXRFORM(vcmpeqfp, 3, 3)
1404GEN_VXRFORM(vcmpgefp, 3, 7)
1405GEN_VXRFORM(vcmpgtfp, 3, 11)
1406GEN_VXRFORM(vcmpbfp, 3, 15)
1407
1408static void gen_vsplti(DisasContext *ctx, int vece)
1409{
1410    int simm;
1411
1412    if (unlikely(!ctx->altivec_enabled)) {
1413        gen_exception(ctx, POWERPC_EXCP_VPU);
1414        return;
1415    }
1416
1417    simm = SIMM5(ctx->opcode);
1418    tcg_gen_gvec_dup_imm(vece, avr_full_offset(rD(ctx->opcode)), 16, 16, simm);
1419}
1420
1421#define GEN_VXFORM_VSPLTI(name, vece, opc2, opc3) \
1422static void glue(gen_, name)(DisasContext *ctx) { gen_vsplti(ctx, vece); }
1423
1424GEN_VXFORM_VSPLTI(vspltisb, MO_8, 6, 12);
1425GEN_VXFORM_VSPLTI(vspltish, MO_16, 6, 13);
1426GEN_VXFORM_VSPLTI(vspltisw, MO_32, 6, 14);
1427
1428#define GEN_VXFORM_NOA(name, opc2, opc3)                                \
1429static void glue(gen_, name)(DisasContext *ctx)                         \
1430    {                                                                   \
1431        TCGv_ptr rb, rd;                                                \
1432        if (unlikely(!ctx->altivec_enabled)) {                          \
1433            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
1434            return;                                                     \
1435        }                                                               \
1436        rb = gen_avr_ptr(rB(ctx->opcode));                              \
1437        rd = gen_avr_ptr(rD(ctx->opcode));                              \
1438        gen_helper_##name(rd, rb);                                      \
1439    }
1440
1441#define GEN_VXFORM_NOA_ENV(name, opc2, opc3)                            \
1442static void glue(gen_, name)(DisasContext *ctx)                         \
1443    {                                                                   \
1444        TCGv_ptr rb, rd;                                                \
1445                                                                        \
1446        if (unlikely(!ctx->altivec_enabled)) {                          \
1447            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
1448            return;                                                     \
1449        }                                                               \
1450        rb = gen_avr_ptr(rB(ctx->opcode));                              \
1451        rd = gen_avr_ptr(rD(ctx->opcode));                              \
1452        gen_helper_##name(tcg_env, rd, rb);                             \
1453    }
1454
1455#define GEN_VXFORM_NOA_2(name, opc2, opc3, opc4)                        \
1456static void glue(gen_, name)(DisasContext *ctx)                         \
1457    {                                                                   \
1458        TCGv_ptr rb, rd;                                                \
1459        if (unlikely(!ctx->altivec_enabled)) {                          \
1460            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
1461            return;                                                     \
1462        }                                                               \
1463        rb = gen_avr_ptr(rB(ctx->opcode));                              \
1464        rd = gen_avr_ptr(rD(ctx->opcode));                              \
1465        gen_helper_##name(rd, rb);                                      \
1466    }
1467
1468#define GEN_VXFORM_NOA_3(name, opc2, opc3, opc4)                        \
1469static void glue(gen_, name)(DisasContext *ctx)                         \
1470    {                                                                   \
1471        TCGv_ptr rb;                                                    \
1472        if (unlikely(!ctx->altivec_enabled)) {                          \
1473            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
1474            return;                                                     \
1475        }                                                               \
1476        rb = gen_avr_ptr(rB(ctx->opcode));                              \
1477        gen_helper_##name(cpu_gpr[rD(ctx->opcode)], rb);                \
1478    }
1479GEN_VXFORM_NOA(vupkhsb, 7, 8);
1480GEN_VXFORM_NOA(vupkhsh, 7, 9);
1481GEN_VXFORM_NOA(vupkhsw, 7, 25);
1482GEN_VXFORM_NOA(vupklsb, 7, 10);
1483GEN_VXFORM_NOA(vupklsh, 7, 11);
1484GEN_VXFORM_NOA(vupklsw, 7, 27);
1485GEN_VXFORM_NOA(vupkhpx, 7, 13);
1486GEN_VXFORM_NOA(vupklpx, 7, 15);
1487GEN_VXFORM_NOA_ENV(vrefp, 5, 4);
1488GEN_VXFORM_NOA_ENV(vrsqrtefp, 5, 5);
1489GEN_VXFORM_NOA_ENV(vexptefp, 5, 6);
1490GEN_VXFORM_NOA_ENV(vlogefp, 5, 7);
1491GEN_VXFORM_NOA_ENV(vrfim, 5, 11);
1492GEN_VXFORM_NOA_ENV(vrfin, 5, 8);
1493GEN_VXFORM_NOA_ENV(vrfip, 5, 10);
1494GEN_VXFORM_NOA_ENV(vrfiz, 5, 9);
1495
1496static void gen_vprtyb_vec(unsigned vece, TCGv_vec t, TCGv_vec b)
1497{
1498    int i;
1499    TCGv_vec tmp = tcg_temp_new_vec_matching(b);
1500    /* MO_32 is 2, so 2 iterations for MO_32 and 3 for MO_64 */
1501    for (i = 0; i < vece; i++) {
1502        tcg_gen_shri_vec(vece, tmp, b, (4 << (vece - i)));
1503        tcg_gen_xor_vec(vece, b, tmp, b);
1504    }
1505    tcg_gen_and_vec(vece, t, b, tcg_constant_vec_matching(t, vece, 1));
1506}
1507
1508/* vprtybw */
1509static void gen_vprtyb_i32(TCGv_i32 t, TCGv_i32 b)
1510{
1511    tcg_gen_ctpop_i32(t, b);
1512    tcg_gen_and_i32(t, t, tcg_constant_i32(1));
1513}
1514
1515/* vprtybd */
1516static void gen_vprtyb_i64(TCGv_i64 t, TCGv_i64 b)
1517{
1518    tcg_gen_ctpop_i64(t, b);
1519    tcg_gen_and_i64(t, t, tcg_constant_i64(1));
1520}
1521
1522static bool do_vx_vprtyb(DisasContext *ctx, arg_VX_tb *a, unsigned vece)
1523{
1524    static const TCGOpcode vecop_list[] = {
1525        INDEX_op_shri_vec, 0
1526    };
1527
1528    static const GVecGen2 op[] = {
1529        {
1530            .fniv = gen_vprtyb_vec,
1531            .fni4 = gen_vprtyb_i32,
1532            .opt_opc = vecop_list,
1533            .vece = MO_32
1534        },
1535        {
1536            .fniv = gen_vprtyb_vec,
1537            .fni8 = gen_vprtyb_i64,
1538            .opt_opc = vecop_list,
1539            .vece = MO_64
1540        },
1541        {
1542            .fno = gen_helper_VPRTYBQ,
1543            .vece = MO_128
1544        },
1545    };
1546
1547    REQUIRE_INSNS_FLAGS2(ctx, ISA300);
1548    REQUIRE_VECTOR(ctx);
1549
1550    tcg_gen_gvec_2(avr_full_offset(a->vrt), avr_full_offset(a->vrb),
1551                   16, 16, &op[vece - MO_32]);
1552
1553    return true;
1554}
1555
1556TRANS(VPRTYBW, do_vx_vprtyb, MO_32)
1557TRANS(VPRTYBD, do_vx_vprtyb, MO_64)
1558TRANS(VPRTYBQ, do_vx_vprtyb, MO_128)
1559
1560static void gen_vsplt(DisasContext *ctx, int vece)
1561{
1562    int uimm, dofs, bofs;
1563
1564    if (unlikely(!ctx->altivec_enabled)) {
1565        gen_exception(ctx, POWERPC_EXCP_VPU);
1566        return;
1567    }
1568
1569    uimm = UIMM5(ctx->opcode);
1570    bofs = avr_full_offset(rB(ctx->opcode));
1571    dofs = avr_full_offset(rD(ctx->opcode));
1572
1573    /* Experimental testing shows that hardware masks the immediate.  */
1574    bofs += (uimm << vece) & 15;
1575#if !HOST_BIG_ENDIAN
1576    bofs ^= 15;
1577    bofs &= ~((1 << vece) - 1);
1578#endif
1579
1580    tcg_gen_gvec_dup_mem(vece, dofs, bofs, 16, 16);
1581}
1582
1583#define GEN_VXFORM_VSPLT(name, vece, opc2, opc3) \
1584static void glue(gen_, name)(DisasContext *ctx) { gen_vsplt(ctx, vece); }
1585
1586#define GEN_VXFORM_UIMM_ENV(name, opc2, opc3)                           \
1587static void glue(gen_, name)(DisasContext *ctx)                         \
1588    {                                                                   \
1589        TCGv_ptr rb, rd;                                                \
1590        TCGv_i32 uimm;                                                  \
1591                                                                        \
1592        if (unlikely(!ctx->altivec_enabled)) {                          \
1593            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
1594            return;                                                     \
1595        }                                                               \
1596        uimm = tcg_constant_i32(UIMM5(ctx->opcode));                    \
1597        rb = gen_avr_ptr(rB(ctx->opcode));                              \
1598        rd = gen_avr_ptr(rD(ctx->opcode));                              \
1599        gen_helper_##name(tcg_env, rd, rb, uimm);                       \
1600    }
1601
1602#define GEN_VXFORM_UIMM_SPLAT(name, opc2, opc3, splat_max)              \
1603static void glue(gen_, name)(DisasContext *ctx)                         \
1604    {                                                                   \
1605        TCGv_ptr rb, rd;                                                \
1606        uint8_t uimm = UIMM4(ctx->opcode);                              \
1607        TCGv_i32 t0;                                                    \
1608        if (unlikely(!ctx->altivec_enabled)) {                          \
1609            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
1610            return;                                                     \
1611        }                                                               \
1612        if (uimm > splat_max) {                                         \
1613            uimm = 0;                                                   \
1614        }                                                               \
1615        t0 = tcg_temp_new_i32();                                        \
1616        tcg_gen_movi_i32(t0, uimm);                                     \
1617        rb = gen_avr_ptr(rB(ctx->opcode));                              \
1618        rd = gen_avr_ptr(rD(ctx->opcode));                              \
1619        gen_helper_##name(rd, rb, t0);                                  \
1620    }
1621
1622GEN_VXFORM_VSPLT(vspltb, MO_8, 6, 8);
1623GEN_VXFORM_VSPLT(vsplth, MO_16, 6, 9);
1624GEN_VXFORM_VSPLT(vspltw, MO_32, 6, 10);
1625GEN_VXFORM_UIMM_SPLAT(vextractub, 6, 8, 15);
1626GEN_VXFORM_UIMM_SPLAT(vextractuh, 6, 9, 14);
1627GEN_VXFORM_UIMM_SPLAT(vextractuw, 6, 10, 12);
1628GEN_VXFORM_UIMM_SPLAT(vextractd, 6, 11, 8);
1629GEN_VXFORM_UIMM_ENV(vcfux, 5, 12);
1630GEN_VXFORM_UIMM_ENV(vcfsx, 5, 13);
1631GEN_VXFORM_UIMM_ENV(vctuxs, 5, 14);
1632GEN_VXFORM_UIMM_ENV(vctsxs, 5, 15);
1633GEN_VXFORM_DUAL(vspltb, PPC_ALTIVEC, PPC_NONE,
1634                vextractub, PPC_NONE, PPC2_ISA300);
1635GEN_VXFORM_DUAL(vsplth, PPC_ALTIVEC, PPC_NONE,
1636                vextractuh, PPC_NONE, PPC2_ISA300);
1637GEN_VXFORM_DUAL(vspltw, PPC_ALTIVEC, PPC_NONE,
1638                vextractuw, PPC_NONE, PPC2_ISA300);
1639
1640static bool trans_VGNB(DisasContext *ctx, arg_VX_n *a)
1641{
1642    /*
1643     * Similar to do_vextractm, we'll use a sequence of mask-shift-or operations
1644     * to gather the bits. The masks can be created with
1645     *
1646     * uint64_t mask(uint64_t n, uint64_t step)
1647     * {
1648     *     uint64_t p = ((1UL << (1UL << step)) - 1UL) << ((n - 1UL) << step),
1649     *                  plen = n << step, m = 0;
1650     *     for(int i = 0; i < 64/plen; i++) {
1651     *         m |= p;
1652     *         m = ror64(m, plen);
1653     *     }
1654     *     p >>= plen * DIV_ROUND_UP(64, plen) - 64;
1655     *     return m | p;
1656     * }
1657     *
1658     * But since there are few values of N, we'll use a lookup table to avoid
1659     * these calculations at runtime.
1660     */
1661    static const uint64_t mask[6][5] = {
1662        {
1663            0xAAAAAAAAAAAAAAAAULL, 0xccccccccccccccccULL, 0xf0f0f0f0f0f0f0f0ULL,
1664            0xff00ff00ff00ff00ULL, 0xffff0000ffff0000ULL
1665        },
1666        {
1667            0x9249249249249249ULL, 0xC30C30C30C30C30CULL, 0xF00F00F00F00F00FULL,
1668            0xFF0000FF0000FF00ULL, 0xFFFF00000000FFFFULL
1669        },
1670        {
1671            /* For N >= 4, some mask operations can be elided */
1672            0x8888888888888888ULL, 0, 0xf000f000f000f000ULL, 0,
1673            0xFFFF000000000000ULL
1674        },
1675        {
1676            0x8421084210842108ULL, 0, 0xF0000F0000F0000FULL, 0, 0
1677        },
1678        {
1679            0x8208208208208208ULL, 0, 0xF00000F00000F000ULL, 0, 0
1680        },
1681        {
1682            0x8102040810204081ULL, 0, 0xF000000F000000F0ULL, 0, 0
1683        }
1684    };
1685    uint64_t m;
1686    int i, sh, nbits = DIV_ROUND_UP(64, a->n);
1687    TCGv_i64 hi, lo, t0, t1;
1688
1689    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
1690    REQUIRE_VECTOR(ctx);
1691
1692    if (a->n < 2) {
1693        /*
1694         * "N can be any value between 2 and 7, inclusive." Otherwise, the
1695         * result is undefined, so we don't need to change RT. Also, N > 7 is
1696         * impossible since the immediate field is 3 bits only.
1697         */
1698        return true;
1699    }
1700
1701    hi = tcg_temp_new_i64();
1702    lo = tcg_temp_new_i64();
1703    t0 = tcg_temp_new_i64();
1704    t1 = tcg_temp_new_i64();
1705
1706    get_avr64(hi, a->vrb, true);
1707    get_avr64(lo, a->vrb, false);
1708
1709    /* Align the lower doubleword so we can use the same mask */
1710    tcg_gen_shli_i64(lo, lo, a->n * nbits - 64);
1711
1712    /*
1713     * Starting from the most significant bit, gather every Nth bit with a
1714     * sequence of mask-shift-or operation. E.g.: for N=3
1715     * AxxBxxCxxDxxExxFxxGxxHxxIxxJxxKxxLxxMxxNxxOxxPxxQxxRxxSxxTxxUxxV
1716     *     & rep(0b100)
1717     * A..B..C..D..E..F..G..H..I..J..K..L..M..N..O..P..Q..R..S..T..U..V
1718     *     << 2
1719     * .B..C..D..E..F..G..H..I..J..K..L..M..N..O..P..Q..R..S..T..U..V..
1720     *     |
1721     * AB.BC.CD.DE.EF.FG.GH.HI.IJ.JK.KL.LM.MN.NO.OP.PQ.QR.RS.ST.TU.UV.V
1722     *  & rep(0b110000)
1723     * AB....CD....EF....GH....IJ....KL....MN....OP....QR....ST....UV..
1724     *     << 4
1725     * ..CD....EF....GH....IJ....KL....MN....OP....QR....ST....UV......
1726     *     |
1727     * ABCD..CDEF..EFGH..GHIJ..IJKL..KLMN..MNOP..OPQR..QRST..STUV..UV..
1728     *     & rep(0b111100000000)
1729     * ABCD........EFGH........IJKL........MNOP........QRST........UV..
1730     *     << 8
1731     * ....EFGH........IJKL........MNOP........QRST........UV..........
1732     *     |
1733     * ABCDEFGH....EFGHIJKL....IJKLMNOP....MNOPQRST....QRSTUV......UV..
1734     *  & rep(0b111111110000000000000000)
1735     * ABCDEFGH................IJKLMNOP................QRSTUV..........
1736     *     << 16
1737     * ........IJKLMNOP................QRSTUV..........................
1738     *     |
1739     * ABCDEFGHIJKLMNOP........IJKLMNOPQRSTUV..........QRSTUV..........
1740     *     & rep(0b111111111111111100000000000000000000000000000000)
1741     * ABCDEFGHIJKLMNOP................................QRSTUV..........
1742     *     << 32
1743     * ................QRSTUV..........................................
1744     *     |
1745     * ABCDEFGHIJKLMNOPQRSTUV..........................QRSTUV..........
1746     */
1747    for (i = 0, sh = a->n - 1; i < 5; i++, sh <<= 1) {
1748        m = mask[a->n - 2][i];
1749        if (m) {
1750            tcg_gen_andi_i64(hi, hi, m);
1751            tcg_gen_andi_i64(lo, lo, m);
1752        }
1753        if (sh < 64) {
1754            tcg_gen_shli_i64(t0, hi, sh);
1755            tcg_gen_shli_i64(t1, lo, sh);
1756            tcg_gen_or_i64(hi, t0, hi);
1757            tcg_gen_or_i64(lo, t1, lo);
1758        }
1759    }
1760
1761    tcg_gen_andi_i64(hi, hi, ~(~0ULL >> nbits));
1762    tcg_gen_andi_i64(lo, lo, ~(~0ULL >> nbits));
1763    tcg_gen_shri_i64(lo, lo, nbits);
1764    tcg_gen_or_i64(hi, hi, lo);
1765    tcg_gen_trunc_i64_tl(cpu_gpr[a->rt], hi);
1766    return true;
1767}
1768
1769static bool do_vextdx(DisasContext *ctx, arg_VA *a, int size, bool right,
1770               void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv))
1771{
1772    TCGv_ptr vrt, vra, vrb;
1773    TCGv rc;
1774
1775    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
1776    REQUIRE_VECTOR(ctx);
1777
1778    vrt = gen_avr_ptr(a->vrt);
1779    vra = gen_avr_ptr(a->vra);
1780    vrb = gen_avr_ptr(a->vrb);
1781    rc = tcg_temp_new();
1782
1783    tcg_gen_andi_tl(rc, cpu_gpr[a->rc], 0x1F);
1784    if (right) {
1785        tcg_gen_subfi_tl(rc, 32 - size, rc);
1786    }
1787    gen_helper(tcg_env, vrt, vra, vrb, rc);
1788    return true;
1789}
1790
1791TRANS(VEXTDUBVLX, do_vextdx, 1, false, gen_helper_VEXTDUBVLX)
1792TRANS(VEXTDUHVLX, do_vextdx, 2, false, gen_helper_VEXTDUHVLX)
1793TRANS(VEXTDUWVLX, do_vextdx, 4, false, gen_helper_VEXTDUWVLX)
1794TRANS(VEXTDDVLX, do_vextdx, 8, false, gen_helper_VEXTDDVLX)
1795
1796TRANS(VEXTDUBVRX, do_vextdx, 1, true, gen_helper_VEXTDUBVLX)
1797TRANS(VEXTDUHVRX, do_vextdx, 2, true, gen_helper_VEXTDUHVLX)
1798TRANS(VEXTDUWVRX, do_vextdx, 4, true, gen_helper_VEXTDUWVLX)
1799TRANS(VEXTDDVRX, do_vextdx, 8, true, gen_helper_VEXTDDVLX)
1800
1801static bool do_vinsx(DisasContext *ctx, int vrt, int size, bool right, TCGv ra,
1802            TCGv_i64 rb, void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv))
1803{
1804    TCGv_ptr t;
1805    TCGv idx;
1806
1807    t = gen_avr_ptr(vrt);
1808    idx = tcg_temp_new();
1809
1810    tcg_gen_andi_tl(idx, ra, 0xF);
1811    if (right) {
1812        tcg_gen_subfi_tl(idx, 16 - size, idx);
1813    }
1814
1815    gen_helper(tcg_env, t, rb, idx);
1816    return true;
1817}
1818
1819static bool do_vinsvx(DisasContext *ctx, int vrt, int size, bool right, TCGv ra,
1820                int vrb, void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv))
1821{
1822    TCGv_i64 val;
1823
1824    val = tcg_temp_new_i64();
1825    get_avr64(val, vrb, true);
1826    return do_vinsx(ctx, vrt, size, right, ra, val, gen_helper);
1827}
1828
1829static bool do_vinsx_VX(DisasContext *ctx, arg_VX *a, int size, bool right,
1830                        void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv))
1831{
1832    TCGv_i64 val;
1833
1834    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
1835    REQUIRE_VECTOR(ctx);
1836
1837    val = tcg_temp_new_i64();
1838    tcg_gen_extu_tl_i64(val, cpu_gpr[a->vrb]);
1839
1840    return do_vinsx(ctx, a->vrt, size, right, cpu_gpr[a->vra], val, gen_helper);
1841}
1842
1843static bool do_vinsvx_VX(DisasContext *ctx, arg_VX *a, int size, bool right,
1844                        void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv))
1845{
1846    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
1847    REQUIRE_VECTOR(ctx);
1848
1849    return do_vinsvx(ctx, a->vrt, size, right, cpu_gpr[a->vra], a->vrb,
1850                     gen_helper);
1851}
1852
1853static bool do_vins_VX_uim4(DisasContext *ctx, arg_VX_uim4 *a, int size,
1854                        void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv))
1855{
1856    TCGv_i64 val;
1857
1858    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
1859    REQUIRE_VECTOR(ctx);
1860
1861    if (a->uim > (16 - size)) {
1862        /*
1863         * PowerISA v3.1 says that the resulting value is undefined in this
1864         * case, so just log a guest error and leave VRT unchanged. The
1865         * real hardware would do a partial insert, e.g. if VRT is zeroed and
1866         * RB is 0x12345678, executing "vinsw VRT,RB,14" results in
1867         * VRT = 0x0000...00001234, but we don't bother to reproduce this
1868         * behavior as software shouldn't rely on it.
1869         */
1870        qemu_log_mask(LOG_GUEST_ERROR, "Invalid index for VINS* at"
1871            " 0x" TARGET_FMT_lx ", UIM = %d > %d\n", ctx->cia, a->uim,
1872            16 - size);
1873        return true;
1874    }
1875
1876    val = tcg_temp_new_i64();
1877    tcg_gen_extu_tl_i64(val, cpu_gpr[a->vrb]);
1878
1879    return do_vinsx(ctx, a->vrt, size, false, tcg_constant_tl(a->uim), val,
1880                    gen_helper);
1881}
1882
1883static bool do_vinsert_VX_uim4(DisasContext *ctx, arg_VX_uim4 *a, int size,
1884                        void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv))
1885{
1886    REQUIRE_INSNS_FLAGS2(ctx, ISA300);
1887    REQUIRE_VECTOR(ctx);
1888
1889    if (a->uim > (16 - size)) {
1890        qemu_log_mask(LOG_GUEST_ERROR, "Invalid index for VINSERT* at"
1891            " 0x" TARGET_FMT_lx ", UIM = %d > %d\n", ctx->cia, a->uim,
1892            16 - size);
1893        return true;
1894    }
1895
1896    return do_vinsvx(ctx, a->vrt, size, false, tcg_constant_tl(a->uim), a->vrb,
1897                     gen_helper);
1898}
1899
1900TRANS(VINSBLX, do_vinsx_VX, 1, false, gen_helper_VINSBLX)
1901TRANS(VINSHLX, do_vinsx_VX, 2, false, gen_helper_VINSHLX)
1902TRANS(VINSWLX, do_vinsx_VX, 4, false, gen_helper_VINSWLX)
1903TRANS(VINSDLX, do_vinsx_VX, 8, false, gen_helper_VINSDLX)
1904
1905TRANS(VINSBRX, do_vinsx_VX, 1, true, gen_helper_VINSBLX)
1906TRANS(VINSHRX, do_vinsx_VX, 2, true, gen_helper_VINSHLX)
1907TRANS(VINSWRX, do_vinsx_VX, 4, true, gen_helper_VINSWLX)
1908TRANS(VINSDRX, do_vinsx_VX, 8, true, gen_helper_VINSDLX)
1909
1910TRANS(VINSW, do_vins_VX_uim4, 4, gen_helper_VINSWLX)
1911TRANS(VINSD, do_vins_VX_uim4, 8, gen_helper_VINSDLX)
1912
1913TRANS(VINSBVLX, do_vinsvx_VX, 1, false, gen_helper_VINSBLX)
1914TRANS(VINSHVLX, do_vinsvx_VX, 2, false, gen_helper_VINSHLX)
1915TRANS(VINSWVLX, do_vinsvx_VX, 4, false, gen_helper_VINSWLX)
1916
1917TRANS(VINSBVRX, do_vinsvx_VX, 1, true, gen_helper_VINSBLX)
1918TRANS(VINSHVRX, do_vinsvx_VX, 2, true, gen_helper_VINSHLX)
1919TRANS(VINSWVRX, do_vinsvx_VX, 4, true, gen_helper_VINSWLX)
1920
1921TRANS(VINSERTB, do_vinsert_VX_uim4, 1, gen_helper_VINSBLX)
1922TRANS(VINSERTH, do_vinsert_VX_uim4, 2, gen_helper_VINSHLX)
1923TRANS(VINSERTW, do_vinsert_VX_uim4, 4, gen_helper_VINSWLX)
1924TRANS(VINSERTD, do_vinsert_VX_uim4, 8, gen_helper_VINSDLX)
1925
1926static void gen_vsldoi(DisasContext *ctx)
1927{
1928    TCGv_ptr ra, rb, rd;
1929    TCGv_i32 sh;
1930    if (unlikely(!ctx->altivec_enabled)) {
1931        gen_exception(ctx, POWERPC_EXCP_VPU);
1932        return;
1933    }
1934    ra = gen_avr_ptr(rA(ctx->opcode));
1935    rb = gen_avr_ptr(rB(ctx->opcode));
1936    rd = gen_avr_ptr(rD(ctx->opcode));
1937    sh = tcg_constant_i32(VSH(ctx->opcode));
1938    gen_helper_vsldoi(rd, ra, rb, sh);
1939}
1940
1941static bool trans_VSLDBI(DisasContext *ctx, arg_VN *a)
1942{
1943    TCGv_i64 t0, t1, t2;
1944
1945    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
1946    REQUIRE_VECTOR(ctx);
1947
1948    t0 = tcg_temp_new_i64();
1949    t1 = tcg_temp_new_i64();
1950
1951    get_avr64(t0, a->vra, true);
1952    get_avr64(t1, a->vra, false);
1953
1954    if (a->sh != 0) {
1955        t2 = tcg_temp_new_i64();
1956
1957        get_avr64(t2, a->vrb, true);
1958
1959        tcg_gen_extract2_i64(t0, t1, t0, 64 - a->sh);
1960        tcg_gen_extract2_i64(t1, t2, t1, 64 - a->sh);
1961    }
1962
1963    set_avr64(a->vrt, t0, true);
1964    set_avr64(a->vrt, t1, false);
1965    return true;
1966}
1967
1968static bool trans_VSRDBI(DisasContext *ctx, arg_VN *a)
1969{
1970    TCGv_i64 t2, t1, t0;
1971
1972    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
1973    REQUIRE_VECTOR(ctx);
1974
1975    t0 = tcg_temp_new_i64();
1976    t1 = tcg_temp_new_i64();
1977
1978    get_avr64(t0, a->vrb, false);
1979    get_avr64(t1, a->vrb, true);
1980
1981    if (a->sh != 0) {
1982        t2 = tcg_temp_new_i64();
1983
1984        get_avr64(t2, a->vra, false);
1985
1986        tcg_gen_extract2_i64(t0, t0, t1, a->sh);
1987        tcg_gen_extract2_i64(t1, t1, t2, a->sh);
1988    }
1989
1990    set_avr64(a->vrt, t0, false);
1991    set_avr64(a->vrt, t1, true);
1992    return true;
1993}
1994
1995static bool do_vexpand(DisasContext *ctx, arg_VX_tb *a, unsigned vece)
1996{
1997    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
1998    REQUIRE_VECTOR(ctx);
1999
2000    tcg_gen_gvec_sari(vece, avr_full_offset(a->vrt), avr_full_offset(a->vrb),
2001                      (8 << vece) - 1, 16, 16);
2002
2003    return true;
2004}
2005
2006TRANS(VEXPANDBM, do_vexpand, MO_8)
2007TRANS(VEXPANDHM, do_vexpand, MO_16)
2008TRANS(VEXPANDWM, do_vexpand, MO_32)
2009TRANS(VEXPANDDM, do_vexpand, MO_64)
2010
2011static bool trans_VEXPANDQM(DisasContext *ctx, arg_VX_tb *a)
2012{
2013    TCGv_i64 tmp;
2014
2015    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
2016    REQUIRE_VECTOR(ctx);
2017
2018    tmp = tcg_temp_new_i64();
2019
2020    get_avr64(tmp, a->vrb, true);
2021    tcg_gen_sari_i64(tmp, tmp, 63);
2022    set_avr64(a->vrt, tmp, false);
2023    set_avr64(a->vrt, tmp, true);
2024    return true;
2025}
2026
2027static bool do_vextractm(DisasContext *ctx, arg_VX_tb *a, unsigned vece)
2028{
2029    const uint64_t elem_width = 8 << vece, elem_count_half = 8 >> vece,
2030                   mask = dup_const(vece, 1ULL << (elem_width - 1));
2031    uint64_t i, j;
2032    TCGv_i64 lo, hi, t0, t1;
2033
2034    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
2035    REQUIRE_VECTOR(ctx);
2036
2037    hi = tcg_temp_new_i64();
2038    lo = tcg_temp_new_i64();
2039    t0 = tcg_temp_new_i64();
2040    t1 = tcg_temp_new_i64();
2041
2042    get_avr64(lo, a->vrb, false);
2043    get_avr64(hi, a->vrb, true);
2044
2045    tcg_gen_andi_i64(lo, lo, mask);
2046    tcg_gen_andi_i64(hi, hi, mask);
2047
2048    /*
2049     * Gather the most significant bit of each element in the highest element
2050     * element. E.g. for bytes:
2051     * aXXXXXXXbXXXXXXXcXXXXXXXdXXXXXXXeXXXXXXXfXXXXXXXgXXXXXXXhXXXXXXX
2052     *     & dup(1 << (elem_width - 1))
2053     * a0000000b0000000c0000000d0000000e0000000f0000000g0000000h0000000
2054     *     << 32 - 4
2055     * 0000e0000000f0000000g0000000h00000000000000000000000000000000000
2056     *     |
2057     * a000e000b000f000c000g000d000h000e0000000f0000000g0000000h0000000
2058     *     << 16 - 2
2059     * 00c000g000d000h000e0000000f0000000g0000000h000000000000000000000
2060     *     |
2061     * a0c0e0g0b0d0f0h0c0e0g000d0f0h000e0g00000f0h00000g0000000h0000000
2062     *     << 8 - 1
2063     * 0b0d0f0h0c0e0g000d0f0h000e0g00000f0h00000g0000000h00000000000000
2064     *     |
2065     * abcdefghbcdefgh0cdefgh00defgh000efgh0000fgh00000gh000000h0000000
2066     */
2067    for (i = elem_count_half / 2, j = 32; i > 0; i >>= 1, j >>= 1) {
2068        tcg_gen_shli_i64(t0, hi, j - i);
2069        tcg_gen_shli_i64(t1, lo, j - i);
2070        tcg_gen_or_i64(hi, hi, t0);
2071        tcg_gen_or_i64(lo, lo, t1);
2072    }
2073
2074    tcg_gen_shri_i64(hi, hi, 64 - elem_count_half);
2075    tcg_gen_extract2_i64(lo, lo, hi, 64 - elem_count_half);
2076    tcg_gen_trunc_i64_tl(cpu_gpr[a->vrt], lo);
2077    return true;
2078}
2079
2080TRANS(VEXTRACTBM, do_vextractm, MO_8)
2081TRANS(VEXTRACTHM, do_vextractm, MO_16)
2082TRANS(VEXTRACTWM, do_vextractm, MO_32)
2083TRANS(VEXTRACTDM, do_vextractm, MO_64)
2084
2085static bool trans_VEXTRACTQM(DisasContext *ctx, arg_VX_tb *a)
2086{
2087    TCGv_i64 tmp;
2088
2089    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
2090    REQUIRE_VECTOR(ctx);
2091
2092    tmp = tcg_temp_new_i64();
2093
2094    get_avr64(tmp, a->vrb, true);
2095    tcg_gen_shri_i64(tmp, tmp, 63);
2096    tcg_gen_trunc_i64_tl(cpu_gpr[a->vrt], tmp);
2097    return true;
2098}
2099
2100static bool do_mtvsrm(DisasContext *ctx, arg_VX_tb *a, unsigned vece)
2101{
2102    const uint64_t elem_width = 8 << vece, elem_count_half = 8 >> vece;
2103    uint64_t c;
2104    int i, j;
2105    TCGv_i64 hi, lo, t0, t1;
2106
2107    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
2108    REQUIRE_VECTOR(ctx);
2109
2110    hi = tcg_temp_new_i64();
2111    lo = tcg_temp_new_i64();
2112    t0 = tcg_temp_new_i64();
2113    t1 = tcg_temp_new_i64();
2114
2115    tcg_gen_extu_tl_i64(t0, cpu_gpr[a->vrb]);
2116    tcg_gen_extract_i64(hi, t0, elem_count_half, elem_count_half);
2117    tcg_gen_extract_i64(lo, t0, 0, elem_count_half);
2118
2119    /*
2120     * Spread the bits into their respective elements.
2121     * E.g. for bytes:
2122     * 00000000000000000000000000000000000000000000000000000000abcdefgh
2123     *   << 32 - 4
2124     * 0000000000000000000000000000abcdefgh0000000000000000000000000000
2125     *   |
2126     * 0000000000000000000000000000abcdefgh00000000000000000000abcdefgh
2127     *   << 16 - 2
2128     * 00000000000000abcdefgh00000000000000000000abcdefgh00000000000000
2129     *   |
2130     * 00000000000000abcdefgh000000abcdefgh000000abcdefgh000000abcdefgh
2131     *   << 8 - 1
2132     * 0000000abcdefgh000000abcdefgh000000abcdefgh000000abcdefgh0000000
2133     *   |
2134     * 0000000abcdefgXbcdefgXbcdefgXbcdefgXbcdefgXbcdefgXbcdefgXbcdefgh
2135     *   & dup(1)
2136     * 0000000a0000000b0000000c0000000d0000000e0000000f0000000g0000000h
2137     *   * 0xff
2138     * aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffgggggggghhhhhhhh
2139     */
2140    for (i = elem_count_half / 2, j = 32; i > 0; i >>= 1, j >>= 1) {
2141        tcg_gen_shli_i64(t0, hi, j - i);
2142        tcg_gen_shli_i64(t1, lo, j - i);
2143        tcg_gen_or_i64(hi, hi, t0);
2144        tcg_gen_or_i64(lo, lo, t1);
2145    }
2146
2147    c = dup_const(vece, 1);
2148    tcg_gen_andi_i64(hi, hi, c);
2149    tcg_gen_andi_i64(lo, lo, c);
2150
2151    c = MAKE_64BIT_MASK(0, elem_width);
2152    tcg_gen_muli_i64(hi, hi, c);
2153    tcg_gen_muli_i64(lo, lo, c);
2154
2155    set_avr64(a->vrt, lo, false);
2156    set_avr64(a->vrt, hi, true);
2157    return true;
2158}
2159
2160TRANS(MTVSRBM, do_mtvsrm, MO_8)
2161TRANS(MTVSRHM, do_mtvsrm, MO_16)
2162TRANS(MTVSRWM, do_mtvsrm, MO_32)
2163TRANS(MTVSRDM, do_mtvsrm, MO_64)
2164
2165static bool trans_MTVSRQM(DisasContext *ctx, arg_VX_tb *a)
2166{
2167    TCGv_i64 tmp;
2168
2169    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
2170    REQUIRE_VECTOR(ctx);
2171
2172    tmp = tcg_temp_new_i64();
2173
2174    tcg_gen_ext_tl_i64(tmp, cpu_gpr[a->vrb]);
2175    tcg_gen_sextract_i64(tmp, tmp, 0, 1);
2176    set_avr64(a->vrt, tmp, false);
2177    set_avr64(a->vrt, tmp, true);
2178    return true;
2179}
2180
2181static bool trans_MTVSRBMI(DisasContext *ctx, arg_DX_b *a)
2182{
2183    const uint64_t mask = dup_const(MO_8, 1);
2184    uint64_t hi, lo;
2185
2186    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
2187    REQUIRE_VECTOR(ctx);
2188
2189    hi = extract16(a->b, 8, 8);
2190    lo = extract16(a->b, 0, 8);
2191
2192    for (int i = 4, j = 32; i > 0; i >>= 1, j >>= 1) {
2193        hi |= hi << (j - i);
2194        lo |= lo << (j - i);
2195    }
2196
2197    hi = (hi & mask) * 0xFF;
2198    lo = (lo & mask) * 0xFF;
2199
2200    set_avr64(a->vrt, tcg_constant_i64(hi), true);
2201    set_avr64(a->vrt, tcg_constant_i64(lo), false);
2202
2203    return true;
2204}
2205
2206static bool do_vcntmb(DisasContext *ctx, arg_VX_mp *a, int vece)
2207{
2208    TCGv_i64 r[2], mask;
2209
2210    r[0] = tcg_temp_new_i64();
2211    r[1] = tcg_temp_new_i64();
2212    mask = tcg_constant_i64(dup_const(vece, 1ULL << ((8 << vece) - 1)));
2213
2214    for (int i = 0; i < 2; i++) {
2215        get_avr64(r[i], a->vrb, i);
2216        if (a->mp) {
2217            tcg_gen_and_i64(r[i], mask, r[i]);
2218        } else {
2219            tcg_gen_andc_i64(r[i], mask, r[i]);
2220        }
2221        tcg_gen_ctpop_i64(r[i], r[i]);
2222    }
2223
2224    tcg_gen_add_i64(r[0], r[0], r[1]);
2225    tcg_gen_shli_i64(r[0], r[0], TARGET_LONG_BITS - 8 + vece);
2226    tcg_gen_trunc_i64_tl(cpu_gpr[a->rt], r[0]);
2227    return true;
2228}
2229
2230TRANS(VCNTMBB, do_vcntmb, MO_8)
2231TRANS(VCNTMBH, do_vcntmb, MO_16)
2232TRANS(VCNTMBW, do_vcntmb, MO_32)
2233TRANS(VCNTMBD, do_vcntmb, MO_64)
2234
2235static bool do_vstri(DisasContext *ctx, arg_VX_tb_rc *a,
2236                     void (*gen_helper)(TCGv_i32, TCGv_ptr, TCGv_ptr))
2237{
2238    TCGv_ptr vrt, vrb;
2239
2240    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
2241    REQUIRE_VECTOR(ctx);
2242
2243    vrt = gen_avr_ptr(a->vrt);
2244    vrb = gen_avr_ptr(a->vrb);
2245
2246    if (a->rc) {
2247        gen_helper(cpu_crf[6], vrt, vrb);
2248    } else {
2249        TCGv_i32 discard = tcg_temp_new_i32();
2250        gen_helper(discard, vrt, vrb);
2251    }
2252    return true;
2253}
2254
2255TRANS(VSTRIBL, do_vstri, gen_helper_VSTRIBL)
2256TRANS(VSTRIBR, do_vstri, gen_helper_VSTRIBR)
2257TRANS(VSTRIHL, do_vstri, gen_helper_VSTRIHL)
2258TRANS(VSTRIHR, do_vstri, gen_helper_VSTRIHR)
2259
2260static bool do_vclrb(DisasContext *ctx, arg_VX *a, bool right)
2261{
2262    TCGv_i64 rb, mh, ml, tmp,
2263             ones = tcg_constant_i64(-1),
2264             zero = tcg_constant_i64(0);
2265
2266    rb = tcg_temp_new_i64();
2267    mh = tcg_temp_new_i64();
2268    ml = tcg_temp_new_i64();
2269    tmp = tcg_temp_new_i64();
2270
2271    tcg_gen_extu_tl_i64(rb, cpu_gpr[a->vrb]);
2272    tcg_gen_andi_i64(tmp, rb, 7);
2273    tcg_gen_shli_i64(tmp, tmp, 3);
2274    if (right) {
2275        tcg_gen_shr_i64(tmp, ones, tmp);
2276    } else {
2277        tcg_gen_shl_i64(tmp, ones, tmp);
2278    }
2279    tcg_gen_not_i64(tmp, tmp);
2280
2281    if (right) {
2282        tcg_gen_movcond_i64(TCG_COND_LTU, mh, rb, tcg_constant_i64(8),
2283                            tmp, ones);
2284        tcg_gen_movcond_i64(TCG_COND_LTU, ml, rb, tcg_constant_i64(8),
2285                            zero, tmp);
2286        tcg_gen_movcond_i64(TCG_COND_LTU, ml, rb, tcg_constant_i64(16),
2287                            ml, ones);
2288    } else {
2289        tcg_gen_movcond_i64(TCG_COND_LTU, ml, rb, tcg_constant_i64(8),
2290                            tmp, ones);
2291        tcg_gen_movcond_i64(TCG_COND_LTU, mh, rb, tcg_constant_i64(8),
2292                            zero, tmp);
2293        tcg_gen_movcond_i64(TCG_COND_LTU, mh, rb, tcg_constant_i64(16),
2294                            mh, ones);
2295    }
2296
2297    get_avr64(tmp, a->vra, true);
2298    tcg_gen_and_i64(tmp, tmp, mh);
2299    set_avr64(a->vrt, tmp, true);
2300
2301    get_avr64(tmp, a->vra, false);
2302    tcg_gen_and_i64(tmp, tmp, ml);
2303    set_avr64(a->vrt, tmp, false);
2304    return true;
2305}
2306
2307TRANS(VCLRLB, do_vclrb, false)
2308TRANS(VCLRRB, do_vclrb, true)
2309
2310#define GEN_VAFORM_PAIRED(name0, name1, opc2)                           \
2311static void glue(gen_, name0##_##name1)(DisasContext *ctx)              \
2312    {                                                                   \
2313        TCGv_ptr ra, rb, rc, rd;                                        \
2314        if (unlikely(!ctx->altivec_enabled)) {                          \
2315            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
2316            return;                                                     \
2317        }                                                               \
2318        ra = gen_avr_ptr(rA(ctx->opcode));                              \
2319        rb = gen_avr_ptr(rB(ctx->opcode));                              \
2320        rc = gen_avr_ptr(rC(ctx->opcode));                              \
2321        rd = gen_avr_ptr(rD(ctx->opcode));                              \
2322        if (Rc(ctx->opcode)) {                                          \
2323            gen_helper_##name1(tcg_env, rd, ra, rb, rc);                \
2324        } else {                                                        \
2325            gen_helper_##name0(tcg_env, rd, ra, rb, rc);                \
2326        }                                                               \
2327    }
2328
2329GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23)
2330
2331static bool do_va_helper(DisasContext *ctx, arg_VA *a,
2332    void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr))
2333{
2334    TCGv_ptr vrt, vra, vrb, vrc;
2335    REQUIRE_VECTOR(ctx);
2336
2337    vrt = gen_avr_ptr(a->vrt);
2338    vra = gen_avr_ptr(a->vra);
2339    vrb = gen_avr_ptr(a->vrb);
2340    vrc = gen_avr_ptr(a->rc);
2341    gen_helper(vrt, vra, vrb, vrc);
2342    return true;
2343}
2344
2345TRANS_FLAGS2(ALTIVEC_207, VADDECUQ, do_va_helper, gen_helper_VADDECUQ)
2346TRANS_FLAGS2(ALTIVEC_207, VADDEUQM, do_va_helper, gen_helper_VADDEUQM)
2347
2348TRANS_FLAGS2(ALTIVEC_207, VSUBEUQM, do_va_helper, gen_helper_VSUBEUQM)
2349TRANS_FLAGS2(ALTIVEC_207, VSUBECUQ, do_va_helper, gen_helper_VSUBECUQ)
2350
2351TRANS_FLAGS(ALTIVEC, VPERM, do_va_helper, gen_helper_VPERM)
2352TRANS_FLAGS2(ISA300, VPERMR, do_va_helper, gen_helper_VPERMR)
2353
2354static void gen_vmladduhm_vec(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b,
2355                              TCGv_vec c)
2356{
2357    tcg_gen_mul_vec(vece, t, a, b);
2358    tcg_gen_add_vec(vece, t, t, c);
2359}
2360
2361static bool trans_VMLADDUHM(DisasContext *ctx, arg_VA *a)
2362{
2363    static const TCGOpcode vecop_list[] = {
2364        INDEX_op_add_vec, INDEX_op_mul_vec, 0
2365    };
2366
2367    static const GVecGen4 op = {
2368        .fno = gen_helper_VMLADDUHM,
2369        .fniv = gen_vmladduhm_vec,
2370        .opt_opc = vecop_list,
2371        .vece = MO_16
2372    };
2373
2374    REQUIRE_INSNS_FLAGS(ctx, ALTIVEC);
2375    REQUIRE_VECTOR(ctx);
2376
2377    tcg_gen_gvec_4(avr_full_offset(a->vrt), avr_full_offset(a->vra),
2378                   avr_full_offset(a->vrb), avr_full_offset(a->rc),
2379                   16, 16, &op);
2380
2381    return true;
2382}
2383
2384static bool trans_VSEL(DisasContext *ctx, arg_VA *a)
2385{
2386    REQUIRE_INSNS_FLAGS(ctx, ALTIVEC);
2387    REQUIRE_VECTOR(ctx);
2388
2389    tcg_gen_gvec_bitsel(MO_64, avr_full_offset(a->vrt), avr_full_offset(a->rc),
2390                        avr_full_offset(a->vrb), avr_full_offset(a->vra),
2391                        16, 16);
2392
2393    return true;
2394}
2395
2396TRANS_FLAGS(ALTIVEC, VMSUMUBM, do_va_helper, gen_helper_VMSUMUBM)
2397TRANS_FLAGS(ALTIVEC, VMSUMMBM, do_va_helper, gen_helper_VMSUMMBM)
2398TRANS_FLAGS(ALTIVEC, VMSUMSHM, do_va_helper, gen_helper_VMSUMSHM)
2399TRANS_FLAGS(ALTIVEC, VMSUMUHM, do_va_helper, gen_helper_VMSUMUHM)
2400
2401static bool do_va_env_helper(DisasContext *ctx, arg_VA *a,
2402    void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr))
2403{
2404    TCGv_ptr vrt, vra, vrb, vrc;
2405    REQUIRE_VECTOR(ctx);
2406
2407    vrt = gen_avr_ptr(a->vrt);
2408    vra = gen_avr_ptr(a->vra);
2409    vrb = gen_avr_ptr(a->vrb);
2410    vrc = gen_avr_ptr(a->rc);
2411    gen_helper(tcg_env, vrt, vra, vrb, vrc);
2412    return true;
2413}
2414
2415TRANS_FLAGS(ALTIVEC, VMSUMUHS, do_va_env_helper, gen_helper_VMSUMUHS)
2416TRANS_FLAGS(ALTIVEC, VMSUMSHS, do_va_env_helper, gen_helper_VMSUMSHS)
2417
2418TRANS_FLAGS(ALTIVEC, VMHADDSHS, do_va_env_helper, gen_helper_VMHADDSHS)
2419TRANS_FLAGS(ALTIVEC, VMHRADDSHS, do_va_env_helper, gen_helper_VMHRADDSHS)
2420
2421GEN_VXFORM_NOA(vclzb, 1, 28)
2422GEN_VXFORM_NOA(vclzh, 1, 29)
2423GEN_VXFORM_TRANS(vclzw, 1, 30)
2424GEN_VXFORM_TRANS(vclzd, 1, 31)
2425
2426static bool do_vneg(DisasContext *ctx, arg_VX_tb *a, unsigned vece)
2427{
2428    REQUIRE_INSNS_FLAGS2(ctx, ISA300);
2429    REQUIRE_VECTOR(ctx);
2430
2431    tcg_gen_gvec_neg(vece, avr_full_offset(a->vrt), avr_full_offset(a->vrb),
2432                     16, 16);
2433    return true;
2434}
2435
2436TRANS(VNEGW, do_vneg, MO_32)
2437TRANS(VNEGD, do_vneg, MO_64)
2438
2439static void gen_vexts_i64(TCGv_i64 t, TCGv_i64 b, int64_t s)
2440{
2441    tcg_gen_sextract_i64(t, b, 0, 64 - s);
2442}
2443
2444static void gen_vexts_i32(TCGv_i32 t, TCGv_i32 b, int32_t s)
2445{
2446    tcg_gen_sextract_i32(t, b, 0, 32 - s);
2447}
2448
2449static void gen_vexts_vec(unsigned vece, TCGv_vec t, TCGv_vec b, int64_t s)
2450{
2451    tcg_gen_shli_vec(vece, t, b, s);
2452    tcg_gen_sari_vec(vece, t, t, s);
2453}
2454
2455static bool do_vexts(DisasContext *ctx, arg_VX_tb *a, unsigned vece, int64_t s)
2456{
2457    static const TCGOpcode vecop_list[] = {
2458        INDEX_op_shli_vec, INDEX_op_sari_vec, 0
2459    };
2460
2461    static const GVecGen2i op[2] = {
2462        {
2463            .fni4 = gen_vexts_i32,
2464            .fniv = gen_vexts_vec,
2465            .opt_opc = vecop_list,
2466            .vece = MO_32
2467        },
2468        {
2469            .fni8 = gen_vexts_i64,
2470            .fniv = gen_vexts_vec,
2471            .opt_opc = vecop_list,
2472            .vece = MO_64
2473        },
2474    };
2475
2476    REQUIRE_INSNS_FLAGS2(ctx, ISA300);
2477    REQUIRE_VECTOR(ctx);
2478
2479    tcg_gen_gvec_2i(avr_full_offset(a->vrt), avr_full_offset(a->vrb),
2480                    16, 16, s, &op[vece - MO_32]);
2481
2482    return true;
2483}
2484
2485TRANS(VEXTSB2W, do_vexts, MO_32, 24);
2486TRANS(VEXTSH2W, do_vexts, MO_32, 16);
2487TRANS(VEXTSB2D, do_vexts, MO_64, 56);
2488TRANS(VEXTSH2D, do_vexts, MO_64, 48);
2489TRANS(VEXTSW2D, do_vexts, MO_64, 32);
2490
2491static bool trans_VEXTSD2Q(DisasContext *ctx, arg_VX_tb *a)
2492{
2493    TCGv_i64 tmp;
2494
2495    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
2496    REQUIRE_VECTOR(ctx);
2497
2498    tmp = tcg_temp_new_i64();
2499
2500    get_avr64(tmp, a->vrb, false);
2501    set_avr64(a->vrt, tmp, false);
2502    tcg_gen_sari_i64(tmp, tmp, 63);
2503    set_avr64(a->vrt, tmp, true);
2504    return true;
2505}
2506
2507GEN_VXFORM_NOA_2(vctzb, 1, 24, 28)
2508GEN_VXFORM_NOA_2(vctzh, 1, 24, 29)
2509GEN_VXFORM_NOA_2(vctzw, 1, 24, 30)
2510GEN_VXFORM_NOA_2(vctzd, 1, 24, 31)
2511GEN_VXFORM_NOA_3(vclzlsbb, 1, 24, 0)
2512GEN_VXFORM_NOA_3(vctzlsbb, 1, 24, 1)
2513GEN_VXFORM_NOA(vpopcntb, 1, 28)
2514GEN_VXFORM_NOA(vpopcnth, 1, 29)
2515GEN_VXFORM_NOA(vpopcntw, 1, 30)
2516GEN_VXFORM_NOA(vpopcntd, 1, 31)
2517GEN_VXFORM_DUAL(vclzb, PPC_NONE, PPC2_ALTIVEC_207, \
2518                vpopcntb, PPC_NONE, PPC2_ALTIVEC_207)
2519GEN_VXFORM_DUAL(vclzh, PPC_NONE, PPC2_ALTIVEC_207, \
2520                vpopcnth, PPC_NONE, PPC2_ALTIVEC_207)
2521GEN_VXFORM_DUAL(vclzw, PPC_NONE, PPC2_ALTIVEC_207, \
2522                vpopcntw, PPC_NONE, PPC2_ALTIVEC_207)
2523GEN_VXFORM_DUAL(vclzd, PPC_NONE, PPC2_ALTIVEC_207, \
2524                vpopcntd, PPC_NONE, PPC2_ALTIVEC_207)
2525GEN_VXFORM(vbpermd, 6, 23);
2526GEN_VXFORM(vbpermq, 6, 21);
2527GEN_VXFORM_TRANS(vgbbd, 6, 20);
2528GEN_VXFORM(vpmsumb, 4, 16)
2529GEN_VXFORM(vpmsumh, 4, 17)
2530GEN_VXFORM(vpmsumw, 4, 18)
2531
2532#define GEN_BCD(op)                                 \
2533static void gen_##op(DisasContext *ctx)             \
2534{                                                   \
2535    TCGv_ptr ra, rb, rd;                            \
2536    TCGv_i32 ps;                                    \
2537                                                    \
2538    if (unlikely(!ctx->altivec_enabled)) {          \
2539        gen_exception(ctx, POWERPC_EXCP_VPU);       \
2540        return;                                     \
2541    }                                               \
2542                                                    \
2543    ra = gen_avr_ptr(rA(ctx->opcode));              \
2544    rb = gen_avr_ptr(rB(ctx->opcode));              \
2545    rd = gen_avr_ptr(rD(ctx->opcode));              \
2546                                                    \
2547    ps = tcg_constant_i32((ctx->opcode & 0x200) != 0); \
2548                                                    \
2549    gen_helper_##op(cpu_crf[6], rd, ra, rb, ps);    \
2550}
2551
2552#define GEN_BCD2(op)                                \
2553static void gen_##op(DisasContext *ctx)             \
2554{                                                   \
2555    TCGv_ptr rd, rb;                                \
2556    TCGv_i32 ps;                                    \
2557                                                    \
2558    if (unlikely(!ctx->altivec_enabled)) {          \
2559        gen_exception(ctx, POWERPC_EXCP_VPU);       \
2560        return;                                     \
2561    }                                               \
2562                                                    \
2563    rb = gen_avr_ptr(rB(ctx->opcode));              \
2564    rd = gen_avr_ptr(rD(ctx->opcode));              \
2565                                                    \
2566    ps = tcg_constant_i32((ctx->opcode & 0x200) != 0); \
2567                                                    \
2568    gen_helper_##op(cpu_crf[6], rd, rb, ps);        \
2569}
2570
2571GEN_BCD(bcdadd)
2572GEN_BCD(bcdsub)
2573GEN_BCD2(bcdcfn)
2574GEN_BCD2(bcdctn)
2575GEN_BCD2(bcdcfz)
2576GEN_BCD2(bcdctz)
2577GEN_BCD2(bcdcfsq)
2578GEN_BCD2(bcdctsq)
2579GEN_BCD2(bcdsetsgn)
2580GEN_BCD(bcdcpsgn);
2581GEN_BCD(bcds);
2582GEN_BCD(bcdus);
2583GEN_BCD(bcdsr);
2584GEN_BCD(bcdtrunc);
2585GEN_BCD(bcdutrunc);
2586
2587static void gen_xpnd04_1(DisasContext *ctx)
2588{
2589    switch (opc4(ctx->opcode)) {
2590    case 0:
2591        gen_bcdctsq(ctx);
2592        break;
2593    case 2:
2594        gen_bcdcfsq(ctx);
2595        break;
2596    case 4:
2597        gen_bcdctz(ctx);
2598        break;
2599    case 5:
2600        gen_bcdctn(ctx);
2601        break;
2602    case 6:
2603        gen_bcdcfz(ctx);
2604        break;
2605    case 7:
2606        gen_bcdcfn(ctx);
2607        break;
2608    case 31:
2609        gen_bcdsetsgn(ctx);
2610        break;
2611    default:
2612        gen_invalid(ctx);
2613        break;
2614    }
2615}
2616
2617static void gen_xpnd04_2(DisasContext *ctx)
2618{
2619    switch (opc4(ctx->opcode)) {
2620    case 0:
2621        gen_bcdctsq(ctx);
2622        break;
2623    case 2:
2624        gen_bcdcfsq(ctx);
2625        break;
2626    case 4:
2627        gen_bcdctz(ctx);
2628        break;
2629    case 6:
2630        gen_bcdcfz(ctx);
2631        break;
2632    case 7:
2633        gen_bcdcfn(ctx);
2634        break;
2635    case 31:
2636        gen_bcdsetsgn(ctx);
2637        break;
2638    default:
2639        gen_invalid(ctx);
2640        break;
2641    }
2642}
2643
2644
2645GEN_VXFORM_DUAL(vsubsws, PPC_ALTIVEC, PPC_NONE, \
2646                xpnd04_2, PPC_NONE, PPC2_ISA300)
2647
2648GEN_VXFORM_DUAL(vsububm, PPC_ALTIVEC, PPC_NONE, \
2649                bcdadd, PPC_NONE, PPC2_ALTIVEC_207)
2650GEN_VXFORM_DUAL(vsububs, PPC_ALTIVEC, PPC_NONE, \
2651                bcdadd, PPC_NONE, PPC2_ALTIVEC_207)
2652GEN_VXFORM_DUAL(vsubuhm, PPC_ALTIVEC, PPC_NONE, \
2653                bcdsub, PPC_NONE, PPC2_ALTIVEC_207)
2654GEN_VXFORM_DUAL(vsubuhs, PPC_ALTIVEC, PPC_NONE, \
2655                bcdsub, PPC_NONE, PPC2_ALTIVEC_207)
2656GEN_VXFORM_DUAL(vaddshs, PPC_ALTIVEC, PPC_NONE, \
2657                bcdcpsgn, PPC_NONE, PPC2_ISA300)
2658GEN_VXFORM_DUAL(vsubudm, PPC2_ALTIVEC_207, PPC_NONE, \
2659                bcds, PPC_NONE, PPC2_ISA300)
2660GEN_VXFORM_DUAL(vsubuwm, PPC_ALTIVEC, PPC_NONE, \
2661                bcdus, PPC_NONE, PPC2_ISA300)
2662GEN_VXFORM_DUAL(vsubsbs, PPC_ALTIVEC, PPC_NONE, \
2663                bcdtrunc, PPC_NONE, PPC2_ISA300)
2664
2665static void gen_vsbox(DisasContext *ctx)
2666{
2667    TCGv_ptr ra, rd;
2668    if (unlikely(!ctx->altivec_enabled)) {
2669        gen_exception(ctx, POWERPC_EXCP_VPU);
2670        return;
2671    }
2672    ra = gen_avr_ptr(rA(ctx->opcode));
2673    rd = gen_avr_ptr(rD(ctx->opcode));
2674    gen_helper_vsbox(rd, ra);
2675}
2676
2677GEN_VXFORM(vcipher, 4, 20)
2678GEN_VXFORM(vcipherlast, 4, 20)
2679GEN_VXFORM(vncipher, 4, 21)
2680GEN_VXFORM(vncipherlast, 4, 21)
2681
2682GEN_VXFORM_DUAL(vcipher, PPC_NONE, PPC2_ALTIVEC_207,
2683                vcipherlast, PPC_NONE, PPC2_ALTIVEC_207)
2684GEN_VXFORM_DUAL(vncipher, PPC_NONE, PPC2_ALTIVEC_207,
2685                vncipherlast, PPC_NONE, PPC2_ALTIVEC_207)
2686
2687#define VSHASIGMA(op)                         \
2688static void gen_##op(DisasContext *ctx)       \
2689{                                             \
2690    TCGv_ptr ra, rd;                          \
2691    TCGv_i32 st_six;                          \
2692    if (unlikely(!ctx->altivec_enabled)) {    \
2693        gen_exception(ctx, POWERPC_EXCP_VPU); \
2694        return;                               \
2695    }                                         \
2696    ra = gen_avr_ptr(rA(ctx->opcode));        \
2697    rd = gen_avr_ptr(rD(ctx->opcode));        \
2698    st_six = tcg_constant_i32(rB(ctx->opcode));  \
2699    gen_helper_##op(rd, ra, st_six);          \
2700}
2701
2702VSHASIGMA(vshasigmaw)
2703VSHASIGMA(vshasigmad)
2704
2705GEN_VXFORM3(vpermxor, 22, 0xFF)
2706GEN_VXFORM_DUAL(vsldoi, PPC_ALTIVEC, PPC_NONE,
2707                vpermxor, PPC_NONE, PPC2_ALTIVEC_207)
2708
2709static bool trans_VCFUGED(DisasContext *ctx, arg_VX *a)
2710{
2711    static const GVecGen3 g = {
2712        .fni8 = gen_helper_CFUGED,
2713        .vece = MO_64,
2714    };
2715
2716    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
2717    REQUIRE_VECTOR(ctx);
2718
2719    tcg_gen_gvec_3(avr_full_offset(a->vrt), avr_full_offset(a->vra),
2720                   avr_full_offset(a->vrb), 16, 16, &g);
2721
2722    return true;
2723}
2724
2725static bool trans_VCLZDM(DisasContext *ctx, arg_VX *a)
2726{
2727    static const GVecGen3i g = {
2728        .fni8 = do_cntzdm,
2729        .vece = MO_64,
2730    };
2731
2732    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
2733    REQUIRE_VECTOR(ctx);
2734
2735    tcg_gen_gvec_3i(avr_full_offset(a->vrt), avr_full_offset(a->vra),
2736                    avr_full_offset(a->vrb), 16, 16, false, &g);
2737
2738    return true;
2739}
2740
2741static bool trans_VCTZDM(DisasContext *ctx, arg_VX *a)
2742{
2743    static const GVecGen3i g = {
2744        .fni8 = do_cntzdm,
2745        .vece = MO_64,
2746    };
2747
2748    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
2749    REQUIRE_VECTOR(ctx);
2750
2751    tcg_gen_gvec_3i(avr_full_offset(a->vrt), avr_full_offset(a->vra),
2752                    avr_full_offset(a->vrb), 16, 16, true, &g);
2753
2754    return true;
2755}
2756
2757static bool trans_VPDEPD(DisasContext *ctx, arg_VX *a)
2758{
2759    static const GVecGen3 g = {
2760        .fni8 = gen_helper_PDEPD,
2761        .vece = MO_64,
2762    };
2763
2764    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
2765    REQUIRE_VECTOR(ctx);
2766
2767    tcg_gen_gvec_3(avr_full_offset(a->vrt), avr_full_offset(a->vra),
2768                   avr_full_offset(a->vrb), 16, 16, &g);
2769
2770    return true;
2771}
2772
2773static bool trans_VPEXTD(DisasContext *ctx, arg_VX *a)
2774{
2775    static const GVecGen3 g = {
2776        .fni8 = gen_helper_PEXTD,
2777        .vece = MO_64,
2778    };
2779
2780    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
2781    REQUIRE_VECTOR(ctx);
2782
2783    tcg_gen_gvec_3(avr_full_offset(a->vrt), avr_full_offset(a->vra),
2784                   avr_full_offset(a->vrb), 16, 16, &g);
2785
2786    return true;
2787}
2788
2789static bool trans_VMSUMUDM(DisasContext *ctx, arg_VA *a)
2790{
2791    TCGv_i64 rl, rh, src1, src2;
2792    int dw;
2793
2794    REQUIRE_INSNS_FLAGS2(ctx, ISA300);
2795    REQUIRE_VECTOR(ctx);
2796
2797    rh = tcg_temp_new_i64();
2798    rl = tcg_temp_new_i64();
2799    src1 = tcg_temp_new_i64();
2800    src2 = tcg_temp_new_i64();
2801
2802    get_avr64(rl, a->rc, false);
2803    get_avr64(rh, a->rc, true);
2804
2805    for (dw = 0; dw < 2; dw++) {
2806        get_avr64(src1, a->vra, dw);
2807        get_avr64(src2, a->vrb, dw);
2808        tcg_gen_mulu2_i64(src1, src2, src1, src2);
2809        tcg_gen_add2_i64(rl, rh, rl, rh, src1, src2);
2810    }
2811
2812    set_avr64(a->vrt, rl, false);
2813    set_avr64(a->vrt, rh, true);
2814    return true;
2815}
2816
2817static bool trans_VMSUMCUD(DisasContext *ctx, arg_VA *a)
2818{
2819    TCGv_i64 tmp0, tmp1, prod1h, prod1l, prod0h, prod0l, zero;
2820
2821    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
2822    REQUIRE_VECTOR(ctx);
2823
2824    tmp0 = tcg_temp_new_i64();
2825    tmp1 = tcg_temp_new_i64();
2826    prod1h = tcg_temp_new_i64();
2827    prod1l = tcg_temp_new_i64();
2828    prod0h = tcg_temp_new_i64();
2829    prod0l = tcg_temp_new_i64();
2830    zero = tcg_constant_i64(0);
2831
2832    /* prod1 = vsr[vra+32].dw[1] * vsr[vrb+32].dw[1] */
2833    get_avr64(tmp0, a->vra, false);
2834    get_avr64(tmp1, a->vrb, false);
2835    tcg_gen_mulu2_i64(prod1l, prod1h, tmp0, tmp1);
2836
2837    /* prod0 = vsr[vra+32].dw[0] * vsr[vrb+32].dw[0] */
2838    get_avr64(tmp0, a->vra, true);
2839    get_avr64(tmp1, a->vrb, true);
2840    tcg_gen_mulu2_i64(prod0l, prod0h, tmp0, tmp1);
2841
2842    /* Sum lower 64-bits elements */
2843    get_avr64(tmp1, a->rc, false);
2844    tcg_gen_add2_i64(tmp1, tmp0, tmp1, zero, prod1l, zero);
2845    tcg_gen_add2_i64(tmp1, tmp0, tmp1, tmp0, prod0l, zero);
2846
2847    /*
2848     * Discard lower 64-bits, leaving the carry into bit 64.
2849     * Then sum the higher 64-bit elements.
2850     */
2851    get_avr64(tmp1, a->rc, true);
2852    tcg_gen_add2_i64(tmp1, tmp0, tmp0, zero, tmp1, zero);
2853    tcg_gen_add2_i64(tmp1, tmp0, tmp1, tmp0, prod1h, zero);
2854    tcg_gen_add2_i64(tmp1, tmp0, tmp1, tmp0, prod0h, zero);
2855
2856    /* Discard 64 more bits to complete the CHOP128(temp >> 128) */
2857    set_avr64(a->vrt, tmp0, false);
2858    set_avr64(a->vrt, zero, true);
2859    return true;
2860}
2861
2862static bool do_vx_helper(DisasContext *ctx, arg_VX *a,
2863                         void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_ptr))
2864{
2865    TCGv_ptr ra, rb, rd;
2866    REQUIRE_VECTOR(ctx);
2867
2868    ra = gen_avr_ptr(a->vra);
2869    rb = gen_avr_ptr(a->vrb);
2870    rd = gen_avr_ptr(a->vrt);
2871    gen_helper(rd, ra, rb);
2872    return true;
2873}
2874
2875TRANS_FLAGS2(ALTIVEC_207, VADDCUQ, do_vx_helper, gen_helper_VADDCUQ)
2876TRANS_FLAGS2(ALTIVEC_207, VADDUQM, do_vx_helper, gen_helper_VADDUQM)
2877
2878TRANS_FLAGS2(ALTIVEC_207, VPMSUMD, do_vx_helper, gen_helper_VPMSUMD)
2879
2880TRANS_FLAGS2(ALTIVEC_207, VSUBCUQ, do_vx_helper, gen_helper_VSUBCUQ)
2881TRANS_FLAGS2(ALTIVEC_207, VSUBUQM, do_vx_helper, gen_helper_VSUBUQM)
2882
2883static void gen_VADDCUW_vec(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b)
2884{
2885    tcg_gen_not_vec(vece, a, a);
2886    tcg_gen_cmp_vec(TCG_COND_LTU, vece, t, a, b);
2887    tcg_gen_and_vec(vece, t, t, tcg_constant_vec_matching(t, vece, 1));
2888}
2889
2890static void gen_VADDCUW_i32(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b)
2891{
2892    tcg_gen_not_i32(a, a);
2893    tcg_gen_setcond_i32(TCG_COND_LTU, t, a, b);
2894}
2895
2896static void gen_VSUBCUW_vec(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b)
2897{
2898    tcg_gen_cmp_vec(TCG_COND_GEU, vece, t, a, b);
2899    tcg_gen_and_vec(vece, t, t, tcg_constant_vec_matching(t, vece, 1));
2900}
2901
2902static void gen_VSUBCUW_i32(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b)
2903{
2904    tcg_gen_setcond_i32(TCG_COND_GEU, t, a, b);
2905}
2906
2907static bool do_vx_vaddsubcuw(DisasContext *ctx, arg_VX *a, int add)
2908{
2909    static const TCGOpcode vecop_list[] = {
2910        INDEX_op_cmp_vec, 0
2911    };
2912
2913    static const GVecGen3 op[] = {
2914        {
2915            .fniv = gen_VSUBCUW_vec,
2916            .fni4 = gen_VSUBCUW_i32,
2917            .opt_opc = vecop_list,
2918            .vece = MO_32
2919        },
2920        {
2921            .fniv = gen_VADDCUW_vec,
2922            .fni4 = gen_VADDCUW_i32,
2923            .opt_opc = vecop_list,
2924            .vece = MO_32
2925        },
2926    };
2927
2928    REQUIRE_INSNS_FLAGS(ctx, ALTIVEC);
2929    REQUIRE_VECTOR(ctx);
2930
2931    tcg_gen_gvec_3(avr_full_offset(a->vrt), avr_full_offset(a->vra),
2932                   avr_full_offset(a->vrb), 16, 16, &op[add]);
2933
2934    return true;
2935}
2936
2937TRANS(VSUBCUW, do_vx_vaddsubcuw, 0)
2938TRANS(VADDCUW, do_vx_vaddsubcuw, 1)
2939
2940static bool do_vx_vmuleo(DisasContext *ctx, arg_VX *a, bool even,
2941                         void (*gen_mul)(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_i64))
2942{
2943    TCGv_i64 vra, vrb, vrt0, vrt1;
2944    REQUIRE_VECTOR(ctx);
2945
2946    vra = tcg_temp_new_i64();
2947    vrb = tcg_temp_new_i64();
2948    vrt0 = tcg_temp_new_i64();
2949    vrt1 = tcg_temp_new_i64();
2950
2951    get_avr64(vra, a->vra, even);
2952    get_avr64(vrb, a->vrb, even);
2953    gen_mul(vrt0, vrt1, vra, vrb);
2954    set_avr64(a->vrt, vrt0, false);
2955    set_avr64(a->vrt, vrt1, true);
2956    return true;
2957}
2958
2959static bool trans_VMULLD(DisasContext *ctx, arg_VX *a)
2960{
2961    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
2962    REQUIRE_VECTOR(ctx);
2963
2964    tcg_gen_gvec_mul(MO_64, avr_full_offset(a->vrt), avr_full_offset(a->vra),
2965                     avr_full_offset(a->vrb), 16, 16);
2966
2967    return true;
2968}
2969
2970TRANS_FLAGS(ALTIVEC, VMULESB, do_vx_helper, gen_helper_VMULESB)
2971TRANS_FLAGS(ALTIVEC, VMULOSB, do_vx_helper, gen_helper_VMULOSB)
2972TRANS_FLAGS(ALTIVEC, VMULEUB, do_vx_helper, gen_helper_VMULEUB)
2973TRANS_FLAGS(ALTIVEC, VMULOUB, do_vx_helper, gen_helper_VMULOUB)
2974TRANS_FLAGS(ALTIVEC, VMULESH, do_vx_helper, gen_helper_VMULESH)
2975TRANS_FLAGS(ALTIVEC, VMULOSH, do_vx_helper, gen_helper_VMULOSH)
2976TRANS_FLAGS(ALTIVEC, VMULEUH, do_vx_helper, gen_helper_VMULEUH)
2977TRANS_FLAGS(ALTIVEC, VMULOUH, do_vx_helper, gen_helper_VMULOUH)
2978TRANS_FLAGS2(ALTIVEC_207, VMULESW, do_vx_helper, gen_helper_VMULESW)
2979TRANS_FLAGS2(ALTIVEC_207, VMULOSW, do_vx_helper, gen_helper_VMULOSW)
2980TRANS_FLAGS2(ALTIVEC_207, VMULEUW, do_vx_helper, gen_helper_VMULEUW)
2981TRANS_FLAGS2(ALTIVEC_207, VMULOUW, do_vx_helper, gen_helper_VMULOUW)
2982TRANS_FLAGS2(ISA310, VMULESD, do_vx_vmuleo, true , tcg_gen_muls2_i64)
2983TRANS_FLAGS2(ISA310, VMULOSD, do_vx_vmuleo, false, tcg_gen_muls2_i64)
2984TRANS_FLAGS2(ISA310, VMULEUD, do_vx_vmuleo, true , tcg_gen_mulu2_i64)
2985TRANS_FLAGS2(ISA310, VMULOUD, do_vx_vmuleo, false, tcg_gen_mulu2_i64)
2986
2987static void do_vx_vmulhw_i64(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b, bool sign)
2988{
2989    TCGv_i64 hh, lh, temp;
2990
2991    hh = tcg_temp_new_i64();
2992    lh = tcg_temp_new_i64();
2993    temp = tcg_temp_new_i64();
2994
2995    if (sign) {
2996        tcg_gen_ext32s_i64(lh, a);
2997        tcg_gen_ext32s_i64(temp, b);
2998    } else {
2999        tcg_gen_ext32u_i64(lh, a);
3000        tcg_gen_ext32u_i64(temp, b);
3001    }
3002    tcg_gen_mul_i64(lh, lh, temp);
3003
3004    if (sign) {
3005        tcg_gen_sari_i64(hh, a, 32);
3006        tcg_gen_sari_i64(temp, b, 32);
3007    } else {
3008        tcg_gen_shri_i64(hh, a, 32);
3009        tcg_gen_shri_i64(temp, b, 32);
3010    }
3011    tcg_gen_mul_i64(hh, hh, temp);
3012
3013    tcg_gen_shri_i64(lh, lh, 32);
3014    tcg_gen_deposit_i64(t, hh, lh, 0, 32);
3015}
3016
3017static void do_vx_vmulhd_i64(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b, bool sign)
3018{
3019    TCGv_i64 tlow;
3020
3021    tlow  = tcg_temp_new_i64();
3022    if (sign) {
3023        tcg_gen_muls2_i64(tlow, t, a, b);
3024    } else {
3025        tcg_gen_mulu2_i64(tlow, t, a, b);
3026    }
3027}
3028
3029static bool do_vx_mulh(DisasContext *ctx, arg_VX *a, bool sign,
3030                       void (*func)(TCGv_i64, TCGv_i64, TCGv_i64, bool))
3031{
3032    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
3033    REQUIRE_VECTOR(ctx);
3034
3035    TCGv_i64 vra, vrb, vrt;
3036    int i;
3037
3038    vra = tcg_temp_new_i64();
3039    vrb = tcg_temp_new_i64();
3040    vrt = tcg_temp_new_i64();
3041
3042    for (i = 0; i < 2; i++) {
3043        get_avr64(vra, a->vra, i);
3044        get_avr64(vrb, a->vrb, i);
3045        get_avr64(vrt, a->vrt, i);
3046
3047        func(vrt, vra, vrb, sign);
3048
3049        set_avr64(a->vrt, vrt, i);
3050    }
3051    return true;
3052}
3053
3054TRANS(VMULHSW, do_vx_mulh, true , do_vx_vmulhw_i64)
3055TRANS(VMULHSD, do_vx_mulh, true , do_vx_vmulhd_i64)
3056TRANS(VMULHUW, do_vx_mulh, false, do_vx_vmulhw_i64)
3057TRANS(VMULHUD, do_vx_mulh, false, do_vx_vmulhd_i64)
3058
3059static void do_vavg(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b,
3060                    void (*gen_shr_vec)(unsigned, TCGv_vec, TCGv_vec, int64_t))
3061{
3062    TCGv_vec tmp = tcg_temp_new_vec_matching(t);
3063    tcg_gen_or_vec(vece, tmp, a, b);
3064    tcg_gen_and_vec(vece, tmp, tmp, tcg_constant_vec_matching(t, vece, 1));
3065    gen_shr_vec(vece, a, a, 1);
3066    gen_shr_vec(vece, b, b, 1);
3067    tcg_gen_add_vec(vece, t, a, b);
3068    tcg_gen_add_vec(vece, t, t, tmp);
3069}
3070
3071QEMU_FLATTEN
3072static void gen_vavgu(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b)
3073{
3074    do_vavg(vece, t, a, b, tcg_gen_shri_vec);
3075}
3076
3077QEMU_FLATTEN
3078static void gen_vavgs(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b)
3079{
3080    do_vavg(vece, t, a, b, tcg_gen_sari_vec);
3081}
3082
3083static bool do_vx_vavg(DisasContext *ctx, arg_VX *a, int sign, int vece)
3084{
3085    static const TCGOpcode vecop_list_s[] = {
3086        INDEX_op_add_vec, INDEX_op_sari_vec, 0
3087    };
3088    static const TCGOpcode vecop_list_u[] = {
3089        INDEX_op_add_vec, INDEX_op_shri_vec, 0
3090    };
3091
3092    static const GVecGen3 op[2][3] = {
3093        {
3094            {
3095                .fniv = gen_vavgu,
3096                .fno = gen_helper_VAVGUB,
3097                .opt_opc = vecop_list_u,
3098                .vece = MO_8
3099            },
3100            {
3101                .fniv = gen_vavgu,
3102                .fno = gen_helper_VAVGUH,
3103                .opt_opc = vecop_list_u,
3104                .vece = MO_16
3105            },
3106            {
3107                .fniv = gen_vavgu,
3108                .fno = gen_helper_VAVGUW,
3109                .opt_opc = vecop_list_u,
3110                .vece = MO_32
3111            },
3112        },
3113        {
3114            {
3115                .fniv = gen_vavgs,
3116                .fno = gen_helper_VAVGSB,
3117                .opt_opc = vecop_list_s,
3118                .vece = MO_8
3119            },
3120            {
3121                .fniv = gen_vavgs,
3122                .fno = gen_helper_VAVGSH,
3123                .opt_opc = vecop_list_s,
3124                .vece = MO_16
3125            },
3126            {
3127                .fniv = gen_vavgs,
3128                .fno = gen_helper_VAVGSW,
3129                .opt_opc = vecop_list_s,
3130                .vece = MO_32
3131            },
3132        },
3133    };
3134
3135    REQUIRE_VECTOR(ctx);
3136
3137    tcg_gen_gvec_3(avr_full_offset(a->vrt), avr_full_offset(a->vra),
3138                   avr_full_offset(a->vrb), 16, 16, &op[sign][vece]);
3139
3140
3141    return true;
3142}
3143
3144
3145TRANS_FLAGS(ALTIVEC, VAVGSB, do_vx_vavg, 1, MO_8)
3146TRANS_FLAGS(ALTIVEC, VAVGSH, do_vx_vavg, 1, MO_16)
3147TRANS_FLAGS(ALTIVEC, VAVGSW, do_vx_vavg, 1, MO_32)
3148TRANS_FLAGS(ALTIVEC, VAVGUB, do_vx_vavg, 0, MO_8)
3149TRANS_FLAGS(ALTIVEC, VAVGUH, do_vx_vavg, 0, MO_16)
3150TRANS_FLAGS(ALTIVEC, VAVGUW, do_vx_vavg, 0, MO_32)
3151
3152static void gen_vabsdu(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b)
3153{
3154    tcg_gen_umax_vec(vece, t, a, b);
3155    tcg_gen_umin_vec(vece, a, a, b);
3156    tcg_gen_sub_vec(vece, t, t, a);
3157}
3158
3159static bool do_vabsdu(DisasContext *ctx, arg_VX *a, const int vece)
3160{
3161    static const TCGOpcode vecop_list[] = {
3162        INDEX_op_umax_vec, INDEX_op_umin_vec, INDEX_op_sub_vec, 0
3163    };
3164
3165    static const GVecGen3 op[] = {
3166        {
3167            .fniv = gen_vabsdu,
3168            .fno = gen_helper_VABSDUB,
3169            .opt_opc = vecop_list,
3170            .vece = MO_8
3171        },
3172        {
3173            .fniv = gen_vabsdu,
3174            .fno = gen_helper_VABSDUH,
3175            .opt_opc = vecop_list,
3176            .vece = MO_16
3177        },
3178        {
3179            .fniv = gen_vabsdu,
3180            .fno = gen_helper_VABSDUW,
3181            .opt_opc = vecop_list,
3182            .vece = MO_32
3183        },
3184    };
3185
3186    REQUIRE_VECTOR(ctx);
3187
3188    tcg_gen_gvec_3(avr_full_offset(a->vrt), avr_full_offset(a->vra),
3189                   avr_full_offset(a->vrb), 16, 16, &op[vece]);
3190
3191    return true;
3192}
3193
3194TRANS_FLAGS2(ISA300, VABSDUB, do_vabsdu, MO_8)
3195TRANS_FLAGS2(ISA300, VABSDUH, do_vabsdu, MO_16)
3196TRANS_FLAGS2(ISA300, VABSDUW, do_vabsdu, MO_32)
3197
3198static bool do_vdiv_vmod(DisasContext *ctx, arg_VX *a, const int vece,
3199                         void (*func_32)(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b),
3200                         void (*func_64)(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b))
3201{
3202    const GVecGen3 op = {
3203        .fni4 = func_32,
3204        .fni8 = func_64,
3205        .vece = vece
3206    };
3207
3208    REQUIRE_VECTOR(ctx);
3209
3210    tcg_gen_gvec_3(avr_full_offset(a->vrt), avr_full_offset(a->vra),
3211                   avr_full_offset(a->vrb), 16, 16, &op);
3212
3213    return true;
3214}
3215
3216#define DIVU32(NAME, DIV)                                               \
3217static void NAME(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b)                    \
3218{                                                                       \
3219    TCGv_i32 zero = tcg_constant_i32(0);                                \
3220    TCGv_i32 one = tcg_constant_i32(1);                                 \
3221    tcg_gen_movcond_i32(TCG_COND_EQ, b, b, zero, one, b);               \
3222    DIV(t, a, b);                                                       \
3223}
3224
3225#define DIVS32(NAME, DIV)                                               \
3226static void NAME(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b)                    \
3227{                                                                       \
3228    TCGv_i32 t0 = tcg_temp_new_i32();                                   \
3229    TCGv_i32 t1 = tcg_temp_new_i32();                                   \
3230    tcg_gen_setcondi_i32(TCG_COND_EQ, t0, a, INT32_MIN);                \
3231    tcg_gen_setcondi_i32(TCG_COND_EQ, t1, b, -1);                       \
3232    tcg_gen_and_i32(t0, t0, t1);                                        \
3233    tcg_gen_setcondi_i32(TCG_COND_EQ, t1, b, 0);                        \
3234    tcg_gen_or_i32(t0, t0, t1);                                         \
3235    tcg_gen_movi_i32(t1, 0);                                            \
3236    tcg_gen_movcond_i32(TCG_COND_NE, b, t0, t1, t0, b);                 \
3237    DIV(t, a, b);                                                       \
3238}
3239
3240#define DIVU64(NAME, DIV)                                               \
3241static void NAME(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b)                    \
3242{                                                                       \
3243    TCGv_i64 zero = tcg_constant_i64(0);                                \
3244    TCGv_i64 one = tcg_constant_i64(1);                                 \
3245    tcg_gen_movcond_i64(TCG_COND_EQ, b, b, zero, one, b);               \
3246    DIV(t, a, b);                                                       \
3247}
3248
3249#define DIVS64(NAME, DIV)                                               \
3250static void NAME(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b)                    \
3251{                                                                       \
3252    TCGv_i64 t0 = tcg_temp_new_i64();                                   \
3253    TCGv_i64 t1 = tcg_temp_new_i64();                                   \
3254    tcg_gen_setcondi_i64(TCG_COND_EQ, t0, a, INT64_MIN);                \
3255    tcg_gen_setcondi_i64(TCG_COND_EQ, t1, b, -1);                       \
3256    tcg_gen_and_i64(t0, t0, t1);                                        \
3257    tcg_gen_setcondi_i64(TCG_COND_EQ, t1, b, 0);                        \
3258    tcg_gen_or_i64(t0, t0, t1);                                         \
3259    tcg_gen_movi_i64(t1, 0);                                            \
3260    tcg_gen_movcond_i64(TCG_COND_NE, b, t0, t1, t0, b);                 \
3261    DIV(t, a, b);                                                       \
3262}
3263
3264DIVS32(do_divsw, tcg_gen_div_i32)
3265DIVU32(do_divuw, tcg_gen_divu_i32)
3266DIVS64(do_divsd, tcg_gen_div_i64)
3267DIVU64(do_divud, tcg_gen_divu_i64)
3268
3269TRANS_FLAGS2(ISA310, VDIVSW, do_vdiv_vmod, MO_32, do_divsw, NULL)
3270TRANS_FLAGS2(ISA310, VDIVUW, do_vdiv_vmod, MO_32, do_divuw, NULL)
3271TRANS_FLAGS2(ISA310, VDIVSD, do_vdiv_vmod, MO_64, NULL, do_divsd)
3272TRANS_FLAGS2(ISA310, VDIVUD, do_vdiv_vmod, MO_64, NULL, do_divud)
3273TRANS_FLAGS2(ISA310, VDIVSQ, do_vx_helper, gen_helper_VDIVSQ)
3274TRANS_FLAGS2(ISA310, VDIVUQ, do_vx_helper, gen_helper_VDIVUQ)
3275
3276static void do_dives_i32(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b)
3277{
3278    TCGv_i64 val1, val2;
3279
3280    val1 = tcg_temp_new_i64();
3281    val2 = tcg_temp_new_i64();
3282
3283    tcg_gen_ext_i32_i64(val1, a);
3284    tcg_gen_ext_i32_i64(val2, b);
3285
3286    /* (a << 32)/b */
3287    tcg_gen_shli_i64(val1, val1, 32);
3288    tcg_gen_div_i64(val1, val1, val2);
3289
3290    /* if quotient doesn't fit in 32 bits the result is undefined */
3291    tcg_gen_extrl_i64_i32(t, val1);
3292}
3293
3294static void do_diveu_i32(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b)
3295{
3296    TCGv_i64 val1, val2;
3297
3298    val1 = tcg_temp_new_i64();
3299    val2 = tcg_temp_new_i64();
3300
3301    tcg_gen_extu_i32_i64(val1, a);
3302    tcg_gen_extu_i32_i64(val2, b);
3303
3304    /* (a << 32)/b */
3305    tcg_gen_shli_i64(val1, val1, 32);
3306    tcg_gen_divu_i64(val1, val1, val2);
3307
3308    /* if quotient doesn't fit in 32 bits the result is undefined */
3309    tcg_gen_extrl_i64_i32(t, val1);
3310}
3311
3312DIVS32(do_divesw, do_dives_i32)
3313DIVU32(do_diveuw, do_diveu_i32)
3314
3315DIVS32(do_modsw, tcg_gen_rem_i32)
3316DIVU32(do_moduw, tcg_gen_remu_i32)
3317DIVS64(do_modsd, tcg_gen_rem_i64)
3318DIVU64(do_modud, tcg_gen_remu_i64)
3319
3320TRANS_FLAGS2(ISA310, VDIVESW, do_vdiv_vmod, MO_32, do_divesw, NULL)
3321TRANS_FLAGS2(ISA310, VDIVEUW, do_vdiv_vmod, MO_32, do_diveuw, NULL)
3322TRANS_FLAGS2(ISA310, VDIVESD, do_vx_helper, gen_helper_VDIVESD)
3323TRANS_FLAGS2(ISA310, VDIVEUD, do_vx_helper, gen_helper_VDIVEUD)
3324TRANS_FLAGS2(ISA310, VDIVESQ, do_vx_helper, gen_helper_VDIVESQ)
3325TRANS_FLAGS2(ISA310, VDIVEUQ, do_vx_helper, gen_helper_VDIVEUQ)
3326
3327TRANS_FLAGS2(ISA310, VMODSW, do_vdiv_vmod, MO_32, do_modsw , NULL)
3328TRANS_FLAGS2(ISA310, VMODUW, do_vdiv_vmod, MO_32, do_moduw, NULL)
3329TRANS_FLAGS2(ISA310, VMODSD, do_vdiv_vmod, MO_64, NULL, do_modsd)
3330TRANS_FLAGS2(ISA310, VMODUD, do_vdiv_vmod, MO_64, NULL, do_modud)
3331TRANS_FLAGS2(ISA310, VMODSQ, do_vx_helper, gen_helper_VMODSQ)
3332TRANS_FLAGS2(ISA310, VMODUQ, do_vx_helper, gen_helper_VMODUQ)
3333
3334#undef DIVS32
3335#undef DIVU32
3336#undef DIVS64
3337#undef DIVU64
3338
3339#undef GEN_VXFORM
3340#undef GEN_VXFORM_207
3341#undef GEN_VXFORM_DUAL
3342#undef GEN_VXRFORM_DUAL
3343#undef GEN_VXRFORM1
3344#undef GEN_VXRFORM
3345#undef GEN_VXFORM_VSPLTI
3346#undef GEN_VXFORM_NOA
3347#undef GEN_VXFORM_UIMM
3348#undef GEN_VAFORM_PAIRED
3349
3350#undef GEN_BCD2
3351