diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index 17933ed03d587..a90b618607ad6 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -35,6 +35,7 @@ #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/Analysis/VectorUtils.h" +#include "llvm/IR/ConstantFPRange.h" #include "llvm/IR/ConstantRange.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Dominators.h" @@ -1812,6 +1813,46 @@ static Value *simplifyOrOfICmps(ICmpInst *Op0, ICmpInst *Op1, return nullptr; } +/// Test if a pair of compares with a shared operand and 2 constants has an +/// empty set intersection, full set union, or if one compare is a superset of +/// the other. +static Value *simplifyAndOrOfFCmpsWithConstants(FCmpInst *Cmp0, FCmpInst *Cmp1, + bool IsAnd) { + // Look for this pattern: {and/or} (fcmp X, C0), (fcmp X, C1)). + if (Cmp0->getOperand(0) != Cmp1->getOperand(0)) + return nullptr; + + const APFloat *C0, *C1; + if (!match(Cmp0->getOperand(1), m_APFloat(C0)) || + !match(Cmp1->getOperand(1), m_APFloat(C1))) + return nullptr; + + auto Range0 = ConstantFPRange::makeExactFCmpRegion( + IsAnd ? Cmp0->getPredicate() : Cmp0->getInversePredicate(), *C0); + auto Range1 = ConstantFPRange::makeExactFCmpRegion( + IsAnd ? Cmp1->getPredicate() : Cmp1->getInversePredicate(), *C1); + + if (!Range0 || !Range1) + return nullptr; + + // For and-of-compares, check if the intersection is empty: + // (fcmp X, C0) && (fcmp X, C1) --> empty set --> false + if (Range0->intersectWith(*Range1).isEmptySet()) + return ConstantInt::getBool(Cmp0->getType(), !IsAnd); + + // Is one range a superset of the other? + // If this is and-of-compares, take the smaller set: + // (fcmp ogt X, 4) && (fcmp ogt X, 42) --> fcmp ogt X, 42 + // If this is or-of-compares, take the larger set: + // (fcmp ogt X, 4) || (fcmp ogt X, 42) --> fcmp ogt X, 4 + if (Range0->contains(*Range1)) + return Cmp1; + if (Range1->contains(*Range0)) + return Cmp0; + + return nullptr; +} + static Value *simplifyAndOrOfFCmps(const SimplifyQuery &Q, FCmpInst *LHS, FCmpInst *RHS, bool IsAnd) { Value *LHS0 = LHS->getOperand(0), *LHS1 = LHS->getOperand(1); @@ -1850,34 +1891,8 @@ static Value *simplifyAndOrOfFCmps(const SimplifyQuery &Q, FCmpInst *LHS, : ConstantInt::getBool(LHS->getType(), !IsAnd); } - Value *V0; - const APFloat *V0Op1, *V1Op1; - // (fcmp olt V0, V0Op1) || (fcmp olt V0, V1Op1) - // --> fcmp olt V0, max(V0Op1, V1Op1) - // (fcmp ogt V0, V0Op1) || (fcmp ogt V0, V1Op1) - // --> fcmp ogt V0, max(V0Op1, V1Op1) - // - // (fcmp olt V0, V0Op1) && (fcmp olt V0, V1Op1) - // --> fcmp olt V0, min(V0Op1, V1Op1) - // (fcmp ogt V0, V0Op1) && (fcmp ogt V0, V1Op1) - // --> fcmp ogt V0, min(V0Op1, V1Op1) - if (match(LHS, m_SpecificFCmp(FCmpInst::FCMP_OLT, m_Value(V0), - m_APFloat(V0Op1))) && - match(RHS, m_SpecificFCmp(FCmpInst::FCMP_OLT, m_Specific(V0), - m_APFloat(V1Op1)))) { - if (*V0Op1 > *V1Op1) - return IsAnd ? RHS : LHS; - if (*V1Op1 > *V0Op1) - return IsAnd ? LHS : RHS; - } else if (match(LHS, m_SpecificFCmp(FCmpInst::FCMP_OGT, m_Value(V0), - m_APFloat(V0Op1))) && - match(RHS, m_SpecificFCmp(FCmpInst::FCMP_OGT, m_Specific(V0), - m_APFloat(V1Op1)))) { - if (*V0Op1 < *V1Op1) - return IsAnd ? RHS : LHS; - if (*V1Op1 < *V0Op1) - return IsAnd ? LHS : RHS; - } + if (auto *V = simplifyAndOrOfFCmpsWithConstants(LHS, RHS, IsAnd)) + return V; return nullptr; } diff --git a/llvm/test/Transforms/InstCombine/redundant-fcmp.ll b/llvm/test/Transforms/InstCombine/redundant-fcmp.ll index 0f5fe9fb9a1b2..7f579ed9f25c5 100644 --- a/llvm/test/Transforms/InstCombine/redundant-fcmp.ll +++ b/llvm/test/Transforms/InstCombine/redundant-fcmp.ll @@ -117,10 +117,7 @@ define i1 @or_fcmp_redundant_and4(double %v0) { define i1 @or_fcmp_redundant_and_neg1(double %v0) { ; CHECK-LABEL: @or_fcmp_redundant_and_neg1( -; CHECK-NEXT: [[V1:%.*]] = fcmp olt double [[V0:%.*]], 1.000000e-02 -; CHECK-NEXT: [[V2:%.*]] = fcmp ogt double [[V0]], 1.990000e+00 -; CHECK-NEXT: [[V3:%.*]] = and i1 [[V1]], [[V2]] -; CHECK-NEXT: ret i1 [[V3]] +; CHECK-NEXT: ret i1 false ; %v1 = fcmp olt double %v0, 1.000000e-02 %v2 = fcmp ogt double %v0, 1.990000e+00