Skip to content
Permalink
Browse files

[DA] Enable -da-delinearize by default

This enables da-delinearize in Dependence Analysis for delinearizing array
accesses into multiple dimensions. This can help to increase the power of
Dependence analysis on multi-dimensional arrays and prevent having to fall
back to the slower and less accurate MIV tests. It adds static checks on the
bounds of the arrays to ensure that one dimension doesn't overflow into
another, and brings our code in line with our tests.

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

llvm-svn: 335217
  • Loading branch information...
david-green-arm committed Jun 21, 2018
1 parent 2a9cde0 commit d143c65de3c884d09197da279d2f04f094efaf15
@@ -557,6 +557,12 @@ template <typename T> class ArrayRef;
const SCEV *X,
const SCEV *Y) const;

/// isKnownLessThan - Compare to see if S is less than Size
/// Another wrapper for isKnownNegative(S - max(Size, 1)) with some extra
/// checking if S is an AddRec and we can prove lessthan using the loop
/// bounds.
bool isKnownLessThan(const SCEV *S, const SCEV *Size) const;

/// collectUpperBound - All subscripts are the same type (on my machine,
/// an i64). The loop bound may be a smaller type. collectUpperBound
/// find the bound, if available, and zero extends it to the Type T.
@@ -108,8 +108,8 @@ STATISTIC(BanerjeeIndependence, "Banerjee independence");
STATISTIC(BanerjeeSuccesses, "Banerjee successes");

static cl::opt<bool>
Delinearize("da-delinearize", cl::init(false), cl::Hidden, cl::ZeroOrMore,
cl::desc("Try to delinearize array references."));
Delinearize("da-delinearize", cl::init(true), cl::Hidden, cl::ZeroOrMore,
cl::desc("Try to delinearize array references."));

//===----------------------------------------------------------------------===//
// basics
@@ -994,6 +994,38 @@ bool DependenceInfo::isKnownPredicate(ICmpInst::Predicate Pred, const SCEV *X,
}
}

/// Compare to see if S is less than Size, using isKnownNegative(S - max(Size, 1))
/// with some extra checking if S is an AddRec and we can prove less-than using
/// the loop bounds.
bool DependenceInfo::isKnownLessThan(const SCEV *S, const SCEV *Size) const {
// First unify to the same type
auto *SType = dyn_cast<IntegerType>(S->getType());
auto *SizeType = dyn_cast<IntegerType>(Size->getType());
if (!SType || !SizeType)
return false;
Type *MaxType =
(SType->getBitWidth() >= SizeType->getBitWidth()) ? SType : SizeType;
S = SE->getTruncateOrZeroExtend(S, MaxType);
Size = SE->getTruncateOrZeroExtend(Size, MaxType);

// Special check for addrecs using BE taken count
const SCEV *Bound = SE->getMinusSCEV(S, Size);
if (const SCEVAddRecExpr *AddRec = dyn_cast<SCEVAddRecExpr>(Bound)) {
if (AddRec->isAffine()) {
const SCEV *BECount = SE->getBackedgeTakenCount(AddRec->getLoop());
if (!isa<SCEVCouldNotCompute>(BECount)) {
const SCEV *Limit = AddRec->evaluateAtIteration(BECount, *SE);
if (SE->isKnownNegative(Limit))
return true;
}
}
}

// Check using normal isKnownNegative
const SCEV *LimitedBound =
SE->getMinusSCEV(S, SE->getSMaxExpr(Size, SE->getOne(Size->getType())));
return SE->isKnownNegative(LimitedBound);
}

// All subscripts are all the same type.
// Loop bound may be smaller (e.g., a char).
@@ -3253,6 +3285,26 @@ bool DependenceInfo::tryDelinearize(Instruction *Src, Instruction *Dst,

int size = SrcSubscripts.size();

// Statically check that the array bounds are in-range. The first subscript we
// don't have a size for and it cannot overflow into another subscript, so is
// always safe. The others need to be 0 <= subscript[i] < bound, for both src
// and dst.
// FIXME: It may be better to record these sizes and add them as constraints
// to the dependency checks.
for (int i = 1; i < size; ++i) {
if (!SE->isKnownNonNegative(SrcSubscripts[i]))
return false;

if (!isKnownLessThan(SrcSubscripts[i], Sizes[i - 1]))
return false;

if (!SE->isKnownNonNegative(DstSubscripts[i]))
return false;

if (!isKnownLessThan(DstSubscripts[i], Sizes[i - 1]))
return false;
}

LLVM_DEBUG({
dbgs() << "\nSrcSubscripts: ";
for (int i = 0; i < size; i++)
@@ -3271,13 +3323,6 @@ bool DependenceInfo::tryDelinearize(Instruction *Src, Instruction *Dst,
Pair[i].Src = SrcSubscripts[i];
Pair[i].Dst = DstSubscripts[i];
unifySubscriptType(&Pair[i]);

// FIXME: we should record the bounds SrcSizes[i] and DstSizes[i] that the
// delinearization has found, and add these constraints to the dependence
// check to avoid memory accesses overflow from one dimension into another.
// This is related to the problem of determining the existence of data
// dependences in array accesses using a different number of subscripts: in
// C one can access an array A[100][100]; as A[0][9999], *A[9999], etc.
}

return true;
@@ -1,4 +1,4 @@
; RUN: opt -basicaa -da -analyze -da-delinearize < %s
; RUN: opt -basicaa -da -analyze < %s
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

@@ -1,7 +1,6 @@
; RUN: opt < %s -analyze -basicaa -da -da-delinearize=false | FileCheck %s
; RUN: opt < %s -analyze -basicaa -da -da-delinearize | FileCheck %s -check-prefix=DELIN
; RUN: opt < %s -analyze -basicaa -da | FileCheck %s -check-prefix=DELIN

; ModuleID = 'Banerjee.bc'
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.6.0"

@@ -1,6 +1,5 @@
; RUN: opt < %s -analyze -basicaa -da -da-delinearize | FileCheck %s
; RUN: opt < %s -analyze -basicaa -da | FileCheck %s

; ModuleID = 'Coupled.bc'
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.6.0"

0 comments on commit d143c65

Please sign in to comment.
You can’t perform that action at this time.