//===-- BranchProbabilityInfo.cpp - Branch Probability Analysis -*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Loops should be simplified before this analysis. // //===----------------------------------------------------------------------===// #include "llvm/Constants.h" #include "llvm/Instructions.h" #include "llvm/Analysis/BranchProbabilityInfo.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Support/Debug.h" using namespace llvm; INITIALIZE_PASS_BEGIN(BranchProbabilityInfo, "branch-prob", "Branch Probability Analysis", false, true) INITIALIZE_PASS_DEPENDENCY(LoopInfo) INITIALIZE_PASS_END(BranchProbabilityInfo, "branch-prob", "Branch Probability Analysis", false, true) char BranchProbabilityInfo::ID = 0; namespace { // Please note that BranchProbabilityAnalysis is not a FunctionPass. // It is created by BranchProbabilityInfo (which is a FunctionPass), which // provides a clear interface. Thanks to that, all heuristics and other // private methods are hidden in the .cpp file. class BranchProbabilityAnalysis { typedef std::pair Edge; BranchProbabilityInfo *BP; LoopInfo *LI; // Weights are for internal use only. They are used by heuristics to help to // estimate edges' probability. Example: // // Using "Loop Branch Heuristics" we predict weights of edges for the // block BB2. // ... // | // V // BB1<-+ // | | // | | (Weight = 124) // V | // BB2--+ // | // | (Weight = 4) // V // BB3 // // Probability of the edge BB2->BB1 = 124 / (124 + 4) = 0.96875 // Probability of the edge BB2->BB3 = 4 / (124 + 4) = 0.03125 static const uint32_t LBH_TAKEN_WEIGHT = 124; static const uint32_t LBH_NONTAKEN_WEIGHT = 4; static const uint32_t RH_TAKEN_WEIGHT = 24; static const uint32_t RH_NONTAKEN_WEIGHT = 8; static const uint32_t PH_TAKEN_WEIGHT = 20; static const uint32_t PH_NONTAKEN_WEIGHT = 12; static const uint32_t ZH_TAKEN_WEIGHT = 20; static const uint32_t ZH_NONTAKEN_WEIGHT = 12; // Standard weight value. Used when none of the heuristics set weight for // the edge. static const uint32_t NORMAL_WEIGHT = 16; // Minimum weight of an edge. Please note, that weight is NEVER 0. static const uint32_t MIN_WEIGHT = 1; // Return TRUE if BB leads directly to a Return Instruction. static bool isReturningBlock(BasicBlock *BB) { SmallPtrSet Visited; while (true) { TerminatorInst *TI = BB->getTerminator(); if (isa(TI)) return true; if (TI->getNumSuccessors() > 1) break; // It is unreachable block which we can consider as a return instruction. if (TI->getNumSuccessors() == 0) return true; Visited.insert(BB); BB = TI->getSuccessor(0); // Stop if cycle is detected. if (Visited.count(BB)) return false; } return false; } uint32_t getMaxWeightFor(BasicBlock *BB) const { return UINT32_MAX / BB->getTerminator()->getNumSuccessors(); } public: BranchProbabilityAnalysis(BranchProbabilityInfo *BP, LoopInfo *LI) : BP(BP), LI(LI) { } // Return Heuristics bool calcReturnHeuristics(BasicBlock *BB); // Pointer Heuristics bool calcPointerHeuristics(BasicBlock *BB); // Loop Branch Heuristics bool calcLoopBranchHeuristics(BasicBlock *BB); // Zero Heurestics bool calcZeroHeuristics(BasicBlock *BB); bool runOnFunction(Function &F); }; } // end anonymous namespace // Calculate Edge Weights using "Return Heuristics". Predict a successor which // leads directly to Return Instruction will not be taken. bool BranchProbabilityAnalysis::calcReturnHeuristics(BasicBlock *BB){ if (BB->getTerminator()->getNumSuccessors() == 1) return false; SmallPtrSet ReturningEdges; SmallPtrSet StayEdges; for (succ_iterator I = succ_begin(BB), E = succ_end(BB); I != E; ++I) { BasicBlock *Succ = *I; if (isReturningBlock(Succ)) ReturningEdges.insert(Succ); else StayEdges.insert(Succ); } if (uint32_t numStayEdges = StayEdges.size()) { uint32_t stayWeight = RH_TAKEN_WEIGHT / numStayEdges; if (stayWeight < NORMAL_WEIGHT) stayWeight = NORMAL_WEIGHT; for (SmallPtrSet::iterator I = StayEdges.begin(), E = StayEdges.end(); I != E; ++I) BP->setEdgeWeight(BB, *I, stayWeight); } if (uint32_t numRetEdges = ReturningEdges.size()) { uint32_t retWeight = RH_NONTAKEN_WEIGHT / numRetEdges; if (retWeight < MIN_WEIGHT) retWeight = MIN_WEIGHT; for (SmallPtrSet::iterator I = ReturningEdges.begin(), E = ReturningEdges.end(); I != E; ++I) { BP->setEdgeWeight(BB, *I, retWeight); } } return ReturningEdges.size() > 0; } // Calculate Edge Weights using "Pointer Heuristics". Predict a comparsion // between two pointer or pointer and NULL will fail. bool BranchProbabilityAnalysis::calcPointerHeuristics(BasicBlock *BB) { BranchInst * BI = dyn_cast(BB->getTerminator()); if (!BI || !BI->isConditional()) return false; Value *Cond = BI->getCondition(); ICmpInst *CI = dyn_cast(Cond); if (!CI || !CI->isEquality()) return false; Value *LHS = CI->getOperand(0); if (!LHS->getType()->isPointerTy()) return false; assert(CI->getOperand(1)->getType()->isPointerTy()); BasicBlock *Taken = BI->getSuccessor(0); BasicBlock *NonTaken = BI->getSuccessor(1); // p != 0 -> isProb = true // p == 0 -> isProb = false // p != q -> isProb = true // p == q -> isProb = false; bool isProb = CI->getPredicate() == ICmpInst::ICMP_NE; if (!isProb) std::swap(Taken, NonTaken); BP->setEdgeWeight(BB, Taken, PH_TAKEN_WEIGHT); BP->setEdgeWeight(BB, NonTaken, PH_NONTAKEN_WEIGHT); return true; } // Calculate Edge Weights using "Loop Branch Heuristics". Predict backedges // as taken, exiting edges as not-taken. bool BranchProbabilityAnalysis::calcLoopBranchHeuristics(BasicBlock *BB) { uint32_t numSuccs = BB->getTerminator()->getNumSuccessors(); Loop *L = LI->getLoopFor(BB); if (!L) return false; SmallPtrSet BackEdges; SmallPtrSet ExitingEdges; SmallPtrSet InEdges; // Edges from header to the loop. bool isHeader = BB == L->getHeader(); for (succ_iterator I = succ_begin(BB), E = succ_end(BB); I != E; ++I) { BasicBlock *Succ = *I; Loop *SuccL = LI->getLoopFor(Succ); if (SuccL != L) ExitingEdges.insert(Succ); else if (Succ == L->getHeader()) BackEdges.insert(Succ); else if (isHeader) InEdges.insert(Succ); } if (uint32_t numBackEdges = BackEdges.size()) { uint32_t backWeight = LBH_TAKEN_WEIGHT / numBackEdges; if (backWeight < NORMAL_WEIGHT) backWeight = NORMAL_WEIGHT; for (SmallPtrSet::iterator EI = BackEdges.begin(), EE = BackEdges.end(); EI != EE; ++EI) { BasicBlock *Back = *EI; BP->setEdgeWeight(BB, Back, backWeight); } } if (uint32_t numInEdges = InEdges.size()) { uint32_t inWeight = LBH_TAKEN_WEIGHT / numInEdges; if (inWeight < NORMAL_WEIGHT) inWeight = NORMAL_WEIGHT; for (SmallPtrSet::iterator EI = InEdges.begin(), EE = InEdges.end(); EI != EE; ++EI) { BasicBlock *Back = *EI; BP->setEdgeWeight(BB, Back, inWeight); } } uint32_t numExitingEdges = ExitingEdges.size(); if (uint32_t numNonExitingEdges = numSuccs - numExitingEdges) { uint32_t exitWeight = LBH_NONTAKEN_WEIGHT / numNonExitingEdges; if (exitWeight < MIN_WEIGHT) exitWeight = MIN_WEIGHT; for (SmallPtrSet::iterator EI = ExitingEdges.begin(), EE = ExitingEdges.end(); EI != EE; ++EI) { BasicBlock *Exiting = *EI; BP->setEdgeWeight(BB, Exiting, exitWeight); } } return true; } bool BranchProbabilityAnalysis::calcZeroHeuristics(BasicBlock *BB) { BranchInst * BI = dyn_cast(BB->getTerminator()); if (!BI || !BI->isConditional()) return false; Value *Cond = BI->getCondition(); ICmpInst *CI = dyn_cast(Cond); if (!CI) return false; Value *RHS = CI->getOperand(1); ConstantInt *CV = dyn_cast(RHS); if (!CV) return false; bool isProb; if (CV->isZero()) { switch (CI->getPredicate()) { case CmpInst::ICMP_EQ: // X == 0 -> Unlikely isProb = false; break; case CmpInst::ICMP_NE: // X != 0 -> Likely isProb = true; break; case CmpInst::ICMP_SLT: // X < 0 -> Unlikely isProb = false; break; case CmpInst::ICMP_SGT: // X > 0 -> Likely isProb = true; break; default: return false; } } else if (CV->isOne() && CI->getPredicate() == CmpInst::ICMP_SLT) { // InstCombine canonicalizes X <= 0 into X < 1. // X <= 0 -> Unlikely isProb = false; } else if (CV->isAllOnesValue() && CI->getPredicate() == CmpInst::ICMP_SGT) { // InstCombine canonicalizes X >= 0 into X > -1. // X >= 0 -> Likely isProb = true; } else { return false; } BasicBlock *Taken = BI->getSuccessor(0); BasicBlock *NonTaken = BI->getSuccessor(1); if (!isProb) std::swap(Taken, NonTaken); BP->setEdgeWeight(BB, Taken, ZH_TAKEN_WEIGHT); BP->setEdgeWeight(BB, NonTaken, ZH_NONTAKEN_WEIGHT); return true; } bool BranchProbabilityAnalysis::runOnFunction(Function &F) { for (Function::iterator I = F.begin(), E = F.end(); I != E; ) { BasicBlock *BB = I++; if (calcLoopBranchHeuristics(BB)) continue; if (calcReturnHeuristics(BB)) continue; if (calcPointerHeuristics(BB)) continue; calcZeroHeuristics(BB); } return false; } void BranchProbabilityInfo::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); AU.setPreservesAll(); } bool BranchProbabilityInfo::runOnFunction(Function &F) { LoopInfo &LI = getAnalysis(); BranchProbabilityAnalysis BPA(this, &LI); return BPA.runOnFunction(F); } uint32_t BranchProbabilityInfo::getSumForBlock(const BasicBlock *BB) const { uint32_t Sum = 0; for (succ_const_iterator I = succ_begin(BB), E = succ_end(BB); I != E; ++I) { const BasicBlock *Succ = *I; uint32_t Weight = getEdgeWeight(BB, Succ); uint32_t PrevSum = Sum; Sum += Weight; assert(Sum > PrevSum); (void) PrevSum; } return Sum; } bool BranchProbabilityInfo:: isEdgeHot(const BasicBlock *Src, const BasicBlock *Dst) const { // Hot probability is at least 4/5 = 80% uint32_t Weight = getEdgeWeight(Src, Dst); uint32_t Sum = getSumForBlock(Src); // FIXME: Implement BranchProbability::compare then change this code to // compare this BranchProbability against a static "hot" BranchProbability. return (uint64_t)Weight * 5 > (uint64_t)Sum * 4; } BasicBlock *BranchProbabilityInfo::getHotSucc(BasicBlock *BB) const { uint32_t Sum = 0; uint32_t MaxWeight = 0; BasicBlock *MaxSucc = 0; for (succ_iterator I = succ_begin(BB), E = succ_end(BB); I != E; ++I) { BasicBlock *Succ = *I; uint32_t Weight = getEdgeWeight(BB, Succ); uint32_t PrevSum = Sum; Sum += Weight; assert(Sum > PrevSum); (void) PrevSum; if (Weight > MaxWeight) { MaxWeight = Weight; MaxSucc = Succ; } } // FIXME: Use BranchProbability::compare. if ((uint64_t)MaxWeight * 5 > (uint64_t)Sum * 4) return MaxSucc; return 0; } // Return edge's weight. If can't find it, return DEFAULT_WEIGHT value. uint32_t BranchProbabilityInfo:: getEdgeWeight(const BasicBlock *Src, const BasicBlock *Dst) const { Edge E(Src, Dst); DenseMap::const_iterator I = Weights.find(E); if (I != Weights.end()) return I->second; return DEFAULT_WEIGHT; } void BranchProbabilityInfo:: setEdgeWeight(const BasicBlock *Src, const BasicBlock *Dst, uint32_t Weight) { Weights[std::make_pair(Src, Dst)] = Weight; DEBUG(dbgs() << "set edge " << Src->getNameStr() << " -> " << Dst->getNameStr() << " weight to " << Weight << (isEdgeHot(Src, Dst) ? " [is HOT now]\n" : "\n")); } BranchProbability BranchProbabilityInfo:: getEdgeProbability(const BasicBlock *Src, const BasicBlock *Dst) const { uint32_t N = getEdgeWeight(Src, Dst); uint32_t D = getSumForBlock(Src); return BranchProbability(N, D); } raw_ostream & BranchProbabilityInfo::printEdgeProbability(raw_ostream &OS, BasicBlock *Src, BasicBlock *Dst) const { const BranchProbability Prob = getEdgeProbability(Src, Dst); OS << "edge " << Src->getNameStr() << " -> " << Dst->getNameStr() << " probability is " << Prob << (isEdgeHot(Src, Dst) ? " [HOT edge]\n" : "\n"); return OS; }