[llvm] r194527 - delinearization of arrays

Sebastian Pop spop at codeaurora.org
Wed Nov 13 11:55:34 PST 2013


Hi,

Hal Finkel wrote:
> ----- Original Message -----
> > 
> > On Tue, Nov 12, 2013 at 2:47 PM, Sebastian Pop < spop at codeaurora.org
> > > wrote:
> > 
> > 
> > delinearization of arrays
> > This seems like a really underwhelming commit log... ;] There is
> > quite a lot going on here, and it would be helpful to give an
> > overview for those who haven't followed the entire review of this
> > work.
> > 

The core of the patch adds one function to the SCEV tools: delinearize.  That
allows the delinearization of a SCEV representing a memory access function.

For example: when analyzing the memory access A[i][j][k] in this loop nest

+; void foo(long n, long m, long o, double A[n][m][o]) {
+;
+;   for (long i = 0; i < n; i++)
+;     for (long j = 0; j < m; j++)
+;       for (long k = 0; k < o; k++)
+;         A[i][j][k] = 1.0;
+; }

the delinearization input is the following AddRec SCEV:

+; AddRec: {{{%A,+,(8 * %m * %o)}<%for.i>,+,(8 * %o)}<%for.j>,+,8}<%for.k>

>From this SCEV, we are able to say that the base offset of the access is %A
because it appears as an offset that does not divide any of the strides in the
loops:

+; CHECK: Base offset: %A

and then delinearize determines the size of some of the dimensions of the array
as these are the multiples by which the strides are happening:

+; CHECK: ArrayDecl[UnknownSize][%m][%o] with elements of sizeof(double) bytes.

Note that the outermost dimension remains of UnknownSize because there are no
strides that would help identifying the size of the last dimension: when the
array has been statically allocated, one could compute the size of that
dimension by dividing the overall size of the array by the size of the known
dimensions: %m * %o * 8.

Finally delinearize provides the access functions for the array reference that
does correspond to A[i][j][k] of the above C testcase:

+; CHECK: ArrayRef[{0,+,1}<nuw><nsw><%for.i>][{0,+,1}<nuw><nsw><%for.j>][{0,+,1}<nuw><nsw><%for.k>]

The testcases are checking the output of a function pass: DelinearizationPass
that walks through all loads and stores of a function asking for the SCEV of the
memory access with respect to all enclosing loops, calling SCEV->delinearize on
that and printing the results.

The patch also calls SCEV->delinearize within Preston's classical data
dependence analysis.  The flag controlling the call to delinearize from the data
dependence analysis "-da-delinearize" is turned off by default for now.
Attached a patch that shows the results of the dependence analysis with
-da-delinearize turned on. There are more MIV tests (Multiple Induction
Variables dependence test) that can be disambiguated as carrying no dependence
(as SCEV->delinearize translates MIV tests into SIV tests (Single IV tests)):

diff --git a/test/Analysis/DependenceAnalysis/Banerjee.ll b/test/Analysis/DependenceAnalysis/Banerjee.ll
index 09e8fd2..65a1f68 100644
--- a/test/Analysis/DependenceAnalysis/Banerjee.ll
+++ b/test/Analysis/DependenceAnalysis/Banerjee.ll
@@ -490,7 +490,7 @@ entry:
   br label %for.cond1.preheader
 
 ; CHECK: 'Dependence Analysis' for function 'banerjee9':
-; CHECK: da analyze - output [* *]!
+; CHECK: da analyze - none!
 ; CHECK: da analyze - flow [<= =|<]!
 ; CHECK: da analyze - confused!
 ; CHECK: da analyze - none!
diff --git a/test/Analysis/DependenceAnalysis/GCD.ll b/test/Analysis/DependenceAnalysis/GCD.ll
index bb31d11..18942aa 100644
--- a/test/Analysis/DependenceAnalysis/GCD.ll
+++ b/test/Analysis/DependenceAnalysis/GCD.ll
@@ -18,7 +18,7 @@ entry:
 ; CHECK: da analyze - output [* *]!
 ; CHECK: da analyze - flow [=> *|<]!
 ; CHECK: da analyze - confused!
