//===- 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/ADT/PostOrderIterator.h" #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/RegionIterator.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include #include #include using namespace llvm; #define DEBUG_TYPE "region" // Always verify if expensive checking is enabled. #ifdef XDEBUG static bool VerifyRegionInfo = true; #else static bool VerifyRegionInfo = false; #endif static cl::opt 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"); static cl::opt printStyle("print-region-style", cl::Hidden, cl::desc("style of printing regions"), cl::values( clEnumValN(Region::PrintNone, "none", "print no details"), clEnumValN(Region::PrintBB, "bb", "print regions in detail with block_iterator"), clEnumValN(Region::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(); } void Region::replaceEntry(BasicBlock *BB) { entry.setPointer(BB); } void Region::replaceExit(BasicBlock *BB) { assert(exit && "No exit to replace!"); exit = BB; } void Region::replaceEntryRecursive(BasicBlock *NewEntry) { std::vector RegionQueue; BasicBlock *OldEntry = getEntry(); RegionQueue.push_back(this); while (!RegionQueue.empty()) { Region *R = RegionQueue.back(); RegionQueue.pop_back(); R->replaceEntry(NewEntry); for (Region::const_iterator RI = R->begin(), RE = R->end(); RI != RE; ++RI) if ((*RI)->getEntry() == OldEntry) RegionQueue.push_back(RI->get()); } } void Region::replaceExitRecursive(BasicBlock *NewExit) { std::vector RegionQueue; BasicBlock *OldExit = getExit(); RegionQueue.push_back(this); while (!RegionQueue.empty()) { Region *R = RegionQueue.back(); RegionQueue.pop_back(); R->replaceExit(NewExit); for (Region::const_iterator RI = R->begin(), RE = R->end(); RI != RE; ++RI) if ((*RI)->getExit() == OldExit) RegionQueue.push_back(RI->get()); } } bool Region::contains(const BasicBlock *B) const { BasicBlock *BB = const_cast(B); if (!DT->getNode(BB)) return false; 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) return getExit() == nullptr; if (!contains(L->getHeader())) return false; SmallVector ExitingBlocks; L->getExitingBlocks(ExitingBlocks); for (SmallVectorImpl::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 nullptr; 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); } BasicBlock *Region::getEnteringBlock() const { BasicBlock *entry = getEntry(); BasicBlock *Pred; BasicBlock *enteringBlock = nullptr; for (pred_iterator PI = pred_begin(entry), PE = pred_end(entry); PI != PE; ++PI) { Pred = *PI; if (DT->getNode(Pred) && !contains(Pred)) { if (enteringBlock) return nullptr; enteringBlock = Pred; } } return enteringBlock; } BasicBlock *Region::getExitingBlock() const { BasicBlock *exit = getExit(); BasicBlock *Pred; BasicBlock *exitingBlock = nullptr; if (!exit) return nullptr; for (pred_iterator PI = pred_begin(exit), PE = pred_end(exit); PI != PE; ++PI) { Pred = *PI; if (contains(Pred)) { if (exitingBlock) return nullptr; exitingBlock = Pred; } } return exitingBlock; } bool Region::isSimple() const { return !isTopLevelRegion() && getEnteringBlock() && getExitingBlock(); } std::string Region::getNameStr() const { std::string exitName; std::string entryName; if (getEntry()->getName().empty()) { raw_string_ostream OS(entryName); getEntry()->printAsOperand(OS, false); } else entryName = getEntry()->getName(); if (getExit()) { if (getExit()->getName().empty()) { raw_string_ostream OS(exitName); getExit()->printAsOperand(OS, false); } else exitName = getExit()->getName(); } else exitName = ""; 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 *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 visited; verifyWalk(getEntry(), &visited); } void Region::verifyRegionNest() const { for (Region::const_iterator RI = begin(), RE = end(); RI != RE; ++RI) (*RI)->verifyRegionNest(); verifyRegion(); } Region::element_iterator Region::element_begin() { return GraphTraits::nodes_begin(this); } Region::element_iterator Region::element_end() { return GraphTraits::nodes_end(this); } Region::const_element_iterator Region::element_begin() const { return GraphTraits::nodes_begin(this); } Region::const_element_iterator Region::element_end() const { return GraphTraits::nodes_end(this); } Region* Region::getSubRegionNode(BasicBlock *BB) const { Region *R = RI->getRegionFor(BB); if (!R || R == this) return nullptr; // 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 nullptr; 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(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(std::move(*I)); } children.clear(); } void Region::addSubRegion(Region *SubRegion, bool moveChildren) { assert(!SubRegion->parent && "SubRegion already has a parent!"); assert(std::find_if(begin(), end(), [&](const std::unique_ptr &R) { return R.get() == SubRegion; }) == children.end() && "Subregion already exists!"); SubRegion->parent = this; children.push_back(std::unique_ptr(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(); if (SubRegion->contains(BB)) RI->setRegionFor(BB, SubRegion); } std::vector> Keep; for (iterator I = begin(), E = end(); I != E; ++I) if (SubRegion->contains(I->get()) && I->get() != SubRegion) { (*I)->parent = SubRegion; SubRegion->children.push_back(std::move(*I)); } else Keep.push_back(std::move(*I)); children.clear(); children.insert(children.begin(), std::move_iterator(Keep.begin()), std::move_iterator(Keep.end())); } Region *Region::removeSubRegion(Region *Child) { assert(Child->parent == this && "Child is not a child of this region!"); Child->parent = nullptr; RegionSet::iterator I = std::find_if( children.begin(), children.end(), [&](const std::unique_ptr &R) { return R.get() == 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 != nullptr; R = R->parent) ++Depth; return Depth; } Region *Region::getExpandedRegion() const { unsigned NumSuccessors = exit->getTerminator()->getNumSuccessors(); if (NumSuccessors == 0) return nullptr; for (pred_iterator PI = pred_begin(getExit()), PE = pred_end(getExit()); PI != PE; ++PI) if (!DT->dominates(getEntry(), *PI)) return nullptr; 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 nullptr; } 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 nullptr; return new Region(getEntry(), R->getExit(), RI, DT); } void Region::print(raw_ostream &OS, bool print_tree, unsigned level, enum PrintStyle Style) const { if (print_tree) OS.indent(level*2) << "[" << level << "] " << getNameStr(); else OS.indent(level*2) << getNameStr(); OS << "\n"; if (Style != PrintNone) { OS.indent(level*2) << "{\n"; OS.indent(level*2 + 2); if (Style == PrintBB) { for (const auto &BB : blocks()) OS << BB->getName() << ", "; // TODO: remove the last "," } else if (Style == 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, Style); if (Style != PrintNone) OS.indent(level*2) << "} \n"; } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) void Region::dump() const { print(dbgs(), true, getDepth(), printStyle.getValue()); } #endif 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 nullptr; 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= nullptr; 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 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 = nullptr; } RegionInfo::RegionInfo() : FunctionPass(ID) { initializeRegionInfoPass(*PassRegistry::getPassRegistry()); TopLevelRegion = nullptr; } 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().getDomTree(); PDT = &getAnalysis(); DF = &getAnalysis(); TopLevelRegion = new Region(&F.getEntryBlock(), nullptr, this, DT, nullptr); updateStatistics(TopLevelRegion); Calculate(F); return false; } void RegionInfo::getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); AU.addRequiredTransitive(); AU.addRequired(); AU.addRequired(); } void RegionInfo::print(raw_ostream &OS, const Module *) const { OS << "Region tree:\n"; TopLevelRegion->print(OS, true, 0, printStyle.getValue()); 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 : nullptr; } 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 = nullptr; 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 &Regions) const { Region* ret = Regions.back(); Regions.pop_back(); for (SmallVectorImpl::const_iterator I = Regions.begin(), E = Regions.end(); I != E; ++I) ret = getCommonRegion(ret, *I); return ret; } Region* RegionInfo::getCommonRegion(SmallVectorImpl &BBs) const { Region* ret = getRegionFor(BBs.back()); BBs.pop_back(); for (SmallVectorImpl::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(DominatorTreeWrapperPass) 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(); } }