Skip to content

Commit

Permalink
Exploit graph properties during domain generation
Browse files Browse the repository at this point in the history
  As a CFG is often structured we can simplify the steps performed during
  domain generation. When we push domain information we can utilize the
  information from a block A to build the domain of a block B, if A dominates B
  and there is no loop backede on a path from A to B. When we pull domain
  information we can use information from a block A to build the domain of a
  block B if B post-dominates A. This patch implements both ideas and thereby
  simplifies domains that were not simplified by isl. For the FINAL basic block
  in test/ScopInfo/complex-successor-structure-3.ll we used to build a universe
  set with 81 basic sets. Now it actually is represented as universe set.

  While the initial idea to utilize the graph structure depended on the
  dominator and post-dominator tree we can use the available region
  information as a coarse grained replacement. To this end we push the
  region entry domain to the region exit and pull it from the region
  entry for the region exit if applicable.

  With this patch we now successfully compile
    External/SPEC/CINT2006/400_perlbench/400_perlbench
  and
    SingleSource/Benchmarks/Adobe-C++/loop_unroll.

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

llvm-svn: 265285
  • Loading branch information
Johannes Doerfert committed Apr 4, 2016
1 parent a07f0ac commit 642594a
Show file tree
Hide file tree
Showing 14 changed files with 1,131 additions and 86 deletions.
47 changes: 47 additions & 0 deletions polly/include/polly/ScopInfo.h
Expand Up @@ -1421,6 +1421,53 @@ class Scop {
void init(AliasAnalysis &AA, AssumptionCache &AC, ScopDetection &SD,
DominatorTree &DT, LoopInfo &LI);

/// @brief Propagate domains that are known due to graph properties.
///
/// As a CFG is mostly structured we use the graph properties to propagate
/// domains without the need to compute all path conditions. In particular, if
/// a block A dominates a block B and B post-dominates A we know that the
/// domain of B is a superset of the domain of A. As we do not have
/// post-dominator information available here we use the less precise region
/// information. Given a region R, we know that the exit is always executed if
/// the entry was executed, thus the domain of the exit is a superset of the
/// domain of the entry. In case the exit can only be reached from within the
/// region the domains are in fact equal. This function will use this property
/// to avoid the generation of condition constraints that determine when a
/// branch is taken. If @p BB is a region entry block we will propagate its
/// domain to the region exit block. Additionally, we put the region exit
/// block in the @p FinishedExitBlocks set so we can later skip edges from
/// within the region to that block.
///
/// @param BB The block for which the domain is currently propagated.
/// @param BBLoop The innermost affine loop surrounding @p BB.
/// @param FinishedExitBlocks Set of region exits the domain was set for.
/// @param SD The ScopDetection analysis for the current function.
/// @param LI The LoopInfo for the current function.
///
void propagateDomainConstraintsToRegionExit(
BasicBlock *BB, Loop *BBLoop,
SmallPtrSetImpl<BasicBlock *> &FinishedExitBlocks, ScopDetection &SD,
LoopInfo &LI);

/// @brief Compute the union of predecessor domains for @p BB.
///
/// To compute the union of all domains of predecessors of @p BB this
/// function applies similar reasoning on the CFG structure as described for
/// @see propagateDomainConstraintsToRegionExit
///
/// @param BB The block for which the predecessor domains are collected.
/// @param Domain The domain under which BB is executed.
/// @param SD The ScopDetection analysis for the current function.
/// @param DT The DominatorTree for the current function.
/// @param LI The LoopInfo for the current function.
///
/// @returns The domain under which @p BB is executed.
__isl_give isl_set *getPredecessorDomainConstraints(BasicBlock *BB,
isl_set *Domain,
ScopDetection &SD,
DominatorTree &DT,
LoopInfo &LI);

/// @brief Add loop carried constraints to the header block of the loop @p L.
///
/// @param L The loop to process.
Expand Down
161 changes: 132 additions & 29 deletions polly/lib/Analysis/ScopInfo.cpp
Expand Up @@ -2237,6 +2237,52 @@ static __isl_give isl_set *adjustDomainDimensions(Scop &S,

return Dom;
}

void Scop::propagateDomainConstraintsToRegionExit(
BasicBlock *BB, Loop *BBLoop,
SmallPtrSetImpl<BasicBlock *> &FinishedExitBlocks, ScopDetection &SD,
LoopInfo &LI) {

// Check if the block @p BB is the entry of a region. If so we propagate it's
// domain to the exit block of the region. Otherwise we are done.
auto *RI = R.getRegionInfo();
auto *BBReg = RI ? RI->getRegionFor(BB) : nullptr;
auto *ExitBB = BBReg ? BBReg->getExit() : nullptr;
if (!BBReg || BBReg->getEntry() != BB || !R.contains(ExitBB))
return;

auto &BoxedLoops = *SD.getBoxedLoops(&getRegion());
// Do not propagate the domain if there is a loop backedge inside the region
// that would prevent the exit block from beeing executed.
auto *L = BBLoop;
while (L && R.contains(L)) {
SmallVector<BasicBlock *, 4> LatchBBs;
BBLoop->getLoopLatches(LatchBBs);
for (auto *LatchBB : LatchBBs)
if (BB != LatchBB && BBReg->contains(LatchBB))
return;
L = L->getParentLoop();
}

auto *Domain = DomainMap[BB];
assert(Domain && "Cannot propagate a nullptr");

auto *ExitBBLoop = getFirstNonBoxedLoopFor(ExitBB, LI, BoxedLoops);

// Since the dimensions of @p BB and @p ExitBB might be different we have to
// adjust the domain before we can propagate it.
auto *AdjustedDomain =
adjustDomainDimensions(*this, isl_set_copy(Domain), BBLoop, ExitBBLoop);
auto *&ExitDomain = DomainMap[ExitBB];

// If the exit domain is not yet created we set it otherwise we "add" the
// current domain.
ExitDomain =
ExitDomain ? isl_set_union(AdjustedDomain, ExitDomain) : AdjustedDomain;

FinishedExitBlocks.insert(ExitBB);
}

bool Scop::buildDomainsWithBranchConstraints(Region *R, ScopDetection &SD,
DominatorTree &DT, LoopInfo &LI) {
auto &BoxedLoops = *SD.getBoxedLoops(&getRegion());
Expand All @@ -2252,6 +2298,7 @@ bool Scop::buildDomainsWithBranchConstraints(Region *R, ScopDetection &SD,
// As we are only interested in non-loop carried constraints here we can
// simply skip loop back edges.

SmallPtrSet<BasicBlock *, 8> FinishedExitBlocks;
ReversePostOrderTraversal<Region *> RTraversal(R);
for (auto *RN : RTraversal) {

Expand Down Expand Up @@ -2279,7 +2326,22 @@ bool Scop::buildDomainsWithBranchConstraints(Region *R, ScopDetection &SD,
if (!Domain)
continue;

Loop *BBLoop = getRegionNodeLoop(RN, LI);
auto *BBLoop = getRegionNodeLoop(RN, LI);
// Propagate the domain from BB directly to blocks that have a superset
// domain, at the moment only region exit nodes of regions that start in BB.
propagateDomainConstraintsToRegionExit(BB, BBLoop, FinishedExitBlocks, SD,
LI);

// If all successors of BB have been set a domain through the propagation
// above we do not need to build condition sets but can just skip this
// block. However, it is important to note that this is a local property
// with regards to the region @p R. To this end FinishedExitBlocks is a
// local variable.
auto IsFinishedRegionExit = [&FinishedExitBlocks](BasicBlock *SuccBB) {
return FinishedExitBlocks.count(SuccBB);
};
if (std::all_of(succ_begin(BB), succ_end(BB), IsFinishedRegionExit))
continue;

// Build the condition sets for the successor nodes of the current region
// node. If it is a non-affine subregion we will always execute the single
Expand All @@ -2300,6 +2362,13 @@ bool Scop::buildDomainsWithBranchConstraints(Region *R, ScopDetection &SD,
isl_set *CondSet = ConditionSets[u];
BasicBlock *SuccBB = getRegionNodeSuccessor(RN, TI, u);

// If we propagate the domain of some block to "SuccBB" we do not have to
// adjust the domain.
if (FinishedExitBlocks.count(SuccBB)) {
isl_set_free(CondSet);
continue;
}

// Skip back edges.
if (DT.dominates(SuccBB, BB)) {
isl_set_free(CondSet);
Expand Down Expand Up @@ -2352,6 +2421,65 @@ getDomainForBlock(BasicBlock *BB, DenseMap<BasicBlock *, isl_set *> &DomainMap,
return getDomainForBlock(R->getEntry(), DomainMap, RI);
}

isl_set *Scop::getPredecessorDomainConstraints(BasicBlock *BB, isl_set *Domain,
ScopDetection &SD,
DominatorTree &DT,
LoopInfo &LI) {
// If @p BB is the ScopEntry we are done
if (R.getEntry() == BB)
return isl_set_universe(isl_set_get_space(Domain));

// The set of boxed loops (loops in non-affine subregions) for this SCoP.
auto &BoxedLoops = *SD.getBoxedLoops(&getRegion());

// The region info of this function.
auto &RI = *R.getRegionInfo();

auto *BBLoop = getFirstNonBoxedLoopFor(BB, LI, BoxedLoops);

// A domain to collect all predecessor domains, thus all conditions under
// which the block is executed. To this end we start with the empty domain.
isl_set *PredDom = isl_set_empty(isl_set_get_space(Domain));

// Set of regions of which the entry block domain has been propagated to BB.
// all predecessors inside any of the regions can be skipped.
SmallSet<Region *, 8> PropagatedRegions;

for (auto *PredBB : predecessors(BB)) {
// Skip backedges.
if (DT.dominates(BB, PredBB))
continue;

// If the predecessor is in a region we used for propagation we can skip it.
auto PredBBInRegion = [PredBB](Region *PR) { return PR->contains(PredBB); };
if (std::any_of(PropagatedRegions.begin(), PropagatedRegions.end(),
PredBBInRegion)) {
continue;
}

// Check if there is a valid region we can use for propagation, thus look
// for a region that contains the predecessor and has @p BB as exit block.
auto *PredR = RI.getRegionFor(PredBB);
while (PredR->getExit() != BB && !PredR->contains(BB))
PredR->getParent();

// If a valid region for propagation was found use the entry of that region
// for propagation, otherwise the PredBB directly.
if (PredR->getExit() == BB) {
PredBB = PredR->getEntry();
PropagatedRegions.insert(PredR);
}

auto *PredBBDom = getDomainForBlock(PredBB, DomainMap, RI);
auto *PredBBLoop = getFirstNonBoxedLoopFor(PredBB, LI, BoxedLoops);
PredBBDom = adjustDomainDimensions(*this, PredBBDom, PredBBLoop, BBLoop);

PredDom = isl_set_union(PredDom, PredBBDom);
}

return PredDom;
}

void Scop::propagateDomainConstraints(Region *R, ScopDetection &SD,
DominatorTree &DT, LoopInfo &LI) {
// Iterate over the region R and propagate the domain constrains from the
Expand All @@ -2363,9 +2491,6 @@ void Scop::propagateDomainConstraints(Region *R, ScopDetection &SD,
// predecessors have been visited before a block or non-affine subregion is
// visited.

// The set of boxed loops (loops in non-affine subregions) for this SCoP.
auto &BoxedLoops = *SD.getBoxedLoops(&getRegion());

ReversePostOrderTraversal<Region *> RTraversal(R);
for (auto *RN : RTraversal) {

Expand Down Expand Up @@ -2393,34 +2518,12 @@ void Scop::propagateDomainConstraints(Region *R, ScopDetection &SD,
continue;
}

Loop *BBLoop = getRegionNodeLoop(RN, LI);

isl_set *PredDom = isl_set_empty(isl_set_get_space(Domain));
for (auto *PredBB : predecessors(BB)) {

// Skip backedges
if (DT.dominates(BB, PredBB))
continue;

isl_set *PredBBDom = nullptr;

// Handle the SCoP entry block with its outside predecessors.
if (!getRegion().contains(PredBB))
PredBBDom = isl_set_universe(isl_set_get_space(PredDom));

if (!PredBBDom) {
PredBBDom = getDomainForBlock(PredBB, DomainMap, *R->getRegionInfo());
auto *PredBBLoop = getFirstNonBoxedLoopFor(PredBB, LI, BoxedLoops);
PredBBDom =
adjustDomainDimensions(*this, PredBBDom, PredBBLoop, BBLoop);
}

PredDom = isl_set_union(PredDom, PredBBDom);
}

// Under the union of all predecessor conditions we can reach this block.
auto *PredDom = getPredecessorDomainConstraints(BB, Domain, SD, DT, LI);
Domain = isl_set_coalesce(isl_set_intersect(Domain, PredDom));
Domain = isl_set_align_params(Domain, getParamSpace());

Loop *BBLoop = getRegionNodeLoop(RN, LI);
if (BBLoop && BBLoop->getHeader() == BB && getRegion().contains(BBLoop))
addLoopBoundsToHeaderDomain(BBLoop, LI);

Expand Down
2 changes: 1 addition & 1 deletion polly/test/Isl/CodeGen/phi_scalar_simple_1.ll
Expand Up @@ -28,7 +28,7 @@ entry:
; CHECK-LABEL: polly.start:
; CHECK: store i32 %x, i32* %x.addr.0.phiops

; CHECK-LABEL: polly.merge:
; CHECK-LABEL: polly.exiting:
; CHECK: %x.addr.0.final_reload = load i32, i32* %x.addr.0.s2a

for.cond: ; preds = %for.inc4, %entry
Expand Down

0 comments on commit 642594a

Please sign in to comment.