Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 61 additions & 7 deletions llvm/lib/Analysis/DependenceAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1249,10 +1249,33 @@ bool DependenceInfo::strongSIVtest(const SCEV *Coeff, const SCEV *SrcConst,
SE->isKnownNonNegative(Coeff) ? Coeff : SE->getNegativeSCEV(Coeff);
const SCEV *Product = SE->getMulExpr(UpperBound, AbsCoeff);
if (isKnownPredicate(CmpInst::ICMP_SGT, AbsDelta, Product)) {
// Distance greater than trip count - no dependence
++StrongSIVindependence;
++StrongSIVsuccesses;
return true;
// Check if this involves symbolic expressions where we might be too
// conservative.
if (isa<SCEVUnknown>(Delta) || isa<SCEVUnknown>(Coeff) ||
!isa<SCEVConstant>(AbsDelta) || !isa<SCEVConstant>(Product)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if( isa<SCEVUnknown>(Delta) || !isa<SCEVConstant>(Product) )

should be sufficient ?

// For symbolic expressions, add runtime assumption rather than
// rejecting.
const SCEVPredicate *BoundPred =
SE->getComparePredicate(ICmpInst::ICMP_SLE, AbsDelta, Product);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

push this inside if(){...}

if (UnderRuntimeAssumptions) {
SmallVector<const SCEVPredicate *, 4> NewPreds(
Assumptions.getPredicates());
NewPreds.push_back(BoundPred);
const_cast<DependenceInfo *>(this)->Assumptions =
SCEVUnionPredicate(NewPreds, *SE);
LLVM_DEBUG(dbgs() << "\t Added runtime bound assumption\n");
} else {
// Cannot add runtime assumptions, let more complex tests try.
LLVM_DEBUG(dbgs() << "\t Would need runtime bound assumption but "
"not allowed. Failing this test.\n");
return false;
}
} else {
// Distance definitely greater than trip count - no dependence
++StrongSIVindependence;
++StrongSIVsuccesses;
return true;
}
}
}

Expand Down Expand Up @@ -1293,9 +1316,40 @@ bool DependenceInfo::strongSIVtest(const SCEV *Coeff, const SCEV *SrcConst,
Result.DV[Level].Distance = Delta; // since X/1 == X
NewConstraint.setDistance(Delta, CurLoop);
} else {
Result.Consistent = false;
NewConstraint.setLine(Coeff, SE->getNegativeSCEV(Coeff),
SE->getNegativeSCEV(Delta), CurLoop);
// Try symbolic division: Distance = Delta / Coeff.
if (const SCEV *Distance = SE->getUDivExactExpr(Delta, Coeff)) {
LLVM_DEBUG(dbgs() << "\t Symbolic distance = " << *Distance << "\n");
Result.DV[Level].Distance = Distance;
NewConstraint.setDistance(Distance, CurLoop);
} else {
// Cannot compute exact division - check if we can add runtime
// assumptions.
if (isa<SCEVUnknown>(Coeff) && !SE->isKnownNonZero(Coeff)) {
// Add runtime assumption that coefficient is non-zero for division.
const SCEV *Zero = SE->getZero(Coeff->getType());
const SCEVPredicate *NonZeroPred =
SE->getComparePredicate(ICmpInst::ICMP_NE, Coeff, Zero);
if (UnderRuntimeAssumptions) {
SmallVector<const SCEVPredicate *, 4> NewPreds(
Assumptions.getPredicates());
NewPreds.push_back(NonZeroPred);
const_cast<DependenceInfo *>(this)->Assumptions =
SCEVUnionPredicate(NewPreds, *SE);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are we adding constraint once again when we have already added below constraint?

const SCEVPredicate *BoundPred =
            SE->getComparePredicate(ICmpInst::ICMP_SLE, AbsDelta, Product);

LLVM_DEBUG(dbgs() << "\t Added runtime assumption: " << *Coeff
<< " != 0 for symbolic division\n");
} else {
// Cannot add runtime assumptions, this test fails.
LLVM_DEBUG(dbgs()
<< "\t Would need runtime assumption " << *Coeff
<< " != 0 but not allowed. Failing this test.\n");
return false;
}
}

Result.Consistent = false;
NewConstraint.setLine(Coeff, SE->getNegativeSCEV(Coeff),
SE->getNegativeSCEV(Delta), CurLoop);
}
}

