diff --git a/rpcs3/Emu/CPU/CPUTranslator.cpp b/rpcs3/Emu/CPU/CPUTranslator.cpp index 7a9b8fe24e..c77567be79 100644 --- a/rpcs3/Emu/CPU/CPUTranslator.cpp +++ b/rpcs3/Emu/CPU/CPUTranslator.cpp @@ -12,4 +12,120 @@ cpu_translator::cpu_translator(llvm::Module* module, bool is_be) } -#endif \ No newline at end of file +template <> +v128 cpu_translator::get_const_vector(llvm::Constant* c, u32 a, u32 b) +{ + const auto t = c->getType(); + + if (!t->isVectorTy()) + { + fmt::throw_exception("[0x%x, %u] Not a vector" HERE, a, b); + } + + if (uint sz = llvm::cast(t)->getBitWidth() - 128) + { + fmt::throw_exception("[0x%x, %u] Bad vector size: %u" HERE, a, b, sz + 128); + } + + const auto cv = llvm::dyn_cast(c); + + if (!cv) + { + if (llvm::isa(c)) + { + return {}; + } + + fmt::throw_exception("[0x%x, %u] Unexpected constant type" HERE, a, b); + } + + const auto sct = t->getScalarType(); + + v128 result; + + if (sct->isIntegerTy(8)) + { + for (u32 i = 0; i < 16; i++) + { + result._u8[i] = cv->getElementAsInteger(i); + } + } + else if (sct->isIntegerTy(16)) + { + for (u32 i = 0; i < 8; i++) + { + result._u16[i] = cv->getElementAsInteger(i); + } + } + else if (sct->isIntegerTy(32)) + { + for (u32 i = 0; i < 4; i++) + { + result._u32[i] = cv->getElementAsInteger(i); + } + } + else if (sct->isIntegerTy(64)) + { + for (u32 i = 0; i < 2; i++) + { + result._u64[i] = cv->getElementAsInteger(i); + } + } + else if (sct->isFloatTy()) + { + for (u32 i = 0; i < 4; i++) + { + result._f[i] = cv->getElementAsFloat(i); + } + } + else if (sct->isDoubleTy()) + { + for (u32 i = 0; i < 2; i++) + { + result._d[i] = cv->getElementAsDouble(i); + } + } + else + { + fmt::throw_exception("[0x%x, %u] Unexpected vector element type" HERE, a, b); + } + + return result; +} + +template <> +llvm::Constant* cpu_translator::make_const_vector(v128 v, llvm::Type* t) +{ + verify(HERE), t->isVectorTy() && llvm::cast(t)->getBitWidth() == 128; + + const auto sct = t->getScalarType(); + + if (sct->isIntegerTy(8)) + { + return llvm::ConstantDataVector::get(m_context, llvm::makeArrayRef((const u8*)v._bytes, 16)); + } + else if (sct->isIntegerTy(16)) + { + return llvm::ConstantDataVector::get(m_context, llvm::makeArrayRef((const u16*)v._bytes, 8)); + } + else if (sct->isIntegerTy(32)) + { + return llvm::ConstantDataVector::get(m_context, llvm::makeArrayRef((const u32*)v._bytes, 4)); + } + else if (sct->isIntegerTy(64)) + { + return llvm::ConstantDataVector::get(m_context, llvm::makeArrayRef((const u64*)v._bytes, 2)); + } + else if (sct->isFloatTy()) + { + return llvm::ConstantDataVector::get(m_context, llvm::makeArrayRef((const f32*)v._bytes, 4)); + } + else if (sct->isDoubleTy()) + { + return llvm::ConstantDataVector::get(m_context, llvm::makeArrayRef((const f64*)v._bytes, 2)); + } + + fmt::raw_error("No supported constant type" HERE); +} + +#endif diff --git a/rpcs3/Emu/CPU/CPUTranslator.h b/rpcs3/Emu/CPU/CPUTranslator.h index 1803e598e3..caa0c7b2fb 100644 --- a/rpcs3/Emu/CPU/CPUTranslator.h +++ b/rpcs3/Emu/CPU/CPUTranslator.h @@ -26,6 +26,14 @@ #include #include +enum class i2 : char +{ +}; + +enum class i4 : char +{ +}; + template struct llvm_value_t { @@ -77,6 +85,38 @@ struct llvm_value_t : llvm_value_t } }; +template <> +struct llvm_value_t : llvm_value_t +{ + using type = i2; + using base = llvm_value_t; + using base::base; + + static constexpr uint esize = 2; + static constexpr uint is_int = true; + + static llvm::Type* get_type(llvm::LLVMContext& context) + { + return llvm::Type::getIntNTy(context, 2); + } +}; + +template <> +struct llvm_value_t : llvm_value_t +{ + using type = i4; + using base = llvm_value_t; + using base::base; + + static constexpr uint esize = 4; + static constexpr uint is_int = true; + + static llvm::Type* get_type(llvm::LLVMContext& context) + { + return llvm::Type::getIntNTy(context, 4); + } +}; + template <> struct llvm_value_t : llvm_value_t { @@ -753,6 +793,8 @@ struct llvm_icmp_t UPred == llvm::ICmpInst::ICMP_ULT ? llvm::ICmpInst::ICMP_SLT : UPred == llvm::ICmpInst::ICMP_ULE ? llvm::ICmpInst::ICMP_SLE : UPred; + static_assert(llvm_value_t::is_sint || llvm_value_t::is_uint || UPred == llvm::ICmpInst::ICMP_EQ || UPred == llvm::ICmpInst::ICMP_NE, "llvm_eq_t<>: invalid type(II)"); + static inline llvm::Value* icmp(llvm::IRBuilder<>* ir, llvm::Value* lhs, llvm::Value* rhs) { return ir->CreateICmp(pred, lhs, rhs); @@ -1056,6 +1098,17 @@ public: return result; } + template + auto build(Args... args) + { + using value_type = std::remove_extent_t; + const value_type values[]{static_cast(args)...}; + static_assert(sizeof(T) / sizeof(value_type) == sizeof...(Args), "build: unexpected number of arguments"); + value_t result; + result.value = llvm::ConstantDataVector::get(m_context, values); + return result; + } + template llvm::Function* get_intrinsic(llvm::Intrinsic::ID id) { @@ -1102,6 +1155,12 @@ public: result.value = m_ir->CreateFCmp(FPred, a.eval(m_ir), b.eval(m_ir)); return result; } + + template + R get_const_vector(llvm::Constant*, u32 a, u32 b); + + template + llvm::Constant* make_const_vector(T, llvm::Type*); }; #endif