SPU LLVM: Use SVE2 XAR for constant rotates
This commit is contained in:
@@ -1319,11 +1319,96 @@ struct llvm_rol
|
|||||||
|
|
||||||
llvm_expr_t<A1> a1;
|
llvm_expr_t<A1> a1;
|
||||||
llvm_expr_t<A2> a2;
|
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_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;
|
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
|
llvm::Value* eval(llvm::IRBuilder<>* ir) const
|
||||||
{
|
{
|
||||||
const auto v1 = a1.eval(ir);
|
const auto v1 = a1.eval(ir);
|
||||||
@@ -1334,6 +1419,28 @@ struct llvm_rol
|
|||||||
return llvm_fshl<A1, A1, A2>::fold(ir, v1, v1, v2);
|
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});
|
return ir->CreateCall(llvm_fshl<A1, A1, A2>::get_fshl(ir), {v1, v1, v2});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3407,9 +3514,13 @@ public:
|
|||||||
|
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
requires llvm_rol<T, U>::is_ok
|
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)};
|
return llvm_rol<T, U>{std::forward<T>(a), std::forward<U>(b)};
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
|
|||||||
Reference in New Issue
Block a user