diff --git a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp index 9f4491b762..f976dd2d87 100644 --- a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp @@ -5783,6 +5783,45 @@ public: return zshuffle(std::forward(a), 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); } + static auto rotqby_reverse_base() + { + return build(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + } + + static auto rotqby_forward_base() + { + return build(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + } + + static auto rotqby_zero_base() + { +#ifdef ARCH_ARM64 + return rotqby_forward_base(); +#else + return build(112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127); +#endif + } + + static auto rotqby_reverse_zero_base() + { +#ifdef ARCH_ARM64 + return rotqby_reverse_base(); +#else + return build(127, 126, 125, 124, 123, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112); +#endif + } + + // For use in rotqby family of instructions only + template + auto pshufb_for_x86_and_tbl_for_aarch64(T&& a, U&& b) + { +#ifdef ARCH_ARM64 + return tbl(std::forward(a), std::forward(b)); +#else + return pshufb(std::forward(a), std::forward(b)); +#endif + } + template static llvm_calli rotqbybi(T&& a, U&& b) { @@ -5799,7 +5838,7 @@ public: // Data with swapped endian from a load instruction if (auto [ok, as] = match_expr(a, byteswap(match())); ok) { - const auto sc = build(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + const auto sc = rotqby_reverse_base(); const auto sh = sc + (splat_scalar(b) >> 3); if (m_use_avx512_icl) @@ -5807,9 +5846,9 @@ public: return eval(vpermb(as, sh)); } - return eval(pshufb(as, (sh & 0xf))); + return eval(pshufb_for_x86_and_tbl_for_aarch64(as, (sh & 0xf))); } - const auto sc = build(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + const auto sc = rotqby_forward_base(); const auto sh = sc - (splat_scalar(b) >> 3); if (m_use_avx512_icl) @@ -5817,7 +5856,7 @@ public: return eval(vpermb(a, sh)); } - return eval(pshufb(a, (sh & 0xf))); + return eval(pshufb_for_x86_and_tbl_for_aarch64(a, (sh & 0xf))); }); set_vr(op.rt, rotqbybi(get_vr(op.ra), get_vr(op.rb))); @@ -5845,15 +5884,15 @@ public: // Data with swapped endian from a load instruction if (auto [ok, as] = match_expr(a, byteswap(match())); ok) { - const auto sc = build(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + const auto sc = rotqby_reverse_base(); const auto sh = sc - splat_scalar(minusbx); - set_vr(op.rt, pshufb(as, sh)); + set_vr(op.rt, pshufb_for_x86_and_tbl_for_aarch64(as, sh)); return; } - const auto sc = build(112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127); + const auto sc = rotqby_zero_base(); const auto sh = sc + splat_scalar(minusbx); - set_vr(op.rt, pshufb(a, sh)); + set_vr(op.rt, pshufb_for_x86_and_tbl_for_aarch64(a, sh)); } void SHLQBYBI(spu_opcode_t op) @@ -5864,15 +5903,15 @@ public: // Data with swapped endian from a load instruction if (auto [ok, as] = match_expr(a, byteswap(match())); ok) { - const auto sc = build(127, 126, 125, 124, 123, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112); + const auto sc = rotqby_reverse_zero_base(); const auto sh = sc + (splat_scalar(b) >> 3); - set_vr(op.rt, pshufb(as, sh)); + set_vr(op.rt, pshufb_for_x86_and_tbl_for_aarch64(as, sh)); return; } - const auto sc = build(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + const auto sc = rotqby_forward_base(); const auto sh = sc - (splat_scalar(b) >> 3); - set_vr(op.rt, pshufb(a, sh)); + set_vr(op.rt, pshufb_for_x86_and_tbl_for_aarch64(a, sh)); } template @@ -6026,7 +6065,7 @@ public: // Data with swapped endian from a load instruction if (auto [ok, as] = match_expr(a, byteswap(match())); ok) { - const auto sc = build(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + const auto sc = rotqby_reverse_base(); const auto sh = eval(sc + splat_scalar(b)); if (m_use_avx512_icl) @@ -6035,11 +6074,11 @@ public: return; } - set_vr(op.rt, pshufb(as, (sh & 0xf))); + set_vr(op.rt, pshufb_for_x86_and_tbl_for_aarch64(as, (sh & 0xf))); return; } - const auto sc = build(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + const auto sc = rotqby_forward_base(); const auto sh = eval(sc - splat_scalar(b)); if (m_use_avx512_icl) @@ -6048,7 +6087,7 @@ public: return; } - set_vr(op.rt, pshufb(a, (sh & 0xf))); + set_vr(op.rt, pshufb_for_x86_and_tbl_for_aarch64(a, (sh & 0xf))); } void ROTQMBY(spu_opcode_t op) @@ -6067,15 +6106,15 @@ public: // Data with swapped endian from a load instruction if (auto [ok, as] = match_expr(a, byteswap(match())); ok) { - const auto sc = build(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + const auto sc = rotqby_reverse_base(); const auto sh = sc - (splat_scalar(minusbx) & 0x1f); - set_vr(op.rt, pshufb(as, sh)); + set_vr(op.rt, pshufb_for_x86_and_tbl_for_aarch64(as, sh)); return; } - const auto sc = build(112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127); + const auto sc = rotqby_zero_base(); const auto sh = sc + (splat_scalar(minusbx) & 0x1f); - set_vr(op.rt, pshufb(a, sh)); + set_vr(op.rt, pshufb_for_x86_and_tbl_for_aarch64(a, sh)); } void SHLQBY(spu_opcode_t op) @@ -6086,15 +6125,15 @@ public: // Data with swapped endian from a load instruction if (auto [ok, as] = match_expr(a, byteswap(match())); ok) { - const auto sc = build(127, 126, 125, 124, 123, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112); + const auto sc = rotqby_reverse_zero_base(); const auto sh = sc + (splat_scalar(b) & 0x1f); - set_vr(op.rt, pshufb(as, sh)); + set_vr(op.rt, pshufb_for_x86_and_tbl_for_aarch64(as, sh)); return; } - const auto sc = build(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + const auto sc = rotqby_forward_base(); const auto sh = sc - (splat_scalar(b) & 0x1f); - set_vr(op.rt, pshufb(a, sh)); + set_vr(op.rt, pshufb_for_x86_and_tbl_for_aarch64(a, sh)); } template @@ -6192,26 +6231,26 @@ public: void ROTQBYI(spu_opcode_t op) { const auto a = get_vr(op.ra); - const auto sc = build(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + const auto sc = rotqby_forward_base(); const auto sh = (sc - get_imm(op.i7, false)) & 0xf; - set_vr(op.rt, pshufb(a, sh)); + set_vr(op.rt, pshufb_for_x86_and_tbl_for_aarch64(a, sh)); } void ROTQMBYI(spu_opcode_t op) { const auto a = get_vr(op.ra); - const auto sc = build(112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127); + const auto sc = rotqby_zero_base(); const auto sh = sc + (-get_imm(op.i7, false) & 0x1f); - set_vr(op.rt, pshufb(a, sh)); + set_vr(op.rt, pshufb_for_x86_and_tbl_for_aarch64(a, sh)); } void SHLQBYI(spu_opcode_t op) { if (get_reg_raw(op.ra) && !op.i7) return set_reg_fixed(op.rt, get_reg_raw(op.ra), false); // For expressions matching const auto a = get_vr(op.ra); - const auto sc = build(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + const auto sc = rotqby_forward_base(); const auto sh = sc - (get_imm(op.i7, false) & 0x1f); - set_vr(op.rt, pshufb(a, sh)); + set_vr(op.rt, pshufb_for_x86_and_tbl_for_aarch64(a, sh)); } void CGT(spu_opcode_t op)