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