| 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 |