Skip to content

Commit 05dd957

Browse files
authored
[DA] Fix the check between Subscript and Size after delinearization (#151326)
Delinearization provides two values: the size of the array, and the subscript of the access. DA checks their validity (`0 <= subscript < size`), with some special handling. In particular, to ensure `subscript < size`, calculate the maximum value of `subscript - size` and check if it is negative. There was an issue in its process: when `subscript - size` is expressed as an affine format like `init + step * i`, the value in the last iteration (`start + step * (num_iterations - 1)`) was assumed to be the maximum value. This assumption is incorrect in the following cases: - When `step` is negative - When the AddRec wraps This patch introduces extra checks to ensure the sign of `step` and verify the existence of nsw/nuw flags. Also, `isKnownNonNegative(S - smax(1, Size))` was used as a regular check, which is incorrect when `Size` is negative. This patch also replace it with `isKnownNonNegative(S - Size)`, although it's still unclear whether using `isKnownNonNegative` is appropriate in the first place. Fix #150604
1 parent 1458eb2 commit 05dd957

File tree

4 files changed

+114
-17
lines changed

4 files changed

+114
-17
lines changed

llvm/lib/Analysis/DependenceAnalysis.cpp

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,7 +1074,7 @@ bool DependenceInfo::isKnownPredicate(ICmpInst::Predicate Pred, const SCEV *X,
10741074

10751075
/// Compare to see if S is less than Size, using
10761076
///
1077-
/// isKnownNegative(S - max(Size, 1))
1077+
/// isKnownNegative(S - Size)
10781078
///
10791079
/// with some extra checking if S is an AddRec and we can prove less-than using
10801080
/// the loop bounds.
@@ -1090,21 +1090,34 @@ bool DependenceInfo::isKnownLessThan(const SCEV *S, const SCEV *Size) const {
10901090
Size = SE->getTruncateOrZeroExtend(Size, MaxType);
10911091

10921092
// Special check for addrecs using BE taken count
1093-
const SCEV *Bound = SE->getMinusSCEV(S, Size);
1094-
if (const SCEVAddRecExpr *AddRec = dyn_cast<SCEVAddRecExpr>(Bound)) {
1095-
if (AddRec->isAffine()) {
1093+
if (const SCEVAddRecExpr *AddRec = dyn_cast<SCEVAddRecExpr>(S))
1094+
if (AddRec->isAffine() && AddRec->hasNoSignedWrap()) {
10961095
const SCEV *BECount = SE->getBackedgeTakenCount(AddRec->getLoop());
1097-
if (!isa<SCEVCouldNotCompute>(BECount)) {
1098-
const SCEV *Limit = AddRec->evaluateAtIteration(BECount, *SE);
1099-
if (SE->isKnownNegative(Limit))
1100-
return true;
1101-
}
1096+
const SCEV *Start = AddRec->getStart();
1097+
const SCEV *Step = AddRec->getStepRecurrence(*SE);
1098+
const SCEV *End = AddRec->evaluateAtIteration(BECount, *SE);
1099+
const SCEV *Diff0 = SE->getMinusSCEV(Start, Size);
1100+
const SCEV *Diff1 = SE->getMinusSCEV(End, Size);
1101+
1102+
// If the value of Step is non-negative and the AddRec is non-wrap, it
1103+
// reaches its maximum at the last iteration. So it's enouth to check
1104+
// whether End - Size is negative.
1105+
if (SE->isKnownNonNegative(Step) && SE->isKnownNegative(Diff1))
1106+
return true;
1107+
1108+
// If the value of Step is non-positive and the AddRec is non-wrap, the
1109+
// initial value is its maximum.
1110+
if (SE->isKnownNonPositive(Step) && SE->isKnownNegative(Diff0))
1111+
return true;
1112+
1113+
// Even if we don't know the sign of Step, either Start or End must be
1114+
// the maximum value of the AddRec since it is non-wrap.
1115+
if (SE->isKnownNegative(Diff0) && SE->isKnownNegative(Diff1))
1116+
return true;
11021117
}
1103-
}
11041118

11051119
// Check using normal isKnownNegative
1106-
const SCEV *LimitedBound =
1107-
SE->getMinusSCEV(S, SE->getSMaxExpr(Size, SE->getOne(Size->getType())));
1120+
const SCEV *LimitedBound = SE->getMinusSCEV(S, Size);
11081121
return SE->isKnownNegative(LimitedBound);
11091122
}
11101123

llvm/test/Analysis/DDG/basic-loopnest.ll

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
; RUN: opt < %s -disable-output "-passes=print<ddg>" 2>&1 | FileCheck %s
22

3+
; XFAIL: *
4+
; At the moment, DependenceAnalysis cannot infer `n` to be positive.
5+
36

47
; CHECK-LABEL: 'DDG' for loop 'test1.for.cond1.preheader':
58

@@ -378,4 +381,4 @@ for.inc12: ; preds = %for.body4, %test2.f
378381

379382
for.end14: ; preds = %for.inc12, %entry
380383
ret void
381-
}
384+
}

llvm/test/Analysis/DependenceAnalysis/Coupled.ll

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -719,12 +719,14 @@ for.end: ; preds = %for.body
719719
;; for(int j = 0; j < M; j+=1)
720720
;; A[M*N + M*i + j] = 2;
721721

722+
; FIXME: Currently failing to infer %M being positive.
723+
722724
define void @couple_weakzerosiv(ptr noalias nocapture %A, i64 %N, i64 %M) {
723725
; CHECK-LABEL: 'couple_weakzerosiv'
724726
; CHECK-NEXT: Src: store i32 1, ptr %arrayidx.us, align 4 --> Dst: store i32 1, ptr %arrayidx.us, align 4
725727
; CHECK-NEXT: da analyze - none!
726728
; CHECK-NEXT: Src: store i32 1, ptr %arrayidx.us, align 4 --> Dst: store i32 2, ptr %arrayidx9.us, align 4
727-
; CHECK-NEXT: da analyze - output [p>]!
729+
; CHECK-NEXT: da analyze - output [*|<]!
728730
; CHECK-NEXT: Src: store i32 2, ptr %arrayidx9.us, align 4 --> Dst: store i32 2, ptr %arrayidx9.us, align 4
729731
; CHECK-NEXT: da analyze - none!
730732
;

llvm/test/Analysis/DependenceAnalysis/DADelin.ll

Lines changed: 82 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -594,14 +594,15 @@ for.end12: ; preds = %for.inc10, %entry
594594
}
595595

596596

597+
; FIXME? It seems that we cannot prove that %N is non-negative...
597598
define void @nonnegative(ptr nocapture %A, i32 %N) {
598599
; CHECK-LABEL: 'nonnegative'
599600
; CHECK-NEXT: Src: store i32 1, ptr %arrayidx, align 4 --> Dst: store i32 1, ptr %arrayidx, align 4
600-
; CHECK-NEXT: da analyze - none!
601+
; CHECK-NEXT: da analyze - output [* *]!
601602
; CHECK-NEXT: Src: store i32 1, ptr %arrayidx, align 4 --> Dst: store i32 2, ptr %arrayidx, align 4
602-
; CHECK-NEXT: da analyze - consistent output [0 0|<]!
603+
; CHECK-NEXT: da analyze - output [* *|<]!
603604
; CHECK-NEXT: Src: store i32 2, ptr %arrayidx, align 4 --> Dst: store i32 2, ptr %arrayidx, align 4
604-
; CHECK-NEXT: da analyze - none!
605+
; CHECK-NEXT: da analyze - output [* *]!
605606
;
606607
entry:
607608
%cmp44 = icmp eq i32 %N, 0
@@ -630,3 +631,81 @@ for.latch:
630631
exit:
631632
ret void
632633
}
634+
635+
; i = 0;
636+
; do {
637+
; a[k * i] = 42;
638+
; a[k * (i + 1)] = 42;
639+
; i++;
640+
; } while (i != k);
641+
;
642+
; The dependency direction between the two stores depends on the sign of k.
643+
; Note that the loop guard is omitted intentionally.
644+
; FIXME: Each store has loop-carried dependencies on itself if k is zero.
645+
;
646+
define void @coeff_may_negative(ptr %a, i32 %k) {
647+
; CHECK-LABEL: 'coeff_may_negative'
648+
; CHECK-NEXT: Src: store i8 42, ptr %idx.0, align 1 --> Dst: store i8 42, ptr %idx.0, align 1
649+
; CHECK-NEXT: da analyze - none!
650+
; CHECK-NEXT: Src: store i8 42, ptr %idx.0, align 1 --> Dst: store i8 42, ptr %idx.1, align 1
651+
; CHECK-NEXT: da analyze - output [*|<]!
652+
; CHECK-NEXT: Src: store i8 42, ptr %idx.1, align 1 --> Dst: store i8 42, ptr %idx.1, align 1
653+
; CHECK-NEXT: da analyze - none!
654+
;
655+
entry:
656+
br label %loop
657+
658+
loop:
659+
%i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
660+
%i.next = add i32 %i, 1
661+
%subscript.0 = mul i32 %i, %k
662+
%subscript.1 = mul i32 %i.next, %k
663+
%idx.0 = getelementptr i8, ptr %a, i32 %subscript.0
664+
%idx.1 = getelementptr i8, ptr %a, i32 %subscript.1
665+
store i8 42, ptr %idx.0
666+
store i8 42, ptr %idx.1
667+
%cond.exit = icmp eq i32 %i.next, %k
668+
br i1 %cond.exit, label %exit, label %loop
669+
670+
exit:
671+
ret void
672+
}
673+
674+
; i = 0;
675+
; do {
676+
; a[k * i] = 42;
677+
; a[k * (i + 1)] = 42;
678+
; i++;
679+
; } while (i != k);
680+
;
681+
; Note that the loop guard is omitted intentionally.
682+
; FIXME: In principle, we can infer that the value of k is non-negative from
683+
; the nsw flag.
684+
;
685+
define void @coeff_positive(ptr %a, i32 %k) {
686+
; CHECK-LABEL: 'coeff_positive'
687+
; CHECK-NEXT: Src: store i8 42, ptr %idx.0, align 1 --> Dst: store i8 42, ptr %idx.0, align 1
688+
; CHECK-NEXT: da analyze - none!
689+
; CHECK-NEXT: Src: store i8 42, ptr %idx.0, align 1 --> Dst: store i8 42, ptr %idx.1, align 1
690+
; CHECK-NEXT: da analyze - output [*|<]!
691+
; CHECK-NEXT: Src: store i8 42, ptr %idx.1, align 1 --> Dst: store i8 42, ptr %idx.1, align 1
692+
; CHECK-NEXT: da analyze - none!
693+
;
694+
entry:
695+
br label %loop
696+
697+
loop:
698+
%i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
699+
%i.next = add nsw i32 %i, 1
700+
%subscript.0 = mul i32 %i, %k
701+
%subscript.1 = mul i32 %i.next, %k
702+
%idx.0 = getelementptr i8, ptr %a, i32 %subscript.0
703+
%idx.1 = getelementptr i8, ptr %a, i32 %subscript.1
704+
store i8 42, ptr %idx.0
705+
store i8 42, ptr %idx.1
706+
%cond.exit = icmp eq i32 %i.next, %k
707+
br i1 %cond.exit, label %exit, label %loop
708+
709+
exit:
710+
ret void
711+
}

0 commit comments

Comments
 (0)