Skip to content

Commit f7365db

Browse files
committed
[DA] Fix zero coefficient bug in Strong SIV test using runtime assumptions (#149991)
Fix GitHub issue #149991 where Strong SIV test incorrectly concludes 'none' for symbolic coefficients that could be zero, leading to 0/0 undefined behavior. The issue occurs in subscripts like {base,+,coeff} where coeff is symbolic: - When coeff != 0: different iterations access different locations - When coeff = 0: all iterations access the same location (many dependencies) The Strong SIV test's Delta=0 case assumed 0/X=0 where X is the coefficient, but when X could be zero, we have 0/0 which is undefined. The analysis needs to be conservative when the coefficient might be zero. Solution: When coefficient is SCEVUnknown and cannot be proven non-zero at compile time, use SCEV range analysis to attempt proving coefficient > 0. If this fails, add a runtime assumption 'coeff > 0' to the dependence result. This allows precise analysis when possible (none under assumption coeff > 0) while maintaining correctness by exposing the required assumption. Test cases: - zero-coefficient.ll: New test for the reported bug - DADelin.ll: Updated to expect runtime assumptions for symbolic coefficients
1 parent ca28604 commit f7365db

File tree

3 files changed

+68
-1
lines changed

3 files changed

+68
-1
lines changed

llvm/lib/Analysis/DependenceAnalysis.cpp

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1282,7 +1282,40 @@ bool DependenceInfo::strongSIVtest(const SCEV *Coeff, const SCEV *SrcConst,
12821282
Result.DV[Level].Direction &= Dependence::DVEntry::EQ;
12831283
++StrongSIVsuccesses;
12841284
} else if (Delta->isZero()) {
1285-
// since 0/X == 0
1285+
// Check if coefficient could be zero. If so, 0/0 is undefined and we
1286+
// cannot conclude that only same-iteration dependencies exist.
1287+
// When coeff=0, all iterations access the same location.
1288+
if (isa<SCEVUnknown>(Coeff) && !SE->isKnownNonZero(Coeff)) {
1289+
// Use SCEV range analysis to prove coefficient != 0 in loop context.
1290+
const SCEV *Zero = SE->getZero(Coeff->getType());
1291+
1292+
// Ask SCEV's range analysis if it can prove Coeff != Zero.
1293+
if (SE->isKnownPredicate(ICmpInst::ICMP_NE, Coeff, Zero)) {
1294+
LLVM_DEBUG(
1295+
dbgs()
1296+
<< "\t Coefficient proven non-zero by SCEV range analysis\n");
1297+
} else {
1298+
// Cannot prove at compile time, would need runtime assumption.
1299+
if (UnderRuntimeAssumptions) {
1300+
const SCEVPredicate *Pred =
1301+
SE->getComparePredicate(ICmpInst::ICMP_NE, Coeff, Zero);
1302+
SmallVector<const SCEVPredicate *, 4> NewPreds(
1303+
Assumptions.getPredicates());
1304+
NewPreds.push_back(Pred);
1305+
const_cast<DependenceInfo *>(this)->Assumptions =
1306+
SCEVUnionPredicate(NewPreds, *SE);
1307+
LLVM_DEBUG(dbgs() << "\t Added runtime assumption: " << *Coeff
1308+
<< " != 0\n");
1309+
} else {
1310+
// Cannot add runtime assumptions, this test cannot handle this case.
1311+
// Let more complex tests try.
1312+
LLVM_DEBUG(dbgs() << "\t Would need runtime assumption " << *Coeff
1313+
<< " != 0, but not allowed. Failing this test.\n");
1314+
return false;
1315+
}
1316+
}
1317+
}
1318+
// since 0/X == 0 (where X is known non-zero)
12861319
Result.DV[Level].Distance = Delta;
12871320
NewConstraint.setDistance(Delta, CurLoop);
12881321
Result.DV[Level].Direction &= Dependence::DVEntry::EQ;

llvm/test/Analysis/DependenceAnalysis/DADelin.ll

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,8 @@ define void @coeff_may_negative(ptr %a, i32 %k) {
651651
; CHECK-NEXT: da analyze - output [*|<]!
652652
; CHECK-NEXT: Src: store i8 42, ptr %idx.1, align 1 --> Dst: store i8 42, ptr %idx.1, align 1
653653
; CHECK-NEXT: da analyze - none!
654+
; CHECK-NEXT: Runtime Assumptions:
655+
; CHECK-NEXT: Compare predicate: %k ne) 0
654656
;
655657
entry:
656658
br label %loop
@@ -690,6 +692,8 @@ define void @coeff_positive(ptr %a, i32 %k) {
690692
; CHECK-NEXT: da analyze - output [*|<]!
691693
; CHECK-NEXT: Src: store i8 42, ptr %idx.1, align 1 --> Dst: store i8 42, ptr %idx.1, align 1
692694
; CHECK-NEXT: da analyze - none!
695+
; CHECK-NEXT: Runtime Assumptions:
696+
; CHECK-NEXT: Compare predicate: %k ne) 0
693697
;
694698
entry:
695699
br label %loop
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 5
2+
; RUN: opt < %s -disable-output "-passes=print<da>" 2>&1 | FileCheck %s
3+
4+
; Test case for GitHub issue #149991: Strong SIV test with symbolic coefficient
5+
; that could be zero. Fixed using runtime assumptions: assume coefficient != 0.
6+
7+
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
8+
9+
define void @test_zero_coefficient(ptr %a, i64 %k) {
10+
; CHECK-LABEL: 'test_zero_coefficient'
11+
; CHECK-NEXT: Src: store i8 42, ptr %idx, align 1 --> Dst: store i8 42, ptr %idx, align 1
12+
; CHECK-NEXT: da analyze - none!
13+
; CHECK-NEXT: Runtime Assumptions:
14+
; CHECK-NEXT: Compare predicate: %k ne) 0
15+
;
16+
entry:
17+
br label %loop
18+
19+
loop:
20+
%i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
21+
%subscript = mul i64 %i, %k ; When %k=0, all iterations access %a[0]
22+
%idx = getelementptr i8, ptr %a, i64 %subscript
23+
store i8 42, ptr %idx
24+
%i.next = add i64 %i, 1
25+
%cond.exit = icmp eq i64 %i.next, 100
26+
br i1 %cond.exit, label %exit, label %loop
27+
28+
exit:
29+
ret void
30+
}

0 commit comments

Comments
 (0)