diff --git a/rpcs3/Emu/CPU/CPUTranslator.h b/rpcs3/Emu/CPU/CPUTranslator.h index 01949a52f6..e98677ddba 100644 --- a/rpcs3/Emu/CPU/CPUTranslator.h +++ b/rpcs3/Emu/CPU/CPUTranslator.h @@ -1751,6 +1751,55 @@ struct llvm_bitcast } }; +template > +struct llvm_fpcast +{ + using type = U; + + static constexpr auto opc = + llvm_value_t::is_sint ? llvm::Instruction::SIToFP : + llvm_value_t::is_sint ? llvm::Instruction::FPToSI : + llvm_value_t::is_int ? llvm::Instruction::UIToFP : + llvm_value_t::is_int ? llvm::Instruction::FPToUI : + llvm_value_t::esize > llvm_value_t::esize ? llvm::Instruction::FPTrunc : + llvm_value_t::esize < llvm_value_t::esize ? llvm::Instruction::FPExt : llvm::Instruction::BitCast; + + llvm_expr_t a1; + static_assert(llvm_value_t::is_float || llvm_value_t::is_float, "llvm_fpcast<>: invalid type(s)"); + static_assert(opc != llvm::Instruction::BitCast, "llvm_fpcast<>: possible cast to the same type"); + static_assert(llvm_value_t::is_vector == llvm_value_t::is_vector, "llvm_fpcast<>: vector element mismatch"); + + static constexpr bool is_ok = + (llvm_value_t::is_float || llvm_value_t::is_float) && opc != llvm::Instruction::BitCast && + llvm_value_t::is_vector == llvm_value_t::is_vector; + + llvm::Value* eval(llvm::IRBuilder<>* ir) const + { + return ir->CreateCast(opc, a1.eval(ir), llvm_value_t::get_type(ir->getContext())); + } + + llvm_match_tuple match(llvm::Value*& value) const + { + llvm::Value* v1 = {}; + + if (auto i = llvm::dyn_cast_or_null(value); i && i->getOpcode() == opc) + { + v1 = i->getOperand(0); + + if (llvm_value_t::get_type(v1->getContext()) == i->getDestTy()) + { + if (auto r1 = a1.match(v1); v1) + { + return r1; + } + } + } + + value = nullptr; + return {}; + } +}; + template > struct llvm_trunc { @@ -2890,6 +2939,12 @@ public: return llvm_bitcast{std::forward(expr), m_module}; } + template ::is_ok>> + static auto fpcast(T&& expr) + { + return llvm_fpcast{std::forward(expr)}; + } + template ::is_ok>> static auto trunc(T&& expr) {