SPU LLVM: Calculate FREST fraction LUT using vperm2dlculate FREST fraction using vperm2d for AVX512 (#18931)

The `FREST` instruction uses a scalar lookup-table loop to calculate the
mantissa. Given that it's only 32 elements, we can load it into two
512-bit vectors and treat them as the sources to the `vperm2d` shuffle
instruction. This allows it to be calculated in parallel, improving its
performance.
This commit is contained in:
Walter 2026-06-22 22:27:37 +10:00 committed by GitHub
parent c7478d6dcc
commit 927e2492ef
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 47 additions and 10 deletions

View File

@ -3670,6 +3670,23 @@ public:
#endif #endif
} }
template <typename T1, typename T2, typename T3>
value_t<u32[4]> vperm2d128From512(T1 a, T2 b, T3 c)
{
value_t<u32[4]> result;
value_t<u32[16]> perm512;
const auto data0 = a.eval(m_ir);
const auto index128 = b.eval(m_ir);
const auto data1 = c.eval(m_ir);
const auto index512 = m_ir->CreateInsertVector(get_type<u32[16]>(), llvm::UndefValue::get(get_type<u32[16]>()), index128, m_ir->getInt64(0));
perm512.value = m_ir->CreateCall(get_intrinsic(llvm::Intrinsic::x86_avx512_vpermi2var_d_512), {data0, index512, data1});
result.value = m_ir->CreateExtractVector(get_type<u32[4]>(), perm512.value, m_ir->getInt64(0));
return result;
}
template <typename T1, typename T2> template <typename T1, typename T2>
value_t<u8[16]> gf2p8affineqb(T1 a, T2 b, u8 c) value_t<u8[16]> gf2p8affineqb(T1 a, T2 b, u8 c)
{ {

View File

@ -7498,13 +7498,23 @@ public:
const auto a_sign = (a & splat<u32[4]>(0x80000000)); const auto a_sign = (a & splat<u32[4]>(0x80000000));
value_t<u32[4]> final_result = eval(splat<u32[4]>(0)); value_t<u32[4]> final_result = eval(splat<u32[4]>(0));
for (u32 i = 0; i < 4; i++) if (m_use_avx512)
{ {
const auto eval_fraction = eval(extract(a_fraction, i)); value_t<u32[16]> lo_lut;
value_t<u32[16]> hi_lut;
lo_lut.value = llvm::ConstantDataVector::get(m_context, llvm::ArrayRef(spu_frest_fraction_lut, 16));
hi_lut.value = llvm::ConstantDataVector::get(m_context, llvm::ArrayRef(spu_frest_fraction_lut + 16, 16));
value_t<u32> r_fraction = load_const<u32>(m_spu_frest_fraction_lut, eval_fraction); final_result = vperm2d128From512(lo_lut, a_fraction, hi_lut);
}
final_result = eval(insert(final_result, i, r_fraction)); else
{
for (u32 i = 0; i < 4; i++)
{
const auto eval_fraction = eval(extract(a_fraction, i));
value_t<u32> r_fraction = load_const<u32>(m_spu_frest_fraction_lut, eval_fraction);
final_result = eval(insert(final_result, i, r_fraction));
}
} }
//final_result = eval(select(final_result != (0), final_result, bitcast<u32[4]>(pshufb(splat<u8[16]>(0), bitcast<u8[16]>(final_result))))); //final_result = eval(select(final_result != (0), final_result, bitcast<u32[4]>(pshufb(splat<u8[16]>(0), bitcast<u8[16]>(final_result)))));
@ -8551,13 +8561,23 @@ public:
const auto a_sign = (a & splat<u32[4]>(0x80000000)); const auto a_sign = (a & splat<u32[4]>(0x80000000));
value_t<u32[4]> b = eval(splat<u32[4]>(0)); value_t<u32[4]> b = eval(splat<u32[4]>(0));
for (u32 i = 0; i < 4; i++) if (m_use_avx512)
{ {
const auto eval_fraction = eval(extract(a_fraction, i)); value_t<u32[16]> lo_lut;
value_t<u32[16]> hi_lut;
lo_lut.value = llvm::ConstantDataVector::get(m_context, llvm::ArrayRef(spu_frest_fraction_lut, 16));
hi_lut.value = llvm::ConstantDataVector::get(m_context, llvm::ArrayRef(spu_frest_fraction_lut + 16, 16));
value_t<u32> r_fraction = load_const<u32>(m_spu_frest_fraction_lut, eval_fraction); b = vperm2d128From512(lo_lut, a_fraction, hi_lut);
}
b = eval(insert(b, i, r_fraction)); else
{
for (u32 i = 0; i < 4; i++)
{
const auto eval_fraction = eval(extract(a_fraction, i));
value_t<u32> r_fraction = load_const<u32>(m_spu_frest_fraction_lut, eval_fraction);
b = eval(insert(b, i, r_fraction));
}
} }
b = eval(b | fix_exponent | a_sign); b = eval(b | fix_exponent | a_sign);