Skip to content

Conversation

@arsenm
Copy link
Contributor

@arsenm arsenm commented Sep 15, 2023

Rushing this one out before vacation starts. Refactoring on top of #66505

@arsenm arsenm added the floating-point Floating-point math label Sep 15, 2023
@llvmbot llvmbot added llvm:analysis Includes value tracking, cost tables and constant folding llvm:transforms labels Sep 15, 2023
@llvmbot
Copy link
Member

llvmbot commented Sep 15, 2023

@llvm/pr-subscribers-llvm-transforms

@llvm/pr-subscribers-llvm-analysis

Changes

Rushing this one out before vacation starts. Refactoring on top of #66505

Patch is 128.20 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/66522.diff

6 Files Affected:

  • (modified) llvm/include/llvm/Analysis/ValueTracking.h (+27)
  • (modified) llvm/lib/Analysis/ValueTracking.cpp (+242-68)
  • (modified) llvm/test/Transforms/Attributor/nofpclass-implied-by-fcmp.ll (+160-160)
  • (modified) llvm/test/Transforms/Attributor/nofpclass.ll (+8-8)
  • (modified) llvm/test/Transforms/InstSimplify/assume-fcmp-constant-implies-class.ll (+90-180)
  • (modified) llvm/unittests/Analysis/ValueTrackingTest.cpp (+4-4)
diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h index 695f2fecae885b7..8fafdec200fed2c 100644 --- a/llvm/include/llvm/Analysis/ValueTracking.h +++ b/llvm/include/llvm/Analysis/ValueTracking.h @@ -235,6 +235,33 @@ 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 +/// fcmp \Pred \p LHS, \p RHS. +/// +/// Returns { TestedValue, ClassesIfTrue, ClassesIfFalse } +/// +/// If the compare returns an exact class test, ClassesIfTrue == ~ClassesIfFalse +/// +/// This is a less exact version of fcmpToClassTest (e.g. fcmpToClassTest will +/// only succeed for a test of x > 0 implies positive, but not x > 1). +/// +/// If \p LookThroughSrc is true, consider the input value when computing the +/// mask. This may look through sign bit operations. +/// +/// If \p LookThroughSrc is false, ignore the source value (i.e. the first pair +/// element will always be LHS. +/// +std::tuple<Value *, FPClassTest, FPClassTest> +fcmpImpliesClass(CmpInst::Predicate Pred, const Function &F, Value *LHS, + Value *RHS, bool LookThroughSrc = true); +std::tuple<Value *, FPClassTest, FPClassTest> +fcmpImpliesClass(CmpInst::Predicate Pred, const Function &F, Value *LHS, + 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. FPClassTest KnownFPClasses = fcAllFlags; diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index c4153b824c37e0a..ef895bff22e7cb3 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -4008,7 +4008,7 @@ std::pair<Value *, FPClassTest> llvm::fcmpToClassTest(FCmpInst::Predicate Pred, bool LookThroughSrc) { const APFloat *ConstRHS; if (!match(RHS, m_APFloatAllowUndef(ConstRHS))) - return {nullptr, fcNone}; + return {nullptr, fcAllFlags}; return fcmpToClassTest(Pred, F, LHS, ConstRHS, LookThroughSrc); } @@ -4016,67 +4016,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}; - if (ConstRHS->isZero()) { + const bool IsFabs = LookThroughSrc && match(LHS, m_FAbs(m_Value(Src))); + if (IsFabs) + RHSClass = llvm::inverse_fabs(RHSClass); + + 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, fcNone}; + 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, fcNone}; + 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: { @@ -4091,8 +4128,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; @@ -4101,7 +4137,6 @@ llvm::fcmpToClassTest(FCmpInst::Predicate Pred, const Function &F, Value *LHS, if (IsFabs) Mask |= fcNegInf; } - break; } case FCmpInst::FCMP_ONE: @@ -4116,7 +4151,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; @@ -4130,7 +4165,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 @@ -4150,8 +4185,8 @@ llvm::fcmpToClassTest(FCmpInst::Predicate Pred, const Function &F, Value *LHS, } case FCmpInst::FCMP_OGE: case FCmpInst::FCMP_ULT: { - if (ConstRHS->isNegative()) // TODO - return {nullptr, fcNone}; + if (IsNegativeRHS) // TODO + return {nullptr, fcAllFlags, fcAllFlags}; // fcmp oge fabs(x), +inf -> fcInf // fcmp oge x, +inf -> fcPosInf @@ -4164,17 +4199,140 @@ llvm::fcmpToClassTest(FCmpInst::Predicate Pred, const Function &F, Value *LHS, } case FCmpInst::FCMP_OGT: case FCmpInst::FCMP_ULE: { - if (ConstRHS->isNegative()) - return {nullptr, fcNone}; + if (IsNegativeRHS) + return {nullptr, fcAllFlags, fcAllFlags}; // No value is ordered and greater than infinity. Mask = fcNone; break; } default: - return {nullptr, fcNone}; + return {nullptr, fcAllFlags, fcAllFlags}; + } + + // Invert the comparison for the unordered cases. + if (FCmpInst::isUnordered(Pred)) + Mask = ~Mask; + + return exactClass(Src, Mask); + } + + if (Pred == FCmpInst::FCMP_OEQ) + return {Src, RHSClass, fcAllFlags}; + + if (Pred == FCmpInst::FCMP_UEQ) { + FPClassTest Class = RHSClass | fcNan; + return {Src, Class, ~fcNan}; + } + + if (Pred == FCmpInst::FCMP_ONE) + return {Src, ~fcNan, RHSClass}; + + 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) { + // fabs(x) o> -k -> fcmp ord x, x + // fabs(x) u> -k -> true + // fabs(x) o< -k -> false + // fabs(x) u< -k -> fcmp uno x, x + switch (Pred) { + case FCmpInst::FCMP_OGT: + case FCmpInst::FCMP_OGE: + return {Src, ~fcNan, fcNan}; + case FCmpInst::FCMP_UGT: + case FCmpInst::FCMP_UGE: + return {Src, fcAllFlags, fcNone}; + case FCmpInst::FCMP_OLT: + case FCmpInst::FCMP_OLE: + return {Src, fcNone, fcAllFlags}; + case FCmpInst::FCMP_ULT: + case FCmpInst::FCMP_ULE: + return {Src, fcNan, ~fcNan}; + default: + break; + } + + return {nullptr, fcAllFlags, fcAllFlags}; } - } else if (ConstRHS->isSmallestNormalized() && !ConstRHS->isNegative()) { + + FPClassTest ClassesLE = fcNegInf | fcNegNormal; + FPClassTest ClassesGE = fcPositive | fcNegZero | fcNegSubnormal; + + if (IsDenormalRHS) + ClassesLE |= fcNegSubnormal; + else + ClassesGE |= fcNegNormal; + + switch (Pred) { + case FCmpInst::FCMP_OGT: + case FCmpInst::FCMP_OGE: + return {Src, ClassesGE, ~ClassesGE | RHSClass}; + case FCmpInst::FCMP_UGT: + case FCmpInst::FCMP_UGE: + return {Src, ClassesGE | fcNan, ~(ClassesGE | fcNan) | RHSClass}; + case FCmpInst::FCMP_OLT: + case FCmpInst::FCMP_OLE: + return {Src, ClassesLE, ~ClassesLE | RHSClass}; + case FCmpInst::FCMP_ULT: + case FCmpInst::FCMP_ULE: + return {Src, ClassesLE | fcNan, ~(ClassesLE | fcNan) | RHSClass}; + default: + break; + } + } else if (IsPositiveRHS) { + FPClassTest ClassesGE = fcPosNormal | fcPosInf; + FPClassTest ClassesLE = fcNegative | fcPosZero | fcPosNormal; + if (IsDenormalRHS) + ClassesGE |= fcPosNormal; + else + ClassesLE |= fcPosSubnormal; + + FPClassTest FalseClasses = RHSClass; + if (IsFabs) { + ClassesGE = llvm::inverse_fabs(ClassesGE); + ClassesLE = llvm::inverse_fabs(ClassesLE); + } + + switch (Pred) { + case FCmpInst::FCMP_OGT: + case FCmpInst::FCMP_OGE: + return {Src, ClassesGE, ~ClassesGE | FalseClasses}; + case FCmpInst::FCMP_UGT: + case FCmpInst::FCMP_UGE: + return {Src, ClassesGE | fcNan, ~(ClassesGE | fcNan) | FalseClasses}; + case FCmpInst::FCMP_OLT: + case FCmpInst::FCMP_OLE: + return {Src, ClassesLE, ~ClassesLE | FalseClasses}; + case FCmpInst::FCMP_ULT: + case FCmpInst::FCMP_ULE: + return {Src, ClassesLE | fcNan, ~(ClassesLE | fcNan) | FalseClasses}; + default: + break; + } + } + + 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: @@ -4201,20 +4359,29 @@ llvm::fcmpToClassTest(FCmpInst::Predicate Pred, const Function &F, Value *LHS, break; } default: - return {nullptr, fcNone}; + return fcmpImpliesClass(Pred, F, LHS, ConstRHS.classify(), + LookThroughSrc); } - } else if (ConstRHS->isNaN()) { - // fcmp o__ x, nan -> false - // fcmp u__ x, nan -> true - Mask = fcNone; - } else - return {nullptr, fcNone}; - // 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}; + 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}; + + // TODO: Just call computeKnownFPClass for RHS to handle non-constants. + return fcmpImpliesClass(Pred, F, LHS, *ConstRHS, LookThroughSrc); } static FPClassTest computeKnownFPClassFromAssumes(const Value *V, @@ -4241,18 +4408,22 @@ static FPClassTest computeKnownFPClassFromAssumes(const Value *V, Value *LHS, *RHS; uint64_t ClassVal = 0; if (match(I->getArgOperand(0), m_FCmp(Pred, m_Value(LHS), m_Value(RHS)))) { - auto [TestedValue, TestedMask] = - fcmpToClassTest(Pred, *F, LHS, RHS, true); - // First see if we can fold in fabs/fneg into the test. - if (TestedValue == V) - KnownFromAssume &= TestedMask; - else { - // Try again without the lookthrough if we found a different source - // value. - auto [TestedValue, TestedMask] = - fcmpToClassTest(Pred, *F, LHS, RHS, false); - if (TestedValue == V) - KnownFromAssume &= TestedMask; + const APFloat *CRHS; + 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); + 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); + if (CmpVal == V) + KnownFromAssume &= MaskIfTrue; + } } } else if (match(I->getArgOperand(0), m_Intrinsic<Intrinsic::is_fpclass>( @@ -4400,7 +4571,8 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts, FPClassTest FilterRHS = fcAllFlags; Value *TestedValue = nullptr; - FPClassTest TestedMask = fcNone; + FPClassTest MaskIfTrue = fcAllFlags; + FPClassTest MaskIfFalse = fcAllFlags; uint64_t ClassVal = 0; const Function *F = cast<Instruction>(Op)->getFunction(); CmpInst::Predicate Pred; @@ -4412,20 +4584,22 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts, // TODO: In some degenerate cases we can infer something if we try again // without looking through sign operations. bool LookThroughFAbsFNeg = CmpLHS != LHS && CmpLHS != RHS; - std::tie(TestedValue, TestedMask) = - fcmpToClassTest(Pred, *F, CmpLHS, CmpRHS, LookThroughFAbsFNeg); + std::tie(TestedValue, MaskIfTrue, MaskIfFalse) = + fcmpImpliesClass(Pred, *F, CmpLHS, CmpRHS, LookThroughFAbsFNeg); } else if (match(Cond, m_Intrinsic<Intrinsic::is_fpclass>( m_Value(TestedValue), m_ConstantInt(ClassVal)))) { - TestedMask = static_cast<FPClassTest>(ClassVal); + FPClassTest TestedMask = static_cast<FPClassTest>(ClassVal); + MaskIfTrue = TestedMask; + MaskIfFalse = ~TestedMask; } if (TestedValue == LHS) { // match !isnan(x) ? x : y - FilterLHS = TestedMask; - } else if (TestedValue == RHS) { + FilterLHS = MaskIfTrue; + } else if (TestedValue == RHS) { // && IsExactClass // match !isnan(x) ? y : x - FilterRHS = ~TestedMask; + FilterRHS = MaskIfFalse; } KnownFPClass Known2; diff --git a/llvm/test/Transforms/Attributor/nofpclass-implied-by-fcmp.ll b/llvm/test/Transforms/Attributor/nofpclass-implied-by-fcmp.ll index 396b8c84fc898c9..212a8eb2f2451f7 100644 --- a/llvm/test/Transforms/Attributor/nofpclass-implied-by-fcmp.ll +++ b/llvm/test/Transforms/Attributor/nofpclass-implied-by-fcmp.ll @@ -11,7 +11,7 @@ declare void @llvm.assume(i1 noundef) ; can't be +inf define float @clamp_is_ogt_1_to_1(float %arg) { -; CHECK-LABEL: define float @clamp_is_ogt_1_to_1( +; CHECK-LABEL: define nofpclass(pinf) float @clamp_is_ogt_1_to_1( ; CHECK-SAME: float [[ARG:%.*]]) #[[ATTR2:[0-9]+]] { ; CHECK-NEXT: [[IS_OGT_1:%.*]] = fcmp ogt float [[ARG]], 1.000000e+00 ; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[IS_OGT_1]], float 1.000000e+00, float [[ARG]] @@ -23,7 +23,7 @@ define float @clamp_is_ogt_1_to_1(float %arg) { } define float @clamp_is_ogt_1_to_1_commute(float %arg) { -; CHECK-LABEL: define float @clamp_is_ogt_1_to_1_commute( +; CHECK-LABEL: define nofpclass(pinf) float @clamp_is_ogt_1_to_1_commute( ; CHECK-SAME: float [[ARG:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: [[IS_ULE_1:%.*]] = fcmp ule float [[ARG]], 1.000000e+00 ; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[IS_ULE_1]], float [[ARG]], float 1.000000e+00 @@ -36,7 +36,7 @@ define float @clamp_is_ogt_1_to_1_commute(float %arg) { ; can't be +inf or nan define float @clamp_is_ugt_1_to_1(float %arg) { -; CHECK-LABEL: define float @clamp_is_ugt_1_to_1( +; CHECK-LABEL: define nofpclass(nan pinf) float @clamp_is_ugt_1_to_1( ; CHECK-SAME: float [[ARG:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: [[IS_UGT_1:%.*]] = fcmp ugt float [[ARG]], 1.000000e+00 ; CHECK-NEXT... [truncated] 
@arsenm arsenm force-pushed the fcmp-implies-class-3 branch from 9cb03d4 to 26ba021 Compare November 10, 2023 02:51
@arsenm arsenm requested a review from nikic as a code owner November 10, 2023 02:51
@github-actions
Copy link

github-actions bot commented Nov 10, 2023

✅ With the latest revision this PR passed the C/C++ code formatter.

@arsenm arsenm force-pushed the fcmp-implies-class-3 branch from 26ba021 to 0183305 Compare November 10, 2023 02:55
@arsenm arsenm force-pushed the fcmp-implies-class-3 branch from 0183305 to 076ab23 Compare December 6, 2023 03:47
@dtcxzyw
Copy link
Member

dtcxzyw commented Dec 25, 2023

Is there any progress?

dtcxzyw added a commit to dtcxzyw/llvm-opt-benchmark that referenced this pull request Dec 25, 2023
Copy link
Collaborator

@spavloff spavloff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@arsenm arsenm merged commit e44d3b3 into llvm:main Jan 27, 2024
@arsenm arsenm deleted the fcmp-implies-class-3 branch January 27, 2024 03:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

floating-point Floating-point math llvm:analysis Includes value tracking, cost tables and constant folding llvm:transforms

5 participants