aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib
diff options
context:
space:
mode:
authorPhilip Reames <preames@rivosinc.com>2023-09-01 12:10:32 -0700
committerPhilip Reames <listmail@philipreames.com>2023-09-01 12:17:36 -0700
commit294ad08ecc0085e3ae93bbd16d488f284fe0d8fb (patch)
treefdee5ad3cd0bf4b74c929fe03548bbb99d8e21d9 /llvm/lib
parent3e67d7b682deaa05ac79490d43d4050e10d04a40 (diff)
downloadllvm-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.cpp142
-rw-r--r--llvm/lib/Analysis/ValueTracking.cpp8
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};