[SPU LLVM] Add KnownFPClass to clamping
Avoid clamping if the value is known not to be Inf/NaN (overflow). Includes a optional precalculated argument, which only calculates the known if it has not been done already.
This commit is contained in:
@@ -4278,6 +4278,13 @@ template <typename T1, typename T2, typename T3>
|
||||
{
|
||||
return llvm::KnownBits::makeConstant(llvm::APInt(sizeof(T) * 8, u64(value)));
|
||||
}
|
||||
|
||||
template <unsigned depth = llvm::MaxAnalysisRecursionDepth, typename T>
|
||||
llvm::KnownFPClass get_known_fp_class(T a, llvm::FPClassTest interested_classes)
|
||||
{
|
||||
static_assert(depth <= llvm::MaxAnalysisRecursionDepth, "Depth parameter can only decrease search. Default is max.");
|
||||
return llvm::computeKnownFPClass(a.eval(m_ir), m_module->getDataLayout(), interested_classes, llvm::MaxAnalysisRecursionDepth - depth);
|
||||
}
|
||||
|
||||
private:
|
||||
// Custom intrinsic table
|
||||
|
||||
@@ -7768,56 +7768,50 @@ public:
|
||||
set_vr(op.rt, -(a * b + c));
|
||||
}
|
||||
|
||||
bool is_input_positive(value_t<f32[4]> a)
|
||||
{
|
||||
if (auto [ok, v0, v1] = match_expr(a, match<f32[4]>() * match<f32[4]>()); ok && v0.eq(v1))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// clamping helpers
|
||||
value_t<f32[4]> clamp_positive_smax(value_t<f32[4]> v)
|
||||
value_t<f32[4]> clamp_positive_smax(value_t<f32[4]> v, std::optional<llvm::KnownFPClass> known_opt = std::nullopt)
|
||||
{
|
||||
return eval(bitcast<f32[4]>(min(bitcast<s32[4]>(v),splat<s32[4]>(0x7f7fffff))));
|
||||
constexpr auto overflow_classes = llvm::FPClassTest::fcNan | llvm::FPClassTest::fcPosInf;
|
||||
const auto known = known_opt.value_or(get_known_fp_class<3>(v, overflow_classes));
|
||||
|
||||
if (known.isKnownNever(overflow_classes))
|
||||
return v;
|
||||
|
||||
return eval(bitcast<f32[4]>(min(bitcast<s32[4]>(v), splat<s32[4]>(0x7f7fffff))));
|
||||
}
|
||||
|
||||
value_t<f32[4]> clamp_negative_smax(value_t<f32[4]> v)
|
||||
value_t<f32[4]> clamp_negative_smax(value_t<f32[4]> v, std::optional<llvm::KnownFPClass> known_opt = std::nullopt)
|
||||
{
|
||||
if (is_input_positive(v))
|
||||
{
|
||||
constexpr auto overflow_classes = llvm::FPClassTest::fcNan | llvm::FPClassTest::fcNegInf;
|
||||
const auto known = known_opt.value_or(get_known_fp_class<3>(v, overflow_classes));
|
||||
|
||||
if (known.isKnownNever(overflow_classes))
|
||||
return v;
|
||||
|
||||
return eval(bitcast<f32[4]>(min(bitcast<u32[4]>(v), splat<u32[4]>(0xff7fffff))));
|
||||
}
|
||||
|
||||
value_t<f32[4]> clamp_smax(value_t<f32[4]> v, std::optional<llvm::KnownFPClass> known_opt = std::nullopt)
|
||||
{
|
||||
const auto known = known_opt.value_or(get_known_fp_class<3>(v, llvm::FPClassTest::fcNan | llvm::FPClassTest::fcInf));
|
||||
|
||||
// Avoid pessimation when full clamping isn't needed
|
||||
if (m_use_avx512 && !(known.isKnownNeverNaN() && (known.isKnownNeverPosInfinity() || known.isKnownNeverNegInfinity())))
|
||||
{
|
||||
return eval(vrangeps(v, fsplat<f32[4]>(std::bit_cast<f32, u32>(0x7f7fffff)), 0x2, 0xff));
|
||||
}
|
||||
|
||||
return eval(bitcast<f32[4]>(min(bitcast<u32[4]>(v),splat<u32[4]>(0xff7fffff))));
|
||||
return eval(clamp_positive_smax(clamp_negative_smax(v, known), known));
|
||||
}
|
||||
|
||||
value_t<f32[4]> clamp_smax(value_t<f32[4]> v, u32 gpr = s_reg_max)
|
||||
value_t<f32[4]> clamp_smax(value_t<f32[4]> v, u32 gpr)
|
||||
{
|
||||
if (m_reduced_loop_info && gpr < s_reg_max && m_reduced_loop_info->is_gpr_not_NaN_hint(gpr))
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
if (m_use_avx512)
|
||||
{
|
||||
if (is_input_positive(v))
|
||||
{
|
||||
return eval(clamp_positive_smax(v));
|
||||
}
|
||||
|
||||
if (auto [ok, data] = get_const_vector(v.value, m_pos); ok)
|
||||
{
|
||||
// Avoid pessimation when input is constant
|
||||
return eval(clamp_positive_smax(clamp_negative_smax(v)));
|
||||
}
|
||||
|
||||
return eval(vrangeps(v, fsplat<f32[4]>(std::bit_cast<f32, u32>(0x7f7fffff)), 0x2, 0xff));
|
||||
}
|
||||
|
||||
return eval(clamp_positive_smax(clamp_negative_smax(v)));
|
||||
return clamp_smax(v);
|
||||
}
|
||||
|
||||
// Checks for postive and negative zero, or Denormal (treated as zero)
|
||||
|
||||
Reference in New Issue
Block a user