// maybe we can get a useful direction
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/Analysis/DependenceAnalysis/BasePtrBug.ll
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ define void @test1(ptr nocapture %A, ptr nocapture %B, i32 %N) #0 {
; CHECK-NEXT: Src: %0 = load i32, ptr %gep.0, align 4 --> Dst: %0 = load i32, ptr %gep.0, align 4
; CHECK-NEXT: da analyze - none!
; CHECK-NEXT: Src: %0 = load i32, ptr %gep.0, align 4 --> Dst: %1 = load i32, ptr %gep.1, align 4
; CHECK-NEXT: da analyze - input [*|<]!
; CHECK-NEXT: da analyze - consistent input [((-4 * (sext i32 %div to i64))<nsw> /u 4)|<]!
; CHECK-NEXT: Src: %0 = load i32, ptr %gep.0, align 4 --> Dst: store i32 %add, ptr %gep.B, align 4
; CHECK-NEXT: da analyze - confused!
; CHECK-NEXT: Src: %1 = load i32, ptr %gep.1, align 4 --> Dst: %1 = load i32, ptr %gep.1, align 4
Expand Down
4 changes: 2 additions & 2 deletions llvm/test/Analysis/DependenceAnalysis/DADelin.ll
Original file line number Diff line number Diff line change
Expand Up @@ -648,7 +648,7 @@ define void @coeff_may_negative(ptr %a, i32 %k) {
; CHECK-NEXT: Src: store i8 42, ptr %idx.0, align 1 --> Dst: store i8 42, ptr %idx.0, align 1
; CHECK-NEXT: da analyze - none!
; CHECK-NEXT: Src: store i8 42, ptr %idx.0, align 1 --> Dst: store i8 42, ptr %idx.1, align 1
; CHECK-NEXT: da analyze - output [*|<]!
; CHECK-NEXT: da analyze - consistent output [((-1 * %k) /u %k)|<]!
; CHECK-NEXT: Src: store i8 42, ptr %idx.1, align 1 --> Dst: store i8 42, ptr %idx.1, align 1
; CHECK-NEXT: da analyze - none!
;
Expand Down Expand Up @@ -687,7 +687,7 @@ define void @coeff_positive(ptr %a, i32 %k) {
; CHECK-NEXT: Src: store i8 42, ptr %idx.0, align 1 --> Dst: store i8 42, ptr %idx.0, align 1
; CHECK-NEXT: da analyze - none!
; CHECK-NEXT: Src: store i8 42, ptr %idx.0, align 1 --> Dst: store i8 42, ptr %idx.1, align 1
; CHECK-NEXT: da analyze - output [*|<]!
; CHECK-NEXT: da analyze - consistent output [((-1 * %k) /u %k)|<]!
; CHECK-NEXT: Src: store i8 42, ptr %idx.1, align 1 --> Dst: store i8 42, ptr %idx.1, align 1
; CHECK-NEXT: da analyze - none!
;
Expand Down
45 changes: 45 additions & 0 deletions llvm/test/Analysis/DependenceAnalysis/PR149977.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 5
; RUN: opt < %s -disable-output "-passes=print<da>" 2>&1 | FileCheck %s

; Test case for GitHub issue #149977: Strong SIV test with symbolic coefficients and deltas
; The issue was that the bound constraint check was overly conservative with symbolic expressions,
; causing valid dependencies to be rejected before reaching the division logic.
;
; Mathematical analysis:
; - Access patterns: a[-k*i] vs a[-k*i + (2*k + 1)]
; - Strong SIV equation: -k*(i2-i1) = (2*k + 1)
; - Distance: (2*k + 1)/k
; - For k=-1: distance = -1/-1 = 1 (clear dependence)

define void @f(ptr %a, i64 %k) {
; CHECK-LABEL: 'f'
; CHECK-NEXT: Src: store i8 42, ptr %idx.0, align 1 --> Dst: store i8 42, ptr %idx.0, align 1
; CHECK-NEXT: da analyze - none!
; CHECK-NEXT: Src: store i8 42, ptr %idx.0, align 1 --> Dst: store i8 42, ptr %idx.1, align 1
; CHECK-NEXT: da analyze - consistent output [((-1 + (-2 * %k)) /u (-1 * %k))]!
; CHECK-NEXT: Runtime Assumptions:
; CHECK-NEXT: Compare predicate: (1 + (2 * %k))<nuw><nsw> sle) (2 * %k)
; CHECK-NEXT: Src: store i8 42, ptr %idx.1, align 1 --> Dst: store i8 42, ptr %idx.1, align 1
; CHECK-NEXT: da analyze - none!
;
entry:
%mk = sub i64 0, %k ; mk = -k
%kk = mul i64 %k, 2 ; kk = 2*k
%kk.inc = add i64 1, %kk ; kk.inc = 2*k + 1
br label %loop

loop:
%i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
%subscript.0 = mul i64 %mk, %i ; -k * i
%subscript.1 = add i64 %subscript.0, %kk.inc ; -k * i + (2*k + 1)
%idx.0 = getelementptr i8, ptr %a, i64 %subscript.0
%idx.1 = getelementptr i8, ptr %a, i64 %subscript.1
store i8 42, ptr %idx.0
store i8 42, ptr %idx.1
%i.next = add i64 %i, 1
%cond.exit = icmp eq i64 %i.next, 3
br i1 %cond.exit, label %exit, label %loop

exit:
ret void
}
2 changes: 1 addition & 1 deletion llvm/test/Analysis/DependenceAnalysis/StrongSIV.ll
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ define void @strong8(ptr %A, ptr %B, i64 %n) nounwind uwtable ssp {
; CHECK-NEXT: Src: store i32 %conv, ptr %arrayidx, align 4 --> Dst: store i32 %conv, ptr %arrayidx, align 4
; CHECK-NEXT: da analyze - none!
; CHECK-NEXT: Src: store i32 %conv, ptr %arrayidx, align 4 --> Dst: %0 = load i32, ptr %arrayidx1, align 4
; CHECK-NEXT: da analyze - flow [*|<]!
; CHECK-NEXT: da analyze - consistent flow [((4 * %n) /u 4)|<]!
; CHECK-NEXT: Src: store i32 %conv, ptr %arrayidx, align 4 --> Dst: store i32 %0, ptr %B.addr.01, align 4
; CHECK-NEXT: da analyze - confused!
; CHECK-NEXT: Src: %0 = load i32, ptr %arrayidx1, align 4 --> Dst: %0 = load i32, ptr %arrayidx1, align 4
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/Analysis/DependenceAnalysis/SymbolicSIV.ll
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ define void @symbolicsiv7(ptr %A, ptr %B, i64 %n, i64 %N, i64 %M) nounwind uwtab
; CHECK-NEXT: Src: store i32 %conv, ptr %arrayidx, align 4 --> Dst: store i32 %conv, ptr %arrayidx, align 4
; CHECK-NEXT: da analyze - none!
; CHECK-NEXT: Src: store i32 %conv, ptr %arrayidx, align 4 --> Dst: %1 = load i32, ptr %arrayidx6, align 4
; CHECK-NEXT: da analyze - flow [<>]!
; CHECK-NEXT: da analyze - consistent flow [((-8 + (16 * %M)) /u (8 * %N))]!
; CHECK-NEXT: Src: store i32 %conv, ptr %arrayidx, align 4 --> Dst: store i32 %1, ptr %B.addr.02, align 4
; CHECK-NEXT: da analyze - confused!
; CHECK-NEXT: Src: %1 = load i32, ptr %arrayidx6, align 4 --> Dst: %1 = load i32, ptr %arrayidx6, align 4
Expand Down