-; CHECK: da analyze - input [* *]!
+; CHECK: da analyze - none!
 ; CHECK: da analyze - confused!
 ; CHECK: da analyze - none!
 
@@ -71,7 +71,7 @@ entry:
 ; CHECK: da analyze - output [* *]!
 ; CHECK: da analyze - none!
 ; CHECK: da analyze - confused!
-; CHECK: da analyze - input [* *]!
+; CHECK: da analyze - none!
 ; CHECK: da analyze - confused!
 ; CHECK: da analyze - none!
 
@@ -125,7 +125,7 @@ entry:
 ; CHECK: da analyze - output [* *]!
 ; CHECK: da analyze - none!
 ; CHECK: da analyze - confused!
-; CHECK: da analyze - input [* *]!
+; CHECK: da analyze - none!
 ; CHECK: da analyze - confused!
 ; CHECK: da analyze - none!
 
@@ -353,10 +353,10 @@ entry:
   br i1 %cmp4, label %for.cond1.preheader.preheader, label %for.end12
 
 ; CHECK: 'Dependence Analysis' for function 'gcd6'
-; CHECK: da analyze - output [* *]!
+; CHECK: da analyze - flow [0 =>|<]!
 ; CHECK: da analyze - none!
 ; CHECK: da analyze - confused!
-; CHECK: da analyze - input [* *]!
+; CHECK: da analyze - none!
 ; CHECK: da analyze - confused!
 ; CHECK: da analyze - output [* *]!


I'm not sure why we have this change:
-; CHECK: da analyze - output [* *]!
+; CHECK: da analyze - flow [0 =>|<]!
it looks like an error... although, I have not investigated why this happens.

> 
> Yea ;)
> 
> Also, please comment on the current state of any known correctness issues. In
> response to one of Arnold's comments about dealing with
> inner-dimension-overflow cases, you had said, "Right.  It looks like the data
> dependence analysis needs more code to support the contiguous memory
> semantics...", and I'd like to have a clear understanding on the resolution to
> that.

The data dependence analysis has to bound each array access dimension by the
number of elements that the delinearization has determined: i.e., for a
delinearized access of the form (same C testcase as above)

> +; AddRec: {{{%A,+,(8 * %m * %o)}<%for.i>,+,(8 * %o)}<%for.j>,+,8}<%for.k>
> +; CHECK: Base offset: %A
> +; CHECK: ArrayDecl[UnknownSize][%m][%o] with elements of sizeof(double) bytes.
> +; CHECK: ArrayRef[{0,+,1}<nuw><nsw><%for.i>][{0,+,1}<nuw><nsw><%for.j>][{0,+,1}<nuw><nsw><%for.k>]

We will have to add to the data dependence test these two constraints:
"{0,+,1}<nuw><nsw><%for.k> < %o"
"{0,+,1}<nuw><nsw><%for.j> < %m"
to avoid having 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 decide to
access an array A[100][100]; as A[0][9999] or *A[9999], etc.
I am currently not sure how to add these constraints in the classical data
dependence test in lib/Analysis/DependenceAnalysis.cpp.

On the other hand, adding these constraints to Polly is a piece of cake: you
just drop the extra constraints in the bag of constraints that Polly uses to
formulate the dependence test, and then ISL does the rest.  I will post a patch
that integrates SCEV->delinearize in Polly.

> > (And also, awesome to see all of that work paying off!)

SCEV->delinearize will be beneficial in the context of data dependence tests in
multiple nested loops. LLVM would need a loop nest optimizer, a vectorizer, or a
parallelizer on top of lib/Analysis/DependenceAnalysis.cpp (not sure how long
that would take).

On the other hand, Polly would be the first to see the benefits from
SCEV->delinearize: I hope that Polly will start transforming most of the
test-suite/pollybench.

Sebastian
-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation



More information about the llvm-commits mailing list