[polly] r210117 - record delinearization result and reuse it in polyhedral translation
Sebastian Pop
spop at codeaurora.org
Tue Jun 3 11:16:32 PDT 2014
Author: spop
Date: Tue Jun 3 13:16:31 2014
New Revision: 210117
URL: http://llvm.org/viewvc/llvm-project?rev=210117&view=rev
Log:
record delinearization result and reuse it in polyhedral translation
Without this patch, the testcase would fail on the delinearization of the second
array:
; 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+3][j-4][k+7] = 1.0;
; A[i][0][k] = 2.0;
; }
; }
; CHECK: [n, m, o] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[3 + i0, -4 + i1, 7 + i2] };
; CHECK: [n, m, o] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0, 0, i2] };
Here is the output of FileCheck on the testcase without this patch:
; CHECK: [n, m, o] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0, 0, i2] };
^
<stdin>:26:2: note: possible intended match here
[n, m, o] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[o0] };
^
It is possible to find a good delinearization for A[i][0][k] only in the context
of the delinearization of both array accesses.
There are two ways to delinearize together all array subscripts touching the
same base address: either duplicate the code from scop detection to first gather
all array references and then run the delinearization; or as implemented in this
patch, use the same delinearization info that we computed during scop detection.
Added:
polly/trunk/test/ScopInfo/delinearize-together-all-data-refs.ll
Modified:
polly/trunk/include/polly/ScopDetection.h
polly/trunk/lib/Analysis/ScopDetection.cpp
polly/trunk/lib/Analysis/ScopInfo.cpp
polly/trunk/lib/Analysis/TempScopInfo.cpp
Modified: polly/trunk/include/polly/ScopDetection.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/include/polly/ScopDetection.h?rev=210117&r1=210116&r2=210117&view=diff
==============================================================================
--- polly/trunk/include/polly/ScopDetection.h (original)
+++ polly/trunk/include/polly/ScopDetection.h Tue Jun 3 13:16:31 2014
@@ -75,7 +75,33 @@ class Value;
namespace polly {
typedef std::set<const SCEV *> ParamSetType;
-typedef std::vector<const SCEVAddRecExpr *> AFs;
+// Description of the shape of an array.
+struct ArrayShape {
+ // Base pointer identifying all accesses to this array.
+ const SCEVUnknown *BasePointer;
+
+ // Sizes of each delinearized dimension.
+ SmallVector<const SCEV *, 4> DelinearizedSizes;
+
+ ArrayShape(const SCEVUnknown *B) : BasePointer(B), DelinearizedSizes() {}
+};
+
+struct MemAcc {
+ const Instruction *Insn;
+
+ // A pointer to the shape description of the array.
+ ArrayShape *Shape;
+
+ // Subscripts computed by delinearization.
+ SmallVector<const SCEV *, 4> DelinearizedSubscripts;
+
+ MemAcc(const Instruction *I, ArrayShape *S)
+ : Insn(I), Shape(S), DelinearizedSubscripts() {}
+};
+
+typedef std::map<const Instruction *, MemAcc *> MapInsnToMemAcc;
+typedef std::pair<const Instruction *, const SCEVAddRecExpr *> PairInsnAddRec;
+typedef std::vector<PairInsnAddRec> AFs;
typedef std::map<const SCEVUnknown *, AFs> BaseToAFs;
typedef std::map<const SCEVUnknown *, const SCEV *> BaseToElSize;
Modified: polly/trunk/lib/Analysis/ScopDetection.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Analysis/ScopDetection.cpp?rev=210117&r1=210116&r2=210117&view=diff
==============================================================================
--- polly/trunk/lib/Analysis/ScopDetection.cpp (original)
+++ polly/trunk/lib/Analysis/ScopDetection.cpp Tue Jun 3 13:16:31 2014
@@ -347,36 +347,45 @@ bool ScopDetection::isInvariant(const Va
return true;
}
+MapInsnToMemAcc InsnToMemAcc;
+
bool ScopDetection::hasAffineMemoryAccesses(DetectionContext &Context) const {
for (auto P : Context.NonAffineAccesses) {
const SCEVUnknown *BasePointer = P.first;
Value *BaseValue = BasePointer->getValue();
+ ArrayShape *Shape = new ArrayShape(BasePointer);
// First step: collect parametric terms in all array references.
SmallVector<const SCEV *, 4> Terms;
- for (const SCEVAddRecExpr *AF : Context.NonAffineAccesses[BasePointer])
- AF->collectParametricTerms(*SE, Terms);
+ for (PairInsnAddRec PIAF : Context.NonAffineAccesses[BasePointer])
+ PIAF.second->collectParametricTerms(*SE, Terms);
// Also collect terms from the affine memory accesses.
- for (const SCEVAddRecExpr *AF : Context.AffineAccesses[BasePointer])
- AF->collectParametricTerms(*SE, Terms);
+ for (PairInsnAddRec PIAF : Context.AffineAccesses[BasePointer])
+ PIAF.second->collectParametricTerms(*SE, Terms);
// Second step: find array shape.
- SmallVector<const SCEV *, 4> Sizes;
- SE->findArrayDimensions(Terms, Sizes, Context.ElementSize[BasePointer]);
+ SE->findArrayDimensions(Terms, Shape->DelinearizedSizes,
+ Context.ElementSize[BasePointer]);
// Third step: compute the access functions for each subscript.
- for (const SCEVAddRecExpr *AF : Context.NonAffineAccesses[BasePointer]) {
- if (Sizes.empty())
- return invalid<ReportNonAffineAccess>(Context, /*Assert=*/true, AF);
-
- SmallVector<const SCEV *, 4> Subscripts;
- AF->computeAccessFunctions(*SE, Subscripts, Sizes);
- if (Sizes.empty() || Subscripts.empty())
+ for (PairInsnAddRec PIAF : Context.NonAffineAccesses[BasePointer]) {
+ const SCEVAddRecExpr *AF = PIAF.second;
+ const Instruction *Insn = PIAF.first;
+ if (Shape->DelinearizedSizes.empty())
+ return invalid<ReportNonAffineAccess>(Context, /*Assert=*/true,
+ PIAF.second);
+
+ MemAcc *Acc = new MemAcc(Insn, Shape);
+ InsnToMemAcc.insert({ Insn, Acc });
+ AF->computeAccessFunctions(*SE, Acc->DelinearizedSubscripts,
+ Shape->DelinearizedSizes);
+ if (Shape->DelinearizedSizes.empty() ||
+ Acc->DelinearizedSubscripts.empty())
return invalid<ReportNonAffineAccess>(Context, /*Assert=*/true, AF);
// Check that the delinearized subscripts are affine.
- for (const SCEV *S : Subscripts)
+ for (const SCEV *S : Acc->DelinearizedSubscripts)
if (!isAffineExpr(&Context.CurRegion, S, *SE, BaseValue))
return invalid<ReportNonAffineAccess>(Context, /*Assert=*/true, AF);
}
@@ -430,12 +439,12 @@ bool ScopDetection::isValidMemoryAccess(
// accesses to the same array in a unique step.
if (Context.NonAffineAccesses[BasePointer].size() == 0)
Context.NonAffineAccesses[BasePointer] = AFs();
- Context.NonAffineAccesses[BasePointer].push_back(AF);
+ Context.NonAffineAccesses[BasePointer].push_back({ &Inst, AF });
} else if (const SCEVAddRecExpr *AF =
dyn_cast<SCEVAddRecExpr>(AccessFunction)) {
if (Context.AffineAccesses[BasePointer].size() == 0)
Context.AffineAccesses[BasePointer] = AFs();
- Context.AffineAccesses[BasePointer].push_back(AF);
+ Context.AffineAccesses[BasePointer].push_back({ &Inst, AF });
}
// FIXME: Alias Analysis thinks IntToPtrInst aliases with alloca instructions
Modified: polly/trunk/lib/Analysis/ScopInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Analysis/ScopInfo.cpp?rev=210117&r1=210116&r2=210117&view=diff
==============================================================================
--- polly/trunk/lib/Analysis/ScopInfo.cpp (original)
+++ polly/trunk/lib/Analysis/ScopInfo.cpp Tue Jun 3 13:16:31 2014
@@ -344,9 +344,9 @@ MemoryAccess::MemoryAccess(const IRAcces
isl_pw_aff *Affine =
SCEVAffinator::getPwAff(Statement, Access.Subscripts[i]);
- if (i == Size - 1) {
- // Divide the access function of the last subscript by the size of the
- // elements in the array.
+ if (Size == 1) {
+ // For the non delinearized arrays, divide the access function of the last
+ // subscript by the size of the elements in the array.
//
// A stride one array access in C expressed as A[i] is expressed in
// LLVM-IR as something like A[i * elementsize]. This hides the fact that
Modified: polly/trunk/lib/Analysis/TempScopInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Analysis/TempScopInfo.cpp?rev=210117&r1=210116&r2=210117&view=diff
==============================================================================
--- polly/trunk/lib/Analysis/TempScopInfo.cpp (original)
+++ polly/trunk/lib/Analysis/TempScopInfo.cpp Tue Jun 3 13:16:31 2014
@@ -14,6 +14,7 @@
//===----------------------------------------------------------------------===//
#include "polly/TempScopInfo.h"
+#include "polly/ScopDetection.h"
#include "polly/LinkAllPasses.h"
#include "polly/CodeGen/BlockGenerators.h"
#include "polly/Support/GICHelper.h"
@@ -143,6 +144,8 @@ bool TempScopInfo::buildScalarDependence
return AnyCrossStmtUse;
}
+extern MapInsnToMemAcc InsnToMemAcc;
+
IRAccess TempScopInfo::buildIRAccess(Instruction *Inst, Loop *L, Region *R) {
unsigned Size;
Type *SizeType;
@@ -167,34 +170,14 @@ IRAccess TempScopInfo::buildIRAccess(Ins
AccessFunction = SE->getMinusSCEV(AccessFunction, BasePointer);
SmallVector<const SCEV *, 4> Subscripts, Sizes;
- bool IsAffine = isAffineExpr(R, AccessFunction, *SE, BasePointer->getValue());
- const SCEVAddRecExpr *AF = dyn_cast<SCEVAddRecExpr>(AccessFunction);
-
- if (!IsAffine && PollyDelinearize && AF) {
- const SCEV *ElementSize = SE->getElementSize(Inst);
- AF->delinearize(*SE, Subscripts, Sizes, ElementSize);
- int NSubs = Subscripts.size();
-
- if (NSubs > 0) {
- // Normalize the last dimension: integrate the size of the "scalar
- // dimension" and the remainder of the delinearization.
- Subscripts[NSubs - 1] =
- SE->getMulExpr(Subscripts[NSubs - 1], Sizes[NSubs - 1]);
-
- IsAffine = true;
- for (int i = 0; i < NSubs; ++i)
- if (!isAffineExpr(R, Subscripts[i], *SE, BasePointer->getValue())) {
- IsAffine = false;
- break;
- }
- }
- }
-
- if (Subscripts.size() == 0) {
- Subscripts.push_back(AccessFunction);
- Sizes.push_back(SE->getConstant(ZeroOffset->getType(), Size));
- }
+ MemAcc *Acc = InsnToMemAcc[Inst];
+ if (PollyDelinearize && Acc)
+ return IRAccess(Type, BasePointer->getValue(), AccessFunction, Size, true,
+ Acc->DelinearizedSubscripts, Acc->Shape->DelinearizedSizes);
+ bool IsAffine = isAffineExpr(R, AccessFunction, *SE, BasePointer->getValue());
+ Subscripts.push_back(AccessFunction);
+ Sizes.push_back(SE->getConstant(ZeroOffset->getType(), Size));
return IRAccess(Type, BasePointer->getValue(), AccessFunction, Size, IsAffine,
Subscripts, Sizes);
}
Added: polly/trunk/test/ScopInfo/delinearize-together-all-data-refs.ll
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/ScopInfo/delinearize-together-all-data-refs.ll?rev=210117&view=auto
==============================================================================
--- polly/trunk/test/ScopInfo/delinearize-together-all-data-refs.ll (added)
+++ polly/trunk/test/ScopInfo/delinearize-together-all-data-refs.ll Tue Jun 3 13:16:31 2014
@@ -0,0 +1,75 @@
+; RUN: opt %loadPolly -polly-scops -analyze -polly-delinearize < %s | FileCheck %s
+
+; 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+3][j-4][k+7] = 1.0;
+; A[i][0][k] = 2.0;
+; }
+; }
+
+; CHECK: [n, m, o] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[3 + i0, -4 + i1, 7 + i2] };
+; CHECK: [n, m, o] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0, 0, i2] };
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: nounwind uwtable
+define void @foo(i64 %n, i64 %m, i64 %o, double* nocapture %A) {
+entry:
+ %cmp35 = icmp sgt i64 %n, 0
+ br i1 %cmp35, label %for.cond1.preheader.lr.ph, label %for.end18
+
+for.cond1.preheader.lr.ph: ; preds = %entry
+ %cmp233 = icmp sgt i64 %m, 0
+ %cmp531 = icmp sgt i64 %o, 0
+ %0 = mul nuw i64 %o, %m
+ br label %for.cond1.preheader
+
+for.cond1.preheader: ; preds = %for.inc16, %for.cond1.preheader.lr.ph
+ %i.036 = phi i64 [ 0, %for.cond1.preheader.lr.ph ], [ %inc17, %for.inc16 ]
+ br i1 %cmp233, label %for.cond4.preheader.lr.ph, label %for.inc16
+
+for.cond4.preheader.lr.ph: ; preds = %for.cond1.preheader
+ %add7 = add nsw i64 %i.036, 3
+ %1 = mul nsw i64 %add7, %0
+ %add = add i64 %1, 7
+ %2 = mul nsw i64 %i.036, %0
+ br label %for.cond4.preheader
+
+for.cond4.preheader: ; preds = %for.inc13, %for.cond4.preheader.lr.ph
+ %j.034 = phi i64 [ 0, %for.cond4.preheader.lr.ph ], [ %inc14, %for.inc13 ]
+ br i1 %cmp531, label %for.body6.lr.ph, label %for.inc13
+
+for.body6.lr.ph: ; preds = %for.cond4.preheader
+ %sub = add nsw i64 %j.034, -4
+ %3 = mul nsw i64 %sub, %o
+ %arrayidx.sum = add i64 %add, %3
+ br label %for.body6
+
+for.body6: ; preds = %for.body6, %for.body6.lr.ph
+ %k.032 = phi i64 [ 0, %for.body6.lr.ph ], [ %inc, %for.body6 ]
+ %arrayidx8.sum = add i64 %arrayidx.sum, %k.032
+ %arrayidx9 = getelementptr inbounds double* %A, i64 %arrayidx8.sum
+ store double 1.000000e+00, double* %arrayidx9, align 8
+ %arrayidx10.sum = add i64 %k.032, %2
+ %arrayidx12 = getelementptr inbounds double* %A, i64 %arrayidx10.sum
+ store double 2.000000e+00, double* %arrayidx12, align 8
+ %inc = add nsw i64 %k.032, 1
+ %exitcond = icmp eq i64 %inc, %o
+ br i1 %exitcond, label %for.inc13, label %for.body6
+
+for.inc13: ; preds = %for.body6, %for.cond4.preheader
+ %inc14 = add nsw i64 %j.034, 1
+ %exitcond37 = icmp eq i64 %inc14, %m
+ br i1 %exitcond37, label %for.inc16, label %for.cond4.preheader
+
+for.inc16: ; preds = %for.inc13, %for.cond1.preheader
+ %inc17 = add nsw i64 %i.036, 1
+ %exitcond38 = icmp eq i64 %inc17, %n
+ br i1 %exitcond38, label %for.end18, label %for.cond1.preheader
+
+for.end18: ; preds = %for.inc16, %entry
+ ret void
+}
More information about the llvm-commits
mailing list