mirror of
https://github.com/RPCS3/rpcs3.git
synced 2026-07-10 10:04:47 -06:00
SPU LLVM: Use SVE2 XAR for constant rotates
This commit is contained in:
parent
2d1be09180
commit
60918be948
@ -1319,11 +1319,96 @@ struct llvm_rol
|
||||
|
||||
llvm_expr_t<A1> a1;
|
||||
llvm_expr_t<A2> a2;
|
||||
bool use_sve_xar = false;
|
||||
|
||||
static_assert(llvm_value_t<T>::is_sint || llvm_value_t<T>::is_uint, "llvm_rol<>: invalid type");
|
||||
|
||||
static constexpr bool is_ok = llvm_value_t<T>::is_sint || llvm_value_t<T>::is_uint;
|
||||
|
||||
#ifdef ARCH_ARM64
|
||||
static bool get_constant_splat(llvm::Value* value, u64& result)
|
||||
{
|
||||
if (const auto constant = llvm::dyn_cast<llvm::ConstantInt>(value))
|
||||
{
|
||||
result = constant->getZExtValue();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (llvm::isa<llvm::ConstantAggregateZero>(value))
|
||||
{
|
||||
result = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto vector_type = llvm::dyn_cast<llvm::FixedVectorType>(value->getType());
|
||||
|
||||
if (!vector_type)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto element_count = vector_type->getNumElements();
|
||||
const auto get_element = [&](u32 index) -> llvm::Constant*
|
||||
{
|
||||
if (const auto data = llvm::dyn_cast<llvm::ConstantDataVector>(value))
|
||||
{
|
||||
return data->getElementAsConstant(index);
|
||||
}
|
||||
|
||||
if (const auto vector = llvm::dyn_cast<llvm::ConstantVector>(value))
|
||||
{
|
||||
return vector->getAggregateElement(index);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
const auto first_element = llvm::dyn_cast_or_null<llvm::ConstantInt>(get_element(0));
|
||||
|
||||
if (!first_element)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
result = first_element->getZExtValue();
|
||||
|
||||
for (u32 i = 1; i < element_count; i++)
|
||||
{
|
||||
const auto element = llvm::dyn_cast_or_null<llvm::ConstantInt>(get_element(i));
|
||||
|
||||
if (!element || element->getZExtValue() != result)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static llvm::Value* to_sve_vector(llvm::IRBuilder<>* ir, 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 ir->CreateInsertVector(scalable_type, llvm::UndefValue::get(scalable_type), value, ir->getInt64(0));
|
||||
}
|
||||
|
||||
static llvm::Value* from_sve_vector(llvm::IRBuilder<>* ir, llvm::Value* value, llvm::FixedVectorType* fixed_type)
|
||||
{
|
||||
if (value->getType() == fixed_type)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
return ir->CreateExtractVector(fixed_type, value, ir->getInt64(0));
|
||||
}
|
||||
#endif
|
||||
|
||||
llvm::Value* eval(llvm::IRBuilder<>* ir) const
|
||||
{
|
||||
const auto v1 = a1.eval(ir);
|
||||
@ -1334,6 +1419,28 @@ struct llvm_rol
|
||||
return llvm_fshl<A1, A1, A2>::fold(ir, v1, v1, v2);
|
||||
}
|
||||
|
||||
#ifdef ARCH_ARM64
|
||||
u64 rotate = 0;
|
||||
|
||||
if (use_sve_xar && llvm::isa<llvm::FixedVectorType>(v1->getType()) && get_constant_splat(v2, rotate))
|
||||
{
|
||||
constexpr u64 element_size = llvm_value_t<T>::esize;
|
||||
const u32 rotate_right = static_cast<u32>((element_size - (rotate % element_size)) % element_size);
|
||||
|
||||
if (rotate_right == 0)
|
||||
{
|
||||
return v1;
|
||||
}
|
||||
|
||||
const auto fixed_type = llvm::cast<llvm::FixedVectorType>(v1->getType());
|
||||
const auto data = to_sve_vector(ir, v1);
|
||||
const auto zero = llvm::Constant::getNullValue(data->getType());
|
||||
const auto result = ir->CreateIntrinsic(llvm::Intrinsic::aarch64_sve_xar, {data->getType()}, {data, zero, ir->getInt32(rotate_right)});
|
||||
|
||||
return from_sve_vector(ir, result, fixed_type);
|
||||
}
|
||||
#endif
|
||||
|
||||
return ir->CreateCall(llvm_fshl<A1, A1, A2>::get_fshl(ir), {v1, v1, v2});
|
||||
}
|
||||
|
||||
@ -3407,9 +3514,13 @@ public:
|
||||
|
||||
template <typename T, typename U>
|
||||
requires llvm_rol<T, U>::is_ok
|
||||
static auto rol(T&& a, U&& b)
|
||||
auto rol(T&& a, U&& b)
|
||||
{
|
||||
#ifdef ARCH_ARM64
|
||||
return llvm_rol<T, U>{std::forward<T>(a), std::forward<U>(b), m_use_sve2_128};
|
||||
#else
|
||||
return llvm_rol<T, U>{std::forward<T>(a), std::forward<U>(b)};
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user