[DA] Delinearise AddRecs if we can prove they don't wrap

We can prove that some delinearized subscripts do not wrap around to become
negative by the fact that they are from inbound geps of load/store locations.
This helps improve the delinearisation in cases where we can't prove that they
are non-negative from SCEV alone.

Differential Revision: https://reviews.llvm.org/D48481

llvm-svn: 335481
This commit is contained in:
David Green 2018-06-25 15:13:26 +00:00
parent d0ec7bd1c7
commit 8699492304
3 changed files with 61 additions and 3 deletions

View File

@ -563,6 +563,11 @@ template <typename T> class ArrayRef;
/// bounds. /// bounds.
bool isKnownLessThan(const SCEV *S, const SCEV *Size) const; bool isKnownLessThan(const SCEV *S, const SCEV *Size) const;
/// isKnownNonNegative - Compare to see if S is known not to be negative
/// Uses the fact that S comes from Ptr, which may be an inbound GEP,
/// Proving there is no wrapping going on.
bool isKnownNonNegative(const SCEV *S, const Value *Ptr) const;
/// collectUpperBound - All subscripts are the same type (on my machine, /// collectUpperBound - All subscripts are the same type (on my machine,
/// an i64). The loop bound may be a smaller type. collectUpperBound /// an i64). The loop bound may be a smaller type. collectUpperBound
/// find the bound, if available, and zero extends it to the Type T. /// find the bound, if available, and zero extends it to the Type T.

View File

@ -1027,6 +1027,25 @@ bool DependenceInfo::isKnownLessThan(const SCEV *S, const SCEV *Size) const {
return SE->isKnownNegative(LimitedBound); return SE->isKnownNegative(LimitedBound);
} }
bool DependenceInfo::isKnownNonNegative(const SCEV *S, const Value *Ptr) const {
bool Inbounds = false;
if (auto *SrcGEP = dyn_cast<GetElementPtrInst>(Ptr))
Inbounds = SrcGEP->isInBounds();
if (Inbounds) {
if (const SCEVAddRecExpr *AddRec = dyn_cast<SCEVAddRecExpr>(S)) {
if (AddRec->isAffine()) {
// We know S is for Ptr, the operand on a load/store, so doesn't wrap.
// If both parts are NonNegative, the end result will be NonNegative
if (SE->isKnownNonNegative(AddRec->getStart()) &&
SE->isKnownNonNegative(AddRec->getOperand(1)))
return true;
}
}
}
return SE->isKnownNonNegative(S);
}
// All subscripts are all the same type. // All subscripts are all the same type.
// Loop bound may be smaller (e.g., a char). // Loop bound may be smaller (e.g., a char).
// Should zero extend loop bound, since it's always >= 0. // Should zero extend loop bound, since it's always >= 0.
@ -3292,13 +3311,13 @@ bool DependenceInfo::tryDelinearize(Instruction *Src, Instruction *Dst,
// FIXME: It may be better to record these sizes and add them as constraints // FIXME: It may be better to record these sizes and add them as constraints
// to the dependency checks. // to the dependency checks.
for (int i = 1; i < size; ++i) { for (int i = 1; i < size; ++i) {
if (!SE->isKnownNonNegative(SrcSubscripts[i])) if (!isKnownNonNegative(SrcSubscripts[i], SrcPtr))
return false; return false;
if (!isKnownLessThan(SrcSubscripts[i], Sizes[i - 1])) if (!isKnownLessThan(SrcSubscripts[i], Sizes[i - 1]))
return false; return false;
if (!SE->isKnownNonNegative(DstSubscripts[i])) if (!isKnownNonNegative(DstSubscripts[i], DstPtr))
return false; return false;
if (!isKnownLessThan(DstSubscripts[i], Sizes[i - 1])) if (!isKnownLessThan(DstSubscripts[i], Sizes[i - 1]))

View File

@ -553,4 +553,38 @@ for.inc10: ; preds = %for.body5, %for.bod
for.end12: ; preds = %for.inc10, %entry for.end12: ; preds = %for.inc10, %entry
ret double undef ret double undef
} }
; CHECK-LABEL: nonnegative
define void @nonnegative(i32* nocapture %A, i32 %N) {
; CHECK: da analyze - none!
; CHECK: da analyze - consistent output [0 0|<]!
; CHECK: da analyze - none!
entry:
%cmp44 = icmp eq i32 %N, 0
br i1 %cmp44, label %exit, label %for.outer
for.outer:
%h.045 = phi i32 [ %add19, %for.latch ], [ 0, %entry ]
%mul = mul i32 %h.045, %N
br label %for.inner
for.inner:
%i.043 = phi i32 [ 0, %for.outer ], [ %add16, %for.inner ]
%add = add i32 %i.043, %mul
%arrayidx = getelementptr inbounds i32, i32* %A, i32 %add
store i32 1, i32* %arrayidx, align 4
store i32 2, i32* %arrayidx, align 4
%add16 = add nuw i32 %i.043, 1
%exitcond46 = icmp eq i32 %add16, %N
br i1 %exitcond46, label %for.latch, label %for.inner
for.latch:
%add19 = add nuw i32 %h.045, 1
%exitcond47 = icmp eq i32 %add19, %N
br i1 %exitcond47, label %exit, label %for.outer
exit:
ret void
}