diff --git a/llvm/include/llvm/Transforms/Utils/LoopUtils.h b/llvm/include/llvm/Transforms/Utils/LoopUtils.h index 960be75a2eb30..56adb7f72a187 100644 --- a/llvm/include/llvm/Transforms/Utils/LoopUtils.h +++ b/llvm/include/llvm/Transforms/Utils/LoopUtils.h @@ -429,6 +429,14 @@ bool isKnownNegativeInLoop(const SCEV *S, const Loop *L, ScalarEvolution &SE); /// loop \p L. bool isKnownNonNegativeInLoop(const SCEV *S, const Loop *L, ScalarEvolution &SE); +/// Returns true if we can prove that \p S is defined and always positive in +/// loop \p L. +bool isKnownPositiveInLoop(const SCEV *S, const Loop *L, ScalarEvolution &SE); + +/// Returns true if we can prove that \p S is defined and always non-positive in +/// loop \p L. +bool isKnownNonPositiveInLoop(const SCEV *S, const Loop *L, + ScalarEvolution &SE); /// Returns true if \p S is defined and never is equal to signed/unsigned max. bool cannotBeMaxInLoop(const SCEV *S, const Loop *L, ScalarEvolution &SE, diff --git a/llvm/lib/Transforms/Utils/LoopUtils.cpp b/llvm/lib/Transforms/Utils/LoopUtils.cpp index 1c58370a77d55..31872c15b0334 100644 --- a/llvm/lib/Transforms/Utils/LoopUtils.cpp +++ b/llvm/lib/Transforms/Utils/LoopUtils.cpp @@ -1136,6 +1136,20 @@ bool llvm::isKnownNonNegativeInLoop(const SCEV *S, const Loop *L, SE.isLoopEntryGuardedByCond(L, ICmpInst::ICMP_SGE, S, Zero); } +bool llvm::isKnownPositiveInLoop(const SCEV *S, const Loop *L, + ScalarEvolution &SE) { + const SCEV *Zero = SE.getZero(S->getType()); + return SE.isAvailableAtLoopEntry(S, L) && + SE.isLoopEntryGuardedByCond(L, ICmpInst::ICMP_SGT, S, Zero); +} + +bool llvm::isKnownNonPositiveInLoop(const SCEV *S, const Loop *L, + ScalarEvolution &SE) { + const SCEV *Zero = SE.getZero(S->getType()); + return SE.isAvailableAtLoopEntry(S, L) && + SE.isLoopEntryGuardedByCond(L, ICmpInst::ICMP_SLE, S, Zero); +} + bool llvm::cannotBeMinInLoop(const SCEV *S, const Loop *L, ScalarEvolution &SE, bool Signed) { unsigned BitWidth = cast(S->getType())->getBitWidth(); diff --git a/llvm/unittests/Transforms/Utils/LoopUtilsTest.cpp b/llvm/unittests/Transforms/Utils/LoopUtilsTest.cpp index aa0d72cf8bb33..8272c304ba288 100644 --- a/llvm/unittests/Transforms/Utils/LoopUtilsTest.cpp +++ b/llvm/unittests/Transforms/Utils/LoopUtilsTest.cpp @@ -93,3 +93,51 @@ TEST(LoopUtils, DeleteDeadLoopNest) { EXPECT_EQ(BI->getSuccessor(0)->getName(), "for.end"); }); } + +TEST(LoopUtils, IsKnownPositiveInLoopTest) { + LLVMContext C; + std::unique_ptr M = + parseIR(C, "define void @foo(i32 %n, i1 %c) {\n" + "entry:\n" + " %is.positive = icmp sgt i32 %n, 0\n" + " br i1 %is.positive, label %loop, label %exit\n" + "loop:\n" + " br i1 %c, label %loop, label %exit\n" + "exit:\n" + " ret void\n" + "}\n"); + + run(*M, "foo", + [&](Function &F, DominatorTree &DT, ScalarEvolution &SE, LoopInfo &LI) { + assert(LI.begin() != LI.end() && "Expecting loops in function F"); + Loop *L = *LI.begin(); + assert(L && L->getName() == "loop" && "Expecting loop 'loop'"); + auto *Arg = F.getArg(0); + auto *ArgSCEV = SE.getSCEV(Arg); + EXPECT_EQ(isKnownPositiveInLoop(ArgSCEV, L, SE), true); + }); +} + +TEST(LoopUtils, IsKnownNonPositiveInLoopTest) { + LLVMContext C; + std::unique_ptr M = + parseIR(C, "define void @foo(i32 %n, i1 %c) {\n" + "entry:\n" + " %is.non.positive = icmp sle i32 %n, 0\n" + " br i1 %is.non.positive, label %loop, label %exit\n" + "loop:\n" + " br i1 %c, label %loop, label %exit\n" + "exit:\n" + " ret void\n" + "}\n"); + + run(*M, "foo", + [&](Function &F, DominatorTree &DT, ScalarEvolution &SE, LoopInfo &LI) { + assert(LI.begin() != LI.end() && "Expecting loops in function F"); + Loop *L = *LI.begin(); + assert(L && L->getName() == "loop" && "Expecting loop 'loop'"); + auto *Arg = F.getArg(0); + auto *ArgSCEV = SE.getSCEV(Arg); + EXPECT_EQ(isKnownNonPositiveInLoop(ArgSCEV, L, SE), true); + }); +}