mirror of
https://github.com/RPCS3/rpcs3.git
synced 2026-07-10 01:44:41 -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;
|
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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3123,6 +3123,10 @@ protected:
|
|||||||
|
|
||||||
// Allow direct TBL2/TBX2 emission.
|
// Allow direct TBL2/TBX2 emission.
|
||||||
bool m_use_tbl2 = true;
|
bool m_use_tbl2 = true;
|
||||||
|
|
||||||
|
bool m_use_sve_128 = false;
|
||||||
|
|
||||||
|
bool m_use_sve2_128 = false;
|
||||||
#else
|
#else
|
||||||
// Allow FMA
|
// Allow FMA
|
||||||
bool m_use_fma = false;
|
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});
|
result.value = m_ir->CreateCall(get_intrinsic<u32[4]>(llvm::Intrinsic::aarch64_neon_umull), {data0, data1});
|
||||||
return result;
|
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>
|
template <typename T1, typename T2>
|
||||||
auto addp(T1 a, T2 b)
|
auto addp(T1 a, T2 b)
|
||||||
|
|||||||
@ -8220,10 +8220,26 @@ public:
|
|||||||
|
|
||||||
if (g_cfg.core.spu_xfloat_accuracy == xfloat_accuracy::approximate)
|
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));
|
return fma32x4(clamp_smax(a), clamp_smax(b), eval(-c));
|
||||||
}
|
}
|
||||||
else
|
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));
|
return fma32x4(a, b, eval(-c));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#if defined(ARCH_ARM64)
|
#if defined(ARCH_ARM64)
|
||||||
#include "Emu/CPU/Backends/AArch64/AArch64Common.h"
|
#include "Emu/CPU/Backends/AArch64/AArch64Common.h"
|
||||||
|
#include <arm_sve.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
@ -461,6 +462,19 @@ bool utils::has_sve2()
|
|||||||
return g_value;
|
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
|
#endif
|
||||||
|
|
||||||
std::string utils::get_cpu_brand()
|
std::string utils::get_cpu_brand()
|
||||||
|
|||||||
@ -64,6 +64,8 @@ namespace utils
|
|||||||
bool has_sve();
|
bool has_sve();
|
||||||
|
|
||||||
bool has_sve2();
|
bool has_sve2();
|
||||||
|
|
||||||
|
int sve_length();
|
||||||
#endif
|
#endif
|
||||||
std::string get_cpu_brand();
|
std::string get_cpu_brand();
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user