diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp index 51cffac808768..2fdfe243e2dc5 100644 --- a/llvm/lib/Analysis/ScalarEvolution.cpp +++ b/llvm/lib/Analysis/ScalarEvolution.cpp @@ -597,11 +597,14 @@ void SCEVUnknown::allUsesReplacedWith(Value *New) { /// /// Since we do not continue running this routine on expression trees once we /// have seen unequal values, there is no need to track them in the cache. -static int +static std::optional CompareValueComplexity(EquivalenceClasses &EqCacheValue, const LoopInfo *const LI, Value *LV, Value *RV, unsigned Depth) { - if (Depth > MaxValueCompareDepth || EqCacheValue.isEquivalent(LV, RV)) + if (Depth > MaxValueCompareDepth) + return std::nullopt; + + if (EqCacheValue.isEquivalent(LV, RV)) return 0; // Order pointer values after integer values. This helps SCEVExpander form @@ -660,7 +663,7 @@ CompareValueComplexity(EquivalenceClasses &EqCacheValue, return (int)LNumOps - (int)RNumOps; for (unsigned Idx : seq(LNumOps)) { - int Result = + std::optional Result = CompareValueComplexity(EqCacheValue, LI, LInst->getOperand(Idx), RInst->getOperand(Idx), Depth + 1); if (Result != 0) @@ -705,8 +708,8 @@ CompareSCEVComplexity(EquivalenceClasses &EqCacheSCEV, const SCEVUnknown *LU = cast(LHS); const SCEVUnknown *RU = cast(RHS); - int X = CompareValueComplexity(EqCacheValue, LI, LU->getValue(), - RU->getValue(), Depth + 1); + std::optional X = CompareValueComplexity( + EqCacheValue, LI, LU->getValue(), RU->getValue(), Depth + 1); if (X == 0) EqCacheSCEV.unionSets(LHS, RHS); return X; diff --git a/llvm/unittests/Analysis/ScalarEvolutionTest.cpp b/llvm/unittests/Analysis/ScalarEvolutionTest.cpp index a6a5ffda3cb70..76e6095636305 100644 --- a/llvm/unittests/Analysis/ScalarEvolutionTest.cpp +++ b/llvm/unittests/Analysis/ScalarEvolutionTest.cpp @@ -1625,4 +1625,40 @@ TEST_F(ScalarEvolutionsTest, ForgetValueWithOverflowInst) { }); } +TEST_F(ScalarEvolutionsTest, ComplexityComparatorIsStrictWeakOrdering) { + // Regression test for a case where caching of equivalent values caused the + // comparator to get inconsistent. + LLVMContext C; + SMDiagnostic Err; + std::unique_ptr M = parseAssemblyString(R"( + define i32 @foo(i32 %arg0) { + %1 = add i32 %arg0, 1 + %2 = add i32 %arg0, 1 + %3 = xor i32 %2, %1 + %4 = add i32 %3, %2 + %5 = add i32 %arg0, 1 + %6 = xor i32 %5, %arg0 + %7 = add i32 %arg0, %6 + %8 = add i32 %5, %7 + %9 = xor i32 %8, %7 + %10 = add i32 %9, %8 + %11 = xor i32 %10, %9 + %12 = add i32 %11, %10 + %13 = xor i32 %12, %11 + %14 = add i32 %12, %13 + %15 = add i32 %14, %4 + ret i32 %15 + })", + 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) { + // When _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG, this will + // crash if the comparator has the specific caching bug. + SE.getSCEV(F.getEntryBlock().getTerminator()->getOperand(0)); + }); +} + } // end namespace llvm diff --git a/polly/test/ScopInfo/invariant_load_zext_parameter-2.ll b/polly/test/ScopInfo/invariant_load_zext_parameter-2.ll index a6108320d5608..4389fb8b8d033 100644 --- a/polly/test/ScopInfo/invariant_load_zext_parameter-2.ll +++ b/polly/test/ScopInfo/invariant_load_zext_parameter-2.ll @@ -25,8 +25,8 @@ ; CHECK: p0: ((sext i32 %tmp6 to i64) * %p1) ; CHECK: p1: ((sext i32 %tmp3 to i64) * (sext i32 %tmp8 to i64) * (%p0 + %p1) * %p3) ; CHECK: p2: ((sext i32 %tmp3 to i64) * (%p0 + %p1)) -; CHECK: p3: ((sext i32 %tmp5 to i64) * %p0) -; CHECK: p4: ((sext i32 %tmp7 to i64) * %p2) +; CHECK: p3: ((sext i32 %tmp7 to i64) * %p2) +; CHECK: p4: ((sext i32 %tmp5 to i64) * %p0) ; target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"