Value *StartValue =
Phi->getIncomingValueForBlock(AR->getLoop()->getLoopPreheader());
+
+ BasicBlock *Latch = AR->getLoop()->getLoopLatch();
+ if (!Latch)
+ return false;
+ BinaryOperator *BOp =
+ dyn_cast<BinaryOperator>(Phi->getIncomingValueForBlock(Latch));
+
const SCEV *Step = AR->getStepRecurrence(*SE);
// Calculate the pointer stride and check if it is consecutive.
// The stride may be a constant or a loop invariant integer value.
return false;
if (PhiTy->isIntegerTy()) {
- D = InductionDescriptor(StartValue, IK_IntInduction, Step, /*BOp=*/nullptr,
+ D = InductionDescriptor(StartValue, IK_IntInduction, Step, BOp,
CastsToIgnore);
return true;
}
return false;
auto *StepValue =
SE->getConstant(CV->getType(), CVSize / Size, true /* signed */);
- D = InductionDescriptor(StartValue, IK_PtrInduction, StepValue);
+ D = InductionDescriptor(StartValue, IK_PtrInduction, StepValue, BOp);
return true;
}
--- /dev/null
+//===- IVDescriptorsTest.cpp - IVDescriptors unit tests -------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Analysis/IVDescriptors.h"
+#include "llvm/Analysis/AssumptionCache.h"
+#include "llvm/Analysis/LoopInfo.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"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+/// Build the loop info and scalar evolution for the function and run the Test.
+static void runWithLoopInfoAndSE(
+ Module &M, StringRef FuncName,
+ function_ref<void(Function &F, LoopInfo &LI, ScalarEvolution &SE)> 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);
+
+ Test(*F, LI, SE);
+}
+
+static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
+ SMDiagnostic Err;
+ std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
+ if (!Mod)
+ Err.print("IVDescriptorsTests", errs());
+ return Mod;
+}
+
+// This tests that IVDescriptors can obtain the induction binary operator for
+// integer induction variables. And hasUnsafeAlgebra() and
+// getUnsafeAlgebraInst() correctly return the expected behavior, i.e. no unsafe
+// algebra.
+TEST(IVDescriptorsTest, LoopWithSingleLatch) {
+ // Parse the module.
+ LLVMContext Context;
+
+ std::unique_ptr<Module> M = parseIR(
+ Context,
+ R"(define void @foo(i32* %A, i32 %ub) {
+entry:
+ br label %for.body
+for.body:
+ %i = phi i32 [ 0, %entry ], [ %inc, %for.body ]
+ %idxprom = sext i32 %i to i64
+ %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom
+ store i32 %i, i32* %arrayidx, align 4
+ %inc = add nsw i32 %i, 1
+ %cmp = icmp slt i32 %inc, %ub
+ br i1 %cmp, label %for.body, label %for.exit
+for.exit:
+ br label %for.end
+for.end:
+ ret void
+})"
+ );
+
+ runWithLoopInfoAndSE(
+ *M, "foo", [&](Function &F, LoopInfo &LI, ScalarEvolution &SE) {
+ 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);
+ PHINode *Inst_i = dyn_cast<PHINode>(&Header->front());
+ assert(Inst_i->getName() == "i");
+ InductionDescriptor IndDesc;
+ bool IsInductionPHI =
+ InductionDescriptor::isInductionPHI(Inst_i, L, &SE, IndDesc);
+ EXPECT_TRUE(IsInductionPHI);
+ Instruction *Inst_inc = nullptr;
+ BasicBlock::iterator BBI = Header->begin();
+ do {
+ if ((&*BBI)->getName() == "inc")
+ Inst_inc = &*BBI;
+ ++BBI;
+ } while (!Inst_inc);
+ assert(Inst_inc->getName() == "inc");
+ EXPECT_EQ(IndDesc.getInductionBinOp(), Inst_inc);
+ EXPECT_FALSE(IndDesc.hasUnsafeAlgebra());
+ EXPECT_EQ(IndDesc.getUnsafeAlgebraInst(), nullptr);
+ });
+}