diff options
-rw-r--r-- | llvm/include/llvm/Analysis/IVDescriptors.h | 6 | ||||
-rw-r--r-- | llvm/lib/Analysis/IVDescriptors.cpp | 11 | ||||
-rw-r--r-- | llvm/unittests/Analysis/CMakeLists.txt | 1 | ||||
-rw-r--r-- | llvm/unittests/Analysis/IVDescriptorsTest.cpp | 100 |
4 files changed, 115 insertions, 3 deletions
diff --git a/llvm/include/llvm/Analysis/IVDescriptors.h b/llvm/include/llvm/Analysis/IVDescriptors.h index 4e8b6ec202c..7be1fd3f578 100644 --- a/llvm/include/llvm/Analysis/IVDescriptors.h +++ b/llvm/include/llvm/Analysis/IVDescriptors.h @@ -315,12 +315,16 @@ public: /// not have the "fast-math" property. Such operation requires a relaxed FP /// mode. bool hasUnsafeAlgebra() { - return InductionBinOp && !cast<FPMathOperator>(InductionBinOp)->isFast(); + return (IK == IK_FpInduction) && InductionBinOp && + !cast<FPMathOperator>(InductionBinOp)->isFast(); } /// Returns induction operator that does not have "fast-math" property /// and requires FP unsafe mode. Instruction *getUnsafeAlgebraInst() { + if (IK != IK_FpInduction) + return nullptr; + if (!InductionBinOp || cast<FPMathOperator>(InductionBinOp)->isFast()) return nullptr; return InductionBinOp; diff --git a/llvm/lib/Analysis/IVDescriptors.cpp b/llvm/lib/Analysis/IVDescriptors.cpp index 19f1a771b85..ce285f82f72 100644 --- a/llvm/lib/Analysis/IVDescriptors.cpp +++ b/llvm/lib/Analysis/IVDescriptors.cpp @@ -1053,6 +1053,13 @@ bool InductionDescriptor::isInductionPHI( 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. @@ -1061,7 +1068,7 @@ bool InductionDescriptor::isInductionPHI( return false; if (PhiTy->isIntegerTy()) { - D = InductionDescriptor(StartValue, IK_IntInduction, Step, /*BOp=*/nullptr, + D = InductionDescriptor(StartValue, IK_IntInduction, Step, BOp, CastsToIgnore); return true; } @@ -1088,6 +1095,6 @@ bool InductionDescriptor::isInductionPHI( 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; } diff --git a/llvm/unittests/Analysis/CMakeLists.txt b/llvm/unittests/Analysis/CMakeLists.txt index 45d31f88911..20b4ae21edb 100644 --- a/llvm/unittests/Analysis/CMakeLists.txt +++ b/llvm/unittests/Analysis/CMakeLists.txt @@ -18,6 +18,7 @@ add_llvm_unittest(AnalysisTests DivergenceAnalysisTest.cpp DomTreeUpdaterTest.cpp GlobalsModRefTest.cpp + IVDescriptorsTest.cpp LazyCallGraphTest.cpp LoopInfoTest.cpp MemoryBuiltinsTest.cpp diff --git a/llvm/unittests/Analysis/IVDescriptorsTest.cpp b/llvm/unittests/Analysis/IVDescriptorsTest.cpp new file mode 100644 index 00000000000..cba45a96e68 --- /dev/null +++ b/llvm/unittests/Analysis/IVDescriptorsTest.cpp @@ -0,0 +1,100 @@ +//===- 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); + }); +} |