Allow non-affine control flow -- SCoP Modeling

This allows us to model non-affine regions in the SCoP representation.
  SCoP statements can now describe either basic blocks or non-affine
  regions. In the latter case all accesses in the region are accumulated
  for the statement and write accesses, except in the entry, have to be
  marked as may-write.

Differential Revision: http://reviews.llvm.org/D7846

llvm-svn: 230329
This commit is contained in:
Johannes Doerfert 2015-02-24 12:00:50 +00:00
parent e70449400f
commit ff9d1980a7
6 changed files with 362 additions and 67 deletions

View File

@ -429,9 +429,21 @@ class ScopStmt {
//@}
/// The BasicBlock represented by this statement.
/// @brief A SCoP statement represents either a basic block (affine/precise
/// case) or a whole region (non-affine case). Only one of the
/// following two members will therefore be set and indicate which
/// kind of statement this is.
///
///{
/// @brief The BasicBlock represented by this statement (in the affine case).
BasicBlock *BB;
/// @brief The region represented by this statement (in the non-affine case).
Region *R;
///}
/// @brief The isl AST build for the new generated AST.
isl_ast_build *Build;
@ -449,7 +461,17 @@ class ScopStmt {
TempScop &tempScop);
__isl_give isl_set *buildDomain(TempScop &tempScop, const Region &CurRegion);
void buildScattering(SmallVectorImpl<unsigned> &Scatter);
void buildAccesses(TempScop &tempScop);
/// @brief Create the accesses for instructions in @p Block.
///
/// @param tempScop The template SCoP.
/// @param Block The basic block for which accesses should be
/// created.
/// @param isApproximated Flag to indicate blocks that might not be executed,
/// hence for which write accesses need to be modelt as
/// may-write accesses.
void buildAccesses(TempScop &tempScop, BasicBlock *Block,
bool isApproximated = false);
/// @brief Detect and mark reductions in the ScopStmt
void checkForReductions();
@ -489,14 +511,19 @@ class ScopStmt {
/// or non-optimal run-time checks.
void deriveAssumptionsFromGEP(GetElementPtrInst *Inst);
/// @brief Scan the scop and derive assumptions about parameter values.
void deriveAssumptions();
/// @brief Scan @p Block and derive assumptions about parameter values.
void deriveAssumptions(BasicBlock *Block);
/// Create the ScopStmt from a BasicBlock.
ScopStmt(Scop &parent, TempScop &tempScop, const Region &CurRegion,
BasicBlock &bb, SmallVectorImpl<Loop *> &NestLoops,
SmallVectorImpl<unsigned> &Scatter);
/// Create an overapproximating ScopStmt for the region @p R.
ScopStmt(Scop &parent, TempScop &tempScop, const Region &CurRegion, Region &R,
SmallVectorImpl<Loop *> &NestLoops,
SmallVectorImpl<unsigned> &Scatter);
friend class Scop;
public:
@ -532,11 +559,24 @@ public:
/// @brief Get an isl string representing this scattering.
std::string getScatteringStr() const;
/// @brief Get the BasicBlock represented by this ScopStmt.
/// @brief Get the BasicBlock represented by this ScopStmt (if any).
///
/// @return The BasicBlock represented by this ScopStmt.
/// @return The BasicBlock represented by this ScopStmt, or null if the
/// statement represents a region.
BasicBlock *getBasicBlock() const { return BB; }
/// @brief Return true if this statement represents a single basic block.
bool isBlockStmt() const { return BB != nullptr; }
/// @brief Get the region represented by this ScopStmt (if any).
///
/// @return The region represented by this ScopStmt, or null if the statement
/// represents a basic block.
Region *getRegion() const { return R; }
/// @brief Return true if this statement represents a whole region.
bool isRegionStmt() const { return R != nullptr; }
const MemoryAccess &getAccessFor(const Instruction *Inst) const {
MemoryAccess *A = lookupAccessFor(Inst);
assert(A && "Cannot get memory access because it does not exist!");
@ -549,7 +589,12 @@ public:
return at == InstructionToAccess.end() ? NULL : at->second;
}
void setBasicBlock(BasicBlock *Block) { BB = Block; }
void setBasicBlock(BasicBlock *Block) {
// TODO: Handle the case where the statement is a region statement, thus
// the entry block was split and needs to be changed in the region R.
assert(BB && "Cannot set a block for a region statement");
BB = Block;
}
typedef MemoryAccessVec::iterator iterator;
typedef MemoryAccessVec::const_iterator const_iterator;
@ -697,7 +742,8 @@ private:
/// Create the static control part with a region, max loop depth of this
/// region and parameters used in this region.
Scop(TempScop &TempScop, LoopInfo &LI, ScalarEvolution &SE, isl_ctx *ctx);
Scop(TempScop &TempScop, LoopInfo &LI, ScalarEvolution &SE, ScopDetection &SD,
isl_ctx *ctx);
/// @brief Check if a basic block is trivial.
///
@ -719,12 +765,28 @@ private:
/// @brief Simplify the assumed context.
void simplifyAssumedContext();
/// @brief Create a new SCoP statement for either @p BB or @p R.
///
/// Either @p BB or @p R should be non-null. A new statement for the non-null
/// argument will be created and added to the statement vector and map.
///
/// @param BB The basic block we build the statement for (or null)
/// @param R The region we build the statement for (or null).
/// @param tempScop The temp SCoP we use as model.
/// @param CurRegion The SCoP region.
/// @param NestLoops A vector of all surrounding loops.
/// @param Scatter The position of the new statement as scattering.
void addScopStmt(BasicBlock *BB, Region *R, TempScop &tempScop,
const Region &CurRegion, SmallVectorImpl<Loop *> &NestLoops,
SmallVectorImpl<unsigned> &Scatter);
/// Build the Scop and Statement with precalculated scop information.
void buildScop(TempScop &TempScop, const Region &CurRegion,
// Loops in Scop containing CurRegion
SmallVectorImpl<Loop *> &NestLoops,
// The scattering numbers
SmallVectorImpl<unsigned> &Scatter, LoopInfo &LI);
SmallVectorImpl<unsigned> &Scatter, LoopInfo &LI,
ScopDetection &SD);
/// @name Helper function for printing the Scop.
///

View File

@ -80,6 +80,8 @@ public:
bool isWrite() const { return Type == MUST_WRITE; }
void setMayWrite() { Type = MAY_WRITE; }
bool isMayWrite() const { return Type == MAY_WRITE; }
bool isScalar() const { return Subscripts.size() == 0; }
@ -136,7 +138,7 @@ class TempScop {
const BBCondMapType &BBConds;
// Access function of bbs.
const AccFuncMapType &AccFuncMap;
AccFuncMapType &AccFuncMap;
friend class TempScopInfo;
@ -169,8 +171,8 @@ public:
///
/// @return All access functions in BB
///
const AccFuncSetType *getAccessFunctions(const BasicBlock *BB) const {
AccFuncMapType::const_iterator at = AccFuncMap.find(BB);
AccFuncSetType *getAccessFunctions(const BasicBlock *BB) {
AccFuncMapType::iterator at = AccFuncMap.find(BB);
return at != AccFuncMap.end() ? &(at->second) : 0;
}
//@}
@ -239,10 +241,9 @@ class TempScopInfo : public FunctionPass {
/// @brief Build condition constrains to BBs in a valid Scop.
///
/// @param BB The BasicBlock to build condition constrains
/// @param RegionEntry The entry block of the Smallest Region that containing
/// BB
void buildCondition(BasicBlock *BB, BasicBlock *RegionEntry);
/// @param BB The BasicBlock to build condition constrains
/// @param R The region for the current TempScop.
void buildCondition(BasicBlock *BB, Region &R);
// Build the affine function of the given condition
void buildAffineCondition(Value &V, bool inverted, Comparison **Comp) const;

View File

@ -797,15 +797,23 @@ void ScopStmt::buildScattering(SmallVectorImpl<unsigned> &Scatter) {
Scattering = isl_map_align_params(Scattering, Parent.getParamSpace());
}
void ScopStmt::buildAccesses(TempScop &tempScop) {
for (const auto &AccessPair : *tempScop.getAccessFunctions(BB)) {
const IRAccess &Access = AccessPair.first;
void ScopStmt::buildAccesses(TempScop &tempScop, BasicBlock *Block,
bool isApproximated) {
AccFuncSetType *AFS = tempScop.getAccessFunctions(Block);
if (!AFS)
return;
for (auto &AccessPair : *AFS) {
IRAccess &Access = AccessPair.first;
Instruction *AccessInst = AccessPair.second;
Type *AccessType = getAccessInstType(AccessInst)->getPointerTo();
const ScopArrayInfo *SAI = getParent()->getOrCreateScopArrayInfo(
Access.getBase(), AccessType, Access.Sizes);
if (isApproximated && Access.isWrite())
Access.setMayWrite();
MemAccs.push_back(new MemoryAccess(Access, AccessInst, this, SAI));
// We do not track locations for scalar memory accesses at the moment.
@ -894,7 +902,7 @@ __isl_give isl_set *ScopStmt::addConditionsToDomain(__isl_take isl_set *Domain,
const Region &CurRegion) {
const Region *TopRegion = tempScop.getMaxRegion().getParent(),
*CurrentRegion = &CurRegion;
const BasicBlock *BranchingBB = BB;
const BasicBlock *BranchingBB = BB ? BB : R->getEntry();
do {
if (BranchingBB != CurrentRegion->getEntry()) {
@ -978,16 +986,39 @@ void ScopStmt::deriveAssumptionsFromGEP(GetElementPtrInst *GEP) {
isl_local_space_free(LSpace);
}
void ScopStmt::deriveAssumptions() {
for (Instruction &Inst : *BB)
void ScopStmt::deriveAssumptions(BasicBlock *Block) {
for (Instruction &Inst : *Block)
if (auto *GEP = dyn_cast<GetElementPtrInst>(&Inst))
deriveAssumptionsFromGEP(GEP);
}
ScopStmt::ScopStmt(Scop &parent, TempScop &tempScop, const Region &CurRegion,
Region &R, SmallVectorImpl<Loop *> &Nest,
SmallVectorImpl<unsigned> &Scatter)
: Parent(parent), BB(nullptr), R(&R), Build(nullptr),
NestLoops(Nest.size()) {
// Setup the induction variables.
for (unsigned i = 0, e = Nest.size(); i < e; ++i)
NestLoops[i] = Nest[i];
BaseName = getIslCompatibleName("Stmt_(", R.getNameStr(), ")");
Domain = buildDomain(tempScop, CurRegion);
buildScattering(Scatter);
BasicBlock *EntryBB = R.getEntry();
for (BasicBlock *Block : R.blocks()) {
buildAccesses(tempScop, Block, Block != EntryBB);
deriveAssumptions(Block);
}
checkForReductions();
}
ScopStmt::ScopStmt(Scop &parent, TempScop &tempScop, const Region &CurRegion,
BasicBlock &bb, SmallVectorImpl<Loop *> &Nest,
SmallVectorImpl<unsigned> &Scatter)
: Parent(parent), BB(&bb), Build(nullptr), NestLoops(Nest.size()) {
: Parent(parent), BB(&bb), R(nullptr), Build(nullptr),
NestLoops(Nest.size()) {
// Setup the induction variables.
for (unsigned i = 0, e = Nest.size(); i < e; ++i)
NestLoops[i] = Nest[i];
@ -996,20 +1027,23 @@ ScopStmt::ScopStmt(Scop &parent, TempScop &tempScop, const Region &CurRegion,
Domain = buildDomain(tempScop, CurRegion);
buildScattering(Scatter);
buildAccesses(tempScop);
buildAccesses(tempScop, BB);
deriveAssumptions(BB);
checkForReductions();
deriveAssumptions();
}
/// @brief Collect loads which might form a reduction chain with @p StoreMA
///
/// Check if the stored value for @p StoreMA is a binary operator with one or
/// two loads as operands. If the binary operand is commutative & associative,
/// Check if the stored value for @p StoreMA is a binary operator with one
/// or
/// two loads as operands. If the binary operand is commutative &
/// associative,
/// used only once (by @p StoreMA) and its load operands are also used only
/// once, we have found a possible reduction chain. It starts at an operand
/// load and includes the binary operator and @p StoreMA.
///
/// Note: We allow only one use to ensure the load and binary operator cannot
/// Note: We allow only one use to ensure the load and binary operator
/// cannot
/// escape this block or into any other store except @p StoreMA.
void ScopStmt::collectCandiateReductionLoads(
MemoryAccess *StoreMA, SmallVectorImpl<MemoryAccess *> &Loads) {
@ -1026,7 +1060,8 @@ void ScopStmt::collectCandiateReductionLoads(
if (BinOp->getNumUses() != 1)
return;
// Skip if the opcode of the binary operator is not commutative/associative
// Skip if the opcode of the binary operator is not
// commutative/associative
if (!BinOp->isCommutative() || !BinOp->isAssociative())
return;
@ -1057,11 +1092,16 @@ void ScopStmt::collectCandiateReductionLoads(
/// @brief Check for reductions in this ScopStmt
///
/// Iterate over all store memory accesses and check for valid binary reduction
/// like chains. For all candidates we check if they have the same base address
/// and there are no other accesses which overlap with them. The base address
/// check rules out impossible reductions candidates early. The overlap check,
/// together with the "only one user" check in collectCandiateReductionLoads,
/// Iterate over all store memory accesses and check for valid binary
/// reduction
/// like chains. For all candidates we check if they have the same base
/// address
/// and there are no other accesses which overlap with them. The base
/// address
/// check rules out impossible reductions candidates early. The overlap
/// check,
/// together with the "only one user" check in
/// collectCandiateReductionLoads,
/// guarantees that none of the intermediate results will escape during
/// execution of the loop nest. We basically check here that no other memory
/// access can access the same memory as the potential reduction.
@ -1069,7 +1109,8 @@ void ScopStmt::checkForReductions() {
SmallVector<MemoryAccess *, 2> Loads;
SmallVector<std::pair<MemoryAccess *, MemoryAccess *>, 4> Candidates;
// First collect candidate load-store reduction chains by iterating over all
// First collect candidate load-store reduction chains by iterating over
// all
// stores and collecting possible reduction loads.
for (MemoryAccess *StoreMA : MemAccs) {
if (StoreMA->isRead())
@ -1282,10 +1323,13 @@ void Scop::simplifyAssumedContext() {
// WARNING: This only holds if the assumptions we have taken do not reduce
// the set of statement instances that are executed. Otherwise we
// may run into a case where the iteration domains suggest that
// for a certain set of parameter constraints no code is executed,
// for a certain set of parameter constraints no code is
// executed,
// but in the original program some computation would have been
// performed. In such a case, modifying the run-time conditions and
// possibly influencing the run-time check may cause certain scops
// performed. In such a case, modifying the run-time conditions
// and
// possibly influencing the run-time check may cause certain
// scops
// to not be executed.
//
// Example:
@ -1297,7 +1341,8 @@ void Scop::simplifyAssumedContext() {
// A[i+p][j] = 1.0;
//
// we assume that the condition m <= 0 or (m >= 1 and p >= 0) holds as
// otherwise we would access out of bound data. Now, knowing that code is
// otherwise we would access out of bound data. Now, knowing that code
// is
// only executed for the case m >= 0, it is sufficient to assume p >= 0.
AssumedContext =
isl_set_gist_params(AssumedContext, isl_union_set_params(getDomains()));
@ -1374,18 +1419,22 @@ static __isl_give isl_set *getAccessDomain(MemoryAccess *MA) {
bool Scop::buildAliasGroups(AliasAnalysis &AA) {
// To create sound alias checks we perform the following steps:
// o) Use the alias analysis and an alias set tracker to build alias sets
// o) Use the alias analysis and an alias set tracker to build alias
// sets
// for all memory accesses inside the SCoP.
// o) For each alias set we then map the aliasing pointers back to the
// memory accesses we know, thus obtain groups of memory accesses which
// memory accesses we know, thus obtain groups of memory accesses
// which
// might alias.
// o) We divide each group based on the domains of the minimal/maximal
// accesses. That means two minimal/maximal accesses are only in a group
// accesses. That means two minimal/maximal accesses are only in a
// group
// if their access domains intersect, otherwise they are in different
// ones.
// o) We split groups such that they contain at most one read only base
// address.
// o) For each group with more than one base pointer we then compute minimal
// o) For each group with more than one base pointer we then compute
// minimal
// and maximal accesses to each array in this group.
using AliasGroupTy = SmallVector<MemoryAccess *, 4>;
@ -1485,7 +1534,8 @@ bool Scop::buildAliasGroups(AliasAnalysis &AA) {
}
// If we have both read only and non read only base pointers we combine
// the non read only ones with exactly one read only one at a time into a
// the non read only ones with exactly one read only one at a time into
// a
// new alias group and clear the old alias group in the end.
for (const auto &ReadOnlyPair : ReadOnlyPairs) {
AliasGroupTy AGNonReadOnly = AG;
@ -1582,10 +1632,11 @@ void Scop::dropConstantScheduleDims() {
}
Scop::Scop(TempScop &tempScop, LoopInfo &LI, ScalarEvolution &ScalarEvolution,
isl_ctx *Context)
ScopDetection &SD, isl_ctx *Context)
: SE(&ScalarEvolution), R(tempScop.getMaxRegion()), IsOptimized(false),
MaxLoopDepth(getMaxLoopDepthInRegion(tempScop.getMaxRegion(), LI)) {
IslCtx = Context;
buildContext();
SmallVector<Loop *, 8> NestLoops;
@ -1595,7 +1646,7 @@ Scop::Scop(TempScop &tempScop, LoopInfo &LI, ScalarEvolution &ScalarEvolution,
// Build the iteration domain, access functions and scattering functions
// traversing the region tree.
buildScop(tempScop, getRegion(), NestLoops, Scatter, LI);
buildScop(tempScop, getRegion(), NestLoops, Scatter, LI, SD);
realignParams();
addParameterBounds();
@ -1866,9 +1917,39 @@ bool Scop::isTrivialBB(BasicBlock *BB, TempScop &tempScop) {
return true;
}
void Scop::addScopStmt(BasicBlock *BB, Region *R, TempScop &tempScop,
const Region &CurRegion,
SmallVectorImpl<Loop *> &NestLoops,
SmallVectorImpl<unsigned> &Scatter) {
ScopStmt *Stmt;
if (BB) {
Stmt = new ScopStmt(*this, tempScop, CurRegion, *BB, NestLoops, Scatter);
StmtMap[BB] = Stmt;
} else {
assert(R && "Either a basic block or a region is needed to "
"create a new SCoP stmt.");
Stmt = new ScopStmt(*this, tempScop, CurRegion, *R, NestLoops, Scatter);
for (BasicBlock *BB : R->blocks())
StmtMap[BB] = Stmt;
}
// Insert all statements into the statement map and the statement vector.
Stmts.push_back(Stmt);
// Increasing the Scattering function is OK for the moment, because
// we are using a depth first iterator and the program is well structured.
++Scatter[NestLoops.size()];
}
void Scop::buildScop(TempScop &tempScop, const Region &CurRegion,
SmallVectorImpl<Loop *> &NestLoops,
SmallVectorImpl<unsigned> &Scatter, LoopInfo &LI) {
SmallVectorImpl<unsigned> &Scatter, LoopInfo &LI,
ScopDetection &SD) {
if (SD.isNonAffineSubRegion(&CurRegion, &getRegion()))
return addScopStmt(nullptr, const_cast<Region *>(&CurRegion), tempScop,
CurRegion, NestLoops, Scatter);
Loop *L = castToLoop(CurRegion, LI);
if (L)
@ -1880,24 +1961,15 @@ void Scop::buildScop(TempScop &tempScop, const Region &CurRegion,
for (Region::const_element_iterator I = CurRegion.element_begin(),
E = CurRegion.element_end();
I != E; ++I)
if (I->isSubRegion())
buildScop(tempScop, *(I->getNodeAs<Region>()), NestLoops, Scatter, LI);
else {
if (I->isSubRegion()) {
buildScop(tempScop, *I->getNodeAs<Region>(), NestLoops, Scatter, LI, SD);
} else {
BasicBlock *BB = I->getNodeAs<BasicBlock>();
if (isTrivialBB(BB, tempScop))
continue;
ScopStmt *Stmt =
new ScopStmt(*this, tempScop, CurRegion, *BB, NestLoops, Scatter);
// Insert all statements into the statement map and the statement vector.
StmtMap[BB] = Stmt;
Stmts.push_back(Stmt);
// Increasing the Scattering function is OK for the moment, because
// we are using a depth first iterator and the program is well structured.
++Scatter[loopDepth];
addScopStmt(BB, nullptr, tempScop, CurRegion, NestLoops, Scatter);
}
if (!L)
@ -1931,6 +2003,7 @@ void ScopInfo::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<LoopInfoWrapperPass>();
AU.addRequired<RegionInfoPass>();
AU.addRequired<ScalarEvolution>();
AU.addRequired<ScopDetection>();
AU.addRequired<TempScopInfo>();
AU.addRequired<AliasAnalysis>();
AU.setPreservesAll();
@ -1939,6 +2012,7 @@ void ScopInfo::getAnalysisUsage(AnalysisUsage &AU) const {
bool ScopInfo::runOnRegion(Region *R, RGPassManager &RGM) {
LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
AliasAnalysis &AA = getAnalysis<AliasAnalysis>();
ScopDetection &SD = getAnalysis<ScopDetection>();
ScalarEvolution &SE = getAnalysis<ScalarEvolution>();
TempScop *tempScop = getAnalysis<TempScopInfo>().getTempScop(R);
@ -1949,7 +2023,7 @@ bool ScopInfo::runOnRegion(Region *R, RGPassManager &RGM) {
return false;
}
scop = new Scop(*tempScop, LI, SE, ctx);
scop = new Scop(*tempScop, LI, SE, SD, ctx);
if (!PollyUseRuntimeAliasChecks) {
// Statistics.
@ -1971,10 +2045,12 @@ bool ScopInfo::runOnRegion(Region *R, RGPassManager &RGM) {
DEBUG(dbgs()
<< "\n\nNOTE: Run time checks for " << scop->getNameStr()
<< " could not be created as the number of parameters involved is too "
<< " could not be created as the number of parameters involved is "
"too "
"high. The SCoP will be "
"dismissed.\nUse:\n\t--polly-rtc-max-parameters=X\nto adjust the "
"maximal number of parameters but be advised that the compile time "
"maximal number of parameters but be advised that the compile "
"time "
"might increase exponentially.\n\n");
delete scop;
@ -1993,6 +2069,7 @@ INITIALIZE_AG_DEPENDENCY(AliasAnalysis);
INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass);
INITIALIZE_PASS_DEPENDENCY(RegionInfoPass);
INITIALIZE_PASS_DEPENDENCY(ScalarEvolution);
INITIALIZE_PASS_DEPENDENCY(ScopDetection);
INITIALIZE_PASS_DEPENDENCY(TempScopInfo);
INITIALIZE_PASS_END(ScopInfo, "polly-scops",
"Polly - Create polyhedral description of Scops", false,

View File

@ -310,15 +310,17 @@ void TempScopInfo::buildAffineCondition(Value &V, bool inverted,
*Comp = new Comparison(LHS, RHS, Pred);
}
void TempScopInfo::buildCondition(BasicBlock *BB, BasicBlock *RegionEntry) {
void TempScopInfo::buildCondition(BasicBlock *BB, Region &R) {
BasicBlock *RegionEntry = R.getEntry();
BBCond Cond;
DomTreeNode *BBNode = DT->getNode(BB), *EntryNode = DT->getNode(RegionEntry);
assert(BBNode && EntryNode && "Get null node while building condition!");
// Walk up the dominance tree until reaching the entry node. Add all
// conditions on the path to BB except if BB postdominates the block
// Walk up the dominance tree until reaching the entry node. Collect all
// branching blocks on the path to BB except if BB postdominates the block
// containing the condition.
SmallVector<BasicBlock *, 4> DominatorBrBlocks;
while (BBNode != EntryNode) {
BasicBlock *CurBB = BBNode->getBlock();
BBNode = BBNode->getIDom();
@ -333,6 +335,24 @@ void TempScopInfo::buildCondition(BasicBlock *BB, BasicBlock *RegionEntry) {
if (Br->isUnconditional())
continue;
DominatorBrBlocks.push_back(BBNode->getBlock());
}
RegionInfo *RI = R.getRegionInfo();
// Iterate in reverse order over the dominating blocks. Until a non-affine
// branch was encountered add all conditions collected. If a non-affine branch
// was encountered, stop as we overapproximate from here on anyway.
for (auto BIt = DominatorBrBlocks.rbegin(), BEnd = DominatorBrBlocks.rend();
BIt != BEnd; BIt++) {
BasicBlock *BBNode = *BIt;
BranchInst *Br = dyn_cast<BranchInst>(BBNode->getTerminator());
assert(Br && "A Valid Scop should only contain branch instruction");
assert(Br->isConditional() && "Assumed a conditional branch");
if (SD->isNonAffineSubRegion(RI->getRegionFor(BBNode), &R))
break;
BasicBlock *TrueBB = Br->getSuccessor(0), *FalseBB = Br->getSuccessor(1);
// Is BB on the ELSE side of the branch?
@ -365,7 +385,7 @@ TempScop *TempScopInfo::buildTempScop(Region &R) {
for (const auto &BB : R.blocks()) {
buildAccessFunctions(R, *BB);
buildCondition(BB, R.getEntry());
buildCondition(BB, R);
}
return TScop;

View File

@ -0,0 +1,72 @@
; RUN: opt %loadPolly -polly-scops -polly-allow-nonaffine-branches -analyze < %s | FileCheck %s
;
; void f(int *A) {
; for (int i = 0; i < 1024; i++)
; if (A[i])
; if (A[i - 1])
; A[i] = A[i - 2];
; }
;
; CHECK: Region: %bb1---%bb18
; CHECK: Max Loop Depth: 1
; CHECK: Statements {
; CHECK: Stmt_(bb2 => bb16)
; CHECK: Domain :=
; CHECK: { Stmt_(bb2 => bb16)[i0] : i0 >= 0 and i0 <= 1023 };
; CHECK: Scattering :=
; CHECK: { Stmt_(bb2 => bb16)[i0] -> [i0] };
; CHECK: ReadAccess := [Reduction Type: NONE] [Scalar: 0]
; CHECK: { Stmt_(bb2 => bb16)[i0] -> MemRef_A[i0] };
; CHECK: ReadAccess := [Reduction Type: NONE] [Scalar: 0]
; CHECK: { Stmt_(bb2 => bb16)[i0] -> MemRef_A[-1 + i0] };
; CHECK: ReadAccess := [Reduction Type: NONE] [Scalar: 0]
; CHECK: { Stmt_(bb2 => bb16)[i0] -> MemRef_A[-2 + i0] };
; CHECK: MayWriteAccess := [Reduction Type: NONE] [Scalar: 0]
; CHECK: { Stmt_(bb2 => bb16)[i0] -> MemRef_A[i0] };
; CHECK: }
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
define void @f(i32* %A) {
bb:
br label %bb1
bb1: ; preds = %bb17, %bb
%indvars.iv = phi i64 [ %indvars.iv.next, %bb17 ], [ 0, %bb ]
%exitcond = icmp ne i64 %indvars.iv, 1024
br i1 %exitcond, label %bb2, label %bb18
bb2: ; preds = %bb1
%tmp = getelementptr inbounds i32* %A, i64 %indvars.iv
%tmp3 = load i32* %tmp, align 4
%tmp4 = icmp eq i32 %tmp3, 0
br i1 %tmp4, label %bb16, label %bb5
bb5: ; preds = %bb2
%tmp6 = add nsw i64 %indvars.iv, -1
%tmp7 = getelementptr inbounds i32* %A, i64 %tmp6
%tmp8 = load i32* %tmp7, align 4
%tmp9 = icmp eq i32 %tmp8, 0
br i1 %tmp9, label %bb15, label %bb10
bb10: ; preds = %bb5
%tmp11 = add nsw i64 %indvars.iv, -2
%tmp12 = getelementptr inbounds i32* %A, i64 %tmp11
%tmp13 = load i32* %tmp12, align 4
%tmp14 = getelementptr inbounds i32* %A, i64 %indvars.iv
store i32 %tmp13, i32* %tmp14, align 4
br label %bb15
bb15: ; preds = %bb5, %bb10
br label %bb16
bb16: ; preds = %bb2, %bb15
br label %bb17
bb17: ; preds = %bb16
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
br label %bb1
bb18: ; preds = %bb1
ret void
}

View File

@ -0,0 +1,63 @@
; RUN: opt %loadPolly -polly-scops -polly-allow-nonaffine-branches -analyze < %s | FileCheck %s
;
; void f(float *A) {
; for (int i = 0; i < 1024; i++)
; if (A[i] == A[i - 1])
; A[i]++;
; }
;
; CHECK: Function: f
; CHECK: Region: %bb1---%bb14
; CHECK: Max Loop Depth: 1
; CHECK: Statements {
; CHECK: Stmt_(bb2 => bb12)
; CHECK: Domain :=
; CHECK: { Stmt_(bb2 => bb12)[i0] : i0 >= 0 and i0 <= 1023 };
; CHECK: Scattering :=
; CHECK: { Stmt_(bb2 => bb12)[i0] -> [i0] };
; CHECK: ReadAccess := [Reduction Type: NONE] [Scalar: 0]
; CHECK: { Stmt_(bb2 => bb12)[i0] -> MemRef_A[i0] };
; CHECK: ReadAccess := [Reduction Type: NONE] [Scalar: 0]
; CHECK: { Stmt_(bb2 => bb12)[i0] -> MemRef_A[-1 + i0] };
; CHECK: ReadAccess := [Reduction Type: NONE] [Scalar: 0]
; CHECK: { Stmt_(bb2 => bb12)[i0] -> MemRef_A[i0] };
; CHECK: MayWriteAccess := [Reduction Type: NONE] [Scalar: 0]
; CHECK: { Stmt_(bb2 => bb12)[i0] -> MemRef_A[i0] };
; CHECK: }
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
define void @f(float* %A) {
bb:
br label %bb1
bb1: ; preds = %bb13, %bb
%indvars.iv = phi i64 [ %indvars.iv.next, %bb13 ], [ 0, %bb ]
%exitcond = icmp ne i64 %indvars.iv, 1024
br i1 %exitcond, label %bb2, label %bb14
bb2: ; preds = %bb1
%tmp = getelementptr inbounds float* %A, i64 %indvars.iv
%tmp3 = load float* %tmp, align 4
%tmp4 = add nsw i64 %indvars.iv, -1
%tmp5 = getelementptr inbounds float* %A, i64 %tmp4
%tmp6 = load float* %tmp5, align 4
%tmp7 = fcmp oeq float %tmp3, %tmp6
br i1 %tmp7, label %bb8, label %bb12
bb8: ; preds = %bb2
%tmp9 = getelementptr inbounds float* %A, i64 %indvars.iv
%tmp10 = load float* %tmp9, align 4
%tmp11 = fadd float %tmp10, 1.000000e+00
store float %tmp11, float* %tmp9, align 4
br label %bb12
bb12: ; preds = %bb8, %bb2
br label %bb13
bb13: ; preds = %bb12
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
br label %bb1
bb14: ; preds = %bb1
ret void
}