diff --git a/rpcs3/Emu/CPU/CPUTranslator.h b/rpcs3/Emu/CPU/CPUTranslator.h index b66162744f..18798793b3 100644 --- a/rpcs3/Emu/CPU/CPUTranslator.h +++ b/rpcs3/Emu/CPU/CPUTranslator.h @@ -685,6 +685,18 @@ struct llvm_add return std::tuple_cat(r1, r2); } } + + v1 = i->getOperand(0); + v2 = i->getOperand(1); + + // Argument order does not matter here, try when swapped + if (auto r1 = a1.match(v2, _m); v2) + { + if (auto r2 = a2.match(v1, _m); v1) + { + return std::tuple_cat(r1, r2); + } + } } value = nullptr; @@ -858,6 +870,18 @@ struct llvm_mul return std::tuple_cat(r1, r2); } } + + v1 = i->getOperand(0); + v2 = i->getOperand(1); + + // Argument order does not matter here, try when swapped + if (auto r1 = a1.match(v2, _m); v2) + { + if (auto r2 = a2.match(v1, _m); v1) + { + return std::tuple_cat(r1, r2); + } + } } value = nullptr; @@ -2239,6 +2263,18 @@ struct llvm_add_sat return std::tuple_cat(r1, r2); } } + + v1 = i->getOperand(0); + v2 = i->getOperand(1); + + // Argument order does not matter here, try when swapped + if (auto r1 = a1.match(v2, _m); v2) + { + if (auto r2 = a2.match(v1, _m); v1) + { + return std::tuple_cat(r1, r2); + } + } } value = nullptr; @@ -2868,6 +2904,22 @@ struct llvm_fmuladd } } } + + v1 = i->getOperand(0); + v2 = i->getOperand(1); + v3 = i->getOperand(2); + + // With multiplication args swapped + if (auto r1 = a1.match(v2, _m); v2) + { + if (auto r2 = a2.match(v1, _m); v1) + { + if (auto r3 = a3.match(v3, _m); v3) + { + return std::tuple_cat(r1, r2, r3); + } + } + } } value = nullptr; @@ -2884,6 +2936,18 @@ struct llvm_calli std::tuple...> a; + std::array order_equality_hint = []() + { + std::array r{}; + + for (usz i = 0; i < r.size(); i++) + { + r[i] = i; + } + + return r; + }(); + llvm::Value*(*c)(llvm::Value**, llvm::IRBuilder<>*){}; llvm::Value* eval(llvm::IRBuilder<>* ir) const @@ -2917,6 +2981,13 @@ struct llvm_calli return *this; } + template requires (sizeof...(Args) == sizeof...(A)) + llvm_calli& set_order_equality_hint(Args... args) + { + order_equality_hint = {static_cast(args)...}; + return *this; + } + llvm_match_tuple match(llvm::Value*& value, llvm::Module* _m) const { return match(value, _m, std::make_index_sequence()); @@ -2939,6 +3010,20 @@ struct llvm_calli { return std::tuple_cat(std::get(r)...); } + + if constexpr (sizeof...(A) >= 2) + { + if (order_equality_hint[0] == order_equality_hint[1]) + { + // Test if it works with the first pair swapped + ((v[I <= 1 ? I ^ 1 : I] = i->getOperand(I)), ...); + + if (((std::get(r) = std::get(a).match(v[I], _m), v[I]) && ...)) + { + return std::tuple_cat(std::get(r)...); + } + } + } } } diff --git a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp index 4a407cdb3d..ec5b0ee404 100644 --- a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp @@ -5582,7 +5582,7 @@ public: template static llvm_calli fm(T&& a, U&& b) { - return {"spu_fm", {std::forward(a), std::forward(b)}}; + return llvm_calli{"spu_fm", {std::forward(a), std::forward(b)}}.set_order_equality_hint(1, 1); } void FM(spu_opcode_t op) @@ -5933,7 +5933,7 @@ public: template static llvm_calli fnms(T&& a, U&& b, V&& c) { - return {"spu_fnms", {std::forward(a), std::forward(b), std::forward(c)}}; + return llvm_calli{"spu_fnms", {std::forward(a), std::forward(b), std::forward(c)}}.set_order_equality_hint(1, 1, 0); } void FNMS(spu_opcode_t op) @@ -5968,7 +5968,7 @@ public: template static llvm_calli fma(T&& a, U&& b, V&& c) { - return {"spu_fma", {std::forward(a), std::forward(b), std::forward(c)}}; + return llvm_calli{"spu_fma", {std::forward(a), std::forward(b), std::forward(c)}}.set_order_equality_hint(1, 1, 0); } template @@ -6217,7 +6217,7 @@ public: template static llvm_calli fms(T&& a, U&& b, V&& c) { - return {"spu_fms", {std::forward(a), std::forward(b), std::forward(c)}}; + return llvm_calli{"spu_fms", {std::forward(a), std::forward(b), std::forward(c)}}.set_order_equality_hint(1, 1, 0); } void FMS(spu_opcode_t op)