diff options
author | Nikolai Bozhenov <nikolai.bozhenov@intel.com> | 2019-08-07 17:38:38 +0000 |
---|---|---|
committer | Nikolai Bozhenov <nikolai.bozhenov@intel.com> | 2019-08-07 17:38:38 +0000 |
commit | 03edcd68dd739cce53256f8573a141b09ea49ae3 (patch) | |
tree | 344dce7c13f382f63e8b50a2b0b34422267b7d37 | |
parent | a1d20506e771a376e293a61e26842a906487d7ef (diff) | |
download | bcm5719-llvm-03edcd68dd739cce53256f8573a141b09ea49ae3.tar.gz bcm5719-llvm-03edcd68dd739cce53256f8573a141b09ea49ae3.zip |
[SCEV] Return zero from computeConstantDifference(X, X)
Without this patch computeConstantDifference returns None for cases like
these:
computeConstantDifference(%x, %x)
computeConstantDifference({%x,+,16}, {%x,+,16})
Differential Revision: https://reviews.llvm.org/D65474
llvm-svn: 368193
-rw-r--r-- | llvm/include/llvm/Analysis/ScalarEvolution.h | 2 | ||||
-rw-r--r-- | llvm/lib/Analysis/ScalarEvolution.cpp | 4 | ||||
-rw-r--r-- | llvm/unittests/Analysis/ScalarEvolutionTest.cpp | 70 |
3 files changed, 74 insertions, 2 deletions
diff --git a/llvm/include/llvm/Analysis/ScalarEvolution.h b/llvm/include/llvm/Analysis/ScalarEvolution.h index 0bd98ef37e7..eb32991ec12 100644 --- a/llvm/include/llvm/Analysis/ScalarEvolution.h +++ b/llvm/include/llvm/Analysis/ScalarEvolution.h @@ -468,6 +468,8 @@ template <> struct DenseMapInfo<ExitLimitQuery> { /// can't do much with the SCEV objects directly, they must ask this class /// for services. class ScalarEvolution { + friend class ScalarEvolutionsTest; + public: /// An enum describing the relationship between a SCEV and a loop. enum LoopDisposition { diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp index bc2cfd6fcc4..8552d784c43 100644 --- a/llvm/lib/Analysis/ScalarEvolution.cpp +++ b/llvm/lib/Analysis/ScalarEvolution.cpp @@ -9833,6 +9833,10 @@ Optional<APInt> ScalarEvolution::computeConstantDifference(const SCEV *More, // We avoid subtracting expressions here because this function is usually // fairly deep in the call stack (i.e. is called many times). + // X - X = 0. + if (More == Less) + return APInt(getTypeSizeInBits(More->getType()), 0); + if (isa<SCEVAddRecExpr>(Less) && isa<SCEVAddRecExpr>(More)) { const auto *LAR = cast<SCEVAddRecExpr>(Less); const auto *MAR = cast<SCEVAddRecExpr>(More); diff --git a/llvm/unittests/Analysis/ScalarEvolutionTest.cpp b/llvm/unittests/Analysis/ScalarEvolutionTest.cpp index fb8f6689ca7..42c708da6d4 100644 --- a/llvm/unittests/Analysis/ScalarEvolutionTest.cpp +++ b/llvm/unittests/Analysis/ScalarEvolutionTest.cpp @@ -26,7 +26,6 @@ #include "gtest/gtest.h" namespace llvm { -namespace { // We use this fixture to ensure that we clean up ScalarEvolution before // deleting the PassManager. @@ -58,6 +57,12 @@ protected: ScalarEvolution SE = buildSE(*F); Test(*F, *LI, SE); } + + static Optional<APInt> computeConstantDifference(ScalarEvolution &SE, + const SCEV *LHS, + const SCEV *RHS) { + return SE.computeConstantDifference(LHS, RHS); + } }; TEST_F(ScalarEvolutionsTest, SCEVUnknownRAUW) { @@ -1678,5 +1683,66 @@ TEST_F(ScalarEvolutionsTest, SCEVExpanderShlNSW) { "} "); } -} // end anonymous namespace +TEST_F(ScalarEvolutionsTest, SCEVComputeConstantDifference) { + LLVMContext C; + SMDiagnostic Err; + std::unique_ptr<Module> M = parseAssemblyString( + "define void @foo(i32 %sz, i32 %pp) { " + "entry: " + " %v0 = add i32 %pp, 0 " + " %v3 = add i32 %pp, 3 " + " br label %loop.body " + "loop.body: " + " %iv = phi i32 [ %iv.next, %loop.body ], [ 0, %entry ] " + " %xa = add nsw i32 %iv, %v0 " + " %yy = add nsw i32 %iv, %v3 " + " %xb = sub nsw i32 %yy, 3 " + " %iv.next = add nsw i32 %iv, 1 " + " %cmp = icmp sle i32 %iv.next, %sz " + " br i1 %cmp, label %loop.body, label %exit " + "exit: " + " ret void " + "} ", + Err, C); + + ASSERT_TRUE(M && "Could not parse module?"); + ASSERT_TRUE(!verifyModule(*M) && "Must have been well formed!"); + + runWithSE(*M, "foo", [](Function &F, LoopInfo &LI, ScalarEvolution &SE) { + auto *ScevV0 = SE.getSCEV(getInstructionByName(F, "v0")); // %pp + auto *ScevV3 = SE.getSCEV(getInstructionByName(F, "v3")); // (3 + %pp) + auto *ScevIV = SE.getSCEV(getInstructionByName(F, "iv")); // {0,+,1} + auto *ScevXA = SE.getSCEV(getInstructionByName(F, "xa")); // {%pp,+,1} + auto *ScevYY = SE.getSCEV(getInstructionByName(F, "yy")); // {(3 + %pp),+,1} + auto *ScevXB = SE.getSCEV(getInstructionByName(F, "xb")); // {%pp,+,1} + auto *ScevIVNext = SE.getSCEV(getInstructionByName(F, "iv.next")); // {1,+,1} + + auto diff = [&SE](const SCEV *LHS, const SCEV *RHS) -> Optional<int> { + auto ConstantDiffOrNone = computeConstantDifference(SE, LHS, RHS); + if (!ConstantDiffOrNone) + return None; + + auto ExtDiff = ConstantDiffOrNone->getSExtValue(); + int Diff = ExtDiff; + assert(Diff == ExtDiff && "Integer overflow"); + return Diff; + }; + + EXPECT_EQ(diff(ScevV3, ScevV0), 3); + EXPECT_EQ(diff(ScevV0, ScevV3), -3); + EXPECT_EQ(diff(ScevV0, ScevV0), 0); + EXPECT_EQ(diff(ScevV3, ScevV3), 0); + EXPECT_EQ(diff(ScevIV, ScevIV), 0); + EXPECT_EQ(diff(ScevXA, ScevXB), 0); + EXPECT_EQ(diff(ScevXA, ScevYY), -3); + EXPECT_EQ(diff(ScevYY, ScevXB), 3); + EXPECT_EQ(diff(ScevIV, ScevIVNext), -1); + EXPECT_EQ(diff(ScevIVNext, ScevIV), 1); + EXPECT_EQ(diff(ScevIVNext, ScevIVNext), 0); + EXPECT_EQ(diff(ScevV0, ScevIV), None); + EXPECT_EQ(diff(ScevIVNext, ScevV3), None); + EXPECT_EQ(diff(ScevYY, ScevV3), None); + }); +} + } // end namespace llvm |