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