[polly] r234711 - Allow loops in non-affine subregions -- SCoP Detection
Johannes Doerfert
doerfert at cs.uni-saarland.de
Sun Apr 12 15:52:20 PDT 2015
Author: jdoerfert
Date: Sun Apr 12 17:52:20 2015
New Revision: 234711
URL: http://llvm.org/viewvc/llvm-project?rev=234711&view=rev
Log:
Allow loops in non-affine subregions -- SCoP Detection
This will allow the ScopDetection to detect non-affine regions that
contain loops. All loops contained will be collected and are
accessible to later passes in order to adjust the access functions.
As the loops are non-affine and will not be part of the polyhedral
representation later, all accesses that are variant in these loops
have to be over approximated as non-affine accesses. They are
therefore handled the same way as other non-affine accesses.
Additionally, we do not count non-affine loops for the profitability
heuristic, thus a region with only a non-affine loop will only be
detected if the general detection of loop free regions is enabled.
Differential Revision: http://reviews.llvm.org/D8152
Modified:
polly/trunk/include/polly/ScopDetection.h
polly/trunk/lib/Analysis/ScopDetection.cpp
polly/trunk/test/ScopDetectionDiagnostics/ReportLoopBound-01.ll
Modified: polly/trunk/include/polly/ScopDetection.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/include/polly/ScopDetection.h?rev=234711&r1=234710&r2=234711&view=diff
==============================================================================
--- polly/trunk/include/polly/ScopDetection.h (original)
+++ polly/trunk/include/polly/ScopDetection.h Sun Apr 12 17:52:20 2015
@@ -123,6 +123,9 @@ class ScopDetection : public FunctionPas
public:
typedef SetVector<const Region *> RegionSet;
+ /// @brief Set of loops (used to remember loops in non-affine subregions).
+ using BoxedLoopsSetTy = SetVector<const Loop *>;
+
private:
//===--------------------------------------------------------------------===//
ScopDetection(const ScopDetection &) = delete;
@@ -142,6 +145,10 @@ private:
DenseMap<const Region *, NonAffineSubRegionSetTy>;
NonAffineSubRegionMapTy NonAffineSubRegionMap;
+ /// @brief Map to remeber loops in non-affine regions.
+ using BoxedLoopsMapTy = DenseMap<const Region *, BoxedLoopsSetTy>;
+ BoxedLoopsMapTy BoxedLoopsMap;
+
/// @brief Context variables for SCoP detection.
struct DetectionContext {
Region &CurRegion; // The region to check.
@@ -168,13 +175,21 @@ private:
/// @brief The region has at least one store instruction.
bool hasStores;
+ /// @brief The region has at least one loop that is not overapproximated.
+ bool hasAffineLoops;
+
/// @brief The set of non-affine subregions in the region we analyze.
NonAffineSubRegionSetTy &NonAffineSubRegionSet;
+ /// @brief The sef of loops contained in non-affine regions.
+ BoxedLoopsSetTy &BoxedLoopsSet;
+
DetectionContext(Region &R, AliasAnalysis &AA,
- NonAffineSubRegionSetTy &NABS, bool Verify)
+ NonAffineSubRegionSetTy &NASRS, BoxedLoopsSetTy &BLS,
+ bool Verify)
: CurRegion(R), AST(AA), Verifying(Verify), Log(&R), hasLoads(false),
- hasStores(false), NonAffineSubRegionSet(NABS) {}
+ hasStores(false), hasAffineLoops(false), NonAffineSubRegionSet(NASRS),
+ BoxedLoopsSet(BLS) {}
};
// Remember the valid regions
@@ -183,6 +198,14 @@ private:
// Remember a list of errors for every region.
mutable RejectLogsContainer RejectLogs;
+ /// @brief Add the region @p AR as over approximated sub-region in @p Context.
+ ///
+ /// @param AR The non-affine subregion.
+ /// @param Context The current detection context.
+ ///
+ /// @returns True if the subregion can be over approximated, false otherwise.
+ bool addOverApproximatedRegion(Region *AR, DetectionContext &Context) const;
+
// Delinearize all non affine memory accesses and return false when there
// exists a non affine memory access that cannot be delinearized. Return true
// when all array accesses are affine after delinearization.
@@ -310,6 +333,9 @@ public:
/// @return Return true if R is the maximum Region in a Scop, false otherwise.
bool isMaxRegionInScop(const Region &R, bool Verify = true) const;
+ /// @brief Return the set of loops in non-affine subregions for @p R.
+ const BoxedLoopsSetTy *getBoxedLoops(const Region *R) const;
+
/// @brief Return true if @p SubR is a non-affine subregion in @p ScopR.
bool isNonAffineSubRegion(const Region *SubR, const Region *ScopR) const;
Modified: polly/trunk/lib/Analysis/ScopDetection.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Analysis/ScopDetection.cpp?rev=234711&r1=234710&r2=234711&view=diff
==============================================================================
--- polly/trunk/lib/Analysis/ScopDetection.cpp (original)
+++ polly/trunk/lib/Analysis/ScopDetection.cpp Sun Apr 12 17:52:20 2015
@@ -131,6 +131,12 @@ static cl::opt<bool> AllowNonAffineSubRe
cl::desc("Allow non affine conditions for branches"), cl::Hidden,
cl::init(true), cl::ZeroOrMore, cl::cat(PollyCategory));
+static cl::opt<bool>
+ AllowNonAffineSubLoops("polly-allow-nonaffine-loops",
+ cl::desc("Allow non affine conditions for loops"),
+ cl::Hidden, cl::init(false), cl::ZeroOrMore,
+ cl::cat(PollyCategory));
+
static cl::opt<bool> AllowUnsigned("polly-allow-unsigned",
cl::desc("Allow unsigned expressions"),
cl::Hidden, cl::init(false), cl::ZeroOrMore,
@@ -257,9 +263,11 @@ bool ScopDetection::isMaxRegionInScop(co
return false;
if (Verify) {
+ BoxedLoopsSetTy DummyBoxedLoopsSet;
NonAffineSubRegionSetTy DummyNonAffineSubRegionSet;
DetectionContext Context(const_cast<Region &>(R), *AA,
- DummyNonAffineSubRegionSet, false /*verifying*/);
+ DummyNonAffineSubRegionSet, DummyBoxedLoopsSet,
+ false /*verifying*/);
return isValidRegion(Context);
}
@@ -283,13 +291,22 @@ std::string ScopDetection::regionIsInval
return RR->getMessage();
}
-static bool containsLoop(Region *R, LoopInfo *LI) {
- for (BasicBlock *BB : R->blocks()) {
+bool ScopDetection::addOverApproximatedRegion(Region *AR,
+ DetectionContext &Context) const {
+
+ // If we already know about Ar we can exit.
+ if (!Context.NonAffineSubRegionSet.insert(AR))
+ return true;
+
+ // All loops in the region have to be overapproximated too if there
+ // are accesses that depend on the iteration count.
+ for (BasicBlock *BB : AR->blocks()) {
Loop *L = LI->getLoopFor(BB);
- if (R->contains(L))
- return true;
+ if (AR->contains(L))
+ Context.BoxedLoopsSet.insert(L);
}
- return false;
+
+ return (AllowNonAffineSubLoops || Context.BoxedLoopsSet.empty());
}
bool ScopDetection::isValidCFG(BasicBlock &BB,
@@ -318,9 +335,8 @@ bool ScopDetection::isValidCFG(BasicBloc
// Only Constant and ICmpInst are allowed as condition.
if (!(isa<Constant>(Condition) || isa<ICmpInst>(Condition))) {
- if (AllowNonAffineSubRegions && !containsLoop(RI->getRegionFor(&BB), LI))
- Context.NonAffineSubRegionSet.insert(RI->getRegionFor(&BB));
- else
+ if (!AllowNonAffineSubRegions ||
+ !addOverApproximatedRegion(RI->getRegionFor(&BB), Context))
return invalid<ReportInvalidCond>(Context, /*Assert=*/true, Br, &BB);
}
@@ -347,9 +363,8 @@ bool ScopDetection::isValidCFG(BasicBloc
if (!isAffineExpr(&CurRegion, LHS, *SE) ||
!isAffineExpr(&CurRegion, RHS, *SE)) {
- if (AllowNonAffineSubRegions && !containsLoop(RI->getRegionFor(&BB), LI))
- Context.NonAffineSubRegionSet.insert(RI->getRegionFor(&BB));
- else
+ if (!AllowNonAffineSubRegions ||
+ !addOverApproximatedRegion(RI->getRegionFor(&BB), Context))
return invalid<ReportNonAffBranch>(Context, /*Assert=*/true, &BB, LHS,
RHS, ICmp);
}
@@ -579,13 +594,21 @@ bool ScopDetection::isValidMemoryAccess(
Context.ElementSize[BasePointer] = Size;
}
- if (PollyDelinearize) {
+ bool isVariantInNonAffineLoop = false;
+ SetVector<const Loop *> Loops;
+ findLoops(AccessFunction, Loops);
+ for (const Loop *L : Loops)
+ if (Context.BoxedLoopsSet.count(L))
+ isVariantInNonAffineLoop = true;
+
+ if (PollyDelinearize && !isVariantInNonAffineLoop) {
Context.Accesses[BasePointer].push_back({&Inst, AccessFunction});
if (!isAffineExpr(&CurRegion, AccessFunction, *SE, BaseValue))
Context.NonAffineAccesses.insert(BasePointer);
} else if (!AllowNonAffine) {
- if (!isAffineExpr(&CurRegion, AccessFunction, *SE, BaseValue))
+ if (isVariantInNonAffineLoop ||
+ !isAffineExpr(&CurRegion, AccessFunction, *SE, BaseValue))
return invalid<ReportNonAffineAccess>(Context, /*Assert=*/true,
AccessFunction, &Inst, BaseValue);
}
@@ -672,8 +695,17 @@ bool ScopDetection::isValidInstruction(I
bool ScopDetection::isValidLoop(Loop *L, DetectionContext &Context) const {
// Is the loop count affine?
const SCEV *LoopCount = SE->getBackedgeTakenCount(L);
- if (isAffineExpr(&Context.CurRegion, LoopCount, *SE))
+ if (isAffineExpr(&Context.CurRegion, LoopCount, *SE)) {
+ Context.hasAffineLoops = true;
return true;
+ }
+
+ if (AllowNonAffineSubRegions) {
+ Region *R = RI->getRegionFor(L->getHeader());
+ if (R->contains(L))
+ if (addOverApproximatedRegion(R, Context))
+ return true;
+ }
return invalid<ReportLoopBound>(Context, /*Assert=*/true, L, LoopCount);
}
@@ -686,9 +718,9 @@ Region *ScopDetection::expandRegion(Regi
DEBUG(dbgs() << "\tExpanding " << R.getNameStr() << "\n");
while (ExpandedRegion) {
- DetectionContext Context(*ExpandedRegion, *AA,
- NonAffineSubRegionMap[ExpandedRegion],
- false /* verifying */);
+ DetectionContext Context(
+ *ExpandedRegion, *AA, NonAffineSubRegionMap[ExpandedRegion],
+ BoxedLoopsMap[ExpandedRegion], false /* verifying */);
DEBUG(dbgs() << "\t\tTrying " << ExpandedRegion->getNameStr() << "\n");
// Only expand when we did not collect errors.
@@ -761,7 +793,7 @@ static unsigned eraseAllChildren(ScopDet
}
void ScopDetection::findScops(Region &R) {
- DetectionContext Context(R, *AA, NonAffineSubRegionMap[&R],
+ DetectionContext Context(R, *AA, NonAffineSubRegionMap[&R], BoxedLoopsMap[&R],
false /*verifying*/);
bool RegionIsValid = false;
@@ -910,6 +942,11 @@ bool ScopDetection::isValidRegion(Detect
if (!DetectUnprofitable && (!Context.hasStores || !Context.hasLoads))
invalid<ReportUnprofitable>(Context, /*Assert=*/true, &CurRegion);
+ // Check if there was at least one non-overapproximated loop in the region or
+ // we allow regions without loops.
+ if (!DetectRegionsWithoutLoops && !Context.hasAffineLoops)
+ invalid<ReportUnprofitable>(Context, /*Assert=*/true, &CurRegion);
+
DEBUG(dbgs() << "OK\n");
return true;
}
@@ -1000,11 +1037,22 @@ bool ScopDetection::isNonAffineSubRegion
return NonAffineSubRegionMap.lookup(ScopR).count(SubR);
}
+const ScopDetection::BoxedLoopsSetTy *
+ScopDetection::getBoxedLoops(const Region *R) const {
+ auto BLMIt = BoxedLoopsMap.find(R);
+ if (BLMIt == BoxedLoopsMap.end())
+ return nullptr;
+ return &BLMIt->second;
+}
+
void polly::ScopDetection::verifyRegion(const Region &R) const {
assert(isMaxRegionInScop(R) && "Expect R is a valid region.");
+
+ BoxedLoopsSetTy DummyBoxedLoopsSet;
NonAffineSubRegionSetTy DummyNonAffineSubRegionSet;
DetectionContext Context(const_cast<Region &>(R), *AA,
- DummyNonAffineSubRegionSet, true /*verifying*/);
+ DummyNonAffineSubRegionSet, DummyBoxedLoopsSet,
+ true /*verifying*/);
isValidRegion(Context);
}
Modified: polly/trunk/test/ScopDetectionDiagnostics/ReportLoopBound-01.ll
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/ScopDetectionDiagnostics/ReportLoopBound-01.ll?rev=234711&r1=234710&r2=234711&view=diff
==============================================================================
--- polly/trunk/test/ScopDetectionDiagnostics/ReportLoopBound-01.ll (original)
+++ polly/trunk/test/ScopDetectionDiagnostics/ReportLoopBound-01.ll Sun Apr 12 17:52:20 2015
@@ -1,13 +1,29 @@
-; RUN: opt %loadPolly -polly-detect-unprofitable -pass-remarks-missed="polly-detect" -polly-detect-track-failures -polly-detect -analyze < %s 2>&1| FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -pass-remarks-missed="polly-detect" -polly-detect-track-failures -polly-allow-nonaffine-loops=false -polly-detect -analyze < %s 2>&1| FileCheck %s --check-prefix=REJECTNONAFFINELOOPS
+; RUN: opt %loadPolly -polly-detect-unprofitable -pass-remarks-missed="polly-detect" -polly-detect-track-failures -polly-allow-nonaffine-loops=true -polly-detect -analyze < %s 2>&1| FileCheck %s --check-prefix=ALLOWNONAFFINELOOPS
+; RUN: opt %loadPolly -polly-detect-unprofitable -pass-remarks-missed="polly-detect" -polly-detect-track-failures -polly-allow-nonaffine-loops=true -polly-allow-nonaffine -polly-detect -analyze < %s 2>&1| FileCheck %s --check-prefix=ALLOWNONAFFINEALL
; void f(int A[], int n) {
; for (int i = 0; i < A[n]; i++)
; A[i] = 0;
; }
-; CHECK: remark: ReportLoopBound-01.c:2:8: The following errors keep this region from being a Scop.
-; CHECK: remark: ReportLoopBound-01.c:2:8: Failed to derive an affine function from the loop bounds.
-; CHECK: remark: ReportLoopBound-01.c:3:5: Invalid Scop candidate ends here.
+; If we reject non-affine loops the non-affine loop bound will be reported:
+;
+; REJECTNONAFFINELOOPS: remark: ReportLoopBound-01.c:2:8: The following errors keep this region from being a Scop.
+; REJECTNONAFFINELOOPS: remark: ReportLoopBound-01.c:2:8: Failed to derive an affine function from the loop bounds.
+; REJECTNONAFFINELOOPS: remark: ReportLoopBound-01.c:3:5: Invalid Scop candidate ends here.
+
+; If we allow non-affine loops the non-affine access will be reported:
+;
+; ALLOWNONAFFINELOOPS: remark: ReportLoopBound-01.c:2:8: The following errors keep this region from being a Scop.
+; ALLOWNONAFFINELOOPS: remark: ReportLoopBound-01.c:3:5: The array subscript of "A" is not affine
+; ALLOWNONAFFINELOOPS: remark: ReportLoopBound-01.c:3:5: Invalid Scop candidate ends here.
+
+; If we allow non-affine loops and non-affine accesses the region will be reported as not profitable:
+;
+; ALLOWNONAFFINEALL: remark: ReportLoopBound-01.c:2:8: The following errors keep this region from being a Scop.
+; ALLOWNONAFFINEALL: remark: ReportLoopBound-01.c:3:5: The regions does not seem to be amendable to profitable polyhedral optimization
+; ALLOWNONAFFINEALL: remark: ReportLoopBound-01.c:3:5: Invalid Scop candidate ends here.
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
More information about the llvm-commits
mailing list