llvm-6502/lib/Analysis/RegionInfo.cpp
Owen Anderson 081c34b725 Get rid of static constructors for pass registration. Instead, every pass exposes an initializeMyPassFunction(), which
must be called in the pass's constructor.  This function uses static dependency declarations to recursively initialize
the pass's dependencies.

Clients that only create passes through the createFooPass() APIs will require no changes.  Clients that want to use the
CommandLine options for passes will need to manually call the appropriate initialization functions in PassInitialization.h
before parsing commandline arguments.

I have tested this with all standard configurations of clang and llvm-gcc on Darwin.  It is possible that there are problems
with the static dependencies that will only be visible with non-standard options.  If you encounter any crash in pass
registration/creation, please send the testcase to me directly.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@116820 91177308-0d34-0410-b5e6-96231b3b80d8
2010-10-19 17:21:58 +00:00

843 lines
23 KiB
C++

//===- RegionInfo.cpp - SESE region detection analysis --------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Detects single entry single exit regions in the control flow graph.
//===----------------------------------------------------------------------===//
#include "llvm/Analysis/RegionInfo.h"
#include "llvm/Analysis/RegionIterator.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Analysis/LoopInfo.h"
#define DEBUG_TYPE "region"
#include "llvm/Support/Debug.h"
#include <set>
#include <algorithm>
using namespace llvm;
// Always verify if expensive checking is enabled.
#ifdef XDEBUG
static bool VerifyRegionInfo = true;
#else
static bool VerifyRegionInfo = false;
#endif
static cl::opt<bool,true>
VerifyRegionInfoX("verify-region-info", cl::location(VerifyRegionInfo),
cl::desc("Verify region info (time consuming)"));
STATISTIC(numRegions, "The # of regions");
STATISTIC(numSimpleRegions, "The # of simple regions");
//===----------------------------------------------------------------------===//
/// PrintStyle - Print region in difference ways.
enum PrintStyle { PrintNone, PrintBB, PrintRN };
cl::opt<enum PrintStyle> printStyle("print-region-style", cl::Hidden,
cl::desc("style of printing regions"),
cl::values(
clEnumValN(PrintNone, "none", "print no details"),
clEnumValN(PrintBB, "bb", "print regions in detail with block_iterator"),
clEnumValN(PrintRN, "rn", "print regions in detail with element_iterator"),
clEnumValEnd));
//===----------------------------------------------------------------------===//
/// Region Implementation
Region::Region(BasicBlock *Entry, BasicBlock *Exit, RegionInfo* RInfo,
DominatorTree *dt, Region *Parent)
: RegionNode(Parent, Entry, 1), RI(RInfo), DT(dt), exit(Exit) {}
Region::~Region() {
// Free the cached nodes.
for (BBNodeMapT::iterator it = BBNodeMap.begin(),
ie = BBNodeMap.end(); it != ie; ++it)
delete it->second;
// Only clean the cache for this Region. Caches of child Regions will be
// cleaned when the child Regions are deleted.
BBNodeMap.clear();
for (iterator I = begin(), E = end(); I != E; ++I)
delete *I;
}
void Region::replaceEntry(BasicBlock *BB) {
entry.setPointer(BB);
}
void Region::replaceExit(BasicBlock *BB) {
assert(exit && "No exit to replace!");
exit = BB;
}
bool Region::contains(const BasicBlock *B) const {
BasicBlock *BB = const_cast<BasicBlock*>(B);
assert(DT->getNode(BB) && "BB not part of the dominance tree");
BasicBlock *entry = getEntry(), *exit = getExit();
// Toplevel region.
if (!exit)
return true;
return (DT->dominates(entry, BB)
&& !(DT->dominates(exit, BB) && DT->dominates(entry, exit)));
}
bool Region::contains(const Loop *L) const {
// BBs that are not part of any loop are element of the Loop
// described by the NULL pointer. This loop is not part of any region,
// except if the region describes the whole function.
if (L == 0)
return getExit() == 0;
if (!contains(L->getHeader()))
return false;
SmallVector<BasicBlock *, 8> ExitingBlocks;
L->getExitingBlocks(ExitingBlocks);
for (SmallVectorImpl<BasicBlock*>::iterator BI = ExitingBlocks.begin(),
BE = ExitingBlocks.end(); BI != BE; ++BI)
if (!contains(*BI))
return false;
return true;
}
Loop *Region::outermostLoopInRegion(Loop *L) const {
if (!contains(L))
return 0;
while (L && contains(L->getParentLoop())) {
L = L->getParentLoop();
}
return L;
}
Loop *Region::outermostLoopInRegion(LoopInfo *LI, BasicBlock* BB) const {
assert(LI && BB && "LI and BB cannot be null!");
Loop *L = LI->getLoopFor(BB);
return outermostLoopInRegion(L);
}
bool Region::isSimple() const {
bool isSimple = true;
bool found = false;
BasicBlock *entry = getEntry(), *exit = getExit();
if (isTopLevelRegion())
return false;
for (pred_iterator PI = pred_begin(entry), PE = pred_end(entry); PI != PE;
++PI) {
BasicBlock *Pred = *PI;
if (DT->getNode(Pred) && !contains(Pred)) {
if (found) {
isSimple = false;
break;
}
found = true;
}
}
found = false;
for (pred_iterator PI = pred_begin(exit), PE = pred_end(exit); PI != PE;
++PI)
if (contains(*PI)) {
if (found) {
isSimple = false;
break;
}
found = true;
}
return isSimple;
}
std::string Region::getNameStr() const {
std::string exitName;
std::string entryName;
if (getEntry()->getName().empty()) {
raw_string_ostream OS(entryName);
WriteAsOperand(OS, getEntry(), false);
entryName = OS.str();
} else
entryName = getEntry()->getNameStr();
if (getExit()) {
if (getExit()->getName().empty()) {
raw_string_ostream OS(exitName);
WriteAsOperand(OS, getExit(), false);
exitName = OS.str();
} else
exitName = getExit()->getNameStr();
} else
exitName = "<Function Return>";
return entryName + " => " + exitName;
}
void Region::verifyBBInRegion(BasicBlock *BB) const {
if (!contains(BB))
llvm_unreachable("Broken region found!");
BasicBlock *entry = getEntry(), *exit = getExit();
for (succ_iterator SI = succ_begin(BB), SE = succ_end(BB); SI != SE; ++SI)
if (!contains(*SI) && exit != *SI)
llvm_unreachable("Broken region found!");
if (entry != BB)
for (pred_iterator SI = pred_begin(BB), SE = pred_end(BB); SI != SE; ++SI)
if (!contains(*SI))
llvm_unreachable("Broken region found!");
}
void Region::verifyWalk(BasicBlock *BB, std::set<BasicBlock*> *visited) const {
BasicBlock *exit = getExit();
visited->insert(BB);
verifyBBInRegion(BB);
for (succ_iterator SI = succ_begin(BB), SE = succ_end(BB); SI != SE; ++SI)
if (*SI != exit && visited->find(*SI) == visited->end())
verifyWalk(*SI, visited);
}
void Region::verifyRegion() const {
// Only do verification when user wants to, otherwise this expensive
// check will be invoked by PassManager.
if (!VerifyRegionInfo) return;
std::set<BasicBlock*> visited;
verifyWalk(getEntry(), &visited);
}
void Region::verifyRegionNest() const {
for (Region::const_iterator RI = begin(), RE = end(); RI != RE; ++RI)
(*RI)->verifyRegionNest();
verifyRegion();
}
Region::block_iterator Region::block_begin() {
return GraphTraits<FlatIt<Region*> >::nodes_begin(this);
}
Region::block_iterator Region::block_end() {
return GraphTraits<FlatIt<Region*> >::nodes_end(this);
}
Region::const_block_iterator Region::block_begin() const {
return GraphTraits<FlatIt<const Region*> >::nodes_begin(this);
}
Region::const_block_iterator Region::block_end() const {
return GraphTraits<FlatIt<const Region*> >::nodes_end(this);
}
Region::element_iterator Region::element_begin() {
return GraphTraits<Region*>::nodes_begin(this);
}
Region::element_iterator Region::element_end() {
return GraphTraits<Region*>::nodes_end(this);
}
Region::const_element_iterator Region::element_begin() const {
return GraphTraits<const Region*>::nodes_begin(this);
}
Region::const_element_iterator Region::element_end() const {
return GraphTraits<const Region*>::nodes_end(this);
}
Region* Region::getSubRegionNode(BasicBlock *BB) const {
Region *R = RI->getRegionFor(BB);
if (!R || R == this)
return 0;
// If we pass the BB out of this region, that means our code is broken.
assert(contains(R) && "BB not in current region!");
while (contains(R->getParent()) && R->getParent() != this)
R = R->getParent();
if (R->getEntry() != BB)
return 0;
return R;
}
RegionNode* Region::getBBNode(BasicBlock *BB) const {
assert(contains(BB) && "Can get BB node out of this region!");
BBNodeMapT::const_iterator at = BBNodeMap.find(BB);
if (at != BBNodeMap.end())
return at->second;
RegionNode *NewNode = new RegionNode(const_cast<Region*>(this), BB);
BBNodeMap.insert(std::make_pair(BB, NewNode));
return NewNode;
}
RegionNode* Region::getNode(BasicBlock *BB) const {
assert(contains(BB) && "Can get BB node out of this region!");
if (Region* Child = getSubRegionNode(BB))
return Child->getNode();
return getBBNode(BB);
}
void Region::transferChildrenTo(Region *To) {
for (iterator I = begin(), E = end(); I != E; ++I) {
(*I)->parent = To;
To->children.push_back(*I);
}
children.clear();
}
void Region::addSubRegion(Region *SubRegion, bool moveChildren) {
assert(SubRegion->parent == 0 && "SubRegion already has a parent!");
assert(std::find(begin(), end(), SubRegion) == children.end()
&& "Subregion already exists!");
SubRegion->parent = this;
children.push_back(SubRegion);
if (!moveChildren)
return;
assert(SubRegion->children.size() == 0
&& "SubRegions that contain children are not supported");
for (element_iterator I = element_begin(), E = element_end(); I != E; ++I)
if (!(*I)->isSubRegion()) {
BasicBlock *BB = (*I)->getNodeAs<BasicBlock>();
if (SubRegion->contains(BB))
RI->setRegionFor(BB, SubRegion);
}
std::vector<Region*> Keep;
for (iterator I = begin(), E = end(); I != E; ++I)
if (SubRegion->contains(*I) && *I != SubRegion) {
SubRegion->children.push_back(*I);
(*I)->parent = SubRegion;
} else
Keep.push_back(*I);
children.clear();
children.insert(children.begin(), Keep.begin(), Keep.end());
}
Region *Region::removeSubRegion(Region *Child) {
assert(Child->parent == this && "Child is not a child of this region!");
Child->parent = 0;
RegionSet::iterator I = std::find(children.begin(), children.end(), Child);
assert(I != children.end() && "Region does not exit. Unable to remove.");
children.erase(children.begin()+(I-begin()));
return Child;
}
unsigned Region::getDepth() const {
unsigned Depth = 0;
for (Region *R = parent; R != 0; R = R->parent)
++Depth;
return Depth;
}
Region *Region::getExpandedRegion() const {
unsigned NumSuccessors = exit->getTerminator()->getNumSuccessors();
if (NumSuccessors == 0)
return NULL;
for (pred_iterator PI = pred_begin(getExit()), PE = pred_end(getExit());
PI != PE; ++PI)
if (!DT->dominates(getEntry(), *PI))
return NULL;
Region *R = RI->getRegionFor(exit);
if (R->getEntry() != exit) {
if (exit->getTerminator()->getNumSuccessors() == 1)
return new Region(getEntry(), *succ_begin(exit), RI, DT);
else
return NULL;
}
while (R->getParent() && R->getParent()->getEntry() == exit)
R = R->getParent();
if (!DT->dominates(getEntry(), R->getExit()))
for (pred_iterator PI = pred_begin(getExit()), PE = pred_end(getExit());
PI != PE; ++PI)
if (!DT->dominates(R->getExit(), *PI))
return NULL;
return new Region(getEntry(), R->getExit(), RI, DT);
}
void Region::print(raw_ostream &OS, bool print_tree, unsigned level) const {
if (print_tree)
OS.indent(level*2) << "[" << level << "] " << getNameStr();
else
OS.indent(level*2) << getNameStr();
OS << "\n";
if (printStyle != PrintNone) {
OS.indent(level*2) << "{\n";
OS.indent(level*2 + 2);
if (printStyle == PrintBB) {
for (const_block_iterator I = block_begin(), E = block_end(); I!=E; ++I)
OS << **I << ", "; // TODO: remove the last ","
} else if (printStyle == PrintRN) {
for (const_element_iterator I = element_begin(), E = element_end(); I!=E; ++I)
OS << **I << ", "; // TODO: remove the last ",
}
OS << "\n";
}
if (print_tree)
for (const_iterator RI = begin(), RE = end(); RI != RE; ++RI)
(*RI)->print(OS, print_tree, level+1);
if (printStyle != PrintNone)
OS.indent(level*2) << "} \n";
}
void Region::dump() const {
print(dbgs(), true, getDepth());
}
void Region::clearNodeCache() {
// Free the cached nodes.
for (BBNodeMapT::iterator I = BBNodeMap.begin(),
IE = BBNodeMap.end(); I != IE; ++I)
delete I->second;
BBNodeMap.clear();
for (Region::iterator RI = begin(), RE = end(); RI != RE; ++RI)
(*RI)->clearNodeCache();
}
//===----------------------------------------------------------------------===//
// RegionInfo implementation
//
bool RegionInfo::isCommonDomFrontier(BasicBlock *BB, BasicBlock *entry,
BasicBlock *exit) const {
for (pred_iterator PI = pred_begin(BB), PE = pred_end(BB); PI != PE; ++PI) {
BasicBlock *P = *PI;
if (DT->dominates(entry, P) && !DT->dominates(exit, P))
return false;
}
return true;
}
bool RegionInfo::isRegion(BasicBlock *entry, BasicBlock *exit) const {
assert(entry && exit && "entry and exit must not be null!");
typedef DominanceFrontier::DomSetType DST;
DST *entrySuccs = &DF->find(entry)->second;
// Exit is the header of a loop that contains the entry. In this case,
// the dominance frontier must only contain the exit.
if (!DT->dominates(entry, exit)) {
for (DST::iterator SI = entrySuccs->begin(), SE = entrySuccs->end();
SI != SE; ++SI)
if (*SI != exit && *SI != entry)
return false;
return true;
}
DST *exitSuccs = &DF->find(exit)->second;
// Do not allow edges leaving the region.
for (DST::iterator SI = entrySuccs->begin(), SE = entrySuccs->end();
SI != SE; ++SI) {
if (*SI == exit || *SI == entry)
continue;
if (exitSuccs->find(*SI) == exitSuccs->end())
return false;
if (!isCommonDomFrontier(*SI, entry, exit))
return false;
}
// Do not allow edges pointing into the region.
for (DST::iterator SI = exitSuccs->begin(), SE = exitSuccs->end();
SI != SE; ++SI)
if (DT->properlyDominates(entry, *SI) && *SI != exit)
return false;
return true;
}
void RegionInfo::insertShortCut(BasicBlock *entry, BasicBlock *exit,
BBtoBBMap *ShortCut) const {
assert(entry && exit && "entry and exit must not be null!");
BBtoBBMap::iterator e = ShortCut->find(exit);
if (e == ShortCut->end())
// No further region at exit available.
(*ShortCut)[entry] = exit;
else {
// We found a region e that starts at exit. Therefore (entry, e->second)
// is also a region, that is larger than (entry, exit). Insert the
// larger one.
BasicBlock *BB = e->second;
(*ShortCut)[entry] = BB;
}
}
DomTreeNode* RegionInfo::getNextPostDom(DomTreeNode* N,
BBtoBBMap *ShortCut) const {
BBtoBBMap::iterator e = ShortCut->find(N->getBlock());
if (e == ShortCut->end())
return N->getIDom();
return PDT->getNode(e->second)->getIDom();
}
bool RegionInfo::isTrivialRegion(BasicBlock *entry, BasicBlock *exit) const {
assert(entry && exit && "entry and exit must not be null!");
unsigned num_successors = succ_end(entry) - succ_begin(entry);
if (num_successors <= 1 && exit == *(succ_begin(entry)))
return true;
return false;
}
void RegionInfo::updateStatistics(Region *R) {
++numRegions;
// TODO: Slow. Should only be enabled if -stats is used.
if (R->isSimple()) ++numSimpleRegions;
}
Region *RegionInfo::createRegion(BasicBlock *entry, BasicBlock *exit) {
assert(entry && exit && "entry and exit must not be null!");
if (isTrivialRegion(entry, exit))
return 0;
Region *region = new Region(entry, exit, this, DT);
BBtoRegion.insert(std::make_pair(entry, region));
#ifdef XDEBUG
region->verifyRegion();
#else
DEBUG(region->verifyRegion());
#endif
updateStatistics(region);
return region;
}
void RegionInfo::findRegionsWithEntry(BasicBlock *entry, BBtoBBMap *ShortCut) {
assert(entry);
DomTreeNode *N = PDT->getNode(entry);
if (!N)
return;
Region *lastRegion= 0;
BasicBlock *lastExit = entry;
// As only a BasicBlock that postdominates entry can finish a region, walk the
// post dominance tree upwards.
while ((N = getNextPostDom(N, ShortCut))) {
BasicBlock *exit = N->getBlock();
if (!exit)
break;
if (isRegion(entry, exit)) {
Region *newRegion = createRegion(entry, exit);
if (lastRegion)
newRegion->addSubRegion(lastRegion);
lastRegion = newRegion;
lastExit = exit;
}
// This can never be a region, so stop the search.
if (!DT->dominates(entry, exit))
break;
}
// Tried to create regions from entry to lastExit. Next time take a
// shortcut from entry to lastExit.
if (lastExit != entry)
insertShortCut(entry, lastExit, ShortCut);
}
void RegionInfo::scanForRegions(Function &F, BBtoBBMap *ShortCut) {
BasicBlock *entry = &(F.getEntryBlock());
DomTreeNode *N = DT->getNode(entry);
// Iterate over the dominance tree in post order to start with the small
// regions from the bottom of the dominance tree. If the small regions are
// detected first, detection of bigger regions is faster, as we can jump
// over the small regions.
for (po_iterator<DomTreeNode*> FI = po_begin(N), FE = po_end(N); FI != FE;
++FI) {
findRegionsWithEntry(FI->getBlock(), ShortCut);
}
}
Region *RegionInfo::getTopMostParent(Region *region) {
while (region->parent)
region = region->getParent();
return region;
}
void RegionInfo::buildRegionsTree(DomTreeNode *N, Region *region) {
BasicBlock *BB = N->getBlock();
// Passed region exit
while (BB == region->getExit())
region = region->getParent();
BBtoRegionMap::iterator it = BBtoRegion.find(BB);
// This basic block is a start block of a region. It is already in the
// BBtoRegion relation. Only the child basic blocks have to be updated.
if (it != BBtoRegion.end()) {
Region *newRegion = it->second;;
region->addSubRegion(getTopMostParent(newRegion));
region = newRegion;
} else {
BBtoRegion[BB] = region;
}
for (DomTreeNode::iterator CI = N->begin(), CE = N->end(); CI != CE; ++CI)
buildRegionsTree(*CI, region);
}
void RegionInfo::releaseMemory() {
BBtoRegion.clear();
if (TopLevelRegion)
delete TopLevelRegion;
TopLevelRegion = 0;
}
RegionInfo::RegionInfo() : FunctionPass(ID) {
initializeRegionInfoPass(*PassRegistry::getPassRegistry());
TopLevelRegion = 0;
}
RegionInfo::~RegionInfo() {
releaseMemory();
}
void RegionInfo::Calculate(Function &F) {
// ShortCut a function where for every BB the exit of the largest region
// starting with BB is stored. These regions can be threated as single BBS.
// This improves performance on linear CFGs.
BBtoBBMap ShortCut;
scanForRegions(F, &ShortCut);
BasicBlock *BB = &F.getEntryBlock();
buildRegionsTree(DT->getNode(BB), TopLevelRegion);
}
bool RegionInfo::runOnFunction(Function &F) {
releaseMemory();
DT = &getAnalysis<DominatorTree>();
PDT = &getAnalysis<PostDominatorTree>();
DF = &getAnalysis<DominanceFrontier>();
TopLevelRegion = new Region(&F.getEntryBlock(), 0, this, DT, 0);
updateStatistics(TopLevelRegion);
Calculate(F);
return false;
}
void RegionInfo::getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesAll();
AU.addRequiredTransitive<DominatorTree>();
AU.addRequired<PostDominatorTree>();
AU.addRequired<DominanceFrontier>();
}
void RegionInfo::print(raw_ostream &OS, const Module *) const {
OS << "Region tree:\n";
TopLevelRegion->print(OS, true, 0);
OS << "End region tree\n";
}
void RegionInfo::verifyAnalysis() const {
// Only do verification when user wants to, otherwise this expensive check
// will be invoked by PMDataManager::verifyPreservedAnalysis when
// a regionpass (marked PreservedAll) finish.
if (!VerifyRegionInfo) return;
TopLevelRegion->verifyRegionNest();
}
// Region pass manager support.
Region *RegionInfo::getRegionFor(BasicBlock *BB) const {
BBtoRegionMap::const_iterator I=
BBtoRegion.find(BB);
return I != BBtoRegion.end() ? I->second : 0;
}
void RegionInfo::setRegionFor(BasicBlock *BB, Region *R) {
BBtoRegion[BB] = R;
}
Region *RegionInfo::operator[](BasicBlock *BB) const {
return getRegionFor(BB);
}
BasicBlock *RegionInfo::getMaxRegionExit(BasicBlock *BB) const {
BasicBlock *Exit = NULL;
while (true) {
// Get largest region that starts at BB.
Region *R = getRegionFor(BB);
while (R && R->getParent() && R->getParent()->getEntry() == BB)
R = R->getParent();
// Get the single exit of BB.
if (R && R->getEntry() == BB)
Exit = R->getExit();
else if (++succ_begin(BB) == succ_end(BB))
Exit = *succ_begin(BB);
else // No single exit exists.
return Exit;
// Get largest region that starts at Exit.
Region *ExitR = getRegionFor(Exit);
while (ExitR && ExitR->getParent()
&& ExitR->getParent()->getEntry() == Exit)
ExitR = ExitR->getParent();
for (pred_iterator PI = pred_begin(Exit), PE = pred_end(Exit); PI != PE;
++PI)
if (!R->contains(*PI) && !ExitR->contains(*PI))
break;
// This stops infinite cycles.
if (DT->dominates(Exit, BB))
break;
BB = Exit;
}
return Exit;
}
Region*
RegionInfo::getCommonRegion(Region *A, Region *B) const {
assert (A && B && "One of the Regions is NULL");
if (A->contains(B)) return A;
while (!B->contains(A))
B = B->getParent();
return B;
}
Region*
RegionInfo::getCommonRegion(SmallVectorImpl<Region*> &Regions) const {
Region* ret = Regions.back();
Regions.pop_back();
for (SmallVectorImpl<Region*>::const_iterator I = Regions.begin(),
E = Regions.end(); I != E; ++I)
ret = getCommonRegion(ret, *I);
return ret;
}
Region*
RegionInfo::getCommonRegion(SmallVectorImpl<BasicBlock*> &BBs) const {
Region* ret = getRegionFor(BBs.back());
BBs.pop_back();
for (SmallVectorImpl<BasicBlock*>::const_iterator I = BBs.begin(),
E = BBs.end(); I != E; ++I)
ret = getCommonRegion(ret, getRegionFor(*I));
return ret;
}
void RegionInfo::splitBlock(BasicBlock* NewBB, BasicBlock *OldBB)
{
Region *R = getRegionFor(OldBB);
setRegionFor(NewBB, R);
while (R->getEntry() == OldBB && !R->isTopLevelRegion()) {
R->replaceEntry(NewBB);
R = R->getParent();
}
setRegionFor(OldBB, R);
}
char RegionInfo::ID = 0;
INITIALIZE_PASS_BEGIN(RegionInfo, "regions",
"Detect single entry single exit regions", true, true)
INITIALIZE_PASS_DEPENDENCY(DominatorTree)
INITIALIZE_PASS_DEPENDENCY(PostDominatorTree)
INITIALIZE_PASS_DEPENDENCY(DominanceFrontier)
INITIALIZE_PASS_END(RegionInfo, "regions",
"Detect single entry single exit regions", true, true)
// Create methods available outside of this file, to use them
// "include/llvm/LinkAllPasses.h". Otherwise the pass would be deleted by
// the link time optimization.
namespace llvm {
FunctionPass *createRegionInfoPass() {
return new RegionInfo();
}
}