From 8b704588d0a63a36976cb1151e61babe464e269b Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Tue, 1 May 2018 13:21:45 +0300 Subject: [PATCH] Update cpu_translator --- rpcs3/Emu/CPU/CPUTranslator.cpp | 6 +- rpcs3/Emu/CPU/CPUTranslator.h | 246 ++++++++++++++++++++++++++++--- rpcs3/Emu/Cell/PPUTranslator.cpp | 5 +- 3 files changed, 232 insertions(+), 25 deletions(-) diff --git a/rpcs3/Emu/CPU/CPUTranslator.cpp b/rpcs3/Emu/CPU/CPUTranslator.cpp index 6ef7c521b6..7a9b8fe24e 100644 --- a/rpcs3/Emu/CPU/CPUTranslator.cpp +++ b/rpcs3/Emu/CPU/CPUTranslator.cpp @@ -2,8 +2,10 @@ #include "CPUTranslator.h" -cpu_translator::cpu_translator(llvm::LLVMContext& context, llvm::Module* module, bool is_be) - : m_context(context) +llvm::LLVMContext g_llvm_ctx; + +cpu_translator::cpu_translator(llvm::Module* module, bool is_be) + : m_context(g_llvm_ctx) , m_module(module) , m_is_be(is_be) { diff --git a/rpcs3/Emu/CPU/CPUTranslator.h b/rpcs3/Emu/CPU/CPUTranslator.h index 828197fb46..94efd18a8e 100644 --- a/rpcs3/Emu/CPU/CPUTranslator.h +++ b/rpcs3/Emu/CPU/CPUTranslator.h @@ -312,12 +312,34 @@ struct llvm_add_t } }; -template ().eval(0)), typename = std::enable_if_t::value>> +template ().eval(0)), typename = decltype(std::declval().eval(0)), typename = std::enable_if_t::value>> inline llvm_add_t operator +(T1 a1, T2 a2) { return {a1, a2}; } +template +struct llvm_add_const_t +{ + using type = T; + + A1 a1; + u64 c; + + static_assert(llvm_value_t::is_sint || llvm_value_t::is_uint, "llvm_add_const_t<>: invalid type"); + + llvm::Value* eval(llvm::IRBuilder<>* ir) const + { + return ir->CreateAdd(a1.eval(ir), llvm::ConstantInt::get(llvm_value_t::get_type(ir->getContext()), c, llvm_value_t::is_sint)); + } +}; + +template ().eval(0)), typename = std::enable_if_t::is_int>> +inline llvm_add_const_t operator +(T1 a1, u64 c) +{ + return {a1, c}; +} + template struct llvm_sub_t { @@ -345,12 +367,56 @@ struct llvm_sub_t } }; -template ().eval(0)), typename = std::enable_if_t::value>> +template ().eval(0)), typename = decltype(std::declval().eval(0)), typename = std::enable_if_t::value>> inline llvm_sub_t operator -(T1 a1, T2 a2) { return {a1, a2}; } +template +struct llvm_sub_const_t +{ + using type = T; + + A1 a1; + u64 c; + + static_assert(llvm_value_t::is_sint || llvm_value_t::is_uint, "llvm_sub_const_t<>: invalid type"); + + llvm::Value* eval(llvm::IRBuilder<>* ir) const + { + return ir->CreateSub(a1.eval(ir), llvm::ConstantInt::get(llvm_value_t::get_type(ir->getContext()), c, llvm_value_t::is_sint)); + } +}; + +template ().eval(0)), typename = std::enable_if_t::is_int>> +inline llvm_sub_const_t operator -(T1 a1, u64 c) +{ + return {a1, c}; +} + +template +struct llvm_const_sub_t +{ + using type = T; + + A1 a1; + u64 c; + + static_assert(llvm_value_t::is_sint || llvm_value_t::is_uint, "llvm_const_sub_t<>: invalid type"); + + llvm::Value* eval(llvm::IRBuilder<>* ir) const + { + return ir->CreateSub(llvm::ConstantInt::get(llvm_value_t::get_type(ir->getContext()), c, llvm_value_t::is_sint), a1.eval(ir)); + } +}; + +template ().eval(0)), typename = std::enable_if_t::is_int>> +inline llvm_const_sub_t operator -(u64 c, T1 a1) +{ + return {a1, c}; +} + template struct llvm_mul_t { @@ -378,7 +444,7 @@ struct llvm_mul_t } }; -template ().eval(0)), typename = std::enable_if_t::value>> +template ().eval(0)), typename = decltype(std::declval().eval(0)), typename = std::enable_if_t::value>> inline llvm_mul_t operator *(T1 a1, T2 a2) { return {a1, a2}; @@ -416,7 +482,7 @@ struct llvm_div_t } }; -template ().eval(0)), typename = std::enable_if_t::value>> +template ().eval(0)), typename = decltype(std::declval().eval(0)), typename = std::enable_if_t::value>> inline llvm_div_t operator /(T1 a1, T2 a2) { return {a1, a2}; @@ -447,7 +513,7 @@ struct llvm_neg_t } }; -template ().eval(0)), typename = std::enable_if_t::esize>> +template ().eval(0)), typename = std::enable_if_t<(llvm_value_t::esize > 1)>> inline llvm_neg_t operator -(T1 a1) { return {a1}; @@ -491,7 +557,7 @@ struct llvm_shl_t } }; -template ().eval(0)), typename = std::enable_if_t::value>> +template ().eval(0)), typename = decltype(std::declval().eval(0)), typename = std::enable_if_t::value>> inline llvm_shl_t operator <<(T1 a1, T2 a2) { return {a1, a2}; @@ -530,7 +596,7 @@ struct llvm_shr_t } }; -template ().eval(0)), typename = std::enable_if_t::value>> +template ().eval(0)), typename = decltype(std::declval().eval(0)), typename = std::enable_if_t::value>> inline llvm_shr_t operator >>(T1 a1, T2 a2) { return {a1, a2}; @@ -564,7 +630,7 @@ struct llvm_and_t } }; -template ().eval(0)), typename = std::enable_if_t::value>> +template ().eval(0)), typename = decltype(std::declval().eval(0)), typename = std::enable_if_t::value>> inline llvm_and_t operator &(T1 a1, T2 a2) { return {a1, a2}; @@ -598,7 +664,7 @@ struct llvm_or_t } }; -template ().eval(0)), typename = std::enable_if_t::value>> +template ().eval(0)), typename = decltype(std::declval().eval(0)), typename = std::enable_if_t::value>> inline llvm_or_t operator |(T1 a1, T2 a2) { return {a1, a2}; @@ -632,7 +698,7 @@ struct llvm_xor_t } }; -template ().eval(0)), typename = std::enable_if_t::value>> +template ().eval(0)), typename = decltype(std::declval().eval(0)), typename = std::enable_if_t::value>> inline llvm_xor_t operator ^(T1 a1, T2 a2) { return {a1, a2}; @@ -673,7 +739,7 @@ inline llvm_not_t operator ~(T1 a1) template struct llvm_icmp_t { - using type = std::conditional_t::is_vector, bool[llvm_value_t::is_vector], bool>; + using type = std::conditional_t::is_vector != 0, bool[llvm_value_t::is_vector], bool>; A1 a1; A2 a2; @@ -709,7 +775,7 @@ struct llvm_icmp_t } }; -template ().eval(0)), typename = std::enable_if_t::value>> +template ().eval(0)), typename = decltype(std::declval().eval(0)), typename = std::enable_if_t::value>> inline llvm_icmp_t operator ==(T1 a1, T2 a2) { return {a1, a2}; @@ -721,7 +787,7 @@ inline llvm_icmp_t o return {a1, llvm_int_t{a2}}; } -template ().eval(0)), typename = std::enable_if_t::value>> +template ().eval(0)), typename = decltype(std::declval().eval(0)), typename = std::enable_if_t::value>> inline llvm_icmp_t operator !=(T1 a1, T2 a2) { return {a1, a2}; @@ -733,7 +799,7 @@ inline llvm_icmp_t o return {a1, llvm_int_t{a2}}; } -template ().eval(0)), typename = std::enable_if_t::value>> +template ().eval(0)), typename = decltype(std::declval().eval(0)), typename = std::enable_if_t::value>> inline llvm_icmp_t operator >(T1 a1, T2 a2) { return {a1, a2}; @@ -745,7 +811,7 @@ inline llvm_icmp_t return {a1, llvm_int_t{a2}}; } -template ().eval(0)), typename = std::enable_if_t::value>> +template ().eval(0)), typename = decltype(std::declval().eval(0)), typename = std::enable_if_t::value>> inline llvm_icmp_t operator >=(T1 a1, T2 a2) { return {a1, a2}; @@ -757,7 +823,7 @@ inline llvm_icmp_t return {a1, llvm_int_t{a2}}; } -template ().eval(0)), typename = std::enable_if_t::value>> +template ().eval(0)), typename = decltype(std::declval().eval(0)), typename = std::enable_if_t::value>> inline llvm_icmp_t operator <(T1 a1, T2 a2) { return {a1, a2}; @@ -769,7 +835,7 @@ inline llvm_icmp_t return {a1, llvm_int_t{a2}}; } -template ().eval(0)), typename = std::enable_if_t::value>> +template ().eval(0)), typename = decltype(std::declval().eval(0)), typename = std::enable_if_t::value>> inline llvm_icmp_t operator <=(T1 a1, T2 a2) { return {a1, a2}; @@ -784,16 +850,16 @@ inline llvm_icmp_t class cpu_translator { protected: - cpu_translator(llvm::LLVMContext& context, llvm::Module* module, bool is_be); + cpu_translator(llvm::Module* module, bool is_be); // LLVM context - llvm::LLVMContext& m_context; + std::reference_wrapper m_context; // Module to which all generated code is output to - llvm::Module* const m_module; + llvm::Module* m_module; // Endianness, affects vector element numbering (TODO) - const bool m_is_be; + bool m_is_be; // IR builder llvm::IRBuilder<>* m_ir; @@ -889,6 +955,142 @@ public: { return (a >> 1) + (b >> 1) + ((a | b) & 1); } + + // Rotate left + template + static inline auto rol(T a, T b) + { + static constexpr u64 mask = value_t::esize - 1; + return a << (b & mask) | a >> (-b & mask); + } + + // Rotate left + template + static inline auto rol(T a, u64 b) + { + static constexpr u64 mask = value_t::esize - 1; + return a << (b & mask) | a >> ((0 - b) & mask); + } + + template + auto insert(T v, u64 i, E e) + { + value_t result; + result.value = m_ir->CreateInsertElement(v.eval(m_ir), e.eval(m_ir), i); + return result; + } + + template + auto extract(T v, u64 i) + { + typename value_t::base result; + result.value = m_ir->CreateExtractElement(v.eval(m_ir), i); + return result; + } + + template + auto splat(u64 c) + { + value_t result; + result.value = llvm::ConstantInt::get(result.get_type(m_context), c, result.is_sint); + return result; + } + + template + auto fsplat(f64 c) + { + value_t result; + result.value = llvm::ConstantFP::get(result.get_type(m_context), c); + return result; + } + + // Min + template + auto min(T a, T b) + { + T result; + result.value = m_ir->CreateSelect((a > b).eval(m_ir), b.eval(m_ir), a.eval(m_ir)); + return result; + } + + // Max + template + auto max(T a, T b) + { + T result; + result.value = m_ir->CreateSelect((a > b).eval(m_ir), a.eval(m_ir), b.eval(m_ir)); + return result; + } + + // Shuffle single vector using all zeros second vector of the same size + template + auto zshuffle(T1 a, Args... args) + { + static_assert(sizeof(T) / sizeof(std::remove_extent_t) == sizeof...(Args), "zshuffle: unexpected result type"); + const u32 values[]{static_cast(args)...}; + value_t result; + result.value = a.eval(m_ir); + result.value = m_ir->CreateShuffleVector(result.value, llvm::ConstantInt::get(result.value->getType(), 0), values); + return result; + } + + template + auto shuffle2(T1 a, T2 b, Args... args) + { + static_assert(sizeof(T) / sizeof(std::remove_extent_t) == sizeof...(Args), "shuffle2: unexpected result type"); + const u32 values[]{static_cast(args)...}; + value_t result; + result.value = a.eval(m_ir); + result.value = m_ir->CreateShuffleVector(result.value, b.eval(m_ir), values); + return result; + } + + template + llvm::Function* get_intrinsic(llvm::Intrinsic::ID id) + { + const auto module = m_ir->GetInsertBlock()->getParent()->getParent(); + return llvm::Intrinsic::getDeclaration(module, id, {get_type()...}); + } + + template + auto ctlz(T a) + { + value_t result; + result.value = m_ir->CreateCall(get_intrinsic(llvm::Intrinsic::ctlz), {a.eval(m_ir), m_ir->getFalse()}); + return result; + } + + template + auto ctpop(T a) + { + value_t result; + result.value = m_ir->CreateCall(get_intrinsic(llvm::Intrinsic::ctpop), {a.eval(m_ir)}); + return result; + } + + template + auto sqrt(T a) + { + value_t result; + result.value = m_ir->CreateCall(get_intrinsic(llvm::Intrinsic::sqrt), {a.eval(m_ir)}); + return result; + } + + template + auto fabs(T a) + { + value_t result; + result.value = m_ir->CreateCall(get_intrinsic(llvm::Intrinsic::fabs), {a.eval(m_ir)}); + return result; + } + + template + auto fcmp(T a, T b) + { + value_t::is_vector != 0, bool[llvm_value_t::is_vector], bool>> result; + result.value = m_ir->CreateFCmp(FPred, a.eval(m_ir), b.eval(m_ir)); + return result; + } }; -#endif \ No newline at end of file +#endif diff --git a/rpcs3/Emu/Cell/PPUTranslator.cpp b/rpcs3/Emu/Cell/PPUTranslator.cpp index 400ec15763..d7d3fbbf56 100644 --- a/rpcs3/Emu/Cell/PPUTranslator.cpp +++ b/rpcs3/Emu/Cell/PPUTranslator.cpp @@ -12,10 +12,13 @@ using namespace llvm; const ppu_decoder s_ppu_decoder; PPUTranslator::PPUTranslator(LLVMContext& context, Module* module, const ppu_module& info) - : cpu_translator(context, module, false) + : cpu_translator(module, false) , m_info(info) , m_pure_attr(AttributeSet::get(m_context, AttributeSet::FunctionIndex, {Attribute::NoUnwind, Attribute::ReadNone})) { + // Bind context + m_context = context; + // There is no weak linkage on JIT, so let's create variables with different names for each module part const u32 gsuffix = m_info.name.empty() ? info.funcs[0].addr : info.funcs[0].addr - m_info.segs[0].addr;