[BPI][NFC] Consolidate code to deal with SCCs under a dedicated data structure.

In order to facilitate review of D79485 here is a small NFC change which restructures code around handling of SCCs in BPI.

Reviewed By: davidxl

Differential Revision: https://reviews.llvm.org/D84514
This commit is contained in:
Evgeniy Brevnov 2020-07-24 18:57:10 +07:00
parent 7294ca3f6e
commit 3a2b05f9fe
2 changed files with 169 additions and 66 deletions

View File

@ -151,13 +151,66 @@ public:
/// Forget analysis results for the given basic block.
void eraseBlock(const BasicBlock *BB);
// Use to track SCCs for handling irreducible loops.
using SccMap = DenseMap<const BasicBlock *, int>;
using SccHeaderMap = DenseMap<const BasicBlock *, bool>;
using SccHeaderMaps = std::vector<SccHeaderMap>;
struct SccInfo {
class SccInfo {
// Enum of types to classify basic blocks in SCC. Basic block belonging to
// SCC is 'Inner' until it is either 'Header' or 'Exiting'. Note that a
// basic block can be 'Header' and 'Exiting' at the same time.
enum SccBlockType {
Inner = 0x0,
Header = 0x1,
Exiting = 0x2,
};
// Map of basic blocks to SCC IDs they belong to. If basic block doesn't
// belong to any SCC it is not in the map.
using SccMap = DenseMap<const BasicBlock *, int>;
// Each basic block in SCC is attributed with one or several types from
// SccBlockType. Map value has uint32_t type (instead of SccBlockType)
// since basic block may be for example "Header" and "Exiting" at the same
// time and we need to be able to keep more than one value from
// SccBlockType.
using SccBlockTypeMap = DenseMap<const BasicBlock *, uint32_t>;
// Vector containing classification of basic blocks for all SCCs where i'th
// vector element corresponds to SCC with ID equal to i.
using SccBlockTypeMaps = std::vector<SccBlockTypeMap>;
SccMap SccNums;
SccHeaderMaps SccHeaders;
SccBlockTypeMaps SccBlocks;
public:
explicit SccInfo(const Function &F);
/// If \p BB belongs to some SCC then ID of that SCC is returned, otherwise
/// -1 is returned. If \p BB belongs to more than one SCC at the same time
/// result is undefined.
int getSCCNum(const BasicBlock *BB) const;
/// Returns true if \p BB is a 'header' block in SCC with \p SccNum ID,
/// false otherwise.
bool isSCCHeader(const BasicBlock *BB, int SccNum) const {
return getSccBlockType(BB, SccNum) & Header;
}
/// Returns true if \p BB is an 'exiting' block in SCC with \p SccNum ID,
/// false otherwise.
bool isSCCExitingBlock(const BasicBlock *BB, int SccNum) const {
return getSccBlockType(BB, SccNum) & Exiting;
}
/// Fills in \p Enters vector with all such blocks that don't belong to
/// SCC with \p SccNum ID but there is an edge to a block belonging to the
/// SCC.
void getSccEnterBlocks(int SccNum,
SmallVectorImpl<BasicBlock *> &Enters) const;
/// Fills in \p Exits vector with all such blocks that don't belong to
/// SCC with \p SccNum ID but there is an edge from a block belonging to the
/// SCC.
void getSccExitBlocks(int SccNum,
SmallVectorImpl<BasicBlock *> &Exits) const;
private:
/// Returns \p BB's type according to classification given by SccBlockType
/// enum. Please note that \p BB must belong to SSC with \p SccNum ID.
uint32_t getSccBlockType(const BasicBlock *BB, int SccNum) const;
/// Calculates \p BB's type and stores it in internal data structures for
/// future use. Please note that \p BB must belong to SSC with \p SccNum ID.
void calculateSccBlockType(const BasicBlock *BB, int SccNum);
};
private:
@ -196,6 +249,9 @@ private:
/// Track the last function we run over for printing.
const Function *LastF = nullptr;
/// Keeps information about all SCCs in a function.
std::unique_ptr<const SccInfo> SccI;
/// Track the set of blocks directly succeeded by a returning block.
SmallPtrSet<const BasicBlock *, 16> PostDominatedByUnreachable;
@ -210,8 +266,7 @@ private:
bool calcMetadataWeights(const BasicBlock *BB);
bool calcColdCallHeuristics(const BasicBlock *BB);
bool calcPointerHeuristics(const BasicBlock *BB);
bool calcLoopBranchHeuristics(const BasicBlock *BB, const LoopInfo &LI,
SccInfo &SccI);
bool calcLoopBranchHeuristics(const BasicBlock *BB, const LoopInfo &LI);
bool calcZeroHeuristics(const BasicBlock *BB, const TargetLibraryInfo *TLI);
bool calcFloatingPointHeuristics(const BasicBlock *BB);
bool calcInvokeHeuristics(const BasicBlock *BB);

View File

@ -148,6 +148,105 @@ static const uint32_t IH_TAKEN_WEIGHT = 1024 * 1024 - 1;
/// instruction. This is essentially never taken.
static const uint32_t IH_NONTAKEN_WEIGHT = 1;
BranchProbabilityInfo::SccInfo::SccInfo(const Function &F) {
// Record SCC numbers of blocks in the CFG to identify irreducible loops.
// FIXME: We could only calculate this if the CFG is known to be irreducible
// (perhaps cache this info in LoopInfo if we can easily calculate it there?).
int SccNum = 0;
for (scc_iterator<const Function *> It = scc_begin(&F); !It.isAtEnd();
++It, ++SccNum) {
// Ignore single-block SCCs since they either aren't loops or LoopInfo will
// catch them.
const std::vector<const BasicBlock *> &Scc = *It;
if (Scc.size() == 1)
continue;
LLVM_DEBUG(dbgs() << "BPI: SCC " << SccNum << ":");
for (const auto *BB : Scc) {
LLVM_DEBUG(dbgs() << " " << BB->getName());
SccNums[BB] = SccNum;
calculateSccBlockType(BB, SccNum);
}
LLVM_DEBUG(dbgs() << "\n");
}
}
int BranchProbabilityInfo::SccInfo::getSCCNum(const BasicBlock *BB) const {
auto SccIt = SccNums.find(BB);
if (SccIt == SccNums.end())
return -1;
return SccIt->second;
}
void BranchProbabilityInfo::SccInfo::getSccEnterBlocks(
int SccNum, SmallVectorImpl<BasicBlock *> &Enters) const {
for (auto MapIt : SccBlocks[SccNum]) {
const auto *BB = MapIt.first;
if (isSCCHeader(BB, SccNum))
for (const auto *Pred : predecessors(BB))
if (getSCCNum(Pred) != SccNum)
Enters.push_back(const_cast<BasicBlock *>(BB));
}
}
void BranchProbabilityInfo::SccInfo::getSccExitBlocks(
int SccNum, SmallVectorImpl<BasicBlock *> &Exits) const {
for (auto MapIt : SccBlocks[SccNum]) {
const auto *BB = MapIt.first;
if (isSCCExitingBlock(BB, SccNum))
for (const auto *Succ : successors(BB))
if (getSCCNum(Succ) != SccNum)
Exits.push_back(const_cast<BasicBlock *>(BB));
}
}
uint32_t BranchProbabilityInfo::SccInfo::getSccBlockType(const BasicBlock *BB,
int SccNum) const {
assert(getSCCNum(BB) == SccNum);
assert(SccBlocks.size() > static_cast<unsigned>(SccNum) && "Unknown SCC");
const auto &SccBlockTypes = SccBlocks[SccNum];
auto It = SccBlockTypes.find(BB);
if (It != SccBlockTypes.end()) {
return It->second;
}
return Inner;
}
void BranchProbabilityInfo::SccInfo::calculateSccBlockType(const BasicBlock *BB,
int SccNum) {
assert(getSCCNum(BB) == SccNum);
uint32_t BlockType = Inner;
if (llvm::any_of(make_range(pred_begin(BB), pred_end(BB)),
[&](const BasicBlock *Pred) {
// Consider any block that is an entry point to the SCC as
// a header.
return getSCCNum(Pred) != SccNum;
}))
BlockType |= Header;
if (llvm::any_of(
make_range(succ_begin(BB), succ_end(BB)),
[&](const BasicBlock *Succ) { return getSCCNum(Succ) != SccNum; }))
BlockType |= Exiting;
// Lazily compute the set of headers for a given SCC and cache the results
// in the SccHeaderMap.
if (SccBlocks.size() <= static_cast<unsigned>(SccNum))
SccBlocks.resize(SccNum + 1);
auto &SccBlockTypes = SccBlocks[SccNum];
if (BlockType != Inner) {
bool IsInserted;
std::tie(std::ignore, IsInserted) =
SccBlockTypes.insert(std::make_pair(BB, BlockType));
assert(IsInserted && "Duplicated block in SCC");
}
}
static void UpdatePDTWorklist(const BasicBlock *BB, PostDominatorTree *PDT,
SmallVectorImpl<const BasicBlock *> &WorkList,
SmallPtrSetImpl<const BasicBlock *> &TargetSet) {
@ -511,38 +610,6 @@ bool BranchProbabilityInfo::calcPointerHeuristics(const BasicBlock *BB) {
return true;
}
static int getSCCNum(const BasicBlock *BB,
const BranchProbabilityInfo::SccInfo &SccI) {
auto SccIt = SccI.SccNums.find(BB);
if (SccIt == SccI.SccNums.end())
return -1;
return SccIt->second;
}
// Consider any block that is an entry point to the SCC as a header.
static bool isSCCHeader(const BasicBlock *BB, int SccNum,
BranchProbabilityInfo::SccInfo &SccI) {
assert(getSCCNum(BB, SccI) == SccNum);
// Lazily compute the set of headers for a given SCC and cache the results
// in the SccHeaderMap.
if (SccI.SccHeaders.size() <= static_cast<unsigned>(SccNum))
SccI.SccHeaders.resize(SccNum + 1);
auto &HeaderMap = SccI.SccHeaders[SccNum];
bool Inserted;
BranchProbabilityInfo::SccHeaderMap::iterator HeaderMapIt;
std::tie(HeaderMapIt, Inserted) = HeaderMap.insert(std::make_pair(BB, false));
if (Inserted) {
bool IsHeader = llvm::any_of(make_range(pred_begin(BB), pred_end(BB)),
[&](const BasicBlock *Pred) {
return getSCCNum(Pred, SccI) != SccNum;
});
HeaderMapIt->second = IsHeader;
return IsHeader;
} else
return HeaderMapIt->second;
}
// Compute the unlikely successors to the block BB in the loop L, specifically
// those that are unlikely because this is a loop, and add them to the
// UnlikelyBlocks set.
@ -653,12 +720,11 @@ computeUnlikelySuccessors(const BasicBlock *BB, Loop *L,
// Calculate Edge Weights using "Loop Branch Heuristics". Predict backedges
// as taken, exiting edges as not-taken.
bool BranchProbabilityInfo::calcLoopBranchHeuristics(const BasicBlock *BB,
const LoopInfo &LI,
SccInfo &SccI) {
const LoopInfo &LI) {
int SccNum;
Loop *L = LI.getLoopFor(BB);
if (!L) {
SccNum = getSCCNum(BB, SccI);
SccNum = SccI->getSCCNum(BB);
if (SccNum < 0)
return false;
}
@ -685,9 +751,9 @@ bool BranchProbabilityInfo::calcLoopBranchHeuristics(const BasicBlock *BB,
else
InEdges.push_back(I.getSuccessorIndex());
} else {
if (getSCCNum(*I, SccI) != SccNum)
if (SccI->getSCCNum(*I) != SccNum)
ExitingEdges.push_back(I.getSuccessorIndex());
else if (isSCCHeader(*I, SccNum, SccI))
else if (SccI->isSCCHeader(*I, SccNum))
BackEdges.push_back(I.getSuccessorIndex());
else
InEdges.push_back(I.getSuccessorIndex());
@ -1072,26 +1138,7 @@ void BranchProbabilityInfo::calculate(const Function &F, const LoopInfo &LI,
assert(PostDominatedByUnreachable.empty());
assert(PostDominatedByColdCall.empty());
// Record SCC numbers of blocks in the CFG to identify irreducible loops.
// FIXME: We could only calculate this if the CFG is known to be irreducible
// (perhaps cache this info in LoopInfo if we can easily calculate it there?).
int SccNum = 0;
SccInfo SccI;
for (scc_iterator<const Function *> It = scc_begin(&F); !It.isAtEnd();
++It, ++SccNum) {
// Ignore single-block SCCs since they either aren't loops or LoopInfo will
// catch them.
const std::vector<const BasicBlock *> &Scc = *It;
if (Scc.size() == 1)
continue;
LLVM_DEBUG(dbgs() << "BPI: SCC " << SccNum << ":");
for (auto *BB : Scc) {
LLVM_DEBUG(dbgs() << " " << BB->getName());
SccI.SccNums[BB] = SccNum;
}
LLVM_DEBUG(dbgs() << "\n");
}
SccI = std::make_unique<SccInfo>(F);
std::unique_ptr<PostDominatorTree> PDTPtr;
@ -1119,7 +1166,7 @@ void BranchProbabilityInfo::calculate(const Function &F, const LoopInfo &LI,
continue;
if (calcColdCallHeuristics(BB))
continue;
if (calcLoopBranchHeuristics(BB, LI, SccI))
if (calcLoopBranchHeuristics(BB, LI))
continue;
if (calcPointerHeuristics(BB))
continue;
@ -1131,6 +1178,7 @@ void BranchProbabilityInfo::calculate(const Function &F, const LoopInfo &LI,
PostDominatedByUnreachable.clear();
PostDominatedByColdCall.clear();
SccI.release();
if (PrintBranchProb &&
(PrintBranchProbFuncName.empty() ||