diff options
author | Philip Reames <preames@rivosinc.com> | 2023-09-01 12:10:32 -0700 |
---|---|---|
committer | Philip Reames <listmail@philipreames.com> | 2023-09-01 12:17:36 -0700 |
commit | 294ad08ecc0085e3ae93bbd16d488f284fe0d8fb (patch) | |
tree | fdee5ad3cd0bf4b74c929fe03548bbb99d8e21d9 /llvm/lib | |
parent | 3e67d7b682deaa05ac79490d43d4050e10d04a40 (diff) | |
download | llvm-294ad08ecc0085e3ae93bbd16d488f284fe0d8fb.zip llvm-294ad08ecc0085e3ae93bbd16d488f284fe0d8fb.tar.gz llvm-294ad08ecc0085e3ae93bbd16d488f284fe0d8fb.tar.bz2 |
Revert "Revert "InstSimplify: Use correct interested FP classes when simplifying fcmp""
This reverts commit 89f0314ee14a4d7f5a92fd63574ba545863df016. Change does not build.
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/Analysis/InstructionSimplify.cpp | 142 | ||||
-rw-r--r-- | llvm/lib/Analysis/ValueTracking.cpp | 8 |
2 files changed, 80 insertions, 70 deletions
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index 600418a..040c2e5 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -4060,19 +4060,6 @@ static Value *simplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS, if (Pred == FCmpInst::FCMP_TRUE) return getTrue(RetTy); - // Fold (un)ordered comparison if we can determine there are no NaNs. - if (Pred == FCmpInst::FCMP_UNO || Pred == FCmpInst::FCMP_ORD) - if (FMF.noNaNs() || - (isKnownNeverNaN(LHS, Q.DL, Q.TLI, 0, Q.AC, Q.CxtI, Q.DT) && - isKnownNeverNaN(RHS, Q.DL, Q.TLI, 0, Q.AC, Q.CxtI, Q.DT))) - return ConstantInt::get(RetTy, Pred == FCmpInst::FCMP_ORD); - - // NaN is unordered; NaN is not ordered. - assert((FCmpInst::isOrdered(Pred) || FCmpInst::isUnordered(Pred)) && - "Comparison must be either ordered or unordered"); - if (match(RHS, m_NaN())) - return ConstantInt::get(RetTy, CmpInst::isUnordered(Pred)); - // fcmp pred x, poison and fcmp pred poison, x // fold to poison if (isa<PoisonValue>(LHS) || isa<PoisonValue>(RHS)) @@ -4094,80 +4081,86 @@ static Value *simplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS, return getFalse(RetTy); } - // Handle fcmp with constant RHS. - // TODO: Use match with a specific FP value, so these work with vectors with - // undef lanes. - const APFloat *C; - if (match(RHS, m_APFloat(C))) { - // Check whether the constant is an infinity. - if (C->isInfinity()) { - if (C->isNegative()) { - switch (Pred) { - case FCmpInst::FCMP_OLT: - // No value is ordered and less than negative infinity. - return getFalse(RetTy); - case FCmpInst::FCMP_UGE: - // All values are unordered with or at least negative infinity. - return getTrue(RetTy); - default: - break; - } - } else { - switch (Pred) { - case FCmpInst::FCMP_OGT: - // No value is ordered and greater than infinity. - return getFalse(RetTy); - case FCmpInst::FCMP_ULE: - // All values are unordered with and at most infinity. - return getTrue(RetTy); - default: - break; - } - } + // Fold (un)ordered comparison if we can determine there are no NaNs. + // + // This catches the 2 variable input case, constants are handled below as a + // class-like compare. + if (Pred == FCmpInst::FCMP_ORD || Pred == FCmpInst::FCMP_UNO) { + if (FMF.noNaNs() || + (isKnownNeverNaN(RHS, Q.DL, Q.TLI, 0, Q.AC, Q.CxtI, Q.DT) && + isKnownNeverNaN(LHS, Q.DL, Q.TLI, 0, Q.AC, Q.CxtI, Q.DT))) + return ConstantInt::get(RetTy, Pred == FCmpInst::FCMP_ORD); + } - // LHS == Inf - if (Pred == FCmpInst::FCMP_OEQ && - isKnownNeverInfinity(LHS, Q.DL, Q.TLI, 0, Q.AC, Q.CxtI, Q.DT)) - return getFalse(RetTy); - // LHS != Inf - if (Pred == FCmpInst::FCMP_UNE && - isKnownNeverInfinity(LHS, Q.DL, Q.TLI, 0, Q.AC, Q.CxtI, Q.DT)) - return getTrue(RetTy); - // LHS == Inf || LHS == NaN - if (Pred == FCmpInst::FCMP_UEQ && - isKnownNeverInfOrNaN(LHS, Q.DL, Q.TLI, 0, Q.AC, Q.CxtI, Q.DT)) + const APFloat *C = nullptr; + match(RHS, m_APFloatAllowUndef(C)); + std::optional<KnownFPClass> FullKnownClassLHS; + + // Lazily compute the possible classes for LHS. Avoid computing it twice if + // RHS is a 0. + auto computeLHSClass = [=, &FullKnownClassLHS](FPClassTest InterestedFlags = + fcAllFlags) { + if (FullKnownClassLHS) + return *FullKnownClassLHS; + return computeKnownFPClass(LHS, FMF, Q.DL, InterestedFlags, 0, Q.TLI, Q.AC, + Q.CxtI, Q.DT, Q.IIQ.UseInstrInfo); + }; + + if (C && Q.CxtI) { + // Fold out compares that express a class test. + // + // FIXME: Should be able to perform folds without context + // instruction. Always pass in the context function? + + const Function *ParentF = Q.CxtI->getFunction(); + auto [ClassVal, ClassTest] = fcmpToClassTest(Pred, *ParentF, LHS, C); + if (ClassVal) { + FullKnownClassLHS = computeLHSClass(); + if ((FullKnownClassLHS->KnownFPClasses & ClassTest) == fcNone) return getFalse(RetTy); - // LHS != Inf && LHS != NaN - if (Pred == FCmpInst::FCMP_ONE && - isKnownNeverInfOrNaN(LHS, Q.DL, Q.TLI, 0, Q.AC, Q.CxtI, Q.DT)) + if ((FullKnownClassLHS->KnownFPClasses & ~ClassTest) == fcNone) return getTrue(RetTy); } + } + + // Handle fcmp with constant RHS. + if (C) { + // TODO: Need version fcmpToClassTest which returns implied class when the + // compare isn't a complete class test. e.g. > 1.0 implies fcPositive, but + // isn't implementable as a class call. if (C->isNegative() && !C->isNegZero()) { + FPClassTest Interested = KnownFPClass::OrderedLessThanZeroMask; + + // FIXME: This assert won't always hold if we depend on the context + // instruction above assert(!C->isNaN() && "Unexpected NaN constant!"); // TODO: We can catch more cases by using a range check rather than // relying on CannotBeOrderedLessThanZero. switch (Pred) { case FCmpInst::FCMP_UGE: case FCmpInst::FCMP_UGT: - case FCmpInst::FCMP_UNE: + case FCmpInst::FCMP_UNE: { + KnownFPClass KnownClass = computeLHSClass(Interested); + // (X >= 0) implies (X > C) when (C < 0) - if (cannotBeOrderedLessThanZero(LHS, Q.DL, Q.TLI, 0, - Q.AC, Q.CxtI, Q.DT)) + if (KnownClass.cannotBeOrderedLessThanZero()) return getTrue(RetTy); break; + } case FCmpInst::FCMP_OEQ: case FCmpInst::FCMP_OLE: - case FCmpInst::FCMP_OLT: + case FCmpInst::FCMP_OLT: { + KnownFPClass KnownClass = computeLHSClass(Interested); + // (X >= 0) implies !(X < C) when (C < 0) - if (cannotBeOrderedLessThanZero(LHS, Q.DL, Q.TLI, 0, Q.AC, Q.CxtI, - Q.DT)) + if (KnownClass.cannotBeOrderedLessThanZero()) return getFalse(RetTy); break; + } default: break; } } - // Check comparison of [minnum/maxnum with constant] with other constant. const APFloat *C2; if ((match(LHS, m_Intrinsic<Intrinsic::minnum>(m_Value(), m_APFloat(C2))) && @@ -4214,13 +4207,17 @@ static Value *simplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS, } } + // TODO: Could fold this with above if there were a matcher which returned all + // classes in a non-splat vector. if (match(RHS, m_AnyZeroFP())) { switch (Pred) { case FCmpInst::FCMP_OGE: case FCmpInst::FCMP_ULT: { - FPClassTest Interested = FMF.noNaNs() ? fcNegative : fcNegative | fcNan; - KnownFPClass Known = computeKnownFPClass(LHS, Q.DL, Interested, 0, - Q.TLI, Q.AC, Q.CxtI, Q.DT); + FPClassTest Interested = KnownFPClass::OrderedLessThanZeroMask; + if (!FMF.noNaNs()) + Interested |= fcNan; + + KnownFPClass Known = computeLHSClass(Interested); // Positive or zero X >= 0.0 --> true // Positive or zero X < 0.0 --> false @@ -4230,12 +4227,16 @@ static Value *simplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS, break; } case FCmpInst::FCMP_UGE: - case FCmpInst::FCMP_OLT: + case FCmpInst::FCMP_OLT: { + FPClassTest Interested = KnownFPClass::OrderedLessThanZeroMask; + KnownFPClass Known = computeLHSClass(Interested); + // Positive or zero or nan X >= 0.0 --> true // Positive or zero or nan X < 0.0 --> false - if (cannotBeOrderedLessThanZero(LHS, Q.DL, Q.TLI, 0, Q.AC, Q.CxtI, Q.DT)) + if (Known.cannotBeOrderedLessThanZero()) return Pred == FCmpInst::FCMP_UGE ? getTrue(RetTy) : getFalse(RetTy); break; + } default: break; } @@ -6816,6 +6817,9 @@ static Value *simplifyInstructionWithOperands(Instruction *I, const SimplifyQuery &SQ, unsigned MaxRecurse) { assert(I->getFunction() && "instruction should be inserted in a function"); + assert((!SQ.CxtI || SQ.CxtI->getFunction() == I->getFunction()) && + "context instruction should be in the same function"); + const SimplifyQuery Q = SQ.CxtI ? SQ : SQ.getWithInstruction(I); switch (I->getOpcode()) { diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 0c31dc2..801814e 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -4007,9 +4007,15 @@ std::pair<Value *, FPClassTest> llvm::fcmpToClassTest(FCmpInst::Predicate Pred, Value *LHS, Value *RHS, bool LookThroughSrc) { const APFloat *ConstRHS; - if (!match(RHS, m_APFloat(ConstRHS))) + if (!match(RHS, m_APFloatAllowUndef(ConstRHS))) return {nullptr, fcNone}; + return fcmpToClassTest(Pred, F, LHS, ConstRHS, LookThroughSrc); +} + +std::pair<Value *, FPClassTest> +llvm::fcmpToClassTest(FCmpInst::Predicate Pred, const Function &F, Value *LHS, + const APFloat *ConstRHS, bool LookThroughSrc) { // fcmp ord x, zero|normal|subnormal|inf -> ~fcNan if (Pred == FCmpInst::FCMP_ORD && !ConstRHS->isNaN()) return {LHS, ~fcNan}; |