mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-26 12:42:41 +01:00
SPU LLVM: implement spu_re, spu_rsqrte
Improve matching with peek_through_bitcasts() helper. Implement erase_stores() helper.
This commit is contained in:
parent
aba332d4c4
commit
d28b0ba2fa
@ -7,6 +7,18 @@
|
||||
|
||||
llvm::LLVMContext g_llvm_ctx;
|
||||
|
||||
llvm::Value* peek_through_bitcasts(llvm::Value* arg)
|
||||
{
|
||||
llvm::CastInst* i;
|
||||
|
||||
while ((i = llvm::dyn_cast_or_null<llvm::CastInst>(arg)) && i->getOpcode() == llvm::Instruction::BitCast)
|
||||
{
|
||||
arg = i->getOperand(0);
|
||||
}
|
||||
|
||||
return arg;
|
||||
}
|
||||
|
||||
cpu_translator::cpu_translator(llvm::Module* _module, bool is_be)
|
||||
: m_context(g_llvm_ctx)
|
||||
, m_module(_module)
|
||||
@ -312,4 +324,27 @@ void cpu_translator::replace_intrinsics(llvm::Function& f)
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_translator::erase_stores(llvm::ArrayRef<llvm::Value*> args)
|
||||
{
|
||||
for (auto v : args)
|
||||
{
|
||||
for (auto it = v->use_begin(); it != v->use_end(); ++it)
|
||||
{
|
||||
llvm::Value* i = *it;
|
||||
llvm::CastInst* bci = nullptr;
|
||||
|
||||
// Walk through bitcasts
|
||||
while (i && (bci = llvm::dyn_cast<llvm::CastInst>(i)) && bci->getOpcode() == llvm::Instruction::BitCast)
|
||||
{
|
||||
i = *bci->use_begin();
|
||||
}
|
||||
|
||||
if (auto si = llvm::dyn_cast_or_null<llvm::StoreInst>(i))
|
||||
{
|
||||
si->eraseFromParent();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -427,6 +427,9 @@ using llvm_common_t = std::enable_if_t<(is_llvm_expr_of<T, Types>::ok && ...), t
|
||||
template <typename... Args>
|
||||
using llvm_match_tuple = decltype(std::tuple_cat(std::declval<llvm_expr_t<Args>&>().match(std::declval<llvm::Value*&>(), nullptr)...));
|
||||
|
||||
// Helper function
|
||||
llvm::Value* peek_through_bitcasts(llvm::Value*);
|
||||
|
||||
template <typename T, typename U = llvm_common_t<llvm_value_t<T>>>
|
||||
struct llvm_match_t
|
||||
{
|
||||
@ -442,7 +445,8 @@ struct llvm_match_t
|
||||
template <typename... Args>
|
||||
bool eq(const Args&... args) const
|
||||
{
|
||||
return value && ((value == args.value) && ...);
|
||||
llvm::Value* lhs = nullptr;
|
||||
return value && (lhs = peek_through_bitcasts(value)) && ((lhs == peek_through_bitcasts(args.value)) && ...);
|
||||
}
|
||||
|
||||
llvm::Value* eval(llvm::IRBuilder<>*) const
|
||||
@ -3491,6 +3495,15 @@ public:
|
||||
// Finalize processing custom intrinsics
|
||||
void replace_intrinsics(llvm::Function&);
|
||||
|
||||
// Erase store instructions of provided
|
||||
void erase_stores(llvm::ArrayRef<llvm::Value*> args);
|
||||
|
||||
template <typename... Args>
|
||||
void erase_stores(Args... args)
|
||||
{
|
||||
erase_stores({args.value...});
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
static auto pshufb(T&& a, U&& b)
|
||||
{
|
||||
|
@ -7778,13 +7778,10 @@ public:
|
||||
|
||||
bool is_input_positive(value_t<f32[4]> a)
|
||||
{
|
||||
if (auto [ok, v0, v1] = match_expr(a, match<f32[4]>() * match<f32[4]>()); ok)
|
||||
{
|
||||
if (v0.value == v1.value)
|
||||
if (auto [ok, v0, v1] = match_expr(a, match<f32[4]>() * match<f32[4]>()); ok && v0.eq(v1))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -8496,6 +8493,18 @@ public:
|
||||
return {"spu_fi", {std::forward<T>(a), std::forward<U>(b)}};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static llvm_calli<f32[4], T> spu_re(T&& a)
|
||||
{
|
||||
return {"spu_re", {std::forward<T>(a)}};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static llvm_calli<f32[4], T> spu_rsqrte(T&& a)
|
||||
{
|
||||
return {"spu_rsqrte", {std::forward<T>(a)}};
|
||||
}
|
||||
|
||||
void FI(spu_opcode_t op)
|
||||
{
|
||||
// TODO
|
||||
@ -8527,7 +8536,39 @@ public:
|
||||
return bitcast<f32[4]>((b & 0xff800000u) | (bitcast<u32[4]>(fpcast<f32[4]>(bnew)) & ~0xff800000u)); // Inject old sign and exponent
|
||||
});
|
||||
|
||||
set_vr(op.rt, fi(get_vr<f32[4]>(op.ra), get_vr<f32[4]>(op.rb)));
|
||||
register_intrinsic("spu_re", [&](llvm::CallInst* ci)
|
||||
{
|
||||
const auto a = value<f32[4]>(ci->getOperand(0));
|
||||
return fre(a);
|
||||
});
|
||||
|
||||
register_intrinsic("spu_rsqrte", [&](llvm::CallInst* ci)
|
||||
{
|
||||
const auto a = value<f32[4]>(ci->getOperand(0));
|
||||
return frsqe(fabs(a));
|
||||
});
|
||||
|
||||
const auto [a, b] = get_vrs<f32[4]>(op.ra, op.rb);
|
||||
|
||||
if (const auto [ok, mb] = match_expr(b, frest(match<f32[4]>())); ok && mb.eq(a))
|
||||
{
|
||||
erase_stores(b);
|
||||
set_vr(op.rt, spu_re(a));
|
||||
return;
|
||||
}
|
||||
|
||||
if (const auto [ok, mb] = match_expr(b, frsqest(match<f32[4]>())); ok && mb.eq(a))
|
||||
{
|
||||
erase_stores(b);
|
||||
set_vr(op.rt, spu_rsqrte(a));
|
||||
return;
|
||||
}
|
||||
|
||||
const auto r = eval(fi(a, b));
|
||||
if (!m_interp_magn)
|
||||
spu_log.todo("[%s:0x%05x] Unmatched spu_fi found", m_hash, m_pos);
|
||||
|
||||
set_vr(op.rt, r);
|
||||
}
|
||||
|
||||
void CFLTS(spu_opcode_t op)
|
||||
|
Loading…
Reference in New Issue
Block a user