diff --git a/llvm/include/llvm/IR/ConstantRange.h b/llvm/include/llvm/IR/ConstantRange.h --- a/llvm/include/llvm/IR/ConstantRange.h +++ b/llvm/include/llvm/IR/ConstantRange.h @@ -124,6 +124,25 @@ static ConstantRange makeExactICmpRegion(CmpInst::Predicate Pred, const APInt &Other); + /// Return true iff CR1 ult CR2 is equivalent to CR1 slt CR2. + /// Does not depend on strictness/direction of the predicate. + static bool + areInsensitiveToSignednessOfICmpPredicate(const ConstantRange &CR1, + const ConstantRange &CR2); + + /// Return true iff CR1 ult CR2 is equivalent to CR1 sgt CR2. + static bool + areInsensitiveToSignednessOfSwappedICmpPredicate(const ConstantRange &CR1, + const ConstantRange &CR2); + + /// If the comparison between constant ranges this and Other + /// is insensitive to the signedness of the comparison predicate, + /// return a predicate equivalent to \p Pred, with flipped signedness + /// (i.e. unsigned instead of signed or vice versa), and maybe swapped. + CmpInst::Predicate + getEquivalentPredWithFlippedSignedness(CmpInst::Predicate Pred, + const ConstantRange &Other) const; + /// Produce the largest range containing all X such that "X BinOp Y" is /// guaranteed not to wrap (overflow) for *all* Y in Other. However, there may /// be *some* Y in Other for which additional X not contained in the result diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp --- a/llvm/lib/Analysis/ScalarEvolution.cpp +++ b/llvm/lib/Analysis/ScalarEvolution.cpp @@ -10645,29 +10645,39 @@ if (Depth > MaxSCEVOperationsImplicationDepth) return false; +// // We want signed comparisons, so if it's and unsigned one, +// // see if it can be just replaced with a signed one.. +// if (ICmpInst::isUnsigned(Pred)) { +// ICmpInst::Predicate SignedPred = +// getSignedRange(LHS).getEquivalentPredWithFlippedSignedness( +// Pred, getSignedRange(RHS)); +// if (SignedPred != CmpInst::Predicate::BAD_ICMP_PREDICATE) +// Pred = SignedPred; +// } + // We only want to work with GT comparison so far. - if (Pred == ICmpInst::ICMP_ULT || Pred == ICmpInst::ICMP_SLT) { + if (ICmpInst::isLT(Pred)) { Pred = CmpInst::getSwappedPredicate(Pred); std::swap(LHS, RHS); std::swap(FoundLHS, FoundRHS); } - - // For unsigned, try to reduce it to corresponding signed comparison. - if (Pred == ICmpInst::ICMP_UGT) - // We can replace unsigned predicate with its signed counterpart if all - // involved values are non-negative. - // TODO: We could have better support for unsigned. - if (isKnownNonNegative(FoundLHS) && isKnownNonNegative(FoundRHS)) { - // Knowing that both FoundLHS and FoundRHS are non-negative, and knowing - // FoundLHS >u FoundRHS, we also know that FoundLHS >s FoundRHS. Let us - // use this fact to prove that LHS and RHS are non-negative. - const SCEV *MinusOne = getMinusOne(LHS->getType()); - if (isImpliedCondOperands(ICmpInst::ICMP_SGT, LHS, MinusOne, FoundLHS, - FoundRHS) && - isImpliedCondOperands(ICmpInst::ICMP_SGT, RHS, MinusOne, FoundLHS, - FoundRHS)) - Pred = ICmpInst::ICMP_SGT; - } +/* + // For unsigned, try to reduce it to corresponding signed comparison. + if (Pred == ICmpInst::ICMP_UGT) + // We can replace unsigned predicate with its signed counterpart if all + // involved values are non-negative. + // TODO: We could have better support for unsigned. + if (isKnownNonNegative(FoundLHS) && isKnownNonNegative(FoundRHS)) { + // Knowing that both FoundLHS and FoundRHS are non-negative, and knowing + // FoundLHS >u FoundRHS, we also know that FoundLHS >s FoundRHS. Let us + // use this fact to prove that LHS and RHS are non-negative. + const SCEV *MinusOne = getMinusOne(LHS->getType()); + if (isImpliedCondOperands(ICmpInst::ICMP_SGT, LHS, MinusOne, FoundLHS, + FoundRHS) && + isImpliedCondOperands(ICmpInst::ICMP_SGT, RHS, MinusOne, FoundLHS, + FoundRHS)) + Pred = ICmpInst::ICMP_SGT; + }*/ if (Pred != ICmpInst::ICMP_SGT) return false; diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp --- a/llvm/lib/IR/ConstantRange.cpp +++ b/llvm/lib/IR/ConstantRange.cpp @@ -147,6 +147,65 @@ return makeAllowedICmpRegion(Pred, C); } +bool ConstantRange::areInsensitiveToSignednessOfICmpPredicate( + const ConstantRange &CR1, const ConstantRange &CR2) { + if (CR1.isEmptySet() || CR2.isEmptySet()) + return true; + + if (CR1.isFullSet() || CR2.isFullSet()) + return false; + if (CR1.isWrappedSet() || CR2.isWrappedSet()) + return false; + if (CR1.isSignWrappedSet() || CR2.isSignWrappedSet()) + return false; + + if (CR1.contains(CR2) || CR2.contains(CR1)) + return true; + + if (CR1.isAllNonNegative() && CR2.isAllNonNegative()) + return true; + + if (CR1.isAllNegative() && CR2.isAllNegative()) + return !CR1.isUpperWrapped() || !CR2.isUpperWrapped(); + + return false; +}; + +bool ConstantRange::areInsensitiveToSignednessOfSwappedICmpPredicate( + const ConstantRange &CR1, const ConstantRange &CR2) { + if (CR1.isEmptySet() || CR2.isEmptySet()) + return true; + if (CR1.isFullSet() || CR2.isFullSet()) + return false; + + bool TrulyEquivalent = true; + + for (auto N1 : {CR1.getUnsignedMin(), CR1.getUnsignedMax(), + CR1.getSignedMin(), CR1.getSignedMax()}) + for (auto N2 : {CR2.getUnsignedMin(), CR2.getUnsignedMax(), + CR2.getSignedMin(), CR2.getSignedMax()}) + TrulyEquivalent &= N1.slt(N2) == N1.ugt(N2); + + return TrulyEquivalent; +}; + +CmpInst::Predicate ConstantRange::getEquivalentPredWithFlippedSignedness( + CmpInst::Predicate Pred, const ConstantRange &Other) const { + assert(CmpInst::isIntPredicate(Pred) && CmpInst::isRelational(Pred) && + "Only for relational integer predicates!"); + + CmpInst::Predicate FlippedSignednessPred = + CmpInst::getFlippedSignednessPredicate(Pred); + + if (areInsensitiveToSignednessOfICmpPredicate(*this, Other)) + return FlippedSignednessPred; + + if (areInsensitiveToSignednessOfSwappedICmpPredicate(*this, Other)) + return CmpInst::getSwappedPredicate(FlippedSignednessPred); + + return CmpInst::Predicate::BAD_ICMP_PREDICATE; +} + bool ConstantRange::getEquivalentICmp(CmpInst::Predicate &Pred, APInt &RHS) const { bool Success = false; diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/basic.ll b/llvm/test/Transforms/CorrelatedValuePropagation/basic.ll --- a/llvm/test/Transforms/CorrelatedValuePropagation/basic.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/basic.ll @@ -338,8 +338,8 @@ ; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[B:%.*]], 20 ; CHECK-NEXT: br i1 [[CMP2]], label [[B_GUARD:%.*]], label [[OUT]] ; CHECK: b_guard: -; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp sle i32 [[A]], [[B]] -; CHECK-NEXT: [[MIN:%.*]] = select i1 [[SEL_CMP]], i32 [[A]], i32 [[B]] +; CHECK-NEXT: [[SEL_CMP1:%.*]] = icmp ule i32 [[A]], [[B]] +; CHECK-NEXT: [[MIN:%.*]] = select i1 [[SEL_CMP1]], i32 [[A]], i32 [[B]] ; CHECK-NEXT: ret i1 false ; CHECK: out: ; CHECK-NEXT: ret i1 false @@ -370,8 +370,8 @@ ; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[B:%.*]], 20 ; CHECK-NEXT: br i1 [[CMP2]], label [[B_GUARD:%.*]], label [[OUT]] ; CHECK: b_guard: -; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp sge i32 [[A]], [[B]] -; CHECK-NEXT: [[MAX:%.*]] = select i1 [[SEL_CMP]], i32 [[A]], i32 [[B]] +; CHECK-NEXT: [[SEL_CMP1:%.*]] = icmp uge i32 [[A]], [[B]] +; CHECK-NEXT: [[MAX:%.*]] = select i1 [[SEL_CMP1]], i32 [[A]], i32 [[B]] ; CHECK-NEXT: ret i1 false ; CHECK: out: ; CHECK-NEXT: ret i1 false @@ -573,11 +573,11 @@ ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[A]], 0 ; CHECK-NEXT: [[ABS:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 [[A]] ; CHECK-NEXT: store i1 true, i1* [[P:%.*]], align 1 -; CHECK-NEXT: [[C2:%.*]] = icmp slt i32 [[ABS]], 19 -; CHECK-NEXT: store i1 [[C2]], i1* [[P]], align 1 +; CHECK-NEXT: [[C21:%.*]] = icmp ult i32 [[ABS]], 19 +; CHECK-NEXT: store i1 [[C21]], i1* [[P]], align 1 ; CHECK-NEXT: store i1 true, i1* [[P]], align 1 -; CHECK-NEXT: [[C4:%.*]] = icmp sge i32 [[ABS]], 1 -; CHECK-NEXT: store i1 [[C4]], i1* [[P]], align 1 +; CHECK-NEXT: [[C42:%.*]] = icmp uge i32 [[ABS]], 1 +; CHECK-NEXT: store i1 [[C42]], i1* [[P]], align 1 ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: ret void @@ -618,11 +618,11 @@ ; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[A]], 0 ; CHECK-NEXT: [[ABS:%.*]] = select i1 [[CMP]], i32 [[A]], i32 [[SUB]] ; CHECK-NEXT: store i1 true, i1* [[P:%.*]], align 1 -; CHECK-NEXT: [[C2:%.*]] = icmp slt i32 [[ABS]], 19 -; CHECK-NEXT: store i1 [[C2]], i1* [[P]], align 1 +; CHECK-NEXT: [[C21:%.*]] = icmp ult i32 [[ABS]], 19 +; CHECK-NEXT: store i1 [[C21]], i1* [[P]], align 1 ; CHECK-NEXT: store i1 true, i1* [[P]], align 1 -; CHECK-NEXT: [[C4:%.*]] = icmp sge i32 [[ABS]], 1 -; CHECK-NEXT: store i1 [[C4]], i1* [[P]], align 1 +; CHECK-NEXT: [[C42:%.*]] = icmp uge i32 [[ABS]], 1 +; CHECK-NEXT: store i1 [[C42]], i1* [[P]], align 1 ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: ret void diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/deopt.ll b/llvm/test/Transforms/CorrelatedValuePropagation/deopt.ll --- a/llvm/test/Transforms/CorrelatedValuePropagation/deopt.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/deopt.ll @@ -97,8 +97,8 @@ ; CHECK-LABEL: @test3( ; CHECK-NEXT: [[SEL:%.*]] = select i1 [[C:%.*]], i64 0, i64 1 ; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[C2:%.*]], i64 [[SEL]], i64 2 -; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[SEL2]], 1 -; CHECK-NEXT: br i1 [[CMP]], label [[TAKEN:%.*]], label [[UNTAKEN:%.*]] +; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i64 [[SEL2]], 1 +; CHECK-NEXT: br i1 [[CMP1]], label [[TAKEN:%.*]], label [[UNTAKEN:%.*]] ; CHECK: taken: ; CHECK-NEXT: call void @use() [ "deopt"(i64 2) ] ; CHECK-NEXT: ret void @@ -122,8 +122,8 @@ ; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[C2:%.*]], i64 0, i64 1 ; CHECK-NEXT: [[ADD1:%.*]] = add nuw nsw i64 0, [[SEL]] ; CHECK-NEXT: [[ADD2:%.*]] = add nuw nsw i64 [[ADD1]], [[SEL2]] -; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[ADD2]], 1 -; CHECK-NEXT: br i1 [[CMP]], label [[TAKEN:%.*]], label [[UNTAKEN:%.*]] +; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i64 [[ADD2]], 1 +; CHECK-NEXT: br i1 [[CMP1]], label [[TAKEN:%.*]], label [[UNTAKEN:%.*]] ; CHECK: taken: ; CHECK-NEXT: call void @use() [ "deopt"(i64 2) ] ; CHECK-NEXT: ret void diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/minmaxabs.ll b/llvm/test/Transforms/CorrelatedValuePropagation/minmaxabs.ll --- a/llvm/test/Transforms/CorrelatedValuePropagation/minmaxabs.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/minmaxabs.ll @@ -60,8 +60,8 @@ ; CHECK-LABEL: @test_smax( ; CHECK-NEXT: [[M:%.*]] = call i32 @llvm.smax.i32(i32 [[X:%.*]], i32 10) ; CHECK-NEXT: call void @use(i1 true) -; CHECK-NEXT: [[C2:%.*]] = icmp sgt i32 [[M]], 10 -; CHECK-NEXT: call void @use(i1 [[C2]]) +; CHECK-NEXT: [[C21:%.*]] = icmp ugt i32 [[M]], 10 +; CHECK-NEXT: call void @use(i1 [[C21]]) ; CHECK-NEXT: ret void ; %m = call i32 @llvm.smax.i32(i32 %x, i32 10) @@ -110,8 +110,8 @@ ; CHECK-LABEL: @test_abs3( ; CHECK-NEXT: [[A:%.*]] = call i32 @llvm.abs.i32(i32 [[X:%.*]], i1 true) ; CHECK-NEXT: call void @use(i1 true) -; CHECK-NEXT: [[C2:%.*]] = icmp sgt i32 [[A]], 0 -; CHECK-NEXT: call void @use(i1 [[C2]]) +; CHECK-NEXT: [[C21:%.*]] = icmp ugt i32 [[A]], 0 +; CHECK-NEXT: call void @use(i1 [[C21]]) ; CHECK-NEXT: ret void ; %a = call i32 @llvm.abs.i32(i32 %x, i1 true) diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/overflow_predicate.ll b/llvm/test/Transforms/CorrelatedValuePropagation/overflow_predicate.ll --- a/llvm/test/Transforms/CorrelatedValuePropagation/overflow_predicate.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/overflow_predicate.ll @@ -113,8 +113,8 @@ ; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1 ; CHECK-NEXT: br i1 [[OV]], label [[OVERFLOW:%.*]], label [[TRAP:%.*]] ; CHECK: overflow: -; CHECK-NEXT: [[C1:%.*]] = icmp sgt i8 [[X]], 28 -; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]], align 1 +; CHECK-NEXT: [[C11:%.*]] = icmp ugt i8 [[X]], 28 +; CHECK-NEXT: store i1 [[C11]], i1* [[PC:%.*]], align 1 ; CHECK-NEXT: ret i1 true ; CHECK: trap: ; CHECK-NEXT: call void @llvm.trap() @@ -241,8 +241,8 @@ ; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1 ; CHECK-NEXT: br i1 [[OV]], label [[OVERFLOW:%.*]], label [[TRAP:%.*]] ; CHECK: overflow: -; CHECK-NEXT: [[C1:%.*]] = icmp slt i8 [[X]], -29 -; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]], align 1 +; CHECK-NEXT: [[C11:%.*]] = icmp ult i8 [[X]], -29 +; CHECK-NEXT: store i1 [[C11]], i1* [[PC:%.*]], align 1 ; CHECK-NEXT: ret i1 true ; CHECK: trap: ; CHECK-NEXT: call void @llvm.trap() diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/overflows.ll b/llvm/test/Transforms/CorrelatedValuePropagation/overflows.ll --- a/llvm/test/Transforms/CorrelatedValuePropagation/overflows.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/overflows.ll @@ -50,8 +50,8 @@ ; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[TMP3]], [[X:%.*]] ; CHECK-NEXT: br i1 [[CMP1]], label [[COND_END:%.*]], label [[COND_FALSE:%.*]] ; CHECK: lor.lhs.false: -; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[Y]], 0 -; CHECK-NEXT: br i1 [[CMP2]], label [[LAND_LHS_TRUE3:%.*]], label [[COND_FALSE]] +; CHECK-NEXT: [[CMP21:%.*]] = icmp ugt i32 [[Y]], 0 +; CHECK-NEXT: br i1 [[CMP21]], label [[LAND_LHS_TRUE3:%.*]], label [[COND_FALSE]] ; CHECK: land.lhs.true3: ; CHECK-NEXT: [[TMP4:%.*]] = sub nsw i32 -2147483648, [[Y]] ; CHECK-NEXT: [[TMP5:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[TMP4]], 0 diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/range.ll b/llvm/test/Transforms/CorrelatedValuePropagation/range.ll --- a/llvm/test/Transforms/CorrelatedValuePropagation/range.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/range.ll @@ -64,8 +64,8 @@ ; CHECK: if.then: ; CHECK-NEXT: ret i32 1 ; CHECK: if.end: -; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[C]], 3 -; CHECK-NEXT: br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[IF_END8:%.*]] +; CHECK-NEXT: [[CMP11:%.*]] = icmp ult i32 [[C]], 3 +; CHECK-NEXT: br i1 [[CMP11]], label [[IF_THEN2:%.*]], label [[IF_END8:%.*]] ; CHECK: if.then2: ; CHECK-NEXT: br i1 true, label [[IF_THEN4:%.*]], label [[IF_END6:%.*]] ; CHECK: if.end6: diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/sdiv.ll b/llvm/test/Transforms/CorrelatedValuePropagation/sdiv.ll --- a/llvm/test/Transforms/CorrelatedValuePropagation/sdiv.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/sdiv.ll @@ -127,12 +127,12 @@ ; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[N:%.*]], 0 ; CHECK-NEXT: br i1 [[CMP]], label [[LOOP:%.*]], label [[EXIT:%.*]] ; CHECK: loop: -; CHECK-NEXT: [[A:%.*]] = phi i32 [ [[N]], [[ENTRY:%.*]] ], [ [[DIV1:%.*]], [[LOOP]] ] -; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[A]], 4 -; CHECK-NEXT: call void @llvm.assume(i1 [[COND]]) -; CHECK-NEXT: [[DIV1]] = udiv i32 [[A]], 6 -; CHECK-NEXT: [[LOOPCOND:%.*]] = icmp sgt i32 [[DIV1]], 8 -; CHECK-NEXT: br i1 [[LOOPCOND]], label [[LOOP]], label [[EXIT]] +; CHECK-NEXT: [[A:%.*]] = phi i32 [ [[N]], [[ENTRY:%.*]] ], [ [[DIV2:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[COND1:%.*]] = icmp ugt i32 [[A]], 4 +; CHECK-NEXT: call void @llvm.assume(i1 [[COND1]]) +; CHECK-NEXT: [[DIV2]] = udiv i32 [[A]], 6 +; CHECK-NEXT: [[LOOPCOND3:%.*]] = icmp ugt i32 [[DIV2]], 8 +; CHECK-NEXT: br i1 [[LOOPCOND3]], label [[LOOP]], label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: ret void ; diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/srem.ll b/llvm/test/Transforms/CorrelatedValuePropagation/srem.ll --- a/llvm/test/Transforms/CorrelatedValuePropagation/srem.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/srem.ll @@ -40,12 +40,12 @@ ; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[N:%.*]], 0 ; CHECK-NEXT: br i1 [[CMP]], label [[LOOP:%.*]], label [[EXIT:%.*]] ; CHECK: loop: -; CHECK-NEXT: [[A:%.*]] = phi i32 [ [[N]], [[ENTRY:%.*]] ], [ [[REM1:%.*]], [[LOOP]] ] -; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[A]], 4 -; CHECK-NEXT: call void @llvm.assume(i1 [[COND]]) -; CHECK-NEXT: [[REM1]] = urem i32 [[A]], 17 -; CHECK-NEXT: [[LOOPCOND:%.*]] = icmp sgt i32 [[REM1]], 8 -; CHECK-NEXT: br i1 [[LOOPCOND]], label [[LOOP]], label [[EXIT]] +; CHECK-NEXT: [[A:%.*]] = phi i32 [ [[N]], [[ENTRY:%.*]] ], [ [[REM2:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[COND1:%.*]] = icmp ugt i32 [[A]], 4 +; CHECK-NEXT: call void @llvm.assume(i1 [[COND1]]) +; CHECK-NEXT: [[REM2]] = urem i32 [[A]], 17 +; CHECK-NEXT: [[LOOPCOND3:%.*]] = icmp ugt i32 [[REM2]], 8 +; CHECK-NEXT: br i1 [[LOOPCOND3]], label [[LOOP]], label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: ret void ; diff --git a/llvm/unittests/IR/ConstantRangeTest.cpp b/llvm/unittests/IR/ConstantRangeTest.cpp --- a/llvm/unittests/IR/ConstantRangeTest.cpp +++ b/llvm/unittests/IR/ConstantRangeTest.cpp @@ -6,8 +6,9 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/BitVector.h" #include "llvm/IR/ConstantRange.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/Sequence.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Operator.h" #include "llvm/Support/KnownBits.h" @@ -2418,4 +2419,113 @@ [](const APInt &N) { return ~N; }); } -} // anonymous namespace +bool compare(const APInt &LHS, const APInt &RHS, ICmpInst::Predicate Pred) { + assert(ICmpInst::isIntPredicate(Pred) && "Only for integer predicates!"); + switch (Pred) { + case ICmpInst::Predicate::ICMP_EQ: + return LHS.eq(RHS); + case ICmpInst::Predicate::ICMP_NE: + return LHS.ne(RHS); + case ICmpInst::Predicate::ICMP_UGT: + return LHS.ugt(RHS); + case ICmpInst::Predicate::ICMP_UGE: + return LHS.uge(RHS); + case ICmpInst::Predicate::ICMP_ULT: + return LHS.ult(RHS); + case ICmpInst::Predicate::ICMP_ULE: + return LHS.ule(RHS); + case ICmpInst::Predicate::ICMP_SGT: + return LHS.sgt(RHS); + case ICmpInst::Predicate::ICMP_SGE: + return LHS.sge(RHS); + case ICmpInst::Predicate::ICMP_SLT: + return LHS.slt(RHS); + case ICmpInst::Predicate::ICMP_SLE: + return LHS.sle(RHS); + default: + llvm_unreachable("Unexpected non-integer predicate."); + }; +} + +template +void testConstantRangeICmpPredEquivalence(ICmpInst::Predicate SrcPred, T Func) { + unsigned Bits = 4; + EnumerateTwoConstantRanges(Bits, [&](const ConstantRange &CR1, + const ConstantRange &CR2) { + ICmpInst::Predicate TgtPred; + bool ExpectedEquivalent; + std::tie(TgtPred, ExpectedEquivalent) = Func(CR1, CR2, SrcPred); + if (TgtPred == CmpInst::Predicate::BAD_ICMP_PREDICATE) + return; + bool TrulyEquivalent = true; + ForeachNumInConstantRange(CR1, [&](const APInt &N1) { + if (!TrulyEquivalent) + return; + ForeachNumInConstantRange(CR2, [&](const APInt &N2) { + if (!TrulyEquivalent) + return; + TrulyEquivalent &= compare(N1, N2, SrcPred) == compare(N1, N2, TgtPred); + }); + }); + ASSERT_EQ(TrulyEquivalent, ExpectedEquivalent); + }); +} + +TEST_F(ConstantRangeTest, areInsensitiveToSignednessOfICmpPredicate) { + for (auto Pred : seq((unsigned)ICmpInst::Predicate::FIRST_ICMP_PREDICATE, + ICmpInst::Predicate::LAST_ICMP_PREDICATE + 1)) { + if (ICmpInst::isEquality((ICmpInst::Predicate)Pred)) + continue; + ICmpInst::Predicate FlippedSignednessPred = + ICmpInst::getFlippedSignednessPredicate((ICmpInst::Predicate)Pred); + testConstantRangeICmpPredEquivalence( + (ICmpInst::Predicate)Pred, + [FlippedSignednessPred](const ConstantRange &CR1, + const ConstantRange &CR2, + ICmpInst::Predicate SrcPred) { + return std::make_pair( + FlippedSignednessPred, + ConstantRange::areInsensitiveToSignednessOfICmpPredicate(CR1, + CR2)); + }); + } +} + +TEST_F(ConstantRangeTest, areInsensitiveToSignednessOfSwappedICmpPredicate) { + for (auto Pred : seq((unsigned)ICmpInst::Predicate::FIRST_ICMP_PREDICATE, + ICmpInst::Predicate::LAST_ICMP_PREDICATE + 1)) { + if (ICmpInst::isEquality((ICmpInst::Predicate)Pred)) + continue; + ICmpInst::Predicate FlippedSignednessPred = + ICmpInst::getFlippedSignednessPredicate((ICmpInst::Predicate)Pred); + ICmpInst::Predicate SwappedFlippedSignednessPred = + ICmpInst::getSwappedPredicate(FlippedSignednessPred); + testConstantRangeICmpPredEquivalence( + (ICmpInst::Predicate)Pred, + [SwappedFlippedSignednessPred](const ConstantRange &CR1, + const ConstantRange &CR2, + ICmpInst::Predicate SrcPred) { + return std::make_pair( + SwappedFlippedSignednessPred, + ConstantRange::areInsensitiveToSignednessOfSwappedICmpPredicate( + CR1, CR2)); + }); + } +} + +TEST_F(ConstantRangeTest, getEquivalentPredWithFlippedSignedness) { + for (auto Pred : seq((unsigned)ICmpInst::Predicate::FIRST_ICMP_PREDICATE, + ICmpInst::Predicate::LAST_ICMP_PREDICATE + 1)) { + if (ICmpInst::isEquality((ICmpInst::Predicate)Pred)) + continue; + testConstantRangeICmpPredEquivalence( + (ICmpInst::Predicate)Pred, + [](const ConstantRange &CR1, const ConstantRange &CR2, + ICmpInst::Predicate SrcPred) { + return std::make_pair( + CR1.getEquivalentPredWithFlippedSignedness(SrcPred, CR2), true); + }); + } +} + +} // anonymous namespace