mirror of
https://github.com/RPCS3/rpcs3.git
synced 2026-07-09 17:25:18 -06:00
SPU LLVM: Use 128-bit SVE2 for FMS
This commit is contained in:
parent
9a2243bfcb
commit
4a92d96cf4
@ -207,6 +207,16 @@ void cpu_translator::initialize(llvm::LLVMContext& context, llvm::ExecutionEngin
|
||||
{
|
||||
m_use_dotprod = true;
|
||||
}
|
||||
|
||||
if (utils::has_sve() && utils::sve_length() == 128)
|
||||
{
|
||||
m_use_sve_128 = true;
|
||||
}
|
||||
|
||||
if (utils::has_sve2() && utils::sve_length() == 128)
|
||||
{
|
||||
m_use_sve2_128 = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -3123,6 +3123,10 @@ protected:
|
||||
|
||||
// Allow direct TBL2/TBX2 emission.
|
||||
bool m_use_tbl2 = true;
|
||||
|
||||
bool m_use_sve_128 = false;
|
||||
|
||||
bool m_use_sve2_128 = false;
|
||||
#else
|
||||
// Allow FMA
|
||||
bool m_use_fma = false;
|
||||
@ -3747,6 +3751,45 @@ template <typename T1, typename T2, typename T3>
|
||||
result.value = m_ir->CreateCall(get_intrinsic<u32[4]>(llvm::Intrinsic::aarch64_neon_umull), {data0, data1});
|
||||
return result;
|
||||
}
|
||||
|
||||
llvm::Value* to_sve_vector(llvm::Value* value)
|
||||
{
|
||||
if (llvm::isa<llvm::ScalableVectorType>(value->getType()))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
const auto fixed_type = llvm::cast<llvm::FixedVectorType>(value->getType());
|
||||
const auto scalable_type = llvm::ScalableVectorType::get(fixed_type->getElementType(), fixed_type->getNumElements());
|
||||
return m_ir->CreateInsertVector(scalable_type, llvm::UndefValue::get(scalable_type), value, m_ir->getInt64(0));
|
||||
}
|
||||
|
||||
llvm::Value* from_sve_vector(llvm::Value* value, llvm::FixedVectorType* fixed_type)
|
||||
{
|
||||
if (value->getType() == fixed_type)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
return m_ir->CreateExtractVector(fixed_type, value, m_ir->getInt64(0));
|
||||
}
|
||||
|
||||
llvm::Value* sve_ptrue(llvm::FixedVectorType* fixed_type)
|
||||
{
|
||||
const auto pred_type = llvm::ScalableVectorType::get(m_ir->getInt1Ty(), fixed_type->getNumElements());
|
||||
return m_ir->CreateIntrinsic(llvm::Intrinsic::aarch64_sve_ptrue, {pred_type}, {m_ir->getInt32(31)});
|
||||
}
|
||||
|
||||
llvm::Value* sve_fnmls(llvm::Value* acc, llvm::Value* lhs, llvm::Value* rhs)
|
||||
{
|
||||
const auto fixed_type = llvm::cast<llvm::FixedVectorType>(acc->getType());
|
||||
const auto vacc = to_sve_vector(acc);
|
||||
const auto vlhs = to_sve_vector(lhs);
|
||||
const auto vrhs = to_sve_vector(rhs);
|
||||
const auto result = m_ir->CreateIntrinsic(llvm::Intrinsic::aarch64_sve_fnmls, {vacc->getType()}, {sve_ptrue(fixed_type), vacc, vlhs, vrhs});
|
||||
|
||||
return from_sve_vector(result, fixed_type);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
auto addp(T1 a, T2 b)
|
||||
|
||||
@ -8220,10 +8220,26 @@ public:
|
||||
|
||||
if (g_cfg.core.spu_xfloat_accuracy == xfloat_accuracy::approximate)
|
||||
{
|
||||
#ifdef ARCH_ARM64
|
||||
if (m_use_sve2_128)
|
||||
{
|
||||
const auto ca = eval(clamp_smax(a));
|
||||
const auto cb = eval(clamp_smax(b));
|
||||
return value<f32[4]>(sve_fnmls(c.value, ca.value, cb.value));
|
||||
}
|
||||
#endif
|
||||
|
||||
return fma32x4(clamp_smax(a), clamp_smax(b), eval(-c));
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef ARCH_ARM64
|
||||
if (m_use_sve2_128)
|
||||
{
|
||||
return value<f32[4]>(sve_fnmls(c.value, a.value, b.value));
|
||||
}
|
||||
#endif
|
||||
|
||||
return fma32x4(a, b, eval(-c));
|
||||
}
|
||||
});
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
|
||||
#if defined(ARCH_ARM64)
|
||||
#include "Emu/CPU/Backends/AArch64/AArch64Common.h"
|
||||
#include <arm_sve.h>
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#include "windows.h"
|
||||
@ -461,6 +462,19 @@ bool utils::has_sve2()
|
||||
return g_value;
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define sve_func
|
||||
#else
|
||||
#define sve_func __attribute__((__target__("+sve")))
|
||||
#endif
|
||||
|
||||
// svcntb returns sve length in bytes, our function retuns length in bits
|
||||
sve_func int utils::sve_length()
|
||||
{
|
||||
static const int g_value = static_cast<int>(svcntb() * 8);
|
||||
return g_value;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
std::string utils::get_cpu_brand()
|
||||
|
||||
@ -64,6 +64,8 @@ namespace utils
|
||||
bool has_sve();
|
||||
|
||||
bool has_sve2();
|
||||
|
||||
int sve_length();
|
||||
#endif
|
||||
std::string get_cpu_brand();
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user