Skip to content

Commit 65697b1

Browse files
authored
Remove value cache in SCEV comparator. (#100721)
The cache triggers almost never, and seems unlikely to help with performance. However, when it does, it is likely to cause the comparator to become inconsistent due to a bad interaction of the depth limit and cache hits. This leads to crashes in debug builds. See the new unit test for a reproducer.
1 parent 41c0f89 commit 65697b1

File tree

2 files changed

+46
-17
lines changed

2 files changed

+46
-17
lines changed

llvm/lib/Analysis/ScalarEvolution.cpp

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -597,11 +597,9 @@ void SCEVUnknown::allUsesReplacedWith(Value *New) {
597597
///
598598
/// Since we do not continue running this routine on expression trees once we
599599
/// have seen unequal values, there is no need to track them in the cache.
600-
static int
601-
CompareValueComplexity(EquivalenceClasses<const Value *> &EqCacheValue,
602-
const LoopInfo *const LI, Value *LV, Value *RV,
603-
unsigned Depth) {
604-
if (Depth > MaxValueCompareDepth || EqCacheValue.isEquivalent(LV, RV))
600+
static int CompareValueComplexity(const LoopInfo *const LI, Value *LV,
601+
Value *RV, unsigned Depth) {
602+
if (Depth > MaxValueCompareDepth)
605603
return 0;
606604

607605
// Order pointer values after integer values. This helps SCEVExpander form
@@ -660,15 +658,13 @@ CompareValueComplexity(EquivalenceClasses<const Value *> &EqCacheValue,
660658
return (int)LNumOps - (int)RNumOps;
661659

662660
for (unsigned Idx : seq(LNumOps)) {
663-
int Result =
664-
CompareValueComplexity(EqCacheValue, LI, LInst->getOperand(Idx),
665-
RInst->getOperand(Idx), Depth + 1);
661+
int Result = CompareValueComplexity(LI, LInst->getOperand(Idx),
662+
RInst->getOperand(Idx), Depth + 1);
666663
if (Result != 0)
667664
return Result;
668665
}
669666
}
670667

671-
EqCacheValue.unionSets(LV, RV);
672668
return 0;
673669
}
674670

@@ -679,7 +675,6 @@ CompareValueComplexity(EquivalenceClasses<const Value *> &EqCacheValue,
679675
// not know if they are equivalent for sure.
680676
static std::optional<int>
681677
CompareSCEVComplexity(EquivalenceClasses<const SCEV *> &EqCacheSCEV,
682-
EquivalenceClasses<const Value *> &EqCacheValue,
683678
const LoopInfo *const LI, const SCEV *LHS,
684679
const SCEV *RHS, DominatorTree &DT, unsigned Depth = 0) {
685680
// Fast-path: SCEVs are uniqued so we can do a quick equality check.
@@ -705,8 +700,8 @@ CompareSCEVComplexity(EquivalenceClasses<const SCEV *> &EqCacheSCEV,
705700
const SCEVUnknown *LU = cast<SCEVUnknown>(LHS);
706701
const SCEVUnknown *RU = cast<SCEVUnknown>(RHS);
707702

708-
int X = CompareValueComplexity(EqCacheValue, LI, LU->getValue(),
709-
RU->getValue(), Depth + 1);
703+
int X =
704+
CompareValueComplexity(LI, LU->getValue(), RU->getValue(), Depth + 1);
710705
if (X == 0)
711706
EqCacheSCEV.unionSets(LHS, RHS);
712707
return X;
@@ -773,8 +768,8 @@ CompareSCEVComplexity(EquivalenceClasses<const SCEV *> &EqCacheSCEV,
773768
return (int)LNumOps - (int)RNumOps;
774769

775770
for (unsigned i = 0; i != LNumOps; ++i) {
776-
auto X = CompareSCEVComplexity(EqCacheSCEV, EqCacheValue, LI, LOps[i],
777-
ROps[i], DT, Depth + 1);
771+
auto X = CompareSCEVComplexity(EqCacheSCEV, LI, LOps[i], ROps[i], DT,
772+
Depth + 1);
778773
if (X != 0)
779774
return X;
780775
}
@@ -802,12 +797,10 @@ static void GroupByComplexity(SmallVectorImpl<const SCEV *> &Ops,
802797
if (Ops.size() < 2) return; // Noop
803798

804799
EquivalenceClasses<const SCEV *> EqCacheSCEV;
805-
EquivalenceClasses<const Value *> EqCacheValue;
806800

807801
// Whether LHS has provably less complexity than RHS.
808802
auto IsLessComplex = [&](const SCEV *LHS, const SCEV *RHS) {
809-
auto Complexity =
810-
CompareSCEVComplexity(EqCacheSCEV, EqCacheValue, LI, LHS, RHS, DT);
803+
auto Complexity = CompareSCEVComplexity(EqCacheSCEV, LI, LHS, RHS, DT);
811804
return Complexity && *Complexity < 0;
812805
};
813806
if (Ops.size() == 2) {

llvm/unittests/Analysis/ScalarEvolutionTest.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1625,4 +1625,40 @@ TEST_F(ScalarEvolutionsTest, ForgetValueWithOverflowInst) {
16251625
});
16261626
}
16271627

1628+
TEST_F(ScalarEvolutionsTest, ComplexityComparatorIsStrictWeakOrdering) {
1629+
// Regression test for a case where caching of equivalent values caused the
1630+
// comparator to get inconsistent.
1631+
LLVMContext C;
1632+
SMDiagnostic Err;
1633+
std::unique_ptr<Module> M = parseAssemblyString(R"(
1634+
define i32 @foo(i32 %arg0) {
1635+
%1 = add i32 %arg0, 1
1636+
%2 = add i32 %arg0, 1
1637+
%3 = xor i32 %2, %1
1638+
%4 = add i32 %3, %2
1639+
%5 = add i32 %arg0, 1
1640+
%6 = xor i32 %5, %arg0
1641+
%7 = add i32 %arg0, %6
1642+
%8 = add i32 %5, %7
1643+
%9 = xor i32 %8, %7
1644+
%10 = add i32 %9, %8
1645+
%11 = xor i32 %10, %9
1646+
%12 = add i32 %11, %10
1647+
%13 = xor i32 %12, %11
1648+
%14 = add i32 %12, %13
1649+
%15 = add i32 %14, %4
1650+
ret i32 %15
1651+
})",
1652+
Err, C);
1653+
1654+
ASSERT_TRUE(M && "Could not parse module?");
1655+
ASSERT_TRUE(!verifyModule(*M) && "Must have been well formed!");
1656+
1657+
runWithSE(*M, "foo", [](Function &F, LoopInfo &LI, ScalarEvolution &SE) {
1658+
// When _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG, this will
1659+
// crash if the comparator has the specific caching bug.
1660+
SE.getSCEV(F.getEntryBlock().getTerminator()->getOperand(0));
1661+
});
1662+
}
1663+
16281664
} // end namespace llvm

0 commit comments

Comments
 (0)