diff --git a/Utilities/JIT.cpp b/Utilities/JIT.cpp index eec7e0a812..6bda27ba4c 100644 --- a/Utilities/JIT.cpp +++ b/Utilities/JIT.cpp @@ -500,6 +500,25 @@ jit_compiler::~jit_compiler() { } +bool jit_compiler::has_ssse3() const +{ + if (m_cpu == "generic" || + m_cpu == "k8" || + m_cpu == "opteron" || + m_cpu == "athlon64" || + m_cpu == "athlon-fx" || + m_cpu == "k8-sse3" || + m_cpu == "opteron-sse3" || + m_cpu == "athlon64-sse3" || + m_cpu == "amdfam10" || + m_cpu == "barcelona") + { + return false; + } + + return true; +} + void jit_compiler::add(std::unique_ptr module, const std::string& path) { ObjectCache cache{path}; diff --git a/Utilities/JIT.h b/Utilities/JIT.h index 40d9af4ada..1d27c4fbc0 100644 --- a/Utilities/JIT.h +++ b/Utilities/JIT.h @@ -111,6 +111,9 @@ public: return *m_engine; } + // Test SSSE3 feature + bool has_ssse3() const; + // Add module (path to obj cache dir) void add(std::unique_ptr module, const std::string& path); diff --git a/rpcs3/Emu/Cell/SPURecompiler.cpp b/rpcs3/Emu/Cell/SPURecompiler.cpp index 844acabd10..4b7b0bb089 100644 --- a/rpcs3/Emu/Cell/SPURecompiler.cpp +++ b/rpcs3/Emu/Cell/SPURecompiler.cpp @@ -1089,7 +1089,29 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator value_t pshufb(T1 a, T2 b) { value_t result; - result.value = m_ir->CreateCall(get_intrinsic(llvm::Intrinsic::x86_ssse3_pshuf_b_128), {a.eval(m_ir), b.eval(m_ir)}); + + if (m_spurt->m_jit.has_ssse3()) + { + result.value = m_ir->CreateCall(get_intrinsic(llvm::Intrinsic::x86_ssse3_pshuf_b_128), {a.eval(m_ir), b.eval(m_ir)}); + } + else + { + const auto data0 = a.eval(m_ir); + const auto index = b.eval(m_ir); + const auto mask = m_ir->CreateAnd(index, 0xf); + const auto zero = llvm::ConstantInt::get(get_type(), 0u); + + result.value = zero; + + for (u32 i = 0; i < 16; i++) + { + const auto x = m_ir->CreateExtractElement(data0, m_ir->CreateExtractElement(mask, i)); + result.value = m_ir->CreateInsertElement(result.value, x, i); + } + + result.value = m_ir->CreateSelect(m_ir->CreateICmpSLT(index, zero), zero, result.value); + } + return result; }