diff --git a/rpcs3/Emu/CPU/CPUTranslator.h b/rpcs3/Emu/CPU/CPUTranslator.h index 4cb3aca770..b95ea4051b 100644 --- a/rpcs3/Emu/CPU/CPUTranslator.h +++ b/rpcs3/Emu/CPU/CPUTranslator.h @@ -3694,11 +3694,22 @@ public: // Infinite-precision shift left template > - auto inf_shl(T&& a, U&& b) + value_t inf_shl(T&& a, U&& b) { static constexpr u32 esz = llvm_value_t::esize; - return expr(select(b < esz, a << b, splat(0)), [](llvm::Value*& value, llvm::Module* _m) -> llvm_match_tuple +#ifdef ARCH_ARM64 + auto sh = eval(std::forward(b)); + auto k = get_known_bits(sh); + const auto max_shift = llvm::APInt(k.Zero.getBitWidth(), esz * 2 - 1); + + if ((k.Zero | max_shift).isAllOnes()) + { + return ushl(std::forward(a), sh); + } +#endif + + auto result = expr(select(b < esz, a << b, splat(0)), [](llvm::Value*& value, llvm::Module* _m) -> llvm_match_tuple { static const auto M = match(); @@ -3716,15 +3727,28 @@ public: value = nullptr; return {}; }); + + return eval(result); } // Infinite-precision logical shift right (unsigned) template > - auto inf_lshr(T&& a, U&& b) + value_t inf_lshr(T&& a, U&& b) { static constexpr u32 esz = llvm_value_t::esize; - return expr(select(b < esz, a >> b, splat(0)), [](llvm::Value*& value, llvm::Module* _m) -> llvm_match_tuple +#ifdef ARCH_ARM64 + auto sh = eval(std::forward(b)); + auto k = get_known_bits(sh); + const auto max_shift = llvm::APInt(k.Zero.getBitWidth(), esz * 2 - 1); + + if ((k.Zero | max_shift).isAllOnes()) + { + return ushl(std::forward(a), -sh); + } +#endif + + auto result = expr(select(b < esz, a >> b, splat(0)), [](llvm::Value*& value, llvm::Module* _m) -> llvm_match_tuple { static const auto M = match(); @@ -3742,6 +3766,8 @@ public: value = nullptr; return {}; }); + + return eval(result); } // Infinite-precision arithmetic shift right (signed) @@ -4021,6 +4047,18 @@ template return sve_mlal(llvm::Intrinsic::aarch64_sve_umlalt, acc, a, b); } + template > + value_t ushl(T1 a, T2 b) + { + value_t result; + + const auto data0 = a.eval(m_ir); + const auto data1 = b.eval(m_ir); + + result.value = m_ir->CreateCall(get_intrinsic(llvm::Intrinsic::aarch64_neon_ushl), {data0, data1}); + return result; + } + template auto addp(T1 a, T2 b) {