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