https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/66522
>From 076ab2374d84c4112e0bf3fb11ecda2f5774785e Mon Sep 17 00:00:00 2001 From: Matt Arsenault <matthew.arsena...@amd.com> Date: Mon, 11 Sep 2023 10:56:40 +0300 Subject: [PATCH 1/6] ValueTracking: Merge fcmpImpliesClass and fcmpToClassTest --- llvm/include/llvm/Analysis/ValueTracking.h | 13 +- llvm/lib/Analysis/ValueTracking.cpp | 250 ++++++++++++--------- 2 files changed, 147 insertions(+), 116 deletions(-) diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h index c25dcad5e2242a7..ce2571cccf77cf1 100644 --- a/llvm/include/llvm/Analysis/ValueTracking.h +++ b/llvm/include/llvm/Analysis/ValueTracking.h @@ -214,8 +214,10 @@ std::pair<Value *, FPClassTest> fcmpToClassTest(CmpInst::Predicate Pred, const APFloat *ConstRHS, bool LookThroughSrc = true); -/// Compute the possible floating-point classes that \p LHS could be based on an -/// fcmp returning true. Returns { TestedValue, ClassesIfTrue, ClassesIfFalse } +/// Compute the possible floating-point classes that \p LHS could be based on +/// fcmp \Pred \p LHS, \p RHS. +/// +/// Returns { TestedValue, ClassesIfTrue, ClassesIfFalse } /// /// If the compare returns an exact class test, ClassesIfTrue == ~ClassesIfFalse /// @@ -230,10 +232,13 @@ std::pair<Value *, FPClassTest> fcmpToClassTest(CmpInst::Predicate Pred, /// std::tuple<Value *, FPClassTest, FPClassTest> fcmpImpliesClass(CmpInst::Predicate Pred, const Function &F, Value *LHS, - const APFloat *ConstRHS, bool LookThroughSrc = true); + Value *RHS, bool LookThroughSrc = true); std::tuple<Value *, FPClassTest, FPClassTest> fcmpImpliesClass(CmpInst::Predicate Pred, const Function &F, Value *LHS, - Value *RHS, bool LookThroughSrc = true); + FPClassTest RHS, bool LookThroughSrc = true); +std::tuple<Value *, FPClassTest, FPClassTest> +fcmpImpliesClass(CmpInst::Predicate Pred, const Function &F, Value *LHS, + const APFloat &RHS, bool LookThroughSrc = true); struct KnownFPClass { /// Floating-point classes the value could be one of. diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 1f09d912f7339f7..d1c453807cea5ee 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -3948,67 +3948,104 @@ std::pair<Value *, FPClassTest> llvm::fcmpToClassTest(FCmpInst::Predicate Pred, std::pair<Value *, FPClassTest> llvm::fcmpToClassTest(FCmpInst::Predicate Pred, const Function &F, Value *LHS, const APFloat *ConstRHS, bool LookThroughSrc) { + + auto [Src, ClassIfTrue, ClassIfFalse] = + fcmpImpliesClass(Pred, F, LHS, *ConstRHS, LookThroughSrc); + if (Src && ClassIfTrue == ~ClassIfFalse) + return {Src, ClassIfTrue}; + return {nullptr, fcAllFlags}; +} + +/// Return the return value for fcmpImpliesClass for a compare that produces an +/// exact class test. +static std::tuple<Value *, FPClassTest, FPClassTest> exactClass(Value *V, + FPClassTest M) { + return {V, M, ~M}; +} + +std::tuple<Value *, FPClassTest, FPClassTest> +llvm::fcmpImpliesClass(CmpInst::Predicate Pred, const Function &F, Value *LHS, + FPClassTest RHSClass, bool LookThroughSrc) { + assert(RHSClass != fcNone); + + const FPClassTest OrigClass = RHSClass; + + Value *Src = LHS; + const bool IsNegativeRHS = (RHSClass & fcNegative) == RHSClass; + const bool IsPositiveRHS = (RHSClass & fcPositive) == RHSClass; + const bool IsNaN = (RHSClass & ~fcNan) == fcNone; + + if (IsNaN) { + // fcmp o__ x, nan -> false + // fcmp u__ x, nan -> true + return exactClass(Src, CmpInst::isOrdered(Pred) ? fcNone : fcAllFlags); + } + // fcmp ord x, zero|normal|subnormal|inf -> ~fcNan - if (Pred == FCmpInst::FCMP_ORD && !ConstRHS->isNaN()) - return {LHS, ~fcNan}; + if (Pred == FCmpInst::FCMP_ORD) + return {Src, ~fcNan, fcNan}; // fcmp uno x, zero|normal|subnormal|inf -> fcNan - if (Pred == FCmpInst::FCMP_UNO && !ConstRHS->isNaN()) - return {LHS, fcNan}; + if (Pred == FCmpInst::FCMP_UNO) + return {Src, fcNan, ~fcNan}; + + const bool IsFabs = LookThroughSrc && match(LHS, m_FAbs(m_Value(Src))); + if (IsFabs) + RHSClass = llvm::inverse_fabs(RHSClass); - if (ConstRHS->isZero()) { + const bool IsZero = (OrigClass & fcZero) == OrigClass; + if (IsZero) { // Compares with fcNone are only exactly equal to fcZero if input denormals // are not flushed. // TODO: Handle DAZ by expanding masks to cover subnormal cases. if (Pred != FCmpInst::FCMP_ORD && Pred != FCmpInst::FCMP_UNO && !inputDenormalIsIEEE(F, LHS->getType())) - return {nullptr, fcAllFlags}; + return {nullptr, fcAllFlags, fcAllFlags}; switch (Pred) { case FCmpInst::FCMP_OEQ: // Match x == 0.0 - return {LHS, fcZero}; + return exactClass(Src, fcZero); case FCmpInst::FCMP_UEQ: // Match isnan(x) || (x == 0.0) - return {LHS, fcZero | fcNan}; + return exactClass(Src, fcZero | fcNan); case FCmpInst::FCMP_UNE: // Match (x != 0.0) - return {LHS, ~fcZero}; + return exactClass(Src, ~fcZero); case FCmpInst::FCMP_ONE: // Match !isnan(x) && x != 0.0 - return {LHS, ~fcNan & ~fcZero}; + return exactClass(Src, ~fcNan & ~fcZero); case FCmpInst::FCMP_ORD: // Canonical form of ord/uno is with a zero. We could also handle // non-canonical other non-NaN constants or LHS == RHS. - return {LHS, ~fcNan}; + return exactClass(Src, ~fcNan); case FCmpInst::FCMP_UNO: - return {LHS, fcNan}; + return exactClass(Src, fcNan); case FCmpInst::FCMP_OGT: // x > 0 - return {LHS, fcPosSubnormal | fcPosNormal | fcPosInf}; + return exactClass(Src, fcPosSubnormal | fcPosNormal | fcPosInf); case FCmpInst::FCMP_UGT: // isnan(x) || x > 0 - return {LHS, fcPosSubnormal | fcPosNormal | fcPosInf | fcNan}; + return exactClass(Src, fcPosSubnormal | fcPosNormal | fcPosInf | fcNan); case FCmpInst::FCMP_OGE: // x >= 0 - return {LHS, fcPositive | fcNegZero}; + return exactClass(Src, fcPositive | fcNegZero); case FCmpInst::FCMP_UGE: // isnan(x) || x >= 0 - return {LHS, fcPositive | fcNegZero | fcNan}; + return exactClass(Src, fcPositive | fcNegZero | fcNan); case FCmpInst::FCMP_OLT: // x < 0 - return {LHS, fcNegSubnormal | fcNegNormal | fcNegInf}; + return exactClass(Src, fcNegSubnormal | fcNegNormal | fcNegInf); case FCmpInst::FCMP_ULT: // isnan(x) || x < 0 - return {LHS, fcNegSubnormal | fcNegNormal | fcNegInf | fcNan}; + return exactClass(Src, fcNegSubnormal | fcNegNormal | fcNegInf | fcNan); case FCmpInst::FCMP_OLE: // x <= 0 - return {LHS, fcNegative | fcPosZero}; + return exactClass(Src, fcNegative | fcPosZero); case FCmpInst::FCMP_ULE: // isnan(x) || x <= 0 - return {LHS, fcNegative | fcPosZero | fcNan}; + return exactClass(Src, fcNegative | fcPosZero | fcNan); default: break; } - return {nullptr, fcAllFlags}; + return {nullptr, fcAllFlags, fcAllFlags}; } - Value *Src = LHS; - const bool IsFabs = LookThroughSrc && match(LHS, m_FAbs(m_Value(Src))); + const bool IsDenormalRHS = (OrigClass & fcSubnormal) == OrigClass; - // Compute the test mask that would return true for the ordered comparisons. - FPClassTest Mask; + const bool IsInf = (OrigClass & fcInf) == OrigClass; + if (IsInf) { + FPClassTest Mask = fcAllFlags; - if (ConstRHS->isInfinity()) { switch (Pred) { case FCmpInst::FCMP_OEQ: case FCmpInst::FCMP_UNE: { @@ -4023,8 +4060,7 @@ llvm::fcmpToClassTest(FCmpInst::Predicate Pred, const Function &F, Value *LHS, // fcmp une fabs(x), +inf -> is_fpclass x, ~fcInf // fcmp une x, -inf -> is_fpclass x, ~fcNegInf // fcmp une fabs(x), -inf -> is_fpclass x, fcAllFlags -> true - - if (ConstRHS->isNegative()) { + if (IsNegativeRHS) { Mask = fcNegInf; if (IsFabs) Mask = fcNone; @@ -4033,7 +4069,6 @@ llvm::fcmpToClassTest(FCmpInst::Predicate Pred, const Function &F, Value *LHS, if (IsFabs) Mask |= fcNegInf; } - break; } case FCmpInst::FCMP_ONE: @@ -4048,7 +4083,7 @@ llvm::fcmpToClassTest(FCmpInst::Predicate Pred, const Function &F, Value *LHS, // fcmp ueq (fabs x), +inf -> is_fpclass x, fcInf|fcNan // fcmp ueq x, -inf -> is_fpclass x, fcNegInf|fcNan // fcmp ueq fabs(x), -inf -> is_fpclass x, fcNan - if (ConstRHS->isNegative()) { + if (IsNegativeRHS) { Mask = ~fcNegInf & ~fcNan; if (IsFabs) Mask = ~fcNan; @@ -4062,7 +4097,7 @@ llvm::fcmpToClassTest(FCmpInst::Predicate Pred, const Function &F, Value *LHS, } case FCmpInst::FCMP_OLT: case FCmpInst::FCMP_UGE: { - if (ConstRHS->isNegative()) { + if (IsNegativeRHS) { // No value is ordered and less than negative infinity. // All values are unordered with or at least negative infinity. // fcmp olt x, -inf -> false @@ -4082,7 +4117,7 @@ llvm::fcmpToClassTest(FCmpInst::Predicate Pred, const Function &F, Value *LHS, } case FCmpInst::FCMP_OGE: case FCmpInst::FCMP_ULT: { - if (ConstRHS->isNegative()) { + if (IsNegativeRHS) { // fcmp oge x, -inf -> ~fcNan // fcmp oge fabs(x), -inf -> ~fcNan // fcmp ult x, -inf -> fcNan @@ -4102,7 +4137,7 @@ llvm::fcmpToClassTest(FCmpInst::Predicate Pred, const Function &F, Value *LHS, } case FCmpInst::FCMP_OGT: case FCmpInst::FCMP_ULE: { - if (ConstRHS->isNegative()) { + if (IsNegativeRHS) { // fcmp ogt x, -inf -> fcmp one x, -inf // fcmp ogt fabs(x), -inf -> fcmp ord x, x // fcmp ule x, -inf -> fcmp ueq x, -inf @@ -4116,83 +4151,15 @@ llvm::fcmpToClassTest(FCmpInst::Predicate Pred, const Function &F, Value *LHS, break; } default: - return {nullptr, fcAllFlags}; - } - } else if (ConstRHS->isSmallestNormalized() && !ConstRHS->isNegative()) { - // Match pattern that's used in __builtin_isnormal. - switch (Pred) { - case FCmpInst::FCMP_OLT: - case FCmpInst::FCMP_UGE: { - // fcmp olt x, smallest_normal -> fcNegInf|fcNegNormal|fcSubnormal|fcZero - // fcmp olt fabs(x), smallest_normal -> fcSubnormal|fcZero - // fcmp uge x, smallest_normal -> fcNan|fcPosNormal|fcPosInf - // fcmp uge fabs(x), smallest_normal -> ~(fcSubnormal|fcZero) - Mask = fcZero | fcSubnormal; - if (!IsFabs) - Mask |= fcNegNormal | fcNegInf; - - break; - } - case FCmpInst::FCMP_OGE: - case FCmpInst::FCMP_ULT: { - // fcmp oge x, smallest_normal -> fcPosNormal | fcPosInf - // fcmp oge fabs(x), smallest_normal -> fcInf | fcNormal - // fcmp ult x, smallest_normal -> ~(fcPosNormal | fcPosInf) - // fcmp ult fabs(x), smallest_normal -> ~(fcInf | fcNormal) - Mask = fcPosInf | fcPosNormal; - if (IsFabs) - Mask |= fcNegInf | fcNegNormal; - break; - } - default: - return {nullptr, fcAllFlags}; + return {nullptr, fcAllFlags, fcAllFlags}; } - } else if (ConstRHS->isNaN()) { - // fcmp o__ x, nan -> false - // fcmp u__ x, nan -> true - Mask = fcNone; - } else - return {nullptr, fcAllFlags}; - // Invert the comparison for the unordered cases. - if (FCmpInst::isUnordered(Pred)) - Mask = ~Mask; + // Invert the comparison for the unordered cases. + if (FCmpInst::isUnordered(Pred)) + Mask = ~Mask; - return {Src, Mask}; -} - -std::tuple<Value *, FPClassTest, FPClassTest> -llvm::fcmpImpliesClass(CmpInst::Predicate Pred, const Function &F, Value *LHS, - const APFloat *ConstRHS, bool LookThroughSrc) { - auto [Val, ClassMask] = - fcmpToClassTest(Pred, F, LHS, ConstRHS, LookThroughSrc); - if (Val) - return {Val, ClassMask, ~ClassMask}; - - FPClassTest RHSClass = ConstRHS->classify(); - - // If we see a zero here, we are using dynamic denormal-fp-math, and can't - // treat comparisons to 0 as an exact class test. - // - // TODO: We could do better and still recognize non-equality cases. - if (RHSClass == fcPosZero || RHSClass == fcNegZero) - return {nullptr, fcAllFlags, fcAllFlags}; - - assert((RHSClass == fcPosNormal || RHSClass == fcNegNormal || - RHSClass == fcPosSubnormal || RHSClass == fcNegSubnormal) && - "should have been recognized as an exact class test"); - - const bool IsNegativeRHS = (RHSClass & fcNegative) == RHSClass; - const bool IsPositiveRHS = (RHSClass & fcPositive) == RHSClass; - - assert(IsNegativeRHS == ConstRHS->isNegative()); - assert(IsPositiveRHS == !ConstRHS->isNegative()); - - Value *Src = LHS; - const bool IsFabs = LookThroughSrc && match(LHS, m_FAbs(m_Value(Src))); - - if (IsFabs) - RHSClass = llvm::inverse_fabs(RHSClass); + return exactClass(Src, Mask); + } if (Pred == FCmpInst::FCMP_OEQ) return {Src, RHSClass, fcAllFlags}; @@ -4208,6 +4175,12 @@ llvm::fcmpImpliesClass(CmpInst::Predicate Pred, const Function &F, Value *LHS, if (Pred == FCmpInst::FCMP_UNE) return {Src, fcAllFlags, RHSClass}; + assert((RHSClass == fcNone || RHSClass == fcPosNormal || + RHSClass == fcNegNormal || RHSClass == fcNormal || + RHSClass == fcPosSubnormal || RHSClass == fcNegSubnormal || + RHSClass == fcSubnormal) && + "should have been recognized as an exact class test"); + if (IsNegativeRHS) { // TODO: Handle fneg(fabs) if (IsFabs) { @@ -4238,7 +4211,7 @@ llvm::fcmpImpliesClass(CmpInst::Predicate Pred, const Function &F, Value *LHS, FPClassTest ClassesLE = fcNegInf | fcNegNormal; FPClassTest ClassesGE = fcPositive | fcNegZero | fcNegSubnormal; - if (ConstRHS->isDenormal()) + if (IsDenormalRHS) ClassesLE |= fcNegSubnormal; else ClassesGE |= fcNegNormal; @@ -4262,7 +4235,7 @@ llvm::fcmpImpliesClass(CmpInst::Predicate Pred, const Function &F, Value *LHS, } else if (IsPositiveRHS) { FPClassTest ClassesGE = fcPosNormal | fcPosInf; FPClassTest ClassesLE = fcNegative | fcPosZero | fcPosNormal; - if (ConstRHS->isDenormal()) + if (IsDenormalRHS) ClassesGE |= fcPosNormal; else ClassesLE |= fcPosSubnormal; @@ -4293,13 +4266,65 @@ llvm::fcmpImpliesClass(CmpInst::Predicate Pred, const Function &F, Value *LHS, return {nullptr, fcAllFlags, fcAllFlags}; } +std::tuple<Value *, FPClassTest, FPClassTest> +llvm::fcmpImpliesClass(CmpInst::Predicate Pred, const Function &F, Value *LHS, + const APFloat &ConstRHS, bool LookThroughSrc) { + // We can refine checks against smallest normal / largest denormal to an + // exact class test. + if (!ConstRHS.isNegative() && ConstRHS.isSmallestNormalized()) { + Value *Src = LHS; + const bool IsFabs = LookThroughSrc && match(LHS, m_FAbs(m_Value(Src))); + + FPClassTest Mask; + // Match pattern that's used in __builtin_isnormal. + switch (Pred) { + case FCmpInst::FCMP_OLT: + case FCmpInst::FCMP_UGE: { + // fcmp olt x, smallest_normal -> fcNegInf|fcNegNormal|fcSubnormal|fcZero + // fcmp olt fabs(x), smallest_normal -> fcSubnormal|fcZero + // fcmp uge x, smallest_normal -> fcNan|fcPosNormal|fcPosInf + // fcmp uge fabs(x), smallest_normal -> ~(fcSubnormal|fcZero) + Mask = fcZero | fcSubnormal; + if (!IsFabs) + Mask |= fcNegNormal | fcNegInf; + + break; + } + case FCmpInst::FCMP_OGE: + case FCmpInst::FCMP_ULT: { + // fcmp oge x, smallest_normal -> fcPosNormal | fcPosInf + // fcmp oge fabs(x), smallest_normal -> fcInf | fcNormal + // fcmp ult x, smallest_normal -> ~(fcPosNormal | fcPosInf) + // fcmp ult fabs(x), smallest_normal -> ~(fcInf | fcNormal) + Mask = fcPosInf | fcPosNormal; + if (IsFabs) + Mask |= fcNegInf | fcNegNormal; + break; + } + default: + return fcmpImpliesClass(Pred, F, LHS, ConstRHS.classify(), + LookThroughSrc); + } + + // Invert the comparison for the unordered cases. + if (FCmpInst::isUnordered(Pred)) + Mask = ~Mask; + + return exactClass(Src, Mask); + } + + return fcmpImpliesClass(Pred, F, LHS, ConstRHS.classify(), LookThroughSrc); +} + std::tuple<Value *, FPClassTest, FPClassTest> llvm::fcmpImpliesClass(CmpInst::Predicate Pred, const Function &F, Value *LHS, Value *RHS, bool LookThroughSrc) { const APFloat *ConstRHS; if (!match(RHS, m_APFloatAllowUndef(ConstRHS))) return {nullptr, fcAllFlags, fcNone}; - return fcmpImpliesClass(Pred, F, LHS, ConstRHS, LookThroughSrc); + + // TODO: Just call computeKnownFPClass for RHS to handle non-constants. + return fcmpImpliesClass(Pred, F, LHS, *ConstRHS, LookThroughSrc); } static FPClassTest computeKnownFPClassFromAssumes(const Value *V, @@ -4330,14 +4355,15 @@ static FPClassTest computeKnownFPClassFromAssumes(const Value *V, if (match(RHS, m_APFloat(CRHS))) { // First see if we can fold in fabs/fneg into the test. auto [CmpVal, MaskIfTrue, MaskIfFalse] = - fcmpImpliesClass(Pred, *F, LHS, CRHS, true); + fcmpImpliesClass(Pred, *F, LHS, *CRHS, true); if (CmpVal == V) KnownFromAssume &= MaskIfTrue; + else { // Try again without the lookthrough if we found a different source // value. auto [CmpVal, MaskIfTrue, MaskIfFalse] = - fcmpImpliesClass(Pred, *F, LHS, CRHS, false); + fcmpImpliesClass(Pred, *F, LHS, *CRHS, false); if (CmpVal == V) KnownFromAssume &= MaskIfTrue; } >From 0a7cae3b429ee62340bb075c4933147f74bd7045 Mon Sep 17 00:00:00 2001 From: Matt Arsenault <matthew.arsena...@amd.com> Date: Fri, 26 Jan 2024 13:12:41 +0530 Subject: [PATCH 2/6] Fix resolve --- llvm/include/llvm/Analysis/ValueTracking.h | 2 +- llvm/lib/Analysis/ValueTracking.cpp | 18 ++-------- .../Attributor/nofpclass-implied-by-fcmp.ll | 34 +++++++++---------- 3 files changed, 21 insertions(+), 33 deletions(-) diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h index be2d7402868eca9..0dd691bb928592c 100644 --- a/llvm/include/llvm/Analysis/ValueTracking.h +++ b/llvm/include/llvm/Analysis/ValueTracking.h @@ -217,7 +217,7 @@ std::pair<Value *, FPClassTest> fcmpToClassTest(CmpInst::Predicate Pred, /// Compute the possible floating-point classes that \p LHS could be based on /// fcmp \Pred \p LHS, \p RHS. /// -/// Returns { TestedValue, ClassesIfTrue, ClassesIfFalse } +/// \returns { TestedValue, ClassesIfTrue, ClassesIfFalse } /// /// If the compare returns an exact class test, ClassesIfTrue == ~ClassesIfFalse /// diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 83e6190e22e7e03..b6d19c6e1a7d0f0 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -4053,10 +4053,10 @@ llvm::fcmpImpliesClass(CmpInst::Predicate Pred, const Function &F, Value *LHS, return {Src, fcNan, ~fcNan}; if (Pred == FCmpInst::FCMP_TRUE) - return {LHS, fcAllFlags}; + return {LHS, fcAllFlags, fcAllFlags}; if (Pred == FCmpInst::FCMP_FALSE) - return {LHS, fcNone}; + return {LHS, fcNone, fcNone}; const bool IsFabs = LookThroughSrc && match(LHS, m_FAbs(m_Value(Src))); if (IsFabs) @@ -4221,7 +4221,7 @@ llvm::fcmpImpliesClass(CmpInst::Predicate Pred, const Function &F, Value *LHS, } case FCmpInst::FCMP_OLE: case FCmpInst::FCMP_UGT: { - if (ConstRHS->isNegative()) { + if (IsNegativeRHS) { Mask = IsFabs ? fcNone : fcNegInf; break; } @@ -4233,16 +4233,6 @@ llvm::fcmpImpliesClass(CmpInst::Predicate Pred, const Function &F, Value *LHS, Mask = ~fcNan; break; } - case FCmpInst::FCMP_OGE: - case FCmpInst::FCMP_ULT: { - // fcmp oge x, smallest_normal -> fcPosNormal | fcPosInf - // fcmp oge fabs(x), smallest_normal -> fcInf | fcNormal - // fcmp ult x, smallest_normal -> ~(fcPosNormal | fcPosInf) - // fcmp ult fabs(x), smallest_normal -> ~(fcInf | fcNormal) - Mask = fcPosInf | fcPosNormal; - if (IsFabs) - Mask |= fcNegInf | fcNegNormal; - break; default: llvm_unreachable("all compare types are handled"); } @@ -4250,8 +4240,6 @@ llvm::fcmpImpliesClass(CmpInst::Predicate Pred, const Function &F, Value *LHS, // Invert the comparison for the unordered cases. if (FCmpInst::isUnordered(Pred)) Mask = ~Mask; - break; - } return exactClass(Src, Mask); } diff --git a/llvm/test/Transforms/Attributor/nofpclass-implied-by-fcmp.ll b/llvm/test/Transforms/Attributor/nofpclass-implied-by-fcmp.ll index cfadc5dab9c84bd..20145d3f8c5064f 100644 --- a/llvm/test/Transforms/Attributor/nofpclass-implied-by-fcmp.ll +++ b/llvm/test/Transforms/Attributor/nofpclass-implied-by-fcmp.ll @@ -2578,8 +2578,8 @@ define float @assume_false_ninf(float %arg) { } define float @clamp_false_pinf_0.0(float %arg) { -; CHECK-LABEL: define float @clamp_false_pinf_0.0( -; CHECK-SAME: float returned [[ARG:%.*]]) #[[ATTR2]] { +; CHECK-LABEL: define nofpclass(nan inf nzero sub norm) float @clamp_false_pinf_0.0( +; CHECK-SAME: float returned nofpclass(nan inf nzero sub norm) [[ARG:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret float [[ARG]] ; %fcmp = fcmp false float %arg, 0x7FF0000000000000 @@ -2588,8 +2588,8 @@ define float @clamp_false_pinf_0.0(float %arg) { } define float @clamp_false_ninf_0.0(float %arg) { -; CHECK-LABEL: define float @clamp_false_ninf_0.0( -; CHECK-SAME: float returned [[ARG:%.*]]) #[[ATTR2]] { +; CHECK-LABEL: define nofpclass(nan inf nzero sub norm) float @clamp_false_ninf_0.0( +; CHECK-SAME: float returned nofpclass(nan inf nzero sub norm) [[ARG:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret float [[ARG]] ; %fcmp = fcmp false float %arg, 0xFFF0000000000000 @@ -2598,8 +2598,8 @@ define float @clamp_false_ninf_0.0(float %arg) { } define float @clamp_false_smallest_normal_0.0(float %arg) { -; CHECK-LABEL: define float @clamp_false_smallest_normal_0.0( -; CHECK-SAME: float returned [[ARG:%.*]]) #[[ATTR2]] { +; CHECK-LABEL: define nofpclass(nan inf nzero sub norm) float @clamp_false_smallest_normal_0.0( +; CHECK-SAME: float returned nofpclass(nan inf nzero sub norm) [[ARG:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret float [[ARG]] ; %fcmp = fcmp false float %arg, 0x3810000000000000 @@ -2641,8 +2641,8 @@ define float @assume_false_smallest_normal(float %arg) { } define float @clamp_false_nan(float %arg) { -; CHECK-LABEL: define float @clamp_false_nan( -; CHECK-SAME: float returned [[ARG:%.*]]) #[[ATTR2]] { +; CHECK-LABEL: define nofpclass(nan inf nzero sub norm) float @clamp_false_nan( +; CHECK-SAME: float returned nofpclass(nan inf nzero sub norm) [[ARG:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret float [[ARG]] ; %fcmp = fcmp false float %arg, 0x7FF8000000000000 @@ -2651,8 +2651,8 @@ define float @clamp_false_nan(float %arg) { } define float @clamp_false_p0(float %arg) { -; CHECK-LABEL: define float @clamp_false_p0( -; CHECK-SAME: float returned [[ARG:%.*]]) #[[ATTR2]] { +; CHECK-LABEL: define nofpclass(nan inf nzero sub norm) float @clamp_false_p0( +; CHECK-SAME: float returned nofpclass(nan inf nzero sub norm) [[ARG:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret float [[ARG]] ; %fcmp = fcmp false float %arg, 0.0 @@ -2661,8 +2661,8 @@ define float @clamp_false_p0(float %arg) { } define float @clamp_false_n0(float %arg) { -; CHECK-LABEL: define float @clamp_false_n0( -; CHECK-SAME: float returned [[ARG:%.*]]) #[[ATTR2]] { +; CHECK-LABEL: define nofpclass(nan inf nzero sub norm) float @clamp_false_n0( +; CHECK-SAME: float returned nofpclass(nan inf nzero sub norm) [[ARG:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret float [[ARG]] ; %fcmp = fcmp false float %arg, -0.0 @@ -2755,7 +2755,7 @@ define float @assume_true_smallest_normal(float %arg) { define float @clamp_true_pinf_0.0(float %arg) { ; CHECK-LABEL: define noundef nofpclass(nan inf nzero sub norm) float @clamp_true_pinf_0.0( -; CHECK-SAME: float nofpclass(nan inf nzero sub norm) [[ARG:%.*]]) #[[ATTR2]] { +; CHECK-SAME: float [[ARG:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret float 0.000000e+00 ; %fcmp = fcmp true float %arg, 0x7FF0000000000000 @@ -2765,7 +2765,7 @@ define float @clamp_true_pinf_0.0(float %arg) { define float @clamp_true_ninf_0.0(float %arg) { ; CHECK-LABEL: define noundef nofpclass(nan inf nzero sub norm) float @clamp_true_ninf_0.0( -; CHECK-SAME: float nofpclass(nan inf nzero sub norm) [[ARG:%.*]]) #[[ATTR2]] { +; CHECK-SAME: float [[ARG:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret float 0.000000e+00 ; %fcmp = fcmp true float %arg, 0xFFF0000000000000 @@ -2775,7 +2775,7 @@ define float @clamp_true_ninf_0.0(float %arg) { define float @clamp_true_smallest_normal_0.0(float %arg) { ; CHECK-LABEL: define noundef nofpclass(nan inf nzero sub norm) float @clamp_true_smallest_normal_0.0( -; CHECK-SAME: float nofpclass(nan inf nzero sub norm) [[ARG:%.*]]) #[[ATTR2]] { +; CHECK-SAME: float [[ARG:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret float 0.000000e+00 ; %fcmp = fcmp true float %arg, 0x3810000000000000 @@ -2795,7 +2795,7 @@ define float @clamp_true_nan(float %arg) { define float @clamp_true_p0(float %arg) { ; CHECK-LABEL: define noundef nofpclass(nan inf nzero sub norm) float @clamp_true_p0( -; CHECK-SAME: float nofpclass(nan inf nzero sub norm) [[ARG:%.*]]) #[[ATTR2]] { +; CHECK-SAME: float [[ARG:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret float 0.000000e+00 ; %fcmp = fcmp true float %arg, 0.0 @@ -2805,7 +2805,7 @@ define float @clamp_true_p0(float %arg) { define float @clamp_true_n0(float %arg) { ; CHECK-LABEL: define noundef nofpclass(nan inf nzero sub norm) float @clamp_true_n0( -; CHECK-SAME: float nofpclass(nan inf nzero sub norm) [[ARG:%.*]]) #[[ATTR2]] { +; CHECK-SAME: float [[ARG:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret float 0.000000e+00 ; %fcmp = fcmp true float %arg, -0.0 >From 5926614407ec4d17992cd9ebc3e3df81ad0a39d8 Mon Sep 17 00:00:00 2001 From: Matt Arsenault <matthew.arsena...@amd.com> Date: Fri, 26 Jan 2024 15:28:43 +0530 Subject: [PATCH 3/6] Cleanups --- llvm/lib/Analysis/ValueTracking.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index b6d19c6e1a7d0f0..8e6010a45fbf3ce 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -4064,11 +4064,11 @@ llvm::fcmpImpliesClass(CmpInst::Predicate Pred, const Function &F, Value *LHS, const bool IsZero = (OrigClass & fcZero) == OrigClass; if (IsZero) { + assert(Pred != FCmpInst::FCMP_ORD && Pred != FCmpInst::FCMP_UNO); // Compares with fcNone are only exactly equal to fcZero if input denormals // are not flushed. // TODO: Handle DAZ by expanding masks to cover subnormal cases. - if (Pred != FCmpInst::FCMP_ORD && Pred != FCmpInst::FCMP_UNO && - !inputDenormalIsIEEE(F, LHS->getType())) + if (!inputDenormalIsIEEE(F, LHS->getType())) return {nullptr, fcAllFlags, fcAllFlags}; switch (Pred) { >From 8b4d96d21466f41fa63ec426dfbdf0ad907755bf Mon Sep 17 00:00:00 2001 From: Matt Arsenault <matthew.arsena...@amd.com> Date: Fri, 26 Jan 2024 15:40:05 +0530 Subject: [PATCH 4/6] Correct src for true/false --- llvm/lib/Analysis/ValueTracking.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 8e6010a45fbf3ce..77a3f57c950495d 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -4053,10 +4053,10 @@ llvm::fcmpImpliesClass(CmpInst::Predicate Pred, const Function &F, Value *LHS, return {Src, fcNan, ~fcNan}; if (Pred == FCmpInst::FCMP_TRUE) - return {LHS, fcAllFlags, fcAllFlags}; + return {Src, fcAllFlags, fcAllFlags}; if (Pred == FCmpInst::FCMP_FALSE) - return {LHS, fcNone, fcNone}; + return {Src, fcNone, fcNone}; const bool IsFabs = LookThroughSrc && match(LHS, m_FAbs(m_Value(Src))); if (IsFabs) >From 5481b555b7daf2079f7f00050209114c38edd5d6 Mon Sep 17 00:00:00 2001 From: Matt Arsenault <matthew.arsena...@amd.com> Date: Fri, 26 Jan 2024 15:40:47 +0530 Subject: [PATCH 5/6] Cleanup --- llvm/lib/Analysis/ValueTracking.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 77a3f57c950495d..43d7fc6f32ddefc 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -4046,11 +4046,11 @@ llvm::fcmpImpliesClass(CmpInst::Predicate Pred, const Function &F, Value *LHS, // fcmp ord x, zero|normal|subnormal|inf -> ~fcNan if (Pred == FCmpInst::FCMP_ORD) - return {Src, ~fcNan, fcNan}; + return exactClass(Src, ~fcNan); // fcmp uno x, zero|normal|subnormal|inf -> fcNan if (Pred == FCmpInst::FCMP_UNO) - return {Src, fcNan, ~fcNan}; + return exactClass(Src, fcNan); if (Pred == FCmpInst::FCMP_TRUE) return {Src, fcAllFlags, fcAllFlags}; >From 5ac753b0e379be3944523f084fdaf113eb8e3d6a Mon Sep 17 00:00:00 2001 From: Matt Arsenault <matthew.arsena...@amd.com> Date: Fri, 26 Jan 2024 15:47:17 +0530 Subject: [PATCH 6/6] Fix fcmp false case --- llvm/lib/Analysis/ValueTracking.cpp | 4 +-- .../Attributor/nofpclass-implied-by-fcmp.ll | 30 +++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 43d7fc6f32ddefc..7dc918c99e6f023 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -4053,10 +4053,10 @@ llvm::fcmpImpliesClass(CmpInst::Predicate Pred, const Function &F, Value *LHS, return exactClass(Src, fcNan); if (Pred == FCmpInst::FCMP_TRUE) - return {Src, fcAllFlags, fcAllFlags}; + return exactClass(Src, fcAllFlags); if (Pred == FCmpInst::FCMP_FALSE) - return {Src, fcNone, fcNone}; + return exactClass(Src, fcNone); const bool IsFabs = LookThroughSrc && match(LHS, m_FAbs(m_Value(Src))); if (IsFabs) diff --git a/llvm/test/Transforms/Attributor/nofpclass-implied-by-fcmp.ll b/llvm/test/Transforms/Attributor/nofpclass-implied-by-fcmp.ll index 20145d3f8c5064f..d64f8cf3e56dc14 100644 --- a/llvm/test/Transforms/Attributor/nofpclass-implied-by-fcmp.ll +++ b/llvm/test/Transforms/Attributor/nofpclass-implied-by-fcmp.ll @@ -2578,8 +2578,8 @@ define float @assume_false_ninf(float %arg) { } define float @clamp_false_pinf_0.0(float %arg) { -; CHECK-LABEL: define nofpclass(nan inf nzero sub norm) float @clamp_false_pinf_0.0( -; CHECK-SAME: float returned nofpclass(nan inf nzero sub norm) [[ARG:%.*]]) #[[ATTR2]] { +; CHECK-LABEL: define float @clamp_false_pinf_0.0( +; CHECK-SAME: float returned [[ARG:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret float [[ARG]] ; %fcmp = fcmp false float %arg, 0x7FF0000000000000 @@ -2588,8 +2588,8 @@ define float @clamp_false_pinf_0.0(float %arg) { } define float @clamp_false_ninf_0.0(float %arg) { -; CHECK-LABEL: define nofpclass(nan inf nzero sub norm) float @clamp_false_ninf_0.0( -; CHECK-SAME: float returned nofpclass(nan inf nzero sub norm) [[ARG:%.*]]) #[[ATTR2]] { +; CHECK-LABEL: define float @clamp_false_ninf_0.0( +; CHECK-SAME: float returned [[ARG:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret float [[ARG]] ; %fcmp = fcmp false float %arg, 0xFFF0000000000000 @@ -2598,8 +2598,8 @@ define float @clamp_false_ninf_0.0(float %arg) { } define float @clamp_false_smallest_normal_0.0(float %arg) { -; CHECK-LABEL: define nofpclass(nan inf nzero sub norm) float @clamp_false_smallest_normal_0.0( -; CHECK-SAME: float returned nofpclass(nan inf nzero sub norm) [[ARG:%.*]]) #[[ATTR2]] { +; CHECK-LABEL: define float @clamp_false_smallest_normal_0.0( +; CHECK-SAME: float returned [[ARG:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret float [[ARG]] ; %fcmp = fcmp false float %arg, 0x3810000000000000 @@ -2651,8 +2651,8 @@ define float @clamp_false_nan(float %arg) { } define float @clamp_false_p0(float %arg) { -; CHECK-LABEL: define nofpclass(nan inf nzero sub norm) float @clamp_false_p0( -; CHECK-SAME: float returned nofpclass(nan inf nzero sub norm) [[ARG:%.*]]) #[[ATTR2]] { +; CHECK-LABEL: define float @clamp_false_p0( +; CHECK-SAME: float returned [[ARG:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret float [[ARG]] ; %fcmp = fcmp false float %arg, 0.0 @@ -2661,8 +2661,8 @@ define float @clamp_false_p0(float %arg) { } define float @clamp_false_n0(float %arg) { -; CHECK-LABEL: define nofpclass(nan inf nzero sub norm) float @clamp_false_n0( -; CHECK-SAME: float returned nofpclass(nan inf nzero sub norm) [[ARG:%.*]]) #[[ATTR2]] { +; CHECK-LABEL: define float @clamp_false_n0( +; CHECK-SAME: float returned [[ARG:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret float [[ARG]] ; %fcmp = fcmp false float %arg, -0.0 @@ -2755,7 +2755,7 @@ define float @assume_true_smallest_normal(float %arg) { define float @clamp_true_pinf_0.0(float %arg) { ; CHECK-LABEL: define noundef nofpclass(nan inf nzero sub norm) float @clamp_true_pinf_0.0( -; CHECK-SAME: float [[ARG:%.*]]) #[[ATTR2]] { +; CHECK-SAME: float nofpclass(nan inf nzero sub norm) [[ARG:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret float 0.000000e+00 ; %fcmp = fcmp true float %arg, 0x7FF0000000000000 @@ -2765,7 +2765,7 @@ define float @clamp_true_pinf_0.0(float %arg) { define float @clamp_true_ninf_0.0(float %arg) { ; CHECK-LABEL: define noundef nofpclass(nan inf nzero sub norm) float @clamp_true_ninf_0.0( -; CHECK-SAME: float [[ARG:%.*]]) #[[ATTR2]] { +; CHECK-SAME: float nofpclass(nan inf nzero sub norm) [[ARG:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret float 0.000000e+00 ; %fcmp = fcmp true float %arg, 0xFFF0000000000000 @@ -2775,7 +2775,7 @@ define float @clamp_true_ninf_0.0(float %arg) { define float @clamp_true_smallest_normal_0.0(float %arg) { ; CHECK-LABEL: define noundef nofpclass(nan inf nzero sub norm) float @clamp_true_smallest_normal_0.0( -; CHECK-SAME: float [[ARG:%.*]]) #[[ATTR2]] { +; CHECK-SAME: float nofpclass(nan inf nzero sub norm) [[ARG:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret float 0.000000e+00 ; %fcmp = fcmp true float %arg, 0x3810000000000000 @@ -2795,7 +2795,7 @@ define float @clamp_true_nan(float %arg) { define float @clamp_true_p0(float %arg) { ; CHECK-LABEL: define noundef nofpclass(nan inf nzero sub norm) float @clamp_true_p0( -; CHECK-SAME: float [[ARG:%.*]]) #[[ATTR2]] { +; CHECK-SAME: float nofpclass(nan inf nzero sub norm) [[ARG:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret float 0.000000e+00 ; %fcmp = fcmp true float %arg, 0.0 @@ -2805,7 +2805,7 @@ define float @clamp_true_p0(float %arg) { define float @clamp_true_n0(float %arg) { ; CHECK-LABEL: define noundef nofpclass(nan inf nzero sub norm) float @clamp_true_n0( -; CHECK-SAME: float [[ARG:%.*]]) #[[ATTR2]] { +; CHECK-SAME: float nofpclass(nan inf nzero sub norm) [[ARG:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret float 0.000000e+00 ; %fcmp = fcmp true float %arg, -0.0 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits