#include "llvm/Analysis/BranchProbabilityInfo.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/SCCIterator.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Analysis/ConstantFolding.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/PostDominators.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Value.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
#include "llvm/Support/BranchProbability.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <cstdint>
#include <iterator>
#include <map>
#include <utility>
using namespace llvm;
#define DEBUG_TYPE "branch-prob"
static cl::opt<bool> PrintBranchProb(
"print-bpi", cl::init(false), cl::Hidden,
cl::desc("Print the branch probability info."));
cl::opt<std::string> PrintBranchProbFuncName(
"print-bpi-func-name", cl::Hidden,
cl::desc("The option to specify the name of the function "
"whose branch probability info is printed."));
INITIALIZE_PASS_BEGIN(BranchProbabilityInfoWrapperPass, "branch-prob",
"Branch Probability Analysis", false, true)
INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(PostDominatorTreeWrapperPass)
INITIALIZE_PASS_END(BranchProbabilityInfoWrapperPass, "branch-prob",
"Branch Probability Analysis", false, true)
BranchProbabilityInfoWrapperPass::BranchProbabilityInfoWrapperPass()
: FunctionPass(ID) {
initializeBranchProbabilityInfoWrapperPassPass(
*PassRegistry::getPassRegistry());
}
char BranchProbabilityInfoWrapperPass::ID = 0;
static const uint32_t LBH_TAKEN_WEIGHT = 124;
static const uint32_t LBH_NONTAKEN_WEIGHT = 4;
static const BranchProbability UR_TAKEN_PROB = BranchProbability::getRaw(1);
static const uint32_t PH_TAKEN_WEIGHT = 20;
static const uint32_t PH_NONTAKEN_WEIGHT = 12;
static const BranchProbability
PtrTakenProb(PH_TAKEN_WEIGHT, PH_TAKEN_WEIGHT + PH_NONTAKEN_WEIGHT);
static const BranchProbability
PtrUntakenProb(PH_NONTAKEN_WEIGHT, PH_TAKEN_WEIGHT + PH_NONTAKEN_WEIGHT);
using ProbabilityList = SmallVector<BranchProbability>;
using ProbabilityTable = std::map<CmpInst::Predicate, ProbabilityList>;
static const ProbabilityTable PointerTable{
{ICmpInst::ICMP_NE, {PtrTakenProb, PtrUntakenProb}}, {ICmpInst::ICMP_EQ, {PtrUntakenProb, PtrTakenProb}}, };
static const uint32_t ZH_TAKEN_WEIGHT = 20;
static const uint32_t ZH_NONTAKEN_WEIGHT = 12;
static const BranchProbability
ZeroTakenProb(ZH_TAKEN_WEIGHT, ZH_TAKEN_WEIGHT + ZH_NONTAKEN_WEIGHT);
static const BranchProbability
ZeroUntakenProb(ZH_NONTAKEN_WEIGHT, ZH_TAKEN_WEIGHT + ZH_NONTAKEN_WEIGHT);
static const ProbabilityTable ICmpWithZeroTable{
{CmpInst::ICMP_EQ, {ZeroUntakenProb, ZeroTakenProb}}, {CmpInst::ICMP_NE, {ZeroTakenProb, ZeroUntakenProb}}, {CmpInst::ICMP_SLT, {ZeroUntakenProb, ZeroTakenProb}}, {CmpInst::ICMP_SGT, {ZeroTakenProb, ZeroUntakenProb}}, };
static const ProbabilityTable ICmpWithMinusOneTable{
{CmpInst::ICMP_EQ, {ZeroUntakenProb, ZeroTakenProb}}, {CmpInst::ICMP_NE, {ZeroTakenProb, ZeroUntakenProb}}, {CmpInst::ICMP_SGT, {ZeroTakenProb, ZeroUntakenProb}}, };
static const ProbabilityTable ICmpWithOneTable{
{CmpInst::ICMP_SLT, {ZeroUntakenProb, ZeroTakenProb}}, };
static const ProbabilityTable ICmpWithLibCallTable{
{CmpInst::ICMP_EQ, {ZeroUntakenProb, ZeroTakenProb}},
{CmpInst::ICMP_NE, {ZeroTakenProb, ZeroUntakenProb}},
};
static const uint32_t FPH_TAKEN_WEIGHT = 20;
static const uint32_t FPH_NONTAKEN_WEIGHT = 12;
static const uint32_t FPH_ORD_WEIGHT = 1024 * 1024 - 1;
static const uint32_t FPH_UNO_WEIGHT = 1;
static const BranchProbability FPOrdTakenProb(FPH_ORD_WEIGHT,
FPH_ORD_WEIGHT + FPH_UNO_WEIGHT);
static const BranchProbability
FPOrdUntakenProb(FPH_UNO_WEIGHT, FPH_ORD_WEIGHT + FPH_UNO_WEIGHT);
static const BranchProbability
FPTakenProb(FPH_TAKEN_WEIGHT, FPH_TAKEN_WEIGHT + FPH_NONTAKEN_WEIGHT);
static const BranchProbability
FPUntakenProb(FPH_NONTAKEN_WEIGHT, FPH_TAKEN_WEIGHT + FPH_NONTAKEN_WEIGHT);
static const ProbabilityTable FCmpTable{
{FCmpInst::FCMP_ORD, {FPOrdTakenProb, FPOrdUntakenProb}}, {FCmpInst::FCMP_UNO, {FPOrdUntakenProb, FPOrdTakenProb}}, };
enum class BlockExecWeight : std::uint32_t {
ZERO = 0x0,
LOWEST_NON_ZERO = 0x1,
UNREACHABLE = ZERO,
NORETURN = LOWEST_NON_ZERO,
UNWIND = LOWEST_NON_ZERO,
COLD = 0xffff,
DEFAULT = 0xfffff
};
BranchProbabilityInfo::SccInfo::SccInfo(const Function &F) {
int SccNum = 0;
for (scc_iterator<const Function *> It = scc_begin(&F); !It.isAtEnd();
++It, ++SccNum) {
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 *>(Succ));
}
}
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(predecessors(BB), [&](const BasicBlock *Pred) {
return getSCCNum(Pred) != SccNum;
}))
BlockType |= Header;
if (llvm::any_of(successors(BB), [&](const BasicBlock *Succ) {
return getSCCNum(Succ) != SccNum;
}))
BlockType |= Exiting;
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");
}
}
BranchProbabilityInfo::LoopBlock::LoopBlock(const BasicBlock *BB,
const LoopInfo &LI,
const SccInfo &SccI)
: BB(BB) {
LD.first = LI.getLoopFor(BB);
if (!LD.first) {
LD.second = SccI.getSCCNum(BB);
}
}
bool BranchProbabilityInfo::isLoopEnteringEdge(const LoopEdge &Edge) const {
const auto &SrcBlock = Edge.first;
const auto &DstBlock = Edge.second;
return (DstBlock.getLoop() &&
!DstBlock.getLoop()->contains(SrcBlock.getLoop())) ||
(DstBlock.getSccNum() != -1 &&
SrcBlock.getSccNum() != DstBlock.getSccNum());
}
bool BranchProbabilityInfo::isLoopExitingEdge(const LoopEdge &Edge) const {
return isLoopEnteringEdge({Edge.second, Edge.first});
}
bool BranchProbabilityInfo::isLoopEnteringExitingEdge(
const LoopEdge &Edge) const {
return isLoopEnteringEdge(Edge) || isLoopExitingEdge(Edge);
}
bool BranchProbabilityInfo::isLoopBackEdge(const LoopEdge &Edge) const {
const auto &SrcBlock = Edge.first;
const auto &DstBlock = Edge.second;
return SrcBlock.belongsToSameLoop(DstBlock) &&
((DstBlock.getLoop() &&
DstBlock.getLoop()->getHeader() == DstBlock.getBlock()) ||
(DstBlock.getSccNum() != -1 &&
SccI->isSCCHeader(DstBlock.getBlock(), DstBlock.getSccNum())));
}
void BranchProbabilityInfo::getLoopEnterBlocks(
const LoopBlock &LB, SmallVectorImpl<BasicBlock *> &Enters) const {
if (LB.getLoop()) {
auto *Header = LB.getLoop()->getHeader();
Enters.append(pred_begin(Header), pred_end(Header));
} else {
assert(LB.getSccNum() != -1 && "LB doesn't belong to any loop?");
SccI->getSccEnterBlocks(LB.getSccNum(), Enters);
}
}
void BranchProbabilityInfo::getLoopExitBlocks(
const LoopBlock &LB, SmallVectorImpl<BasicBlock *> &Exits) const {
if (LB.getLoop()) {
LB.getLoop()->getExitBlocks(Exits);
} else {
assert(LB.getSccNum() != -1 && "LB doesn't belong to any loop?");
SccI->getSccExitBlocks(LB.getSccNum(), Exits);
}
}
bool BranchProbabilityInfo::calcMetadataWeights(const BasicBlock *BB) {
const Instruction *TI = BB->getTerminator();
assert(TI->getNumSuccessors() > 1 && "expected more than one successor!");
if (!(isa<BranchInst>(TI) || isa<SwitchInst>(TI) || isa<IndirectBrInst>(TI) ||
isa<InvokeInst>(TI)))
return false;
MDNode *WeightsNode = TI->getMetadata(LLVMContext::MD_prof);
if (!WeightsNode)
return false;
assert(TI->getNumSuccessors() < UINT32_MAX && "Too many successors");
if (WeightsNode->getNumOperands() != TI->getNumSuccessors() + 1)
return false;
uint64_t WeightSum = 0;
SmallVector<uint32_t, 2> Weights;
SmallVector<unsigned, 2> UnreachableIdxs;
SmallVector<unsigned, 2> ReachableIdxs;
Weights.reserve(TI->getNumSuccessors());
for (unsigned I = 1, E = WeightsNode->getNumOperands(); I != E; ++I) {
ConstantInt *Weight =
mdconst::dyn_extract<ConstantInt>(WeightsNode->getOperand(I));
if (!Weight)
return false;
assert(Weight->getValue().getActiveBits() <= 32 &&
"Too many bits for uint32_t");
Weights.push_back(Weight->getZExtValue());
WeightSum += Weights.back();
const LoopBlock SrcLoopBB = getLoopBlock(BB);
const LoopBlock DstLoopBB = getLoopBlock(TI->getSuccessor(I - 1));
auto EstimatedWeight = getEstimatedEdgeWeight({SrcLoopBB, DstLoopBB});
if (EstimatedWeight &&
*EstimatedWeight <= static_cast<uint32_t>(BlockExecWeight::UNREACHABLE))
UnreachableIdxs.push_back(I - 1);
else
ReachableIdxs.push_back(I - 1);
}
assert(Weights.size() == TI->getNumSuccessors() && "Checked above");
uint64_t ScalingFactor =
(WeightSum > UINT32_MAX) ? WeightSum / UINT32_MAX + 1 : 1;
if (ScalingFactor > 1) {
WeightSum = 0;
for (unsigned I = 0, E = TI->getNumSuccessors(); I != E; ++I) {
Weights[I] /= ScalingFactor;
WeightSum += Weights[I];
}
}
assert(WeightSum <= UINT32_MAX &&
"Expected weights to scale down to 32 bits");
if (WeightSum == 0 || ReachableIdxs.size() == 0) {
for (unsigned I = 0, E = TI->getNumSuccessors(); I != E; ++I)
Weights[I] = 1;
WeightSum = TI->getNumSuccessors();
}
SmallVector<BranchProbability, 2> BP;
for (unsigned I = 0, E = TI->getNumSuccessors(); I != E; ++I)
BP.push_back({ Weights[I], static_cast<uint32_t>(WeightSum) });
if (UnreachableIdxs.size() == 0 || ReachableIdxs.size() == 0) {
setEdgeProbability(BB, BP);
return true;
}
auto UnreachableProb = UR_TAKEN_PROB;
for (auto I : UnreachableIdxs)
if (UnreachableProb < BP[I]) {
BP[I] = UnreachableProb;
}
BranchProbability NewUnreachableSum = BranchProbability::getZero();
for (auto I : UnreachableIdxs)
NewUnreachableSum += BP[I];
BranchProbability NewReachableSum =
BranchProbability::getOne() - NewUnreachableSum;
BranchProbability OldReachableSum = BranchProbability::getZero();
for (auto I : ReachableIdxs)
OldReachableSum += BP[I];
if (OldReachableSum != NewReachableSum) { if (OldReachableSum.isZero()) {
BranchProbability PerEdge = NewReachableSum / ReachableIdxs.size();
for (auto I : ReachableIdxs)
BP[I] = PerEdge;
} else {
for (auto I : ReachableIdxs) {
uint64_t Mul = static_cast<uint64_t>(NewReachableSum.getNumerator()) *
BP[I].getNumerator();
uint32_t Div = static_cast<uint32_t>(
divideNearest(Mul, OldReachableSum.getNumerator()));
BP[I] = BranchProbability::getRaw(Div);
}
}
}
setEdgeProbability(BB, BP);
return true;
}
bool BranchProbabilityInfo::calcPointerHeuristics(const BasicBlock *BB) {
const BranchInst *BI = dyn_cast<BranchInst>(BB->getTerminator());
if (!BI || !BI->isConditional())
return false;
Value *Cond = BI->getCondition();
ICmpInst *CI = dyn_cast<ICmpInst>(Cond);
if (!CI || !CI->isEquality())
return false;
Value *LHS = CI->getOperand(0);
if (!LHS->getType()->isPointerTy())
return false;
assert(CI->getOperand(1)->getType()->isPointerTy());
auto Search = PointerTable.find(CI->getPredicate());
if (Search == PointerTable.end())
return false;
setEdgeProbability(BB, Search->second);
return true;
}
static void
computeUnlikelySuccessors(const BasicBlock *BB, Loop *L,
SmallPtrSetImpl<const BasicBlock*> &UnlikelyBlocks) {
const BranchInst *BI = dyn_cast<BranchInst>(BB->getTerminator());
if (!BI || !BI->isConditional())
return;
CmpInst *CI = dyn_cast<CmpInst>(BI->getCondition());
if (!CI || !isa<Instruction>(CI->getOperand(0)) ||
!isa<Constant>(CI->getOperand(1)))
return;
Instruction *CmpLHS = dyn_cast<Instruction>(CI->getOperand(0));
PHINode *CmpPHI = dyn_cast<PHINode>(CmpLHS);
Constant *CmpConst = dyn_cast<Constant>(CI->getOperand(1));
SmallVector<BinaryOperator *, 1> InstChain;
while (!CmpPHI && CmpLHS && isa<BinaryOperator>(CmpLHS) &&
isa<Constant>(CmpLHS->getOperand(1))) {
if (!L->contains(CmpLHS))
return;
InstChain.push_back(cast<BinaryOperator>(CmpLHS));
CmpLHS = dyn_cast<Instruction>(CmpLHS->getOperand(0));
if (CmpLHS)
CmpPHI = dyn_cast<PHINode>(CmpLHS);
}
if (!CmpPHI || !L->contains(CmpPHI))
return;
SmallPtrSet<PHINode*, 8> VisitedInsts;
SmallVector<PHINode*, 8> WorkList;
WorkList.push_back(CmpPHI);
VisitedInsts.insert(CmpPHI);
while (!WorkList.empty()) {
PHINode *P = WorkList.pop_back_val();
for (BasicBlock *B : P->blocks()) {
if (!L->contains(B))
continue;
Value *V = P->getIncomingValueForBlock(B);
if (PHINode *PN = dyn_cast<PHINode>(V)) {
if (VisitedInsts.insert(PN).second)
WorkList.push_back(PN);
continue;
}
Constant *CmpLHSConst = dyn_cast<Constant>(V);
if (!CmpLHSConst || !llvm::is_contained(successors(BB), B))
continue;
const DataLayout &DL = BB->getModule()->getDataLayout();
for (Instruction *I : llvm::reverse(InstChain)) {
CmpLHSConst = ConstantFoldBinaryOpOperands(
I->getOpcode(), CmpLHSConst, cast<Constant>(I->getOperand(1)), DL);
if (!CmpLHSConst)
break;
}
if (!CmpLHSConst)
continue;
Constant *Result = ConstantExpr::getCompare(CI->getPredicate(),
CmpLHSConst, CmpConst, true);
if (Result &&
((Result->isZeroValue() && B == BI->getSuccessor(0)) ||
(Result->isOneValue() && B == BI->getSuccessor(1))))
UnlikelyBlocks.insert(B);
}
}
}
Optional<uint32_t>
BranchProbabilityInfo::getEstimatedBlockWeight(const BasicBlock *BB) const {
auto WeightIt = EstimatedBlockWeight.find(BB);
if (WeightIt == EstimatedBlockWeight.end())
return None;
return WeightIt->second;
}
Optional<uint32_t>
BranchProbabilityInfo::getEstimatedLoopWeight(const LoopData &L) const {
auto WeightIt = EstimatedLoopWeight.find(L);
if (WeightIt == EstimatedLoopWeight.end())
return None;
return WeightIt->second;
}
Optional<uint32_t>
BranchProbabilityInfo::getEstimatedEdgeWeight(const LoopEdge &Edge) const {
return isLoopEnteringEdge(Edge)
? getEstimatedLoopWeight(Edge.second.getLoopData())
: getEstimatedBlockWeight(Edge.second.getBlock());
}
template <class IterT>
Optional<uint32_t> BranchProbabilityInfo::getMaxEstimatedEdgeWeight(
const LoopBlock &SrcLoopBB, iterator_range<IterT> Successors) const {
SmallVector<uint32_t, 4> Weights;
Optional<uint32_t> MaxWeight;
for (const BasicBlock *DstBB : Successors) {
const LoopBlock DstLoopBB = getLoopBlock(DstBB);
auto Weight = getEstimatedEdgeWeight({SrcLoopBB, DstLoopBB});
if (!Weight)
return None;
if (!MaxWeight || *MaxWeight < *Weight)
MaxWeight = Weight;
}
return MaxWeight;
}
bool BranchProbabilityInfo::updateEstimatedBlockWeight(
LoopBlock &LoopBB, uint32_t BBWeight,
SmallVectorImpl<BasicBlock *> &BlockWorkList,
SmallVectorImpl<LoopBlock> &LoopWorkList) {
BasicBlock *BB = LoopBB.getBlock();
if (!EstimatedBlockWeight.insert({BB, BBWeight}).second)
return false;
for (BasicBlock *PredBlock : predecessors(BB)) {
LoopBlock PredLoop = getLoopBlock(PredBlock);
if (isLoopExitingEdge({PredLoop, LoopBB})) {
if (!EstimatedLoopWeight.count(PredLoop.getLoopData()))
LoopWorkList.push_back(PredLoop);
} else if (!EstimatedBlockWeight.count(PredBlock))
BlockWorkList.push_back(PredBlock);
}
return true;
}
void BranchProbabilityInfo::propagateEstimatedBlockWeight(
const LoopBlock &LoopBB, DominatorTree *DT, PostDominatorTree *PDT,
uint32_t BBWeight, SmallVectorImpl<BasicBlock *> &BlockWorkList,
SmallVectorImpl<LoopBlock> &LoopWorkList) {
const BasicBlock *BB = LoopBB.getBlock();
const auto *DTStartNode = DT->getNode(BB);
const auto *PDTStartNode = PDT->getNode(BB);
for (const auto *DTNode = DTStartNode; DTNode != nullptr;
DTNode = DTNode->getIDom()) {
auto *DomBB = DTNode->getBlock();
if (!PDT->dominates(PDTStartNode, PDT->getNode(DomBB)))
break;
LoopBlock DomLoopBB = getLoopBlock(DomBB);
const LoopEdge Edge{DomLoopBB, LoopBB};
if (!isLoopEnteringExitingEdge(Edge)) {
if (!updateEstimatedBlockWeight(DomLoopBB, BBWeight, BlockWorkList,
LoopWorkList))
break;
} else if (isLoopExitingEdge(Edge)) {
LoopWorkList.push_back(DomLoopBB);
}
}
}
Optional<uint32_t> BranchProbabilityInfo::getInitialEstimatedBlockWeight(
const BasicBlock *BB) {
auto hasNoReturn = [&](const BasicBlock *BB) {
for (const auto &I : reverse(*BB))
if (const CallInst *CI = dyn_cast<CallInst>(&I))
if (CI->hasFnAttr(Attribute::NoReturn))
return true;
return false;
};
if (isa<UnreachableInst>(BB->getTerminator()) ||
BB->getTerminatingDeoptimizeCall())
return hasNoReturn(BB)
? static_cast<uint32_t>(BlockExecWeight::NORETURN)
: static_cast<uint32_t>(BlockExecWeight::UNREACHABLE);
for (const auto *Pred : predecessors(BB))
if (Pred)
if (const auto *II = dyn_cast<InvokeInst>(Pred->getTerminator()))
if (II->getUnwindDest() == BB)
return static_cast<uint32_t>(BlockExecWeight::UNWIND);
for (const auto &I : *BB)
if (const CallInst *CI = dyn_cast<CallInst>(&I))
if (CI->hasFnAttr(Attribute::Cold))
return static_cast<uint32_t>(BlockExecWeight::COLD);
return None;
}
void BranchProbabilityInfo::computeEestimateBlockWeight(
const Function &F, DominatorTree *DT, PostDominatorTree *PDT) {
SmallVector<BasicBlock *, 8> BlockWorkList;
SmallVector<LoopBlock, 8> LoopWorkList;
ReversePostOrderTraversal<const Function *> RPOT(&F);
for (const auto *BB : RPOT)
if (auto BBWeight = getInitialEstimatedBlockWeight(BB))
propagateEstimatedBlockWeight(getLoopBlock(BB), DT, PDT, BBWeight.value(),
BlockWorkList, LoopWorkList);
do {
while (!LoopWorkList.empty()) {
const LoopBlock LoopBB = LoopWorkList.pop_back_val();
if (EstimatedLoopWeight.count(LoopBB.getLoopData()))
continue;
SmallVector<BasicBlock *, 4> Exits;
getLoopExitBlocks(LoopBB, Exits);
auto LoopWeight = getMaxEstimatedEdgeWeight(
LoopBB, make_range(Exits.begin(), Exits.end()));
if (LoopWeight) {
if (LoopWeight <= static_cast<uint32_t>(BlockExecWeight::UNREACHABLE))
LoopWeight = static_cast<uint32_t>(BlockExecWeight::LOWEST_NON_ZERO);
EstimatedLoopWeight.insert({LoopBB.getLoopData(), *LoopWeight});
getLoopEnterBlocks(LoopBB, BlockWorkList);
}
}
while (!BlockWorkList.empty()) {
const BasicBlock *BB = BlockWorkList.pop_back_val();
if (EstimatedBlockWeight.count(BB))
continue;
const LoopBlock LoopBB = getLoopBlock(BB);
auto MaxWeight = getMaxEstimatedEdgeWeight(LoopBB, successors(BB));
if (MaxWeight)
propagateEstimatedBlockWeight(LoopBB, DT, PDT, *MaxWeight,
BlockWorkList, LoopWorkList);
}
} while (!BlockWorkList.empty() || !LoopWorkList.empty());
}
bool BranchProbabilityInfo::calcEstimatedHeuristics(const BasicBlock *BB) {
assert(BB->getTerminator()->getNumSuccessors() > 1 &&
"expected more than one successor!");
const LoopBlock LoopBB = getLoopBlock(BB);
SmallPtrSet<const BasicBlock *, 8> UnlikelyBlocks;
uint32_t TC = LBH_TAKEN_WEIGHT / LBH_NONTAKEN_WEIGHT;
if (LoopBB.getLoop())
computeUnlikelySuccessors(BB, LoopBB.getLoop(), UnlikelyBlocks);
bool FoundEstimatedWeight = false;
SmallVector<uint32_t, 4> SuccWeights;
uint64_t TotalWeight = 0;
for (const BasicBlock *SuccBB : successors(BB)) {
Optional<uint32_t> Weight;
const LoopBlock SuccLoopBB = getLoopBlock(SuccBB);
const LoopEdge Edge{LoopBB, SuccLoopBB};
Weight = getEstimatedEdgeWeight(Edge);
if (isLoopExitingEdge(Edge) &&
Weight != static_cast<uint32_t>(BlockExecWeight::ZERO)) {
Weight = std::max(
static_cast<uint32_t>(BlockExecWeight::LOWEST_NON_ZERO),
Weight.value_or(static_cast<uint32_t>(BlockExecWeight::DEFAULT)) /
TC);
}
bool IsUnlikelyEdge = LoopBB.getLoop() && UnlikelyBlocks.contains(SuccBB);
if (IsUnlikelyEdge &&
Weight != static_cast<uint32_t>(BlockExecWeight::ZERO)) {
Weight = std::max(
static_cast<uint32_t>(BlockExecWeight::LOWEST_NON_ZERO),
Weight.value_or(static_cast<uint32_t>(BlockExecWeight::DEFAULT)) / 2);
}
if (Weight)
FoundEstimatedWeight = true;
auto WeightVal =
Weight.value_or(static_cast<uint32_t>(BlockExecWeight::DEFAULT));
TotalWeight += WeightVal;
SuccWeights.push_back(WeightVal);
}
if (!FoundEstimatedWeight || TotalWeight == 0)
return false;
assert(SuccWeights.size() == succ_size(BB) && "Missed successor?");
const unsigned SuccCount = SuccWeights.size();
if (TotalWeight > UINT32_MAX) {
uint64_t ScalingFactor = TotalWeight / UINT32_MAX + 1;
TotalWeight = 0;
for (unsigned Idx = 0; Idx < SuccCount; ++Idx) {
SuccWeights[Idx] /= ScalingFactor;
if (SuccWeights[Idx] == static_cast<uint32_t>(BlockExecWeight::ZERO))
SuccWeights[Idx] =
static_cast<uint32_t>(BlockExecWeight::LOWEST_NON_ZERO);
TotalWeight += SuccWeights[Idx];
}
assert(TotalWeight <= UINT32_MAX && "Total weight overflows");
}
SmallVector<BranchProbability, 4> EdgeProbabilities(
SuccCount, BranchProbability::getUnknown());
for (unsigned Idx = 0; Idx < SuccCount; ++Idx) {
EdgeProbabilities[Idx] =
BranchProbability(SuccWeights[Idx], (uint32_t)TotalWeight);
}
setEdgeProbability(BB, EdgeProbabilities);
return true;
}
bool BranchProbabilityInfo::calcZeroHeuristics(const BasicBlock *BB,
const TargetLibraryInfo *TLI) {
const BranchInst *BI = dyn_cast<BranchInst>(BB->getTerminator());
if (!BI || !BI->isConditional())
return false;
Value *Cond = BI->getCondition();
ICmpInst *CI = dyn_cast<ICmpInst>(Cond);
if (!CI)
return false;
auto GetConstantInt = [](Value *V) {
if (auto *I = dyn_cast<BitCastInst>(V))
return dyn_cast<ConstantInt>(I->getOperand(0));
return dyn_cast<ConstantInt>(V);
};
Value *RHS = CI->getOperand(1);
ConstantInt *CV = GetConstantInt(RHS);
if (!CV)
return false;
if (Instruction *LHS = dyn_cast<Instruction>(CI->getOperand(0)))
if (LHS->getOpcode() == Instruction::And)
if (ConstantInt *AndRHS = GetConstantInt(LHS->getOperand(1)))
if (AndRHS->getValue().isPowerOf2())
return false;
LibFunc Func = NumLibFuncs;
if (TLI)
if (CallInst *Call = dyn_cast<CallInst>(CI->getOperand(0)))
if (Function *CalledFn = Call->getCalledFunction())
TLI->getLibFunc(*CalledFn, Func);
ProbabilityTable::const_iterator Search;
if (Func == LibFunc_strcasecmp ||
Func == LibFunc_strcmp ||
Func == LibFunc_strncasecmp ||
Func == LibFunc_strncmp ||
Func == LibFunc_memcmp ||
Func == LibFunc_bcmp) {
Search = ICmpWithLibCallTable.find(CI->getPredicate());
if (Search == ICmpWithLibCallTable.end())
return false;
} else if (CV->isZero()) {
Search = ICmpWithZeroTable.find(CI->getPredicate());
if (Search == ICmpWithZeroTable.end())
return false;
} else if (CV->isOne()) {
Search = ICmpWithOneTable.find(CI->getPredicate());
if (Search == ICmpWithOneTable.end())
return false;
} else if (CV->isMinusOne()) {
Search = ICmpWithMinusOneTable.find(CI->getPredicate());
if (Search == ICmpWithMinusOneTable.end())
return false;
} else {
return false;
}
setEdgeProbability(BB, Search->second);
return true;
}
bool BranchProbabilityInfo::calcFloatingPointHeuristics(const BasicBlock *BB) {
const BranchInst *BI = dyn_cast<BranchInst>(BB->getTerminator());
if (!BI || !BI->isConditional())
return false;
Value *Cond = BI->getCondition();
FCmpInst *FCmp = dyn_cast<FCmpInst>(Cond);
if (!FCmp)
return false;
ProbabilityList ProbList;
if (FCmp->isEquality()) {
ProbList = !FCmp->isTrueWhenEqual() ?
ProbabilityList({FPTakenProb, FPUntakenProb}) :
ProbabilityList({FPUntakenProb, FPTakenProb});
} else {
auto Search = FCmpTable.find(FCmp->getPredicate());
if (Search == FCmpTable.end())
return false;
ProbList = Search->second;
}
setEdgeProbability(BB, ProbList);
return true;
}
void BranchProbabilityInfo::releaseMemory() {
Probs.clear();
Handles.clear();
}
bool BranchProbabilityInfo::invalidate(Function &, const PreservedAnalyses &PA,
FunctionAnalysisManager::Invalidator &) {
auto PAC = PA.getChecker<BranchProbabilityAnalysis>();
return !(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Function>>() ||
PAC.preservedSet<CFGAnalyses>());
}
void BranchProbabilityInfo::print(raw_ostream &OS) const {
OS << "---- Branch Probabilities ----\n";
assert(LastF && "Cannot print prior to running over a function");
for (const auto &BI : *LastF) {
for (const BasicBlock *Succ : successors(&BI))
printEdgeProbability(OS << " ", &BI, Succ);
}
}
bool BranchProbabilityInfo::
isEdgeHot(const BasicBlock *Src, const BasicBlock *Dst) const {
return getEdgeProbability(Src, Dst) > BranchProbability(4, 5);
}
BranchProbability
BranchProbabilityInfo::getEdgeProbability(const BasicBlock *Src,
unsigned IndexInSuccessors) const {
auto I = Probs.find(std::make_pair(Src, IndexInSuccessors));
assert((Probs.end() == Probs.find(std::make_pair(Src, 0))) ==
(Probs.end() == I) &&
"Probability for I-th successor must always be defined along with the "
"probability for the first successor");
if (I != Probs.end())
return I->second;
return {1, static_cast<uint32_t>(succ_size(Src))};
}
BranchProbability
BranchProbabilityInfo::getEdgeProbability(const BasicBlock *Src,
const_succ_iterator Dst) const {
return getEdgeProbability(Src, Dst.getSuccessorIndex());
}
BranchProbability
BranchProbabilityInfo::getEdgeProbability(const BasicBlock *Src,
const BasicBlock *Dst) const {
if (!Probs.count(std::make_pair(Src, 0)))
return BranchProbability(llvm::count(successors(Src), Dst), succ_size(Src));
auto Prob = BranchProbability::getZero();
for (const_succ_iterator I = succ_begin(Src), E = succ_end(Src); I != E; ++I)
if (*I == Dst)
Prob += Probs.find(std::make_pair(Src, I.getSuccessorIndex()))->second;
return Prob;
}
void BranchProbabilityInfo::setEdgeProbability(
const BasicBlock *Src, const SmallVectorImpl<BranchProbability> &Probs) {
assert(Src->getTerminator()->getNumSuccessors() == Probs.size());
eraseBlock(Src); if (Probs.size() == 0)
return;
Handles.insert(BasicBlockCallbackVH(Src, this));
uint64_t TotalNumerator = 0;
for (unsigned SuccIdx = 0; SuccIdx < Probs.size(); ++SuccIdx) {
this->Probs[std::make_pair(Src, SuccIdx)] = Probs[SuccIdx];
LLVM_DEBUG(dbgs() << "set edge " << Src->getName() << " -> " << SuccIdx
<< " successor probability to " << Probs[SuccIdx]
<< "\n");
TotalNumerator += Probs[SuccIdx].getNumerator();
}
assert(TotalNumerator <= BranchProbability::getDenominator() + Probs.size());
assert(TotalNumerator >= BranchProbability::getDenominator() - Probs.size());
(void)TotalNumerator;
}
void BranchProbabilityInfo::copyEdgeProbabilities(BasicBlock *Src,
BasicBlock *Dst) {
eraseBlock(Dst); unsigned NumSuccessors = Src->getTerminator()->getNumSuccessors();
assert(NumSuccessors == Dst->getTerminator()->getNumSuccessors());
if (NumSuccessors == 0)
return; if (this->Probs.find(std::make_pair(Src, 0)) == this->Probs.end())
return;
Handles.insert(BasicBlockCallbackVH(Dst, this));
for (unsigned SuccIdx = 0; SuccIdx < NumSuccessors; ++SuccIdx) {
auto Prob = this->Probs[std::make_pair(Src, SuccIdx)];
this->Probs[std::make_pair(Dst, SuccIdx)] = Prob;
LLVM_DEBUG(dbgs() << "set edge " << Dst->getName() << " -> " << SuccIdx
<< " successor probability to " << Prob << "\n");
}
}
raw_ostream &
BranchProbabilityInfo::printEdgeProbability(raw_ostream &OS,
const BasicBlock *Src,
const BasicBlock *Dst) const {
const BranchProbability Prob = getEdgeProbability(Src, Dst);
OS << "edge " << Src->getName() << " -> " << Dst->getName()
<< " probability is " << Prob
<< (isEdgeHot(Src, Dst) ? " [HOT edge]\n" : "\n");
return OS;
}
void BranchProbabilityInfo::eraseBlock(const BasicBlock *BB) {
LLVM_DEBUG(dbgs() << "eraseBlock " << BB->getName() << "\n");
Handles.erase(BasicBlockCallbackVH(BB, this));
for (unsigned I = 0;; ++I) {
auto MapI = Probs.find(std::make_pair(BB, I));
if (MapI == Probs.end()) {
assert(Probs.count(std::make_pair(BB, I + 1)) == 0 &&
"Must be no more successors");
return;
}
Probs.erase(MapI);
}
}
void BranchProbabilityInfo::calculate(const Function &F, const LoopInfo &LoopI,
const TargetLibraryInfo *TLI,
DominatorTree *DT,
PostDominatorTree *PDT) {
LLVM_DEBUG(dbgs() << "---- Branch Probability Info : " << F.getName()
<< " ----\n\n");
LastF = &F; LI = &LoopI;
SccI = std::make_unique<SccInfo>(F);
assert(EstimatedBlockWeight.empty());
assert(EstimatedLoopWeight.empty());
std::unique_ptr<DominatorTree> DTPtr;
std::unique_ptr<PostDominatorTree> PDTPtr;
if (!DT) {
DTPtr = std::make_unique<DominatorTree>(const_cast<Function &>(F));
DT = DTPtr.get();
}
if (!PDT) {
PDTPtr = std::make_unique<PostDominatorTree>(const_cast<Function &>(F));
PDT = PDTPtr.get();
}
computeEestimateBlockWeight(F, DT, PDT);
for (const auto *BB : post_order(&F.getEntryBlock())) {
LLVM_DEBUG(dbgs() << "Computing probabilities for " << BB->getName()
<< "\n");
if (BB->getTerminator()->getNumSuccessors() < 2)
continue;
if (calcMetadataWeights(BB))
continue;
if (calcEstimatedHeuristics(BB))
continue;
if (calcPointerHeuristics(BB))
continue;
if (calcZeroHeuristics(BB, TLI))
continue;
if (calcFloatingPointHeuristics(BB))
continue;
}
EstimatedLoopWeight.clear();
EstimatedBlockWeight.clear();
SccI.reset();
if (PrintBranchProb &&
(PrintBranchProbFuncName.empty() ||
F.getName().equals(PrintBranchProbFuncName))) {
print(dbgs());
}
}
void BranchProbabilityInfoWrapperPass::getAnalysisUsage(
AnalysisUsage &AU) const {
AU.addRequired<DominatorTreeWrapperPass>();
AU.addRequired<LoopInfoWrapperPass>();
AU.addRequired<TargetLibraryInfoWrapperPass>();
AU.addRequired<DominatorTreeWrapperPass>();
AU.addRequired<PostDominatorTreeWrapperPass>();
AU.setPreservesAll();
}
bool BranchProbabilityInfoWrapperPass::runOnFunction(Function &F) {
const LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
const TargetLibraryInfo &TLI =
getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F);
DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
PostDominatorTree &PDT =
getAnalysis<PostDominatorTreeWrapperPass>().getPostDomTree();
BPI.calculate(F, LI, &TLI, &DT, &PDT);
return false;
}
void BranchProbabilityInfoWrapperPass::releaseMemory() { BPI.releaseMemory(); }
void BranchProbabilityInfoWrapperPass::print(raw_ostream &OS,
const Module *) const {
BPI.print(OS);
}
AnalysisKey BranchProbabilityAnalysis::Key;
BranchProbabilityInfo
BranchProbabilityAnalysis::run(Function &F, FunctionAnalysisManager &AM) {
BranchProbabilityInfo BPI;
BPI.calculate(F, AM.getResult<LoopAnalysis>(F),
&AM.getResult<TargetLibraryAnalysis>(F),
&AM.getResult<DominatorTreeAnalysis>(F),
&AM.getResult<PostDominatorTreeAnalysis>(F));
return BPI;
}
PreservedAnalyses
BranchProbabilityPrinterPass::run(Function &F, FunctionAnalysisManager &AM) {
OS << "Printing analysis results of BPI for function "
<< "'" << F.getName() << "':"
<< "\n";
AM.getResult<BranchProbabilityAnalysis>(F).print(OS);
return PreservedAnalyses::all();
}