mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 03:02:36 +01:00
ae65e281f3
to reflect the new license. We understand that people may be surprised that we're moving the header entirely to discuss the new license. We checked this carefully with the Foundation's lawyer and we believe this is the correct approach. Essentially, all code in the project is now made available by the LLVM project under our new license, so you will see that the license headers include that license only. Some of our contributors have contributed code under our old license, and accordingly, we have retained a copy of our old license notice in the top-level files in each project and repository. llvm-svn: 351636
932 lines
25 KiB
C++
932 lines
25 KiB
C++
//===- RegionInfoImpl.h - SESE region detection analysis --------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
// Detects single entry single exit regions in the control flow graph.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_ANALYSIS_REGIONINFOIMPL_H
|
|
#define LLVM_ANALYSIS_REGIONINFOIMPL_H
|
|
|
|
#include "llvm/ADT/GraphTraits.h"
|
|
#include "llvm/ADT/PostOrderIterator.h"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/ADT/SmallVector.h"
|
|
#include "llvm/ADT/iterator_range.h"
|
|
#include "llvm/Analysis/DominanceFrontier.h"
|
|
#include "llvm/Analysis/LoopInfo.h"
|
|
#include "llvm/Analysis/PostDominators.h"
|
|
#include "llvm/Analysis/RegionInfo.h"
|
|
#include "llvm/Analysis/RegionIterator.h"
|
|
#include "llvm/Config/llvm-config.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
#include <iterator>
|
|
#include <memory>
|
|
#include <set>
|
|
#include <string>
|
|
#include <type_traits>
|
|
#include <vector>
|
|
|
|
#define DEBUG_TYPE "region"
|
|
|
|
namespace llvm {
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
/// RegionBase Implementation
|
|
template <class Tr>
|
|
RegionBase<Tr>::RegionBase(BlockT *Entry, BlockT *Exit,
|
|
typename Tr::RegionInfoT *RInfo, DomTreeT *dt,
|
|
RegionT *Parent)
|
|
: RegionNodeBase<Tr>(Parent, Entry, 1), RI(RInfo), DT(dt), exit(Exit) {}
|
|
|
|
template <class Tr>
|
|
RegionBase<Tr>::~RegionBase() {
|
|
// Only clean the cache for this Region. Caches of child Regions will be
|
|
// cleaned when the child Regions are deleted.
|
|
BBNodeMap.clear();
|
|
}
|
|
|
|
template <class Tr>
|
|
void RegionBase<Tr>::replaceEntry(BlockT *BB) {
|
|
this->entry.setPointer(BB);
|
|
}
|
|
|
|
template <class Tr>
|
|
void RegionBase<Tr>::replaceExit(BlockT *BB) {
|
|
assert(exit && "No exit to replace!");
|
|
exit = BB;
|
|
}
|
|
|
|
template <class Tr>
|
|
void RegionBase<Tr>::replaceEntryRecursive(BlockT *NewEntry) {
|
|
std::vector<RegionT *> RegionQueue;
|
|
BlockT *OldEntry = getEntry();
|
|
|
|
RegionQueue.push_back(static_cast<RegionT *>(this));
|
|
while (!RegionQueue.empty()) {
|
|
RegionT *R = RegionQueue.back();
|
|
RegionQueue.pop_back();
|
|
|
|
R->replaceEntry(NewEntry);
|
|
for (std::unique_ptr<RegionT> &Child : *R) {
|
|
if (Child->getEntry() == OldEntry)
|
|
RegionQueue.push_back(Child.get());
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class Tr>
|
|
void RegionBase<Tr>::replaceExitRecursive(BlockT *NewExit) {
|
|
std::vector<RegionT *> RegionQueue;
|
|
BlockT *OldExit = getExit();
|
|
|
|
RegionQueue.push_back(static_cast<RegionT *>(this));
|
|
while (!RegionQueue.empty()) {
|
|
RegionT *R = RegionQueue.back();
|
|
RegionQueue.pop_back();
|
|
|
|
R->replaceExit(NewExit);
|
|
for (std::unique_ptr<RegionT> &Child : *R) {
|
|
if (Child->getExit() == OldExit)
|
|
RegionQueue.push_back(Child.get());
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class Tr>
|
|
bool RegionBase<Tr>::contains(const BlockT *B) const {
|
|
BlockT *BB = const_cast<BlockT *>(B);
|
|
|
|
if (!DT->getNode(BB))
|
|
return false;
|
|
|
|
BlockT *entry = getEntry(), *exit = getExit();
|
|
|
|
// Toplevel region.
|
|
if (!exit)
|
|
return true;
|
|
|
|
return (DT->dominates(entry, BB) &&
|
|
!(DT->dominates(exit, BB) && DT->dominates(entry, exit)));
|
|
}
|
|
|
|
template <class Tr>
|
|
bool RegionBase<Tr>::contains(const LoopT *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<BlockT *, 8> ExitingBlocks;
|
|
L->getExitingBlocks(ExitingBlocks);
|
|
|
|
for (BlockT *BB : ExitingBlocks) {
|
|
if (!contains(BB))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
template <class Tr>
|
|
typename Tr::LoopT *RegionBase<Tr>::outermostLoopInRegion(LoopT *L) const {
|
|
if (!contains(L))
|
|
return nullptr;
|
|
|
|
while (L && contains(L->getParentLoop())) {
|
|
L = L->getParentLoop();
|
|
}
|
|
|
|
return L;
|
|
}
|
|
|
|
template <class Tr>
|
|
typename Tr::LoopT *RegionBase<Tr>::outermostLoopInRegion(LoopInfoT *LI,
|
|
BlockT *BB) const {
|
|
assert(LI && BB && "LI and BB cannot be null!");
|
|
LoopT *L = LI->getLoopFor(BB);
|
|
return outermostLoopInRegion(L);
|
|
}
|
|
|
|
template <class Tr>
|
|
typename RegionBase<Tr>::BlockT *RegionBase<Tr>::getEnteringBlock() const {
|
|
BlockT *entry = getEntry();
|
|
BlockT *enteringBlock = nullptr;
|
|
|
|
for (BlockT *Pred : make_range(InvBlockTraits::child_begin(entry),
|
|
InvBlockTraits::child_end(entry))) {
|
|
if (DT->getNode(Pred) && !contains(Pred)) {
|
|
if (enteringBlock)
|
|
return nullptr;
|
|
|
|
enteringBlock = Pred;
|
|
}
|
|
}
|
|
|
|
return enteringBlock;
|
|
}
|
|
|
|
template <class Tr>
|
|
bool RegionBase<Tr>::getExitingBlocks(
|
|
SmallVectorImpl<BlockT *> &Exitings) const {
|
|
bool CoverAll = true;
|
|
|
|
if (!exit)
|
|
return CoverAll;
|
|
|
|
for (PredIterTy PI = InvBlockTraits::child_begin(exit),
|
|
PE = InvBlockTraits::child_end(exit);
|
|
PI != PE; ++PI) {
|
|
BlockT *Pred = *PI;
|
|
if (contains(Pred)) {
|
|
Exitings.push_back(Pred);
|
|
continue;
|
|
}
|
|
|
|
CoverAll = false;
|
|
}
|
|
|
|
return CoverAll;
|
|
}
|
|
|
|
template <class Tr>
|
|
typename RegionBase<Tr>::BlockT *RegionBase<Tr>::getExitingBlock() const {
|
|
BlockT *exit = getExit();
|
|
BlockT *exitingBlock = nullptr;
|
|
|
|
if (!exit)
|
|
return nullptr;
|
|
|
|
for (BlockT *Pred : make_range(InvBlockTraits::child_begin(exit),
|
|
InvBlockTraits::child_end(exit))) {
|
|
if (contains(Pred)) {
|
|
if (exitingBlock)
|
|
return nullptr;
|
|
|
|
exitingBlock = Pred;
|
|
}
|
|
}
|
|
|
|
return exitingBlock;
|
|
}
|
|
|
|
template <class Tr>
|
|
bool RegionBase<Tr>::isSimple() const {
|
|
return !isTopLevelRegion() && getEnteringBlock() && getExitingBlock();
|
|
}
|
|
|
|
template <class Tr>
|
|
std::string RegionBase<Tr>::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 = "<Function Return>";
|
|
|
|
return entryName + " => " + exitName;
|
|
}
|
|
|
|
template <class Tr>
|
|
void RegionBase<Tr>::verifyBBInRegion(BlockT *BB) const {
|
|
if (!contains(BB))
|
|
report_fatal_error("Broken region found: enumerated BB not in region!");
|
|
|
|
BlockT *entry = getEntry(), *exit = getExit();
|
|
|
|
for (BlockT *Succ :
|
|
make_range(BlockTraits::child_begin(BB), BlockTraits::child_end(BB))) {
|
|
if (!contains(Succ) && exit != Succ)
|
|
report_fatal_error("Broken region found: edges leaving the region must go "
|
|
"to the exit node!");
|
|
}
|
|
|
|
if (entry != BB) {
|
|
for (BlockT *Pred : make_range(InvBlockTraits::child_begin(BB),
|
|
InvBlockTraits::child_end(BB))) {
|
|
if (!contains(Pred))
|
|
report_fatal_error("Broken region found: edges entering the region must "
|
|
"go to the entry node!");
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class Tr>
|
|
void RegionBase<Tr>::verifyWalk(BlockT *BB, std::set<BlockT *> *visited) const {
|
|
BlockT *exit = getExit();
|
|
|
|
visited->insert(BB);
|
|
|
|
verifyBBInRegion(BB);
|
|
|
|
for (BlockT *Succ :
|
|
make_range(BlockTraits::child_begin(BB), BlockTraits::child_end(BB))) {
|
|
if (Succ != exit && visited->find(Succ) == visited->end())
|
|
verifyWalk(Succ, visited);
|
|
}
|
|
}
|
|
|
|
template <class Tr>
|
|
void RegionBase<Tr>::verifyRegion() 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 (!RegionInfoBase<Tr>::VerifyRegionInfo)
|
|
return;
|
|
|
|
std::set<BlockT *> visited;
|
|
verifyWalk(getEntry(), &visited);
|
|
}
|
|
|
|
template <class Tr>
|
|
void RegionBase<Tr>::verifyRegionNest() const {
|
|
for (const std::unique_ptr<RegionT> &R : *this)
|
|
R->verifyRegionNest();
|
|
|
|
verifyRegion();
|
|
}
|
|
|
|
template <class Tr>
|
|
typename RegionBase<Tr>::element_iterator RegionBase<Tr>::element_begin() {
|
|
return GraphTraits<RegionT *>::nodes_begin(static_cast<RegionT *>(this));
|
|
}
|
|
|
|
template <class Tr>
|
|
typename RegionBase<Tr>::element_iterator RegionBase<Tr>::element_end() {
|
|
return GraphTraits<RegionT *>::nodes_end(static_cast<RegionT *>(this));
|
|
}
|
|
|
|
template <class Tr>
|
|
typename RegionBase<Tr>::const_element_iterator
|
|
RegionBase<Tr>::element_begin() const {
|
|
return GraphTraits<const RegionT *>::nodes_begin(
|
|
static_cast<const RegionT *>(this));
|
|
}
|
|
|
|
template <class Tr>
|
|
typename RegionBase<Tr>::const_element_iterator
|
|
RegionBase<Tr>::element_end() const {
|
|
return GraphTraits<const RegionT *>::nodes_end(
|
|
static_cast<const RegionT *>(this));
|
|
}
|
|
|
|
template <class Tr>
|
|
typename Tr::RegionT *RegionBase<Tr>::getSubRegionNode(BlockT *BB) const {
|
|
using RegionT = typename Tr::RegionT;
|
|
|
|
RegionT *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;
|
|
}
|
|
|
|
template <class Tr>
|
|
typename Tr::RegionNodeT *RegionBase<Tr>::getBBNode(BlockT *BB) const {
|
|
assert(contains(BB) && "Can get BB node out of this region!");
|
|
|
|
typename BBNodeMapT::const_iterator at = BBNodeMap.find(BB);
|
|
|
|
if (at == BBNodeMap.end()) {
|
|
auto Deconst = const_cast<RegionBase<Tr> *>(this);
|
|
typename BBNodeMapT::value_type V = {
|
|
BB,
|
|
llvm::make_unique<RegionNodeT>(static_cast<RegionT *>(Deconst), BB)};
|
|
at = BBNodeMap.insert(std::move(V)).first;
|
|
}
|
|
return at->second.get();
|
|
}
|
|
|
|
template <class Tr>
|
|
typename Tr::RegionNodeT *RegionBase<Tr>::getNode(BlockT *BB) const {
|
|
assert(contains(BB) && "Can get BB node out of this region!");
|
|
if (RegionT *Child = getSubRegionNode(BB))
|
|
return Child->getNode();
|
|
|
|
return getBBNode(BB);
|
|
}
|
|
|
|
template <class Tr>
|
|
void RegionBase<Tr>::transferChildrenTo(RegionT *To) {
|
|
for (std::unique_ptr<RegionT> &R : *this) {
|
|
R->parent = To;
|
|
To->children.push_back(std::move(R));
|
|
}
|
|
children.clear();
|
|
}
|
|
|
|
template <class Tr>
|
|
void RegionBase<Tr>::addSubRegion(RegionT *SubRegion, bool moveChildren) {
|
|
assert(!SubRegion->parent && "SubRegion already has a parent!");
|
|
assert(llvm::find_if(*this,
|
|
[&](const std::unique_ptr<RegionT> &R) {
|
|
return R.get() == SubRegion;
|
|
}) == children.end() &&
|
|
"Subregion already exists!");
|
|
|
|
SubRegion->parent = static_cast<RegionT *>(this);
|
|
children.push_back(std::unique_ptr<RegionT>(SubRegion));
|
|
|
|
if (!moveChildren)
|
|
return;
|
|
|
|
assert(SubRegion->children.empty() &&
|
|
"SubRegions that contain children are not supported");
|
|
|
|
for (RegionNodeT *Element : elements()) {
|
|
if (!Element->isSubRegion()) {
|
|
BlockT *BB = Element->template getNodeAs<BlockT>();
|
|
|
|
if (SubRegion->contains(BB))
|
|
RI->setRegionFor(BB, SubRegion);
|
|
}
|
|
}
|
|
|
|
std::vector<std::unique_ptr<RegionT>> Keep;
|
|
for (std::unique_ptr<RegionT> &R : *this) {
|
|
if (SubRegion->contains(R.get()) && R.get() != SubRegion) {
|
|
R->parent = SubRegion;
|
|
SubRegion->children.push_back(std::move(R));
|
|
} else
|
|
Keep.push_back(std::move(R));
|
|
}
|
|
|
|
children.clear();
|
|
children.insert(
|
|
children.begin(),
|
|
std::move_iterator<typename RegionSet::iterator>(Keep.begin()),
|
|
std::move_iterator<typename RegionSet::iterator>(Keep.end()));
|
|
}
|
|
|
|
template <class Tr>
|
|
typename Tr::RegionT *RegionBase<Tr>::removeSubRegion(RegionT *Child) {
|
|
assert(Child->parent == this && "Child is not a child of this region!");
|
|
Child->parent = nullptr;
|
|
typename RegionSet::iterator I =
|
|
llvm::find_if(children, [&](const std::unique_ptr<RegionT> &R) {
|
|
return R.get() == Child;
|
|
});
|
|
assert(I != children.end() && "Region does not exit. Unable to remove.");
|
|
children.erase(children.begin() + (I - begin()));
|
|
return Child;
|
|
}
|
|
|
|
template <class Tr>
|
|
unsigned RegionBase<Tr>::getDepth() const {
|
|
unsigned Depth = 0;
|
|
|
|
for (RegionT *R = getParent(); R != nullptr; R = R->getParent())
|
|
++Depth;
|
|
|
|
return Depth;
|
|
}
|
|
|
|
template <class Tr>
|
|
typename Tr::RegionT *RegionBase<Tr>::getExpandedRegion() const {
|
|
unsigned NumSuccessors = Tr::getNumSuccessors(exit);
|
|
|
|
if (NumSuccessors == 0)
|
|
return nullptr;
|
|
|
|
RegionT *R = RI->getRegionFor(exit);
|
|
|
|
if (R->getEntry() != exit) {
|
|
for (BlockT *Pred : make_range(InvBlockTraits::child_begin(getExit()),
|
|
InvBlockTraits::child_end(getExit())))
|
|
if (!contains(Pred))
|
|
return nullptr;
|
|
if (Tr::getNumSuccessors(exit) == 1)
|
|
return new RegionT(getEntry(), *BlockTraits::child_begin(exit), RI, DT);
|
|
return nullptr;
|
|
}
|
|
|
|
while (R->getParent() && R->getParent()->getEntry() == exit)
|
|
R = R->getParent();
|
|
|
|
for (BlockT *Pred : make_range(InvBlockTraits::child_begin(getExit()),
|
|
InvBlockTraits::child_end(getExit()))) {
|
|
if (!(contains(Pred) || R->contains(Pred)))
|
|
return nullptr;
|
|
}
|
|
|
|
return new RegionT(getEntry(), R->getExit(), RI, DT);
|
|
}
|
|
|
|
template <class Tr>
|
|
void RegionBase<Tr>::print(raw_ostream &OS, bool print_tree, unsigned level,
|
|
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 RegionNodeT *Element : elements()) {
|
|
OS << *Element << ", "; // TODO: remove the last ",
|
|
}
|
|
}
|
|
|
|
OS << '\n';
|
|
}
|
|
|
|
if (print_tree) {
|
|
for (const std::unique_ptr<RegionT> &R : *this)
|
|
R->print(OS, print_tree, level + 1, Style);
|
|
}
|
|
|
|
if (Style != PrintNone)
|
|
OS.indent(level * 2) << "} \n";
|
|
}
|
|
|
|
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
|
template <class Tr>
|
|
void RegionBase<Tr>::dump() const {
|
|
print(dbgs(), true, getDepth(), RegionInfoBase<Tr>::printStyle);
|
|
}
|
|
#endif
|
|
|
|
template <class Tr>
|
|
void RegionBase<Tr>::clearNodeCache() {
|
|
BBNodeMap.clear();
|
|
for (std::unique_ptr<RegionT> &R : *this)
|
|
R->clearNodeCache();
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// RegionInfoBase implementation
|
|
//
|
|
|
|
template <class Tr>
|
|
RegionInfoBase<Tr>::RegionInfoBase() = default;
|
|
|
|
template <class Tr>
|
|
RegionInfoBase<Tr>::~RegionInfoBase() {
|
|
releaseMemory();
|
|
}
|
|
|
|
template <class Tr>
|
|
void RegionInfoBase<Tr>::verifyBBMap(const RegionT *R) const {
|
|
assert(R && "Re must be non-null");
|
|
for (const typename Tr::RegionNodeT *Element : R->elements()) {
|
|
if (Element->isSubRegion()) {
|
|
const RegionT *SR = Element->template getNodeAs<RegionT>();
|
|
verifyBBMap(SR);
|
|
} else {
|
|
BlockT *BB = Element->template getNodeAs<BlockT>();
|
|
if (getRegionFor(BB) != R)
|
|
report_fatal_error("BB map does not match region nesting");
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class Tr>
|
|
bool RegionInfoBase<Tr>::isCommonDomFrontier(BlockT *BB, BlockT *entry,
|
|
BlockT *exit) const {
|
|
for (BlockT *P : make_range(InvBlockTraits::child_begin(BB),
|
|
InvBlockTraits::child_end(BB))) {
|
|
if (DT->dominates(entry, P) && !DT->dominates(exit, P))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
template <class Tr>
|
|
bool RegionInfoBase<Tr>::isRegion(BlockT *entry, BlockT *exit) const {
|
|
assert(entry && exit && "entry and exit must not be null!");
|
|
|
|
using DST = typename DomFrontierT::DomSetType;
|
|
|
|
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 (typename 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 (BlockT *Succ : *entrySuccs) {
|
|
if (Succ == exit || Succ == entry)
|
|
continue;
|
|
if (exitSuccs->find(Succ) == exitSuccs->end())
|
|
return false;
|
|
if (!isCommonDomFrontier(Succ, entry, exit))
|
|
return false;
|
|
}
|
|
|
|
// Do not allow edges pointing into the region.
|
|
for (BlockT *Succ : *exitSuccs) {
|
|
if (DT->properlyDominates(entry, Succ) && Succ != exit)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
template <class Tr>
|
|
void RegionInfoBase<Tr>::insertShortCut(BlockT *entry, BlockT *exit,
|
|
BBtoBBMap *ShortCut) const {
|
|
assert(entry && exit && "entry and exit must not be null!");
|
|
|
|
typename 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.
|
|
BlockT *BB = e->second;
|
|
(*ShortCut)[entry] = BB;
|
|
}
|
|
}
|
|
|
|
template <class Tr>
|
|
typename Tr::DomTreeNodeT *
|
|
RegionInfoBase<Tr>::getNextPostDom(DomTreeNodeT *N, BBtoBBMap *ShortCut) const {
|
|
typename BBtoBBMap::iterator e = ShortCut->find(N->getBlock());
|
|
|
|
if (e == ShortCut->end())
|
|
return N->getIDom();
|
|
|
|
return PDT->getNode(e->second)->getIDom();
|
|
}
|
|
|
|
template <class Tr>
|
|
bool RegionInfoBase<Tr>::isTrivialRegion(BlockT *entry, BlockT *exit) const {
|
|
assert(entry && exit && "entry and exit must not be null!");
|
|
|
|
unsigned num_successors =
|
|
BlockTraits::child_end(entry) - BlockTraits::child_begin(entry);
|
|
|
|
if (num_successors <= 1 && exit == *(BlockTraits::child_begin(entry)))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
template <class Tr>
|
|
typename Tr::RegionT *RegionInfoBase<Tr>::createRegion(BlockT *entry,
|
|
BlockT *exit) {
|
|
assert(entry && exit && "entry and exit must not be null!");
|
|
|
|
if (isTrivialRegion(entry, exit))
|
|
return nullptr;
|
|
|
|
RegionT *region =
|
|
new RegionT(entry, exit, static_cast<RegionInfoT *>(this), DT);
|
|
BBtoRegion.insert({entry, region});
|
|
|
|
#ifdef EXPENSIVE_CHECKS
|
|
region->verifyRegion();
|
|
#else
|
|
LLVM_DEBUG(region->verifyRegion());
|
|
#endif
|
|
|
|
updateStatistics(region);
|
|
return region;
|
|
}
|
|
|
|
template <class Tr>
|
|
void RegionInfoBase<Tr>::findRegionsWithEntry(BlockT *entry,
|
|
BBtoBBMap *ShortCut) {
|
|
assert(entry);
|
|
|
|
DomTreeNodeT *N = PDT->getNode(entry);
|
|
if (!N)
|
|
return;
|
|
|
|
RegionT *lastRegion = nullptr;
|
|
BlockT *lastExit = entry;
|
|
|
|
// As only a BasicBlock that postdominates entry can finish a region, walk the
|
|
// post dominance tree upwards.
|
|
while ((N = getNextPostDom(N, ShortCut))) {
|
|
BlockT *exit = N->getBlock();
|
|
|
|
if (!exit)
|
|
break;
|
|
|
|
if (isRegion(entry, exit)) {
|
|
RegionT *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);
|
|
}
|
|
|
|
template <class Tr>
|
|
void RegionInfoBase<Tr>::scanForRegions(FuncT &F, BBtoBBMap *ShortCut) {
|
|
using FuncPtrT = typename std::add_pointer<FuncT>::type;
|
|
|
|
BlockT *entry = GraphTraits<FuncPtrT>::getEntryNode(&F);
|
|
DomTreeNodeT *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 (auto DomNode : post_order(N))
|
|
findRegionsWithEntry(DomNode->getBlock(), ShortCut);
|
|
}
|
|
|
|
template <class Tr>
|
|
typename Tr::RegionT *RegionInfoBase<Tr>::getTopMostParent(RegionT *region) {
|
|
while (region->getParent())
|
|
region = region->getParent();
|
|
|
|
return region;
|
|
}
|
|
|
|
template <class Tr>
|
|
void RegionInfoBase<Tr>::buildRegionsTree(DomTreeNodeT *N, RegionT *region) {
|
|
BlockT *BB = N->getBlock();
|
|
|
|
// Passed region exit
|
|
while (BB == region->getExit())
|
|
region = region->getParent();
|
|
|
|
typename 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()) {
|
|
RegionT *newRegion = it->second;
|
|
region->addSubRegion(getTopMostParent(newRegion));
|
|
region = newRegion;
|
|
} else {
|
|
BBtoRegion[BB] = region;
|
|
}
|
|
|
|
for (DomTreeNodeBase<BlockT> *C : *N) {
|
|
buildRegionsTree(C, region);
|
|
}
|
|
}
|
|
|
|
#ifdef EXPENSIVE_CHECKS
|
|
template <class Tr>
|
|
bool RegionInfoBase<Tr>::VerifyRegionInfo = true;
|
|
#else
|
|
template <class Tr>
|
|
bool RegionInfoBase<Tr>::VerifyRegionInfo = false;
|
|
#endif
|
|
|
|
template <class Tr>
|
|
typename Tr::RegionT::PrintStyle RegionInfoBase<Tr>::printStyle =
|
|
RegionBase<Tr>::PrintNone;
|
|
|
|
template <class Tr>
|
|
void RegionInfoBase<Tr>::print(raw_ostream &OS) const {
|
|
OS << "Region tree:\n";
|
|
TopLevelRegion->print(OS, true, 0, printStyle);
|
|
OS << "End region tree\n";
|
|
}
|
|
|
|
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
|
template <class Tr>
|
|
void RegionInfoBase<Tr>::dump() const { print(dbgs()); }
|
|
#endif
|
|
|
|
template <class Tr>
|
|
void RegionInfoBase<Tr>::releaseMemory() {
|
|
BBtoRegion.clear();
|
|
if (TopLevelRegion)
|
|
delete TopLevelRegion;
|
|
TopLevelRegion = nullptr;
|
|
}
|
|
|
|
template <class Tr>
|
|
void RegionInfoBase<Tr>::verifyAnalysis() const {
|
|
// Do only verify regions if explicitely activated using EXPENSIVE_CHECKS or
|
|
// -verify-region-info
|
|
if (!RegionInfoBase<Tr>::VerifyRegionInfo)
|
|
return;
|
|
|
|
TopLevelRegion->verifyRegionNest();
|
|
|
|
verifyBBMap(TopLevelRegion);
|
|
}
|
|
|
|
// Region pass manager support.
|
|
template <class Tr>
|
|
typename Tr::RegionT *RegionInfoBase<Tr>::getRegionFor(BlockT *BB) const {
|
|
typename BBtoRegionMap::const_iterator I = BBtoRegion.find(BB);
|
|
return I != BBtoRegion.end() ? I->second : nullptr;
|
|
}
|
|
|
|
template <class Tr>
|
|
void RegionInfoBase<Tr>::setRegionFor(BlockT *BB, RegionT *R) {
|
|
BBtoRegion[BB] = R;
|
|
}
|
|
|
|
template <class Tr>
|
|
typename Tr::RegionT *RegionInfoBase<Tr>::operator[](BlockT *BB) const {
|
|
return getRegionFor(BB);
|
|
}
|
|
|
|
template <class Tr>
|
|
typename RegionInfoBase<Tr>::BlockT *
|
|
RegionInfoBase<Tr>::getMaxRegionExit(BlockT *BB) const {
|
|
BlockT *Exit = nullptr;
|
|
|
|
while (true) {
|
|
// Get largest region that starts at BB.
|
|
RegionT *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 (++BlockTraits::child_begin(BB) == BlockTraits::child_end(BB))
|
|
Exit = *BlockTraits::child_begin(BB);
|
|
else // No single exit exists.
|
|
return Exit;
|
|
|
|
// Get largest region that starts at Exit.
|
|
RegionT *ExitR = getRegionFor(Exit);
|
|
while (ExitR && ExitR->getParent() &&
|
|
ExitR->getParent()->getEntry() == Exit)
|
|
ExitR = ExitR->getParent();
|
|
|
|
for (BlockT *Pred : make_range(InvBlockTraits::child_begin(Exit),
|
|
InvBlockTraits::child_end(Exit))) {
|
|
if (!R->contains(Pred) && !ExitR->contains(Pred))
|
|
break;
|
|
}
|
|
|
|
// This stops infinite cycles.
|
|
if (DT->dominates(Exit, BB))
|
|
break;
|
|
|
|
BB = Exit;
|
|
}
|
|
|
|
return Exit;
|
|
}
|
|
|
|
template <class Tr>
|
|
typename Tr::RegionT *RegionInfoBase<Tr>::getCommonRegion(RegionT *A,
|
|
RegionT *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;
|
|
}
|
|
|
|
template <class Tr>
|
|
typename Tr::RegionT *
|
|
RegionInfoBase<Tr>::getCommonRegion(SmallVectorImpl<RegionT *> &Regions) const {
|
|
RegionT *ret = Regions.back();
|
|
Regions.pop_back();
|
|
|
|
for (RegionT *R : Regions)
|
|
ret = getCommonRegion(ret, R);
|
|
|
|
return ret;
|
|
}
|
|
|
|
template <class Tr>
|
|
typename Tr::RegionT *
|
|
RegionInfoBase<Tr>::getCommonRegion(SmallVectorImpl<BlockT *> &BBs) const {
|
|
RegionT *ret = getRegionFor(BBs.back());
|
|
BBs.pop_back();
|
|
|
|
for (BlockT *BB : BBs)
|
|
ret = getCommonRegion(ret, getRegionFor(BB));
|
|
|
|
return ret;
|
|
}
|
|
|
|
template <class Tr>
|
|
void RegionInfoBase<Tr>::calculate(FuncT &F) {
|
|
using FuncPtrT = typename std::add_pointer<FuncT>::type;
|
|
|
|
// 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);
|
|
BlockT *BB = GraphTraits<FuncPtrT>::getEntryNode(&F);
|
|
buildRegionsTree(DT->getNode(BB), TopLevelRegion);
|
|
}
|
|
|
|
} // end namespace llvm
|
|
|
|
#undef DEBUG_TYPE
|
|
|
|
#endif // LLVM_ANALYSIS_REGIONINFOIMPL_H
|