summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/Analysis/LoopInfo.h161
-rw-r--r--llvm/lib/Analysis/LoopInfo.cpp214
-rw-r--r--llvm/unittests/Analysis/LoopInfoTest.cpp900
3 files changed, 1275 insertions, 0 deletions
diff --git a/llvm/include/llvm/Analysis/LoopInfo.h b/llvm/include/llvm/Analysis/LoopInfo.h
index 6b964cdf9ea..a4c8f648685 100644
--- a/llvm/include/llvm/Analysis/LoopInfo.h
+++ b/llvm/include/llvm/Analysis/LoopInfo.h
@@ -54,9 +54,11 @@ namespace llvm {
class DominatorTree;
class LoopInfo;
class Loop;
+class InductionDescriptor;
class MDNode;
class MemorySSAUpdater;
class PHINode;
+class ScalarEvolution;
class raw_ostream;
template <class N, bool IsPostDom> class DominatorTreeBase;
template <class N, class M> class LoopInfoBase;
@@ -529,6 +531,165 @@ public:
bool getIncomingAndBackEdge(BasicBlock *&Incoming,
BasicBlock *&Backedge) const;
+ /// Below are some utilities to get loop bounds and induction variable, and
+ /// check if a given phinode is an auxiliary induction variable, as well as
+ /// checking if the loop is canonical.
+ ///
+ /// Here is an example:
+ /// \code
+ /// for (int i = lb; i < ub; i+=step)
+ /// <loop body>
+ /// --- pseudo LLVMIR ---
+ /// beforeloop:
+ /// guardcmp = (lb < ub)
+ /// if (guardcmp) goto preheader; else goto afterloop
+ /// preheader:
+ /// loop:
+ /// i_1 = phi[{lb, preheader}, {i_2, latch}]
+ /// <loop body>
+ /// i_2 = i_1 + step
+ /// latch:
+ /// cmp = (i_2 < ub)
+ /// if (cmp) goto loop
+ /// exit:
+ /// afterloop:
+ /// \endcode
+ ///
+ /// - getBounds
+ /// - getInitialIVValue --> lb
+ /// - getStepInst --> i_2 = i_1 + step
+ /// - getStepValue --> step
+ /// - getFinalIVValue --> ub
+ /// - getCanonicalPredicate --> '<'
+ /// - getDirection --> Increasing
+ ///
+ /// - getInductionVariable --> i_1
+ /// - isAuxiliaryInductionVariable(x) --> true if x == i_1
+ /// - isCanonical --> false
+ struct LoopBounds {
+ /// Return the LoopBounds object if
+ /// - the given \p IndVar is an induction variable
+ /// - the initial value of the induction variable can be found
+ /// - the step instruction of the induction variable can be found
+ /// - the final value of the induction variable can be found
+ ///
+ /// Else None.
+ static Optional<Loop::LoopBounds> getBounds(const Loop &L, PHINode &IndVar,
+ ScalarEvolution &SE);
+
+ /// Get the initial value of the loop induction variable.
+ Value &getInitialIVValue() const { return InitialIVValue; }
+
+ /// Get the instruction that updates the loop induction variable.
+ Instruction &getStepInst() const { return StepInst; }
+
+ /// Get the step that the loop induction variable gets updated by in each
+ /// loop iteration. Return nullptr if not found.
+ Value *getStepValue() const { return StepValue; }
+
+ /// Get the final value of the loop induction variable.
+ Value &getFinalIVValue() const { return FinalIVValue; }
+
+ /// Return the canonical predicate for the latch compare instruction, if
+ /// able to be calcuated. Else BAD_ICMP_PREDICATE.
+ ///
+ /// A predicate is considered as canonical if requirements below are all
+ /// satisfied:
+ /// 1. The first successor of the latch branch is the loop header
+ /// If not, inverse the predicate.
+ /// 2. One of the operands of the latch comparison is StepInst
+ /// If not, and
+ /// - if the current calcuated predicate is not ne or eq, flip the
+ /// predicate.
+ /// - else if the loop is increasing, return slt
+ /// (notice that it is safe to change from ne or eq to sign compare)
+ /// - else if the loop is decreasing, return sgt
+ /// (notice that it is safe to change from ne or eq to sign compare)
+ ///
+ /// Here is an example when both (1) and (2) are not satisfied:
+ /// \code
+ /// loop.header:
+ /// %iv = phi [%initialiv, %loop.preheader], [%inc, %loop.header]
+ /// %inc = add %iv, %step
+ /// %cmp = slt %iv, %finaliv
+ /// br %cmp, %loop.exit, %loop.header
+ /// loop.exit:
+ /// \endcode
+ /// - The second successor of the latch branch is the loop header instead
+ /// of the first successor (slt -> sge)
+ /// - The first operand of the latch comparison (%cmp) is the IndVar (%iv)
+ /// instead of the StepInst (%inc) (sge -> sgt)
+ ///
+ /// The predicate would be sgt if both (1) and (2) are satisfied.
+ /// getCanonicalPredicate() returns sgt for this example.
+ /// Note: The IR is not changed.
+ ICmpInst::Predicate getCanonicalPredicate() const;
+
+ /// An enum for the direction of the loop
+ /// - for (int i = 0; i < ub; ++i) --> Increasing
+ /// - for (int i = ub; i > 0; --i) --> Descresing
+ /// - for (int i = x; i != y; i+=z) --> Unknown
+ enum class Direction { Increasing, Decreasing, Unknown };
+
+ /// Get the direction of the loop.
+ Direction getDirection() const;
+
+ private:
+ LoopBounds(const Loop &Loop, Value &I, Instruction &SI, Value *SV, Value &F,
+ ScalarEvolution &SE)
+ : L(Loop), InitialIVValue(I), StepInst(SI), StepValue(SV),
+ FinalIVValue(F), SE(SE) {}
+
+ const Loop &L;
+
+ // The initial value of the loop induction variable
+ Value &InitialIVValue;
+
+ // The instruction that updates the loop induction variable
+ Instruction &StepInst;
+
+ // The value that the loop induction variable gets updated by in each loop
+ // iteration
+ Value *StepValue;
+
+ // The final value of the loop induction variable
+ Value &FinalIVValue;
+
+ ScalarEvolution &SE;
+ };
+
+ /// Return the struct LoopBounds collected if all struct members are found,
+ /// else None.
+ Optional<LoopBounds> getBounds(ScalarEvolution &SE) const;
+
+ /// Return the loop induction variable if found, else return nullptr.
+ /// An instruction is considered as the loop induction variable if
+ /// - it is an induction variable of the loop; and
+ /// - it is used to determine the condition of the branch in the loop latch
+ ///
+ /// Note: the induction variable doesn't need to be canonical, i.e. starts at
+ /// zero and increments by one each time through the loop (but it can be).
+ PHINode *getInductionVariable(ScalarEvolution &SE) const;
+
+ /// Get the loop induction descriptor for the loop induction variable. Return
+ /// true if the loop induction variable is found.
+ bool getInductionDescriptor(ScalarEvolution &SE,
+ InductionDescriptor &IndDesc) const;
+
+ /// Return true if the given PHINode \p AuxIndVar is
+ /// - in the loop header
+ /// - not used outside of the loop
+ /// - incremented by a loop invariant step for each loop iteration
+ /// - step instruction opcode should be add or sub
+ /// Note: auxiliary induction variable is not required to be used in the
+ /// conditional branch in the loop latch. (but it can be)
+ bool isAuxiliaryInductionVariable(PHINode &AuxIndVar,
+ ScalarEvolution &SE) const;
+
+ /// Return true if the loop induction variable starts at zero and increments
+ /// by one each time through the loop.
+ bool isCanonical(ScalarEvolution &SE) const;
+
/// Return true if the Loop is in LCSSA form.
bool isLCSSAForm(DominatorTree &DT) const;
diff --git a/llvm/lib/Analysis/LoopInfo.cpp b/llvm/lib/Analysis/LoopInfo.cpp
index aa933d98f24..00dbe30c2b3 100644
--- a/llvm/lib/Analysis/LoopInfo.cpp
+++ b/llvm/lib/Analysis/LoopInfo.cpp
@@ -17,10 +17,12 @@
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/Analysis/IVDescriptors.h"
#include "llvm/Analysis/LoopInfoImpl.h"
#include "llvm/Analysis/LoopIterator.h"
#include "llvm/Analysis/MemorySSA.h"
#include "llvm/Analysis/MemorySSAUpdater.h"
+#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/IR/CFG.h"
@@ -164,6 +166,218 @@ PHINode *Loop::getCanonicalInductionVariable() const {
return nullptr;
}
+/// Get the latch condition instruction.
+static ICmpInst *getLatchCmpInst(const Loop &L) {
+ if (BasicBlock *Latch = L.getLoopLatch())
+ if (BranchInst *BI = dyn_cast_or_null<BranchInst>(Latch->getTerminator()))
+ if (BI->isConditional())
+ return dyn_cast<ICmpInst>(BI->getCondition());
+
+ return nullptr;
+}
+
+/// Return the final value of the loop induction variable if found.
+static Value *findFinalIVValue(const Loop &L, const PHINode &IndVar,
+ const Instruction &StepInst) {
+ ICmpInst *LatchCmpInst = getLatchCmpInst(L);
+ if (!LatchCmpInst)
+ return nullptr;
+
+ Value *Op0 = LatchCmpInst->getOperand(0);
+ Value *Op1 = LatchCmpInst->getOperand(1);
+ if (Op0 == &IndVar || Op0 == &StepInst)
+ return Op1;
+
+ if (Op1 == &IndVar || Op1 == &StepInst)
+ return Op0;
+
+ return nullptr;
+}
+
+Optional<Loop::LoopBounds> Loop::LoopBounds::getBounds(const Loop &L,
+ PHINode &IndVar,
+ ScalarEvolution &SE) {
+ InductionDescriptor IndDesc;
+ if (!InductionDescriptor::isInductionPHI(&IndVar, &L, &SE, IndDesc))
+ return None;
+
+ Value *InitialIVValue = IndDesc.getStartValue();
+ Instruction *StepInst = IndDesc.getInductionBinOp();
+ if (!InitialIVValue || !StepInst)
+ return None;
+
+ const SCEV *Step = IndDesc.getStep();
+ Value *StepInstOp1 = StepInst->getOperand(1);
+ Value *StepInstOp0 = StepInst->getOperand(0);
+ Value *StepValue = nullptr;
+ if (SE.getSCEV(StepInstOp1) == Step)
+ StepValue = StepInstOp1;
+ else if (SE.getSCEV(StepInstOp0) == Step)
+ StepValue = StepInstOp0;
+
+ Value *FinalIVValue = findFinalIVValue(L, IndVar, *StepInst);
+ if (!FinalIVValue)
+ return None;
+
+ return LoopBounds(L, *InitialIVValue, *StepInst, StepValue, *FinalIVValue,
+ SE);
+}
+
+using Direction = Loop::LoopBounds::Direction;
+
+ICmpInst::Predicate Loop::LoopBounds::getCanonicalPredicate() const {
+ BasicBlock *Latch = L.getLoopLatch();
+ assert(Latch && "Expecting valid latch");
+
+ BranchInst *BI = dyn_cast_or_null<BranchInst>(Latch->getTerminator());
+ assert(BI && BI->isConditional() && "Expecting conditional latch branch");
+
+ ICmpInst *LatchCmpInst = dyn_cast<ICmpInst>(BI->getCondition());
+ assert(LatchCmpInst &&
+ "Expecting the latch compare instruction to be a CmpInst");
+
+ // Need to inverse the predicate when first successor is not the loop
+ // header
+ ICmpInst::Predicate Pred = (BI->getSuccessor(0) == L.getHeader())
+ ? LatchCmpInst->getPredicate()
+ : LatchCmpInst->getInversePredicate();
+
+ if (LatchCmpInst->getOperand(0) == &getFinalIVValue())
+ Pred = ICmpInst::getSwappedPredicate(Pred);
+
+ // Need to flip strictness of the predicate when the latch compare instruction
+ // is not using StepInst
+ if (LatchCmpInst->getOperand(0) == &getStepInst() ||
+ LatchCmpInst->getOperand(1) == &getStepInst())
+ return Pred;
+
+ // Cannot flip strictness of NE and EQ
+ if (Pred != ICmpInst::ICMP_NE && Pred != ICmpInst::ICMP_EQ)
+ return ICmpInst::getFlippedStrictnessPredicate(Pred);
+
+ Direction D = getDirection();
+ if (D == Direction::Increasing)
+ return ICmpInst::ICMP_SLT;
+
+ if (D == Direction::Decreasing)
+ return ICmpInst::ICMP_SGT;
+
+ // If cannot determine the direction, then unable to find the canonical
+ // predicate
+ return ICmpInst::BAD_ICMP_PREDICATE;
+}
+
+Direction Loop::LoopBounds::getDirection() const {
+ if (const SCEVAddRecExpr *StepAddRecExpr =
+ dyn_cast<SCEVAddRecExpr>(SE.getSCEV(&getStepInst())))
+ if (const SCEV *StepRecur = StepAddRecExpr->getStepRecurrence(SE)) {
+ if (SE.isKnownPositive(StepRecur))
+ return Direction::Increasing;
+ if (SE.isKnownNegative(StepRecur))
+ return Direction::Decreasing;
+ }
+
+ return Direction::Unknown;
+}
+
+Optional<Loop::LoopBounds> Loop::getBounds(ScalarEvolution &SE) const {
+ if (PHINode *IndVar = getInductionVariable(SE))
+ return LoopBounds::getBounds(*this, *IndVar, SE);
+
+ return None;
+}
+
+PHINode *Loop::getInductionVariable(ScalarEvolution &SE) const {
+ if (!isLoopSimplifyForm())
+ return nullptr;
+
+ BasicBlock *Header = getHeader();
+ assert(Header && "Expected a valid loop header");
+ ICmpInst *CmpInst = getLatchCmpInst(*this);
+ if (!CmpInst)
+ return nullptr;
+
+ Instruction *LatchCmpOp0 = dyn_cast<Instruction>(CmpInst->getOperand(0));
+ Instruction *LatchCmpOp1 = dyn_cast<Instruction>(CmpInst->getOperand(1));
+
+ for (PHINode &IndVar : Header->phis()) {
+ InductionDescriptor IndDesc;
+ if (!InductionDescriptor::isInductionPHI(&IndVar, this, &SE, IndDesc))
+ continue;
+
+ Instruction *StepInst = IndDesc.getInductionBinOp();
+
+ // case 1:
+ // IndVar = phi[{InitialValue, preheader}, {StepInst, latch}]
+ // StepInst = IndVar + step
+ // cmp = StepInst < FinalValue
+ if (StepInst == LatchCmpOp0 || StepInst == LatchCmpOp1)
+ return &IndVar;
+
+ // case 2:
+ // IndVar = phi[{InitialValue, preheader}, {StepInst, latch}]
+ // StepInst = IndVar + step
+ // cmp = IndVar < FinalValue
+ if (&IndVar == LatchCmpOp0 || &IndVar == LatchCmpOp1)
+ return &IndVar;
+ }
+
+ return nullptr;
+}
+
+bool Loop::getInductionDescriptor(ScalarEvolution &SE,
+ InductionDescriptor &IndDesc) const {
+ if (PHINode *IndVar = getInductionVariable(SE))
+ return InductionDescriptor::isInductionPHI(IndVar, this, &SE, IndDesc);
+
+ return false;
+}
+
+bool Loop::isAuxiliaryInductionVariable(PHINode &AuxIndVar,
+ ScalarEvolution &SE) const {
+ // Located in the loop header
+ BasicBlock *Header = getHeader();
+ if (AuxIndVar.getParent() != Header)
+ return false;
+
+ // No uses outside of the loop
+ for (User *U : AuxIndVar.users())
+ if (const Instruction *I = dyn_cast<Instruction>(U))
+ if (!contains(I))
+ return false;
+
+ InductionDescriptor IndDesc;
+ if (!InductionDescriptor::isInductionPHI(&AuxIndVar, this, &SE, IndDesc))
+ return false;
+
+ // The step instruction opcode should be add or sub.
+ if (IndDesc.getInductionOpcode() != Instruction::Add &&
+ IndDesc.getInductionOpcode() != Instruction::Sub)
+ return false;
+
+ // Incremented by a loop invariant step for each loop iteration
+ return SE.isLoopInvariant(IndDesc.getStep(), this);
+}
+
+bool Loop::isCanonical(ScalarEvolution &SE) const {
+ InductionDescriptor IndDesc;
+ if (!getInductionDescriptor(SE, IndDesc))
+ return false;
+
+ ConstantInt *Init = dyn_cast_or_null<ConstantInt>(IndDesc.getStartValue());
+ if (!Init || !Init->isZero())
+ return false;
+
+ if (IndDesc.getInductionOpcode() != Instruction::Add)
+ return false;
+
+ ConstantInt *Step = IndDesc.getConstIntStepValue();
+ if (!Step || !Step->isOne())
+ return false;
+
+ return true;
+}
+
// Check that 'BB' doesn't have any uses outside of the 'L'
static bool isBlockInLCSSAForm(const Loop &L, const BasicBlock &BB,
DominatorTree &DT) {
diff --git a/llvm/unittests/Analysis/LoopInfoTest.cpp b/llvm/unittests/Analysis/LoopInfoTest.cpp
index 483532a1875..005e1dc405b 100644
--- a/llvm/unittests/Analysis/LoopInfoTest.cpp
+++ b/llvm/unittests/Analysis/LoopInfoTest.cpp
@@ -7,6 +7,10 @@
//===----------------------------------------------------------------------===//
#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/AssumptionCache.h"
+#include "llvm/Analysis/PostDominators.h"
+#include "llvm/Analysis/ScalarEvolution.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/AsmParser/Parser.h"
#include "llvm/IR/Dominators.h"
#include "llvm/Support/SourceMgr.h"
@@ -26,6 +30,26 @@ runWithLoopInfo(Module &M, StringRef FuncName,
Test(*F, LI);
}
+/// Build the loop info and scalar evolution for the function and run the Test.
+static void runWithLoopInfoPlus(
+ Module &M, StringRef FuncName,
+ function_ref<void(Function &F, LoopInfo &LI, ScalarEvolution &SE,
+ PostDominatorTree &PDT)>
+ Test) {
+ auto *F = M.getFunction(FuncName);
+ ASSERT_NE(F, nullptr) << "Could not find " << FuncName;
+
+ TargetLibraryInfoImpl TLII;
+ TargetLibraryInfo TLI(TLII);
+ AssumptionCache AC(*F);
+ DominatorTree DT(*F);
+ LoopInfo LI(DT);
+ ScalarEvolution SE(*F, TLI, AC, DT, LI);
+
+ PostDominatorTree PDT(*F);
+ Test(*F, LI, SE, PDT);
+}
+
static std::unique_ptr<Module> makeLLVMModule(LLVMContext &Context,
const char *ModuleStr) {
SMDiagnostic Err;
@@ -210,3 +234,879 @@ TEST(LoopInfoTest, PreorderTraversals) {
EXPECT_EQ(&L_0_1, ReverseSiblingPreorder[6]);
EXPECT_EQ(&L_0_0, ReverseSiblingPreorder[7]);
}
+
+TEST(LoopInfoTest, CanonicalLoop) {
+ const char *ModuleStr =
+ "define void @foo(i32* %A, i32 %ub) {\n"
+ "entry:\n"
+ " %guardcmp = icmp slt i32 0, %ub\n"
+ " br i1 %guardcmp, label %for.preheader, label %for.end\n"
+ "for.preheader:\n"
+ " br label %for.body\n"
+ "for.body:\n"
+ " %i = phi i32 [ 0, %for.preheader ], [ %inc, %for.body ]\n"
+ " %idxprom = sext i32 %i to i64\n"
+ " %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom\n"
+ " store i32 %i, i32* %arrayidx, align 4\n"
+ " %inc = add nsw i32 %i, 1\n"
+ " %cmp = icmp slt i32 %inc, %ub\n"
+ " br i1 %cmp, label %for.body, label %for.exit\n"
+ "for.exit:\n"
+ " br label %for.end\n"
+ "for.end:\n"
+ " ret void\n"
+ "}\n";
+
+ // Parse the module.
+ LLVMContext Context;
+ std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleStr);
+
+ runWithLoopInfoPlus(
+ *M, "foo",
+ [&](Function &F, LoopInfo &LI, ScalarEvolution &SE,
+ PostDominatorTree &PDT) {
+ Function::iterator FI = F.begin();
+ // First two basic block are entry and for.preheader - skip them.
+ ++FI;
+ BasicBlock *Header = &*(++FI);
+ assert(Header->getName() == "for.body");
+ Loop *L = LI.getLoopFor(Header);
+ EXPECT_NE(L, nullptr);
+
+ Optional<Loop::LoopBounds> Bounds = L->getBounds(SE);
+ EXPECT_NE(Bounds, None);
+ ConstantInt *InitialIVValue =
+ dyn_cast<ConstantInt>(&Bounds->getInitialIVValue());
+ EXPECT_TRUE(InitialIVValue && InitialIVValue->isZero());
+ EXPECT_EQ(Bounds->getStepInst().getName(), "inc");
+ ConstantInt *StepValue =
+ dyn_cast_or_null<ConstantInt>(Bounds->getStepValue());
+ EXPECT_TRUE(StepValue && StepValue->isOne());
+ EXPECT_EQ(Bounds->getFinalIVValue().getName(), "ub");
+ EXPECT_EQ(Bounds->getCanonicalPredicate(), ICmpInst::ICMP_SLT);
+ EXPECT_EQ(Bounds->getDirection(),
+ Loop::LoopBounds::Direction::Increasing);
+ EXPECT_EQ(L->getInductionVariable(SE)->getName(), "i");
+ });
+}
+
+TEST(LoopInfoTest, LoopWithInverseGuardSuccs) {
+ const char *ModuleStr =
+ "define void @foo(i32* %A, i32 %ub) {\n"
+ "entry:\n"
+ " %guardcmp = icmp sge i32 0, %ub\n"
+ " br i1 %guardcmp, label %for.end, label %for.preheader\n"
+ "for.preheader:\n"
+ " br label %for.body\n"
+ "for.body:\n"
+ " %i = phi i32 [ 0, %for.preheader ], [ %inc, %for.body ]\n"
+ " %idxprom = sext i32 %i to i64\n"
+ " %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom\n"
+ " store i32 %i, i32* %arrayidx, align 4\n"
+ " %inc = add nsw i32 %i, 1\n"
+ " %cmp = icmp slt i32 %inc, %ub\n"
+ " br i1 %cmp, label %for.body, label %for.exit\n"
+ "for.exit:\n"
+ " br label %for.end\n"
+ "for.end:\n"
+ " ret void\n"
+ "}\n";
+
+ // Parse the module.
+ LLVMContext Context;
+ std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleStr);
+
+ runWithLoopInfoPlus(
+ *M, "foo",
+ [&](Function &F, LoopInfo &LI, ScalarEvolution &SE,
+ PostDominatorTree &PDT) {
+ Function::iterator FI = F.begin();
+ // First two basic block are entry and for.preheader - skip them.
+ ++FI;
+ BasicBlock *Header = &*(++FI);
+ assert(Header->getName() == "for.body");
+ Loop *L = LI.getLoopFor(Header);
+ EXPECT_NE(L, nullptr);
+
+ Optional<Loop::LoopBounds> Bounds = L->getBounds(SE);
+ EXPECT_NE(Bounds, None);
+ ConstantInt *InitialIVValue =
+ dyn_cast<ConstantInt>(&Bounds->getInitialIVValue());
+ EXPECT_TRUE(InitialIVValue && InitialIVValue->isZero());
+ EXPECT_EQ(Bounds->getStepInst().getName(), "inc");
+ ConstantInt *StepValue =
+ dyn_cast_or_null<ConstantInt>(Bounds->getStepValue());
+ EXPECT_TRUE(StepValue && StepValue->isOne());
+ EXPECT_EQ(Bounds->getFinalIVValue().getName(), "ub");
+ EXPECT_EQ(Bounds->getCanonicalPredicate(), ICmpInst::ICMP_SLT);
+ EXPECT_EQ(Bounds->getDirection(),
+ Loop::LoopBounds::Direction::Increasing);
+ EXPECT_EQ(L->getInductionVariable(SE)->getName(), "i");
+ });
+}
+
+TEST(LoopInfoTest, LoopWithSwappedGuardCmp) {
+ const char *ModuleStr =
+ "define void @foo(i32* %A, i32 %ub) {\n"
+ "entry:\n"
+ " %guardcmp = icmp sgt i32 %ub, 0\n"
+ " br i1 %guardcmp, label %for.preheader, label %for.end\n"
+ "for.preheader:\n"
+ " br label %for.body\n"
+ "for.body:\n"
+ " %i = phi i32 [ 0, %for.preheader ], [ %inc, %for.body ]\n"
+ " %idxprom = sext i32 %i to i64\n"
+ " %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom\n"
+ " store i32 %i, i32* %arrayidx, align 4\n"
+ " %inc = add nsw i32 %i, 1\n"
+ " %cmp = icmp sge i32 %inc, %ub\n"
+ " br i1 %cmp, label %for.exit, label %for.body\n"
+ "for.exit:\n"
+ " br label %for.end\n"
+ "for.end:\n"
+ " ret void\n"
+ "}\n";
+
+ // Parse the module.
+ LLVMContext Context;
+ std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleStr);
+
+ runWithLoopInfoPlus(
+ *M, "foo",
+ [&](Function &F, LoopInfo &LI, ScalarEvolution &SE,
+ PostDominatorTree &PDT) {
+ Function::iterator FI = F.begin();
+ // First two basic block are entry and for.preheader - skip them.
+ ++FI;
+ BasicBlock *Header = &*(++FI);
+ assert(Header->getName() == "for.body");
+ Loop *L = LI.getLoopFor(Header);
+ EXPECT_NE(L, nullptr);
+
+ Optional<Loop::LoopBounds> Bounds = L->getBounds(SE);
+ EXPECT_NE(Bounds, None);
+ ConstantInt *InitialIVValue =
+ dyn_cast<ConstantInt>(&Bounds->getInitialIVValue());
+ EXPECT_TRUE(InitialIVValue && InitialIVValue->isZero());
+ EXPECT_EQ(Bounds->getStepInst().getName(), "inc");
+ ConstantInt *StepValue =
+ dyn_cast_or_null<ConstantInt>(Bounds->getStepValue());
+ EXPECT_TRUE(StepValue && StepValue->isOne());
+ EXPECT_EQ(Bounds->getFinalIVValue().getName(), "ub");
+ EXPECT_EQ(Bounds->getCanonicalPredicate(), ICmpInst::ICMP_SLT);
+ EXPECT_EQ(Bounds->getDirection(),
+ Loop::LoopBounds::Direction::Increasing);
+ EXPECT_EQ(L->getInductionVariable(SE)->getName(), "i");
+ });
+}
+
+TEST(LoopInfoTest, LoopWithInverseLatchSuccs) {
+ const char *ModuleStr =
+ "define void @foo(i32* %A, i32 %ub) {\n"
+ "entry:\n"
+ " %guardcmp = icmp slt i32 0, %ub\n"
+ " br i1 %guardcmp, label %for.preheader, label %for.end\n"
+ "for.preheader:\n"
+ " br label %for.body\n"
+ "for.body:\n"
+ " %i = phi i32 [ 0, %for.preheader ], [ %inc, %for.body ]\n"
+ " %idxprom = sext i32 %i to i64\n"
+ " %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom\n"
+ " store i32 %i, i32* %arrayidx, align 4\n"
+ " %inc = add nsw i32 %i, 1\n"
+ " %cmp = icmp sge i32 %inc, %ub\n"
+ " br i1 %cmp, label %for.exit, label %for.body\n"
+ "for.exit:\n"
+ " br label %for.end\n"
+ "for.end:\n"
+ " ret void\n"
+ "}\n";
+
+ // Parse the module.
+ LLVMContext Context;
+ std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleStr);
+
+ runWithLoopInfoPlus(
+ *M, "foo",
+ [&](Function &F, LoopInfo &LI, ScalarEvolution &SE,
+ PostDominatorTree &PDT) {
+ Function::iterator FI = F.begin();
+ // First two basic block are entry and for.preheader - skip them.
+ ++FI;
+ BasicBlock *Header = &*(++FI);
+ assert(Header->getName() == "for.body");
+ Loop *L = LI.getLoopFor(Header);
+ EXPECT_NE(L, nullptr);
+
+ Optional<Loop::LoopBounds> Bounds = L->getBounds(SE);
+ EXPECT_NE(Bounds, None);
+ ConstantInt *InitialIVValue =
+ dyn_cast<ConstantInt>(&Bounds->getInitialIVValue());
+ EXPECT_TRUE(InitialIVValue && InitialIVValue->isZero());
+ EXPECT_EQ(Bounds->getStepInst().getName(), "inc");
+ ConstantInt *StepValue =
+ dyn_cast_or_null<ConstantInt>(Bounds->getStepValue());
+ EXPECT_TRUE(StepValue && StepValue->isOne());
+ EXPECT_EQ(Bounds->getFinalIVValue().getName(), "ub");
+ EXPECT_EQ(Bounds->getCanonicalPredicate(), ICmpInst::ICMP_SLT);
+ EXPECT_EQ(Bounds->getDirection(),
+ Loop::LoopBounds::Direction::Increasing);
+ EXPECT_EQ(L->getInductionVariable(SE)->getName(), "i");
+ });
+}
+
+TEST(LoopInfoTest, LoopWithLatchCmpNE) {
+ const char *ModuleStr =
+ "define void @foo(i32* %A, i32 %ub) {\n"
+ "entry:\n"
+ " %guardcmp = icmp slt i32 0, %ub\n"
+ " br i1 %guardcmp, label %for.preheader, label %for.end\n"
+ "for.preheader:\n"
+ " br label %for.body\n"
+ "for.body:\n"
+ " %i = phi i32 [ 0, %for.preheader ], [ %inc, %for.body ]\n"
+ " %idxprom = sext i32 %i to i64\n"
+ " %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom\n"
+ " store i32 %i, i32* %arrayidx, align 4\n"
+ " %inc = add nsw i32 %i, 1\n"
+ " %cmp = icmp ne i32 %i, %ub\n"
+ " br i1 %cmp, label %for.body, label %for.exit\n"
+ "for.exit:\n"
+ " br label %for.end\n"
+ "for.end:\n"
+ " ret void\n"
+ "}\n";
+
+ // Parse the module.
+ LLVMContext Context;
+ std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleStr);
+
+ runWithLoopInfoPlus(
+ *M, "foo",
+ [&](Function &F, LoopInfo &LI, ScalarEvolution &SE,
+ PostDominatorTree &PDT) {
+ Function::iterator FI = F.begin();
+ // First two basic block are entry and for.preheader - skip them.
+ ++FI;
+ BasicBlock *Header = &*(++FI);
+ assert(Header->getName() == "for.body");
+ Loop *L = LI.getLoopFor(Header);
+ EXPECT_NE(L, nullptr);
+
+ Optional<Loop::LoopBounds> Bounds = L->getBounds(SE);
+ EXPECT_NE(Bounds, None);
+ ConstantInt *InitialIVValue =
+ dyn_cast<ConstantInt>(&Bounds->getInitialIVValue());
+ EXPECT_TRUE(InitialIVValue && InitialIVValue->isZero());
+ EXPECT_EQ(Bounds->getStepInst().getName(), "inc");
+ ConstantInt *StepValue =
+ dyn_cast_or_null<ConstantInt>(Bounds->getStepValue());
+ EXPECT_TRUE(StepValue && StepValue->isOne());
+ EXPECT_EQ(Bounds->getFinalIVValue().getName(), "ub");
+ EXPECT_EQ(Bounds->getCanonicalPredicate(), ICmpInst::ICMP_SLT);
+ EXPECT_EQ(Bounds->getDirection(),
+ Loop::LoopBounds::Direction::Increasing);
+ EXPECT_EQ(L->getInductionVariable(SE)->getName(), "i");
+ });
+}
+
+TEST(LoopInfoTest, LoopWithGuardCmpSLE) {
+ const char *ModuleStr =
+ "define void @foo(i32* %A, i32 %ub) {\n"
+ "entry:\n"
+ " %ubPlusOne = add i32 %ub, 1\n"
+ " %guardcmp = icmp sle i32 0, %ub\n"
+ " br i1 %guardcmp, label %for.preheader, label %for.end\n"
+ "for.preheader:\n"
+ " br label %for.body\n"
+ "for.body:\n"
+ " %i = phi i32 [ 0, %for.preheader ], [ %inc, %for.body ]\n"
+ " %idxprom = sext i32 %i to i64\n"
+ " %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom\n"
+ " store i32 %i, i32* %arrayidx, align 4\n"
+ " %inc = add nsw i32 %i, 1\n"
+ " %cmp = icmp ne i32 %i, %ubPlusOne\n"
+ " br i1 %cmp, label %for.body, label %for.exit\n"
+ "for.exit:\n"
+ " br label %for.end\n"
+ "for.end:\n"
+ " ret void\n"
+ "}\n";
+
+ // Parse the module.
+ LLVMContext Context;
+ std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleStr);
+
+ runWithLoopInfoPlus(
+ *M, "foo",
+ [&](Function &F, LoopInfo &LI, ScalarEvolution &SE,
+ PostDominatorTree &PDT) {
+ Function::iterator FI = F.begin();
+ // First two basic block are entry and for.preheader - skip them.
+ ++FI;
+ BasicBlock *Header = &*(++FI);
+ assert(Header->getName() == "for.body");
+ Loop *L = LI.getLoopFor(Header);
+ EXPECT_NE(L, nullptr);
+
+ Optional<Loop::LoopBounds> Bounds = L->getBounds(SE);
+ EXPECT_NE(Bounds, None);
+ ConstantInt *InitialIVValue =
+ dyn_cast<ConstantInt>(&Bounds->getInitialIVValue());
+ EXPECT_TRUE(InitialIVValue && InitialIVValue->isZero());
+ EXPECT_EQ(Bounds->getStepInst().getName(), "inc");
+ ConstantInt *StepValue =
+ dyn_cast_or_null<ConstantInt>(Bounds->getStepValue());
+ EXPECT_TRUE(StepValue && StepValue->isOne());
+ EXPECT_EQ(Bounds->getFinalIVValue().getName(), "ubPlusOne");
+ EXPECT_EQ(Bounds->getCanonicalPredicate(), ICmpInst::ICMP_SLT);
+ EXPECT_EQ(Bounds->getDirection(),
+ Loop::LoopBounds::Direction::Increasing);
+ EXPECT_EQ(L->getInductionVariable(SE)->getName(), "i");
+ });
+}
+
+TEST(LoopInfoTest, LoopNonConstantStep) {
+ const char *ModuleStr =
+ "define void @foo(i32* %A, i32 %ub, i32 %step) {\n"
+ "entry:\n"
+ " %guardcmp = icmp slt i32 0, %ub\n"
+ " br i1 %guardcmp, label %for.preheader, label %for.end\n"
+ "for.preheader:\n"
+ " br label %for.body\n"
+ "for.body:\n"
+ " %i = phi i32 [ 0, %for.preheader ], [ %inc, %for.body ]\n"
+ " %idxprom = zext i32 %i to i64\n"
+ " %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom\n"
+ " store i32 %i, i32* %arrayidx, align 4\n"
+ " %inc = add nsw i32 %i, %step\n"
+ " %cmp = icmp slt i32 %inc, %ub\n"
+ " br i1 %cmp, label %for.body, label %for.exit\n"
+ "for.exit:\n"
+ " br label %for.end\n"
+ "for.end:\n"
+ " ret void\n"
+ "}\n";
+
+ // Parse the module.
+ LLVMContext Context;
+ std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleStr);
+
+ runWithLoopInfoPlus(
+ *M, "foo",
+ [&](Function &F, LoopInfo &LI, ScalarEvolution &SE,
+ PostDominatorTree &PDT) {
+ Function::iterator FI = F.begin();
+ // First two basic block are entry and for.preheader - skip them.
+ ++FI;
+ BasicBlock *Header = &*(++FI);
+ assert(Header->getName() == "for.body");
+ Loop *L = LI.getLoopFor(Header);
+ EXPECT_NE(L, nullptr);
+
+ Optional<Loop::LoopBounds> Bounds = L->getBounds(SE);
+ EXPECT_NE(Bounds, None);
+ ConstantInt *InitialIVValue =
+ dyn_cast<ConstantInt>(&Bounds->getInitialIVValue());
+ EXPECT_TRUE(InitialIVValue && InitialIVValue->isZero());
+ EXPECT_EQ(Bounds->getStepInst().getName(), "inc");
+ EXPECT_EQ(Bounds->getStepValue()->getName(), "step");
+ EXPECT_EQ(Bounds->getFinalIVValue().getName(), "ub");
+ EXPECT_EQ(Bounds->getCanonicalPredicate(), ICmpInst::ICMP_SLT);
+ EXPECT_EQ(Bounds->getDirection(), Loop::LoopBounds::Direction::Unknown);
+ EXPECT_EQ(L->getInductionVariable(SE)->getName(), "i");
+ });
+}
+
+TEST(LoopInfoTest, LoopUnsignedBounds) {
+ const char *ModuleStr =
+ "define void @foo(i32* %A, i32 %ub) {\n"
+ "entry:\n"
+ " %guardcmp = icmp ult i32 0, %ub\n"
+ " br i1 %guardcmp, label %for.preheader, label %for.end\n"
+ "for.preheader:\n"
+ " br label %for.body\n"
+ "for.body:\n"
+ " %i = phi i32 [ 0, %for.preheader ], [ %inc, %for.body ]\n"
+ " %idxprom = zext i32 %i to i64\n"
+ " %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom\n"
+ " store i32 %i, i32* %arrayidx, align 4\n"
+ " %inc = add i32 %i, 1\n"
+ " %cmp = icmp ult i32 %inc, %ub\n"
+ " br i1 %cmp, label %for.body, label %for.exit\n"
+ "for.exit:\n"
+ " br label %for.end\n"
+ "for.end:\n"
+ " ret void\n"
+ "}\n";
+
+ // Parse the module.
+ LLVMContext Context;
+ std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleStr);
+
+ runWithLoopInfoPlus(
+ *M, "foo",
+ [&](Function &F, LoopInfo &LI, ScalarEvolution &SE,
+ PostDominatorTree &PDT) {
+ Function::iterator FI = F.begin();
+ // First two basic block are entry and for.preheader - skip them.
+ ++FI;
+ BasicBlock *Header = &*(++FI);
+ assert(Header->getName() == "for.body");
+ Loop *L = LI.getLoopFor(Header);
+ EXPECT_NE(L, nullptr);
+
+ Optional<Loop::LoopBounds> Bounds = L->getBounds(SE);
+ EXPECT_NE(Bounds, None);
+ ConstantInt *InitialIVValue =
+ dyn_cast<ConstantInt>(&Bounds->getInitialIVValue());
+ EXPECT_TRUE(InitialIVValue && InitialIVValue->isZero());
+ EXPECT_EQ(Bounds->getStepInst().getName(), "inc");
+ ConstantInt *StepValue =
+ dyn_cast_or_null<ConstantInt>(Bounds->getStepValue());
+ EXPECT_TRUE(StepValue && StepValue->isOne());
+ EXPECT_EQ(Bounds->getFinalIVValue().getName(), "ub");
+ EXPECT_EQ(Bounds->getCanonicalPredicate(), ICmpInst::ICMP_ULT);
+ EXPECT_EQ(Bounds->getDirection(),
+ Loop::LoopBounds::Direction::Increasing);
+ EXPECT_EQ(L->getInductionVariable(SE)->getName(), "i");
+ });
+}
+
+TEST(LoopInfoTest, DecreasingLoop) {
+ const char *ModuleStr =
+ "define void @foo(i32* %A, i32 %ub) {\n"
+ "entry:\n"
+ " %guardcmp = icmp slt i32 0, %ub\n"
+ " br i1 %guardcmp, label %for.preheader, label %for.end\n"
+ "for.preheader:\n"
+ " br label %for.body\n"
+ "for.body:\n"
+ " %i = phi i32 [ %ub, %for.preheader ], [ %inc, %for.body ]\n"
+ " %idxprom = sext i32 %i to i64\n"
+ " %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom\n"
+ " store i32 %i, i32* %arrayidx, align 4\n"
+ " %inc = sub nsw i32 %i, 1\n"
+ " %cmp = icmp sgt i32 %inc, 0\n"
+ " br i1 %cmp, label %for.body, label %for.exit\n"
+ "for.exit:\n"
+ " br label %for.end\n"
+ "for.end:\n"
+ " ret void\n"
+ "}\n";
+
+ // Parse the module.
+ LLVMContext Context;
+ std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleStr);
+
+ runWithLoopInfoPlus(
+ *M, "foo",
+ [&](Function &F, LoopInfo &LI, ScalarEvolution &SE,
+ PostDominatorTree &PDT) {
+ Function::iterator FI = F.begin();
+ // First two basic block are entry and for.preheader - skip them.
+ ++FI;
+ BasicBlock *Header = &*(++FI);
+ assert(Header->getName() == "for.body");
+ Loop *L = LI.getLoopFor(Header);
+ EXPECT_NE(L, nullptr);
+
+ Optional<Loop::LoopBounds> Bounds = L->getBounds(SE);
+ EXPECT_NE(Bounds, None);
+ EXPECT_EQ(Bounds->getInitialIVValue().getName(), "ub");
+ EXPECT_EQ(Bounds->getStepInst().getName(), "inc");
+ ConstantInt *StepValue =
+ dyn_cast_or_null<ConstantInt>(Bounds->getStepValue());
+ EXPECT_EQ(StepValue, nullptr);
+ ConstantInt *FinalIVValue =
+ dyn_cast<ConstantInt>(&Bounds->getFinalIVValue());
+ EXPECT_TRUE(FinalIVValue && FinalIVValue->isZero());
+ EXPECT_EQ(Bounds->getCanonicalPredicate(), ICmpInst::ICMP_SGT);
+ EXPECT_EQ(Bounds->getDirection(),
+ Loop::LoopBounds::Direction::Decreasing);
+ EXPECT_EQ(L->getInductionVariable(SE)->getName(), "i");
+ });
+}
+
+TEST(LoopInfoTest, CannotFindDirection) {
+ const char *ModuleStr =
+ "define void @foo(i32* %A, i32 %ub, i32 %step) {\n"
+ "entry:\n"
+ " %guardcmp = icmp slt i32 0, %ub\n"
+ " br i1 %guardcmp, label %for.preheader, label %for.end\n"
+ "for.preheader:\n"
+ " br label %for.body\n"
+ "for.body:\n"
+ " %i = phi i32 [ 0, %for.preheader ], [ %inc, %for.body ]\n"
+ " %idxprom = sext i32 %i to i64\n"
+ " %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom\n"
+ " store i32 %i, i32* %arrayidx, align 4\n"
+ " %inc = add nsw i32 %i, %step\n"
+ " %cmp = icmp ne i32 %i, %ub\n"
+ " br i1 %cmp, label %for.body, label %for.exit\n"
+ "for.exit:\n"
+ " br label %for.end\n"
+ "for.end:\n"
+ " ret void\n"
+ "}\n";
+
+ // Parse the module.
+ LLVMContext Context;
+ std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleStr);
+
+ runWithLoopInfoPlus(*M, "foo",
+ [&](Function &F, LoopInfo &LI, ScalarEvolution &SE,
+ PostDominatorTree &PDT) {
+ Function::iterator FI = F.begin();
+ // First two basic block are entry and for.preheader
+ // - skip them.
+ ++FI;
+ BasicBlock *Header = &*(++FI);
+ assert(Header->getName() == "for.body");
+ Loop *L = LI.getLoopFor(Header);
+ EXPECT_NE(L, nullptr);
+
+ Optional<Loop::LoopBounds> Bounds = L->getBounds(SE);
+ EXPECT_NE(Bounds, None);
+ ConstantInt *InitialIVValue =
+ dyn_cast<ConstantInt>(&Bounds->getInitialIVValue());
+ EXPECT_TRUE(InitialIVValue && InitialIVValue->isZero());
+ EXPECT_EQ(Bounds->getStepInst().getName(), "inc");
+ EXPECT_EQ(Bounds->getStepValue()->getName(), "step");
+ EXPECT_EQ(Bounds->getFinalIVValue().getName(), "ub");
+ EXPECT_EQ(Bounds->getCanonicalPredicate(),
+ ICmpInst::BAD_ICMP_PREDICATE);
+ EXPECT_EQ(Bounds->getDirection(),
+ Loop::LoopBounds::Direction::Unknown);
+ EXPECT_EQ(L->getInductionVariable(SE)->getName(), "i");
+ });
+}
+
+TEST(LoopInfoTest, ZextIndVar) {
+ const char *ModuleStr =
+ "define void @foo(i32* %A, i32 %ub) {\n"
+ "entry:\n"
+ " %guardcmp = icmp slt i32 0, %ub\n"
+ " br i1 %guardcmp, label %for.preheader, label %for.end\n"
+ "for.preheader:\n"
+ " br label %for.body\n"
+ "for.body:\n"
+ " %indvars.iv = phi i64 [ 0, %for.preheader ], [ %indvars.iv.next, %for.body ]\n"
+ " %i = phi i32 [ 0, %for.preheader ], [ %inc, %for.body ]\n"
+ " %idxprom = sext i32 %i to i64\n"
+ " %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom\n"
+ " store i32 %i, i32* %arrayidx, align 4\n"
+ " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
+ " %inc = add nsw i32 %i, 1\n"
+ " %wide.trip.count = zext i32 %ub to i64\n"
+ " %exitcond = icmp ne i64 %indvars.iv.next, %wide.trip.count\n"
+ " br i1 %exitcond, label %for.body, label %for.exit\n"
+ "for.exit:\n"
+ " br label %for.end\n"
+ "for.end:\n"
+ " ret void\n"
+ "}\n";
+
+ // Parse the module.
+ LLVMContext Context;
+ std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleStr);
+
+ runWithLoopInfoPlus(
+ *M, "foo",
+ [&](Function &F, LoopInfo &LI, ScalarEvolution &SE,
+ PostDominatorTree &PDT) {
+ Function::iterator FI = F.begin();
+ // First two basic block are entry and for.preheader - skip them.
+ ++FI;
+ BasicBlock *Header = &*(++FI);
+ assert(Header->getName() == "for.body");
+ Loop *L = LI.getLoopFor(Header);
+ EXPECT_NE(L, nullptr);
+
+ Optional<Loop::LoopBounds> Bounds = L->getBounds(SE);
+ EXPECT_NE(Bounds, None);
+ ConstantInt *InitialIVValue =
+ dyn_cast<ConstantInt>(&Bounds->getInitialIVValue());
+ EXPECT_TRUE(InitialIVValue && InitialIVValue->isZero());
+ EXPECT_EQ(Bounds->getStepInst().getName(), "indvars.iv.next");
+ ConstantInt *StepValue =
+ dyn_cast_or_null<ConstantInt>(Bounds->getStepValue());
+ EXPECT_TRUE(StepValue && StepValue->isOne());
+ EXPECT_EQ(Bounds->getFinalIVValue().getName(), "wide.trip.count");
+ EXPECT_EQ(Bounds->getCanonicalPredicate(), ICmpInst::ICMP_NE);
+ EXPECT_EQ(Bounds->getDirection(),
+ Loop::LoopBounds::Direction::Increasing);
+ EXPECT_EQ(L->getInductionVariable(SE)->getName(), "indvars.iv");
+ });
+}
+
+TEST(LoopInfoTest, UnguardedLoop) {
+ const char *ModuleStr =
+ "define void @foo(i32* %A, i32 %ub) {\n"
+ "entry:\n"
+ " br label %for.body\n"
+ "for.body:\n"
+ " %i = phi i32 [ 0, %entry ], [ %inc, %for.body ]\n"
+ " %idxprom = sext i32 %i to i64\n"
+ " %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom\n"
+ " store i32 %i, i32* %arrayidx, align 4\n"
+ " %inc = add nsw i32 %i, 1\n"
+ " %cmp = icmp slt i32 %inc, %ub\n"
+ " br i1 %cmp, label %for.body, label %for.exit\n"
+ "for.exit:\n"
+ " br label %for.end\n"
+ "for.end:\n"
+ " ret void\n"
+ "}\n";
+
+ // Parse the module.
+ LLVMContext Context;
+ std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleStr);
+
+ runWithLoopInfoPlus(
+ *M, "foo",
+ [&](Function &F, LoopInfo &LI, ScalarEvolution &SE,
+ PostDominatorTree &PDT) {
+ Function::iterator FI = F.begin();
+ // First basic block is entry - skip it.
+ BasicBlock *Header = &*(++FI);
+ assert(Header->getName() == "for.body");
+ Loop *L = LI.getLoopFor(Header);
+ EXPECT_NE(L, nullptr);
+
+ Optional<Loop::LoopBounds> Bounds = L->getBounds(SE);
+ EXPECT_NE(Bounds, None);
+ ConstantInt *InitialIVValue =
+ dyn_cast<ConstantInt>(&Bounds->getInitialIVValue());
+ EXPECT_TRUE(InitialIVValue && InitialIVValue->isZero());
+ EXPECT_EQ(Bounds->getStepInst().getName(), "inc");
+ ConstantInt *StepValue =
+ dyn_cast_or_null<ConstantInt>(Bounds->getStepValue());
+ EXPECT_TRUE(StepValue && StepValue->isOne());
+ EXPECT_EQ(Bounds->getFinalIVValue().getName(), "ub");
+ EXPECT_EQ(Bounds->getCanonicalPredicate(), ICmpInst::ICMP_SLT);
+ EXPECT_EQ(Bounds->getDirection(),
+ Loop::LoopBounds::Direction::Increasing);
+ EXPECT_EQ(L->getInductionVariable(SE)->getName(), "i");
+ });
+}
+
+TEST(LoopInfoTest, UnguardedLoopWithControlFlow) {
+ const char *ModuleStr =
+ "define void @foo(i32* %A, i32 %ub, i1 %cond) {\n"
+ "entry:\n"
+ " br i1 %cond, label %for.preheader, label %for.end\n"
+ "for.preheader:\n"
+ " br label %for.body\n"
+ "for.body:\n"
+ " %i = phi i32 [ 0, %for.preheader ], [ %inc, %for.body ]\n"
+ " %idxprom = sext i32 %i to i64\n"
+ " %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom\n"
+ " store i32 %i, i32* %arrayidx, align 4\n"
+ " %inc = add nsw i32 %i, 1\n"
+ " %cmp = icmp slt i32 %inc, %ub\n"
+ " br i1 %cmp, label %for.body, label %for.exit\n"
+ "for.exit:\n"
+ " br label %for.end\n"
+ "for.end:\n"
+ " ret void\n"
+ "}\n";
+
+ // Parse the module.
+ LLVMContext Context;
+ std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleStr);
+
+ runWithLoopInfoPlus(
+ *M, "foo",
+ [&](Function &F, LoopInfo &LI, ScalarEvolution &SE,
+ PostDominatorTree &PDT) {
+ Function::iterator FI = F.begin();
+ // First two basic block are entry and for.preheader - skip them.
+ ++FI;
+ BasicBlock *Header = &*(++FI);
+ assert(Header->getName() == "for.body");
+ Loop *L = LI.getLoopFor(Header);
+ EXPECT_NE(L, nullptr);
+
+ Optional<Loop::LoopBounds> Bounds = L->getBounds(SE);
+ EXPECT_NE(Bounds, None);
+ ConstantInt *InitialIVValue =
+ dyn_cast<ConstantInt>(&Bounds->getInitialIVValue());
+ EXPECT_TRUE(InitialIVValue && InitialIVValue->isZero());
+ EXPECT_EQ(Bounds->getStepInst().getName(), "inc");
+ ConstantInt *StepValue =
+ dyn_cast_or_null<ConstantInt>(Bounds->getStepValue());
+ EXPECT_TRUE(StepValue && StepValue->isOne());
+ EXPECT_EQ(Bounds->getFinalIVValue().getName(), "ub");
+ EXPECT_EQ(Bounds->getCanonicalPredicate(), ICmpInst::ICMP_SLT);
+ EXPECT_EQ(Bounds->getDirection(),
+ Loop::LoopBounds::Direction::Increasing);
+ EXPECT_EQ(L->getInductionVariable(SE)->getName(), "i");
+ });
+}
+
+TEST(LoopInfoTest, LoopNest) {
+ const char *ModuleStr =
+ "define void @foo(i32* %A, i32 %ub) {\n"
+ "entry:\n"
+ " %guardcmp = icmp slt i32 0, %ub\n"
+ " br i1 %guardcmp, label %for.outer.preheader, label %for.end\n"
+ "for.outer.preheader:\n"
+ " br label %for.outer\n"
+ "for.outer:\n"
+ " %j = phi i32 [ 0, %for.outer.preheader ], [ %inc.outer, %for.outer.latch ]\n"
+ " br i1 %guardcmp, label %for.inner.preheader, label %for.outer.latch\n"
+ "for.inner.preheader:\n"
+ " br label %for.inner\n"
+ "for.inner:\n"
+ " %i = phi i32 [ 0, %for.inner.preheader ], [ %inc, %for.inner ]\n"
+ " %idxprom = sext i32 %i to i64\n"
+ " %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom\n"
+ " store i32 %i, i32* %arrayidx, align 4\n"
+ " %inc = add nsw i32 %i, 1\n"
+ " %cmp = icmp slt i32 %inc, %ub\n"
+ " br i1 %cmp, label %for.inner, label %for.inner.exit\n"
+ "for.inner.exit:\n"
+ " br label %for.outer.latch\n"
+ "for.outer.latch:\n"
+ " %inc.outer = add nsw i32 %j, 1\n"
+ " %cmp.outer = icmp slt i32 %inc.outer, %ub\n"
+ " br i1 %cmp.outer, label %for.outer, label %for.outer.exit\n"
+ "for.outer.exit:\n"
+ " br label %for.end\n"
+ "for.end:\n"
+ " ret void\n"
+ "}\n";
+
+ // Parse the module.
+ LLVMContext Context;
+ std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleStr);
+
+ runWithLoopInfoPlus(
+ *M, "foo",
+ [&](Function &F, LoopInfo &LI, ScalarEvolution &SE,
+ PostDominatorTree &PDT) {
+ Function::iterator FI = F.begin();
+ // First two basic block are entry and for.outer.preheader - skip them.
+ ++FI;
+ BasicBlock *Header = &*(++FI);
+ assert(Header->getName() == "for.outer");
+ Loop *L = LI.getLoopFor(Header);
+ EXPECT_NE(L, nullptr);
+
+ Optional<Loop::LoopBounds> Bounds = L->getBounds(SE);
+ EXPECT_NE(Bounds, None);
+ ConstantInt *InitialIVValue =
+ dyn_cast<ConstantInt>(&Bounds->getInitialIVValue());
+ EXPECT_TRUE(InitialIVValue && InitialIVValue->isZero());
+ EXPECT_EQ(Bounds->getStepInst().getName(), "inc.outer");
+ ConstantInt *StepValue =
+ dyn_cast_or_null<ConstantInt>(Bounds->getStepValue());
+ EXPECT_TRUE(StepValue && StepValue->isOne());
+ EXPECT_EQ(Bounds->getFinalIVValue().getName(), "ub");
+ EXPECT_EQ(Bounds->getCanonicalPredicate(), ICmpInst::ICMP_SLT);
+ EXPECT_EQ(Bounds->getDirection(),
+ Loop::LoopBounds::Direction::Increasing);
+ EXPECT_EQ(L->getInductionVariable(SE)->getName(), "j");
+
+ // Next two basic blocks are for.outer and for.inner.preheader - skip
+ // them.
+ ++FI;
+ Header = &*(++FI);
+ assert(Header->getName() == "for.inner");
+ L = LI.getLoopFor(Header);
+ EXPECT_NE(L, nullptr);
+
+ Optional<Loop::LoopBounds> InnerBounds = L->getBounds(SE);
+ EXPECT_NE(InnerBounds, None);
+ InitialIVValue =
+ dyn_cast<ConstantInt>(&InnerBounds->getInitialIVValue());
+ EXPECT_TRUE(InitialIVValue && InitialIVValue->isZero());
+ EXPECT_EQ(InnerBounds->getStepInst().getName(), "inc");
+ StepValue = dyn_cast_or_null<ConstantInt>(InnerBounds->getStepValue());
+ EXPECT_TRUE(StepValue && StepValue->isOne());
+ EXPECT_EQ(InnerBounds->getFinalIVValue().getName(), "ub");
+ EXPECT_EQ(InnerBounds->getCanonicalPredicate(), ICmpInst::ICMP_SLT);
+ EXPECT_EQ(InnerBounds->getDirection(),
+ Loop::LoopBounds::Direction::Increasing);
+ EXPECT_EQ(L->getInductionVariable(SE)->getName(), "i");
+ });
+}
+
+TEST(LoopInfoTest, AuxiliaryIV) {
+ const char *ModuleStr =
+ "define void @foo(i32* %A, i32 %ub) {\n"
+ "entry:\n"
+ " %guardcmp = icmp slt i32 0, %ub\n"
+ " br i1 %guardcmp, label %for.preheader, label %for.end\n"
+ "for.preheader:\n"
+ " br label %for.body\n"
+ "for.body:\n"
+ " %i = phi i32 [ 0, %for.preheader ], [ %inc, %for.body ]\n"
+ " %aux = phi i32 [ 0, %for.preheader ], [ %auxinc, %for.body ]\n"
+ " %loopvariant = phi i32 [ 0, %for.preheader ], [ %loopvariantinc, %for.body ]\n"
+ " %usedoutside = phi i32 [ 0, %for.preheader ], [ %usedoutsideinc, %for.body ]\n"
+ " %mulopcode = phi i32 [ 0, %for.preheader ], [ %mulopcodeinc, %for.body ]\n"
+ " %idxprom = sext i32 %i to i64\n"
+ " %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom\n"
+ " store i32 %i, i32* %arrayidx, align 4\n"
+ " %mulopcodeinc = mul nsw i32 %mulopcode, 5\n"
+ " %usedoutsideinc = add nsw i32 %usedoutside, 5\n"
+ " %loopvariantinc = add nsw i32 %loopvariant, %i\n"
+ " %auxinc = add nsw i32 %aux, 5\n"
+ " %inc = add nsw i32 %i, 1\n"
+ " %cmp = icmp slt i32 %inc, %ub\n"
+ " br i1 %cmp, label %for.body, label %for.exit\n"
+ "for.exit:\n"
+ " %lcssa = phi i32 [ %usedoutside, %for.body ]\n"
+ " br label %for.end\n"
+ "for.end:\n"
+ " ret void\n"
+ "}\n";
+
+ // Parse the module.
+ LLVMContext Context;
+ std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleStr);
+
+ runWithLoopInfoPlus(
+ *M, "foo",
+ [&](Function &F, LoopInfo &LI, ScalarEvolution &SE,
+ PostDominatorTree &PDT) {
+ Function::iterator FI = F.begin();
+ // First two basic block are entry and for.preheader - skip them.
+ ++FI;
+ BasicBlock *Header = &*(++FI);
+ assert(Header->getName() == "for.body");
+ Loop *L = LI.getLoopFor(Header);
+ EXPECT_NE(L, nullptr);
+
+ Optional<Loop::LoopBounds> Bounds = L->getBounds(SE);
+ EXPECT_NE(Bounds, None);
+ ConstantInt *InitialIVValue =
+ dyn_cast<ConstantInt>(&Bounds->getInitialIVValue());
+ EXPECT_TRUE(InitialIVValue && InitialIVValue->isZero());
+ EXPECT_EQ(Bounds->getStepInst().getName(), "inc");
+ ConstantInt *StepValue =
+ dyn_cast_or_null<ConstantInt>(Bounds->getStepValue());
+ EXPECT_TRUE(StepValue && StepValue->isOne());
+ EXPECT_EQ(Bounds->getFinalIVValue().getName(), "ub");
+ EXPECT_EQ(Bounds->getCanonicalPredicate(), ICmpInst::ICMP_SLT);
+ EXPECT_EQ(Bounds->getDirection(),
+ Loop::LoopBounds::Direction::Increasing);
+ EXPECT_EQ(L->getInductionVariable(SE)->getName(), "i");
+ BasicBlock::iterator II = Header->begin();
+ PHINode &Instruction_i = cast<PHINode>(*(II));
+ EXPECT_TRUE(L->isAuxiliaryInductionVariable(Instruction_i, SE));
+ PHINode &Instruction_aux = cast<PHINode>(*(++II));
+ EXPECT_TRUE(L->isAuxiliaryInductionVariable(Instruction_aux, SE));
+ PHINode &Instruction_loopvariant = cast<PHINode>(*(++II));
+ EXPECT_FALSE(
+ L->isAuxiliaryInductionVariable(Instruction_loopvariant, SE));
+ PHINode &Instruction_usedoutside = cast<PHINode>(*(++II));
+ EXPECT_FALSE(
+ L->isAuxiliaryInductionVariable(Instruction_usedoutside, SE));
+ PHINode &Instruction_mulopcode = cast<PHINode>(*(++II));
+ EXPECT_FALSE(
+ L->isAuxiliaryInductionVariable(Instruction_mulopcode, SE));
+ });
+}
OpenPOWER on IntegriCloud