diff --git a/rpcs3/Emu/CPU/CPUTranslator.h b/rpcs3/Emu/CPU/CPUTranslator.h index 373ed8a24c..10961d84b9 100644 --- a/rpcs3/Emu/CPU/CPUTranslator.h +++ b/rpcs3/Emu/CPU/CPUTranslator.h @@ -2974,6 +2974,13 @@ public: return {}; } + template > + static auto match_expr(llvm::Value* v, llvm::Module* _m, T&& expr) + { + auto r = expr.match(v, _m); + return std::tuple_cat(std::make_tuple(v != nullptr), r); + } + template > auto match_expr(T&& arg, U&& expr) -> decltype(std::tuple_cat(std::make_tuple(false), expr.match(std::declval(), nullptr))) { @@ -2989,6 +2996,26 @@ public: return (pred(llvm_placeholder_t{}) || ...); } + template + struct expr_t + { + using type = llvm_common_t; + + T a; + F match; + + llvm::Value* eval(llvm::IRBuilder<>* ir) const + { + return a.eval(ir); + } + }; + + template + static auto expr(T&& expr, F matcher) + { + return expr_t{std::forward(expr), std::move(matcher)}; + } + template >::value>> static auto fcmp_ord(T&& cmp_expr) { @@ -3190,6 +3217,39 @@ public: return llvm_fmuladd{std::forward(a), std::forward(b), std::forward(c), m_use_fma}; } + // Absolute difference + template > + static auto absd(T&& a, U&& b) + { + return expr(max(a, b) - min(a, b), [](llvm::Value*& value, llvm::Module* _m) -> llvm_match_tuple + { + static const auto M = match(); + + if (auto [ok, _max, _min] = match_expr(value, _m, M - M); ok) + { + if (auto [ok1, a, b] = match_expr(_max.value, _m, max(M, M)); ok1 && !a.eq(b)) + { + if (auto [ok2, c, d] = match_expr(_min.value, _m, min(M, M)); ok2 && !c.eq(d)) + { + if ((a.eq(c) && b.eq(d)) || (a.eq(d) && b.eq(c))) + { + if (auto r1 = llvm_expr_t{}.match(a.value, _m); a.eq()) + { + if (auto r2 = llvm_expr_t{}.match(b.value, _m); b.eq()) + { + return std::tuple_cat(r1, r2); + } + } + } + } + } + } + + value = nullptr; + return {}; + }); + } + template llvm::Function* get_intrinsic(llvm::Intrinsic::ID id) { diff --git a/rpcs3/Emu/Cell/SPURecompiler.cpp b/rpcs3/Emu/Cell/SPURecompiler.cpp index 0c7c65e28d..19c5543f69 100644 --- a/rpcs3/Emu/Cell/SPURecompiler.cpp +++ b/rpcs3/Emu/Cell/SPURecompiler.cpp @@ -6417,7 +6417,7 @@ public: void ABSDB(spu_opcode_t op) { const auto [a, b] = get_vrs(op.ra, op.rb); - set_vr(op.rt, max(a, b) - min(a, b)); + set_vr(op.rt, absd(a, b)); } template