#ifndef LLVM_ANALYSIS_BLOCKFREQUENCYINFOIMPL_H
#define LLVM_ANALYSIS_BLOCKFREQUENCYINFOIMPL_H
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/GraphTraits.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/SparseBitVector.h"
#include "llvm/ADT/Twine.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/ValueHandle.h"
#include "llvm/Support/BlockFrequency.h"
#include "llvm/Support/BranchProbability.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/DOTGraphTraits.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/ScaledNumber.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <deque>
#include <iterator>
#include <limits>
#include <list>
#include <queue>
#include <string>
#include <utility>
#include <vector>
#define DEBUG_TYPE "block-freq"
namespace llvm {
extern llvm::cl::opt<bool> CheckBFIUnknownBlockQueries;
extern llvm::cl::opt<bool> UseIterativeBFIInference;
extern llvm::cl::opt<unsigned> IterativeBFIMaxIterationsPerBlock;
extern llvm::cl::opt<double> IterativeBFIPrecision;
class BranchProbabilityInfo;
class Function;
class Loop;
class LoopInfo;
class MachineBasicBlock;
class MachineBranchProbabilityInfo;
class MachineFunction;
class MachineLoop;
class MachineLoopInfo;
namespace bfi_detail {
struct IrreducibleGraph;
template <class BT> struct BlockEdgesAdder;
class BlockMass {
uint64_t Mass = 0;
public:
BlockMass() = default;
explicit BlockMass(uint64_t Mass) : Mass(Mass) {}
static BlockMass getEmpty() { return BlockMass(); }
static BlockMass getFull() {
return BlockMass(std::numeric_limits<uint64_t>::max());
}
uint64_t getMass() const { return Mass; }
bool isFull() const { return Mass == std::numeric_limits<uint64_t>::max(); }
bool isEmpty() const { return !Mass; }
bool operator!() const { return isEmpty(); }
BlockMass &operator+=(BlockMass X) {
uint64_t Sum = Mass + X.Mass;
Mass = Sum < Mass ? std::numeric_limits<uint64_t>::max() : Sum;
return *this;
}
BlockMass &operator-=(BlockMass X) {
uint64_t Diff = Mass - X.Mass;
Mass = Diff > Mass ? 0 : Diff;
return *this;
}
BlockMass &operator*=(BranchProbability P) {
Mass = P.scale(Mass);
return *this;
}
bool operator==(BlockMass X) const { return Mass == X.Mass; }
bool operator!=(BlockMass X) const { return Mass != X.Mass; }
bool operator<=(BlockMass X) const { return Mass <= X.Mass; }
bool operator>=(BlockMass X) const { return Mass >= X.Mass; }
bool operator<(BlockMass X) const { return Mass < X.Mass; }
bool operator>(BlockMass X) const { return Mass > X.Mass; }
ScaledNumber<uint64_t> toScaled() const;
void dump() const;
raw_ostream &print(raw_ostream &OS) const;
};
inline BlockMass operator+(BlockMass L, BlockMass R) {
return BlockMass(L) += R;
}
inline BlockMass operator-(BlockMass L, BlockMass R) {
return BlockMass(L) -= R;
}
inline BlockMass operator*(BlockMass L, BranchProbability R) {
return BlockMass(L) *= R;
}
inline BlockMass operator*(BranchProbability L, BlockMass R) {
return BlockMass(R) *= L;
}
inline raw_ostream &operator<<(raw_ostream &OS, BlockMass X) {
return X.print(OS);
}
}
class BlockFrequencyInfoImplBase {
public:
using Scaled64 = ScaledNumber<uint64_t>;
using BlockMass = bfi_detail::BlockMass;
struct BlockNode {
using IndexType = uint32_t;
IndexType Index;
BlockNode() : Index(std::numeric_limits<uint32_t>::max()) {}
BlockNode(IndexType Index) : Index(Index) {}
bool operator==(const BlockNode &X) const { return Index == X.Index; }
bool operator!=(const BlockNode &X) const { return Index != X.Index; }
bool operator<=(const BlockNode &X) const { return Index <= X.Index; }
bool operator>=(const BlockNode &X) const { return Index >= X.Index; }
bool operator<(const BlockNode &X) const { return Index < X.Index; }
bool operator>(const BlockNode &X) const { return Index > X.Index; }
bool isValid() const { return Index <= getMaxIndex(); }
static size_t getMaxIndex() {
return std::numeric_limits<uint32_t>::max() - 1;
}
};
struct FrequencyData {
Scaled64 Scaled;
uint64_t Integer;
};
struct LoopData {
using ExitMap = SmallVector<std::pair<BlockNode, BlockMass>, 4>;
using NodeList = SmallVector<BlockNode, 4>;
using HeaderMassList = SmallVector<BlockMass, 1>;
LoopData *Parent; bool IsPackaged = false; uint32_t NumHeaders = 1; ExitMap Exits; NodeList Nodes; HeaderMassList BackedgeMass; BlockMass Mass;
Scaled64 Scale;
LoopData(LoopData *Parent, const BlockNode &Header)
: Parent(Parent), Nodes(1, Header), BackedgeMass(1) {}
template <class It1, class It2>
LoopData(LoopData *Parent, It1 FirstHeader, It1 LastHeader, It2 FirstOther,
It2 LastOther)
: Parent(Parent), Nodes(FirstHeader, LastHeader) {
NumHeaders = Nodes.size();
Nodes.insert(Nodes.end(), FirstOther, LastOther);
BackedgeMass.resize(NumHeaders);
}
bool isHeader(const BlockNode &Node) const {
if (isIrreducible())
return std::binary_search(Nodes.begin(), Nodes.begin() + NumHeaders,
Node);
return Node == Nodes[0];
}
BlockNode getHeader() const { return Nodes[0]; }
bool isIrreducible() const { return NumHeaders > 1; }
HeaderMassList::difference_type getHeaderIndex(const BlockNode &B) {
assert(isHeader(B) && "this is only valid on loop header blocks");
if (isIrreducible())
return std::lower_bound(Nodes.begin(), Nodes.begin() + NumHeaders, B) -
Nodes.begin();
return 0;
}
NodeList::const_iterator members_begin() const {
return Nodes.begin() + NumHeaders;
}
NodeList::const_iterator members_end() const { return Nodes.end(); }
iterator_range<NodeList::const_iterator> members() const {
return make_range(members_begin(), members_end());
}
};
struct WorkingData {
BlockNode Node; LoopData *Loop = nullptr; BlockMass Mass;
WorkingData(const BlockNode &Node) : Node(Node) {}
bool isLoopHeader() const { return Loop && Loop->isHeader(Node); }
bool isDoubleLoopHeader() const {
return isLoopHeader() && Loop->Parent && Loop->Parent->isIrreducible() &&
Loop->Parent->isHeader(Node);
}
LoopData *getContainingLoop() const {
if (!isLoopHeader())
return Loop;
if (!isDoubleLoopHeader())
return Loop->Parent;
return Loop->Parent->Parent;
}
BlockNode getResolvedNode() const {
auto L = getPackagedLoop();
return L ? L->getHeader() : Node;
}
LoopData *getPackagedLoop() const {
if (!Loop || !Loop->IsPackaged)
return nullptr;
auto L = Loop;
while (L->Parent && L->Parent->IsPackaged)
L = L->Parent;
return L;
}
BlockMass &getMass() {
if (!isAPackage())
return Mass;
if (!isADoublePackage())
return Loop->Mass;
return Loop->Parent->Mass;
}
bool isPackaged() const { return getResolvedNode() != Node; }
bool isAPackage() const { return isLoopHeader() && Loop->IsPackaged; }
bool isADoublePackage() const {
return isDoubleLoopHeader() && Loop->Parent->IsPackaged;
}
};
struct Weight {
enum DistType { Local, Exit, Backedge };
DistType Type = Local;
BlockNode TargetNode;
uint64_t Amount = 0;
Weight() = default;
Weight(DistType Type, BlockNode TargetNode, uint64_t Amount)
: Type(Type), TargetNode(TargetNode), Amount(Amount) {}
};
struct Distribution {
using WeightList = SmallVector<Weight, 4>;
WeightList Weights; uint64_t Total = 0; bool DidOverflow = false;
Distribution() = default;
void addLocal(const BlockNode &Node, uint64_t Amount) {
add(Node, Amount, Weight::Local);
}
void addExit(const BlockNode &Node, uint64_t Amount) {
add(Node, Amount, Weight::Exit);
}
void addBackedge(const BlockNode &Node, uint64_t Amount) {
add(Node, Amount, Weight::Backedge);
}
void normalize();
private:
void add(const BlockNode &Node, uint64_t Amount, Weight::DistType Type);
};
std::vector<FrequencyData> Freqs;
SparseBitVector<> IsIrrLoopHeader;
std::vector<WorkingData> Working;
std::list<LoopData> Loops;
virtual ~BlockFrequencyInfoImplBase() = default;
bool addLoopSuccessorsToDist(const LoopData *OuterLoop, LoopData &Loop,
Distribution &Dist);
bool addToDist(Distribution &Dist, const LoopData *OuterLoop,
const BlockNode &Pred, const BlockNode &Succ, uint64_t Weight);
iterator_range<std::list<LoopData>::iterator>
analyzeIrreducible(const bfi_detail::IrreducibleGraph &G, LoopData *OuterLoop,
std::list<LoopData>::iterator Insert);
void updateLoopWithIrreducible(LoopData &OuterLoop);
void distributeMass(const BlockNode &Source, LoopData *OuterLoop,
Distribution &Dist);
void computeLoopScale(LoopData &Loop);
void adjustLoopHeaderMass(LoopData &Loop);
void distributeIrrLoopHeaderMass(Distribution &Dist);
void packageLoop(LoopData &Loop);
void unwrapLoops();
void finalizeMetrics();
void clear();
virtual std::string getBlockName(const BlockNode &Node) const;
std::string getLoopName(const LoopData &Loop) const;
virtual raw_ostream &print(raw_ostream &OS) const { return OS; }
void dump() const { print(dbgs()); }
Scaled64 getFloatingBlockFreq(const BlockNode &Node) const;
BlockFrequency getBlockFreq(const BlockNode &Node) const;
Optional<uint64_t> getBlockProfileCount(const Function &F,
const BlockNode &Node,
bool AllowSynthetic = false) const;
Optional<uint64_t> getProfileCountFromFreq(const Function &F,
uint64_t Freq,
bool AllowSynthetic = false) const;
bool isIrrLoopHeader(const BlockNode &Node);
void setBlockFreq(const BlockNode &Node, uint64_t Freq);
raw_ostream &printBlockFreq(raw_ostream &OS, const BlockNode &Node) const;
raw_ostream &printBlockFreq(raw_ostream &OS,
const BlockFrequency &Freq) const;
uint64_t getEntryFreq() const {
assert(!Freqs.empty());
return Freqs[0].Integer;
}
};
namespace bfi_detail {
template <class BlockT> struct TypeMap {};
template <> struct TypeMap<BasicBlock> {
using BlockT = BasicBlock;
using BlockKeyT = AssertingVH<const BasicBlock>;
using FunctionT = Function;
using BranchProbabilityInfoT = BranchProbabilityInfo;
using LoopT = Loop;
using LoopInfoT = LoopInfo;
};
template <> struct TypeMap<MachineBasicBlock> {
using BlockT = MachineBasicBlock;
using BlockKeyT = const MachineBasicBlock *;
using FunctionT = MachineFunction;
using BranchProbabilityInfoT = MachineBranchProbabilityInfo;
using LoopT = MachineLoop;
using LoopInfoT = MachineLoopInfo;
};
template <class BlockT, class BFIImplT>
class BFICallbackVH;
template <class BlockT> std::string getBlockName(const BlockT *BB) {
assert(BB && "Unexpected nullptr");
auto MachineName = "BB" + Twine(BB->getNumber());
if (BB->getBasicBlock())
return (MachineName + "[" + BB->getName() + "]").str();
return MachineName.str();
}
template <> inline std::string getBlockName(const BasicBlock *BB) {
assert(BB && "Unexpected nullptr");
return BB->getName().str();
}
struct IrreducibleGraph {
using BFIBase = BlockFrequencyInfoImplBase;
BFIBase &BFI;
using BlockNode = BFIBase::BlockNode;
struct IrrNode {
BlockNode Node;
unsigned NumIn = 0;
std::deque<const IrrNode *> Edges;
IrrNode(const BlockNode &Node) : Node(Node) {}
using iterator = std::deque<const IrrNode *>::const_iterator;
iterator pred_begin() const { return Edges.begin(); }
iterator succ_begin() const { return Edges.begin() + NumIn; }
iterator pred_end() const { return succ_begin(); }
iterator succ_end() const { return Edges.end(); }
};
BlockNode Start;
const IrrNode *StartIrr = nullptr;
std::vector<IrrNode> Nodes;
SmallDenseMap<uint32_t, IrrNode *, 4> Lookup;
template <class BlockEdgesAdder>
IrreducibleGraph(BFIBase &BFI, const BFIBase::LoopData *OuterLoop,
BlockEdgesAdder addBlockEdges) : BFI(BFI) {
initialize(OuterLoop, addBlockEdges);
}
template <class BlockEdgesAdder>
void initialize(const BFIBase::LoopData *OuterLoop,
BlockEdgesAdder addBlockEdges);
void addNodesInLoop(const BFIBase::LoopData &OuterLoop);
void addNodesInFunction();
void addNode(const BlockNode &Node) {
Nodes.emplace_back(Node);
BFI.Working[Node.Index].getMass() = BlockMass::getEmpty();
}
void indexNodes();
template <class BlockEdgesAdder>
void addEdges(const BlockNode &Node, const BFIBase::LoopData *OuterLoop,
BlockEdgesAdder addBlockEdges);
void addEdge(IrrNode &Irr, const BlockNode &Succ,
const BFIBase::LoopData *OuterLoop);
};
template <class BlockEdgesAdder>
void IrreducibleGraph::initialize(const BFIBase::LoopData *OuterLoop,
BlockEdgesAdder addBlockEdges) {
if (OuterLoop) {
addNodesInLoop(*OuterLoop);
for (auto N : OuterLoop->Nodes)
addEdges(N, OuterLoop, addBlockEdges);
} else {
addNodesInFunction();
for (uint32_t Index = 0; Index < BFI.Working.size(); ++Index)
addEdges(Index, OuterLoop, addBlockEdges);
}
StartIrr = Lookup[Start.Index];
}
template <class BlockEdgesAdder>
void IrreducibleGraph::addEdges(const BlockNode &Node,
const BFIBase::LoopData *OuterLoop,
BlockEdgesAdder addBlockEdges) {
auto L = Lookup.find(Node.Index);
if (L == Lookup.end())
return;
IrrNode &Irr = *L->second;
const auto &Working = BFI.Working[Node.Index];
if (Working.isAPackage())
for (const auto &I : Working.Loop->Exits)
addEdge(Irr, I.first, OuterLoop);
else
addBlockEdges(*this, Irr, OuterLoop);
}
}
template <class BT> class BlockFrequencyInfoImpl : BlockFrequencyInfoImplBase {
friend struct bfi_detail::BlockEdgesAdder<BT>;
using BlockT = typename bfi_detail::TypeMap<BT>::BlockT;
using BlockKeyT = typename bfi_detail::TypeMap<BT>::BlockKeyT;
using FunctionT = typename bfi_detail::TypeMap<BT>::FunctionT;
using BranchProbabilityInfoT =
typename bfi_detail::TypeMap<BT>::BranchProbabilityInfoT;
using LoopT = typename bfi_detail::TypeMap<BT>::LoopT;
using LoopInfoT = typename bfi_detail::TypeMap<BT>::LoopInfoT;
using Successor = GraphTraits<const BlockT *>;
using Predecessor = GraphTraits<Inverse<const BlockT *>>;
using BFICallbackVH =
bfi_detail::BFICallbackVH<BlockT, BlockFrequencyInfoImpl>;
const BranchProbabilityInfoT *BPI = nullptr;
const LoopInfoT *LI = nullptr;
const FunctionT *F = nullptr;
std::vector<const BlockT *> RPOT;
DenseMap<BlockKeyT, std::pair<BlockNode, BFICallbackVH>> Nodes;
using rpot_iterator = typename std::vector<const BlockT *>::const_iterator;
rpot_iterator rpot_begin() const { return RPOT.begin(); }
rpot_iterator rpot_end() const { return RPOT.end(); }
size_t getIndex(const rpot_iterator &I) const { return I - rpot_begin(); }
BlockNode getNode(const rpot_iterator &I) const {
return BlockNode(getIndex(I));
}
BlockNode getNode(const BlockT *BB) const { return Nodes.lookup(BB).first; }
const BlockT *getBlock(const BlockNode &Node) const {
assert(Node.Index < RPOT.size());
return RPOT[Node.Index];
}
void initializeRPOT();
void initializeLoops();
bool propagateMassToSuccessors(LoopData *OuterLoop, const BlockNode &Node);
bool computeMassInLoop(LoopData &Loop);
bool tryToComputeMassInFunction();
void computeIrreducibleMass(LoopData *OuterLoop,
std::list<LoopData>::iterator Insert);
void computeMassInLoops();
void computeMassInFunction();
std::string getBlockName(const BlockNode &Node) const override {
return bfi_detail::getBlockName(getBlock(Node));
}
bool needIterativeInference() const;
void applyIterativeInference();
using ProbMatrixType = std::vector<std::vector<std::pair<size_t, Scaled64>>>;
void iterativeInference(const ProbMatrixType &ProbMatrix,
std::vector<Scaled64> &Freq) const;
void findReachableBlocks(std::vector<const BlockT *> &Blocks) const;
void initTransitionProbabilities(
const std::vector<const BlockT *> &Blocks,
const DenseMap<const BlockT *, size_t> &BlockIndex,
ProbMatrixType &ProbMatrix) const;
#ifndef NDEBUG
Scaled64 discrepancy(const ProbMatrixType &ProbMatrix,
const std::vector<Scaled64> &Freq) const;
#endif
public:
BlockFrequencyInfoImpl() = default;
const FunctionT *getFunction() const { return F; }
void calculate(const FunctionT &F, const BranchProbabilityInfoT &BPI,
const LoopInfoT &LI);
using BlockFrequencyInfoImplBase::getEntryFreq;
BlockFrequency getBlockFreq(const BlockT *BB) const {
return BlockFrequencyInfoImplBase::getBlockFreq(getNode(BB));
}
Optional<uint64_t> getBlockProfileCount(const Function &F,
const BlockT *BB,
bool AllowSynthetic = false) const {
return BlockFrequencyInfoImplBase::getBlockProfileCount(F, getNode(BB),
AllowSynthetic);
}
Optional<uint64_t> getProfileCountFromFreq(const Function &F,
uint64_t Freq,
bool AllowSynthetic = false) const {
return BlockFrequencyInfoImplBase::getProfileCountFromFreq(F, Freq,
AllowSynthetic);
}
bool isIrrLoopHeader(const BlockT *BB) {
return BlockFrequencyInfoImplBase::isIrrLoopHeader(getNode(BB));
}
void setBlockFreq(const BlockT *BB, uint64_t Freq);
void forgetBlock(const BlockT *BB) {
Nodes.erase(BB);
}
Scaled64 getFloatingBlockFreq(const BlockT *BB) const {
return BlockFrequencyInfoImplBase::getFloatingBlockFreq(getNode(BB));
}
const BranchProbabilityInfoT &getBPI() const { return *BPI; }
raw_ostream &print(raw_ostream &OS) const override;
using BlockFrequencyInfoImplBase::dump;
using BlockFrequencyInfoImplBase::printBlockFreq;
raw_ostream &printBlockFreq(raw_ostream &OS, const BlockT *BB) const {
return BlockFrequencyInfoImplBase::printBlockFreq(OS, getNode(BB));
}
void verifyMatch(BlockFrequencyInfoImpl<BT> &Other) const;
};
namespace bfi_detail {
template <class BFIImplT>
class BFICallbackVH<BasicBlock, BFIImplT> : public CallbackVH {
BFIImplT *BFIImpl;
public:
BFICallbackVH() = default;
BFICallbackVH(const BasicBlock *BB, BFIImplT *BFIImpl)
: CallbackVH(BB), BFIImpl(BFIImpl) {}
virtual ~BFICallbackVH() = default;
void deleted() override {
BFIImpl->forgetBlock(cast<BasicBlock>(getValPtr()));
}
};
template <class BFIImplT>
class BFICallbackVH<MachineBasicBlock, BFIImplT> {
public:
BFICallbackVH() = default;
BFICallbackVH(const MachineBasicBlock *, BFIImplT *) {}
};
}
template <class BT>
void BlockFrequencyInfoImpl<BT>::calculate(const FunctionT &F,
const BranchProbabilityInfoT &BPI,
const LoopInfoT &LI) {
this->BPI = &BPI;
this->LI = &LI;
this->F = &F;
BlockFrequencyInfoImplBase::clear();
RPOT.clear();
Nodes.clear();
LLVM_DEBUG(dbgs() << "\nblock-frequency: " << F.getName()
<< "\n================="
<< std::string(F.getName().size(), '=') << "\n");
initializeRPOT();
initializeLoops();
computeMassInLoops();
computeMassInFunction();
unwrapLoops();
if (needIterativeInference())
applyIterativeInference();
finalizeMetrics();
if (CheckBFIUnknownBlockQueries) {
for (const BlockT &BB : F)
if (!Nodes.count(&BB))
setBlockFreq(&BB, 0);
}
}
template <class BT>
void BlockFrequencyInfoImpl<BT>::setBlockFreq(const BlockT *BB, uint64_t Freq) {
if (Nodes.count(BB))
BlockFrequencyInfoImplBase::setBlockFreq(getNode(BB), Freq);
else {
BlockNode NewNode(Freqs.size());
Nodes[BB] = {NewNode, BFICallbackVH(BB, this)};
Freqs.emplace_back();
BlockFrequencyInfoImplBase::setBlockFreq(NewNode, Freq);
}
}
template <class BT> void BlockFrequencyInfoImpl<BT>::initializeRPOT() {
const BlockT *Entry = &F->front();
RPOT.reserve(F->size());
std::copy(po_begin(Entry), po_end(Entry), std::back_inserter(RPOT));
std::reverse(RPOT.begin(), RPOT.end());
assert(RPOT.size() - 1 <= BlockNode::getMaxIndex() &&
"More nodes in function than Block Frequency Info supports");
LLVM_DEBUG(dbgs() << "reverse-post-order-traversal\n");
for (rpot_iterator I = rpot_begin(), E = rpot_end(); I != E; ++I) {
BlockNode Node = getNode(I);
LLVM_DEBUG(dbgs() << " - " << getIndex(I) << ": " << getBlockName(Node)
<< "\n");
Nodes[*I] = {Node, BFICallbackVH(*I, this)};
}
Working.reserve(RPOT.size());
for (size_t Index = 0; Index < RPOT.size(); ++Index)
Working.emplace_back(Index);
Freqs.resize(RPOT.size());
}
template <class BT> void BlockFrequencyInfoImpl<BT>::initializeLoops() {
LLVM_DEBUG(dbgs() << "loop-detection\n");
if (LI->empty())
return;
std::deque<std::pair<const LoopT *, LoopData *>> Q;
for (const LoopT *L : *LI)
Q.emplace_back(L, nullptr);
while (!Q.empty()) {
const LoopT *Loop = Q.front().first;
LoopData *Parent = Q.front().second;
Q.pop_front();
BlockNode Header = getNode(Loop->getHeader());
assert(Header.isValid());
Loops.emplace_back(Parent, Header);
Working[Header.Index].Loop = &Loops.back();
LLVM_DEBUG(dbgs() << " - loop = " << getBlockName(Header) << "\n");
for (const LoopT *L : *Loop)
Q.emplace_back(L, &Loops.back());
}
for (size_t Index = 0; Index < RPOT.size(); ++Index) {
if (Working[Index].isLoopHeader()) {
LoopData *ContainingLoop = Working[Index].getContainingLoop();
if (ContainingLoop)
ContainingLoop->Nodes.push_back(Index);
continue;
}
const LoopT *Loop = LI->getLoopFor(RPOT[Index]);
if (!Loop)
continue;
BlockNode Header = getNode(Loop->getHeader());
assert(Header.isValid());
const auto &HeaderData = Working[Header.Index];
assert(HeaderData.isLoopHeader());
Working[Index].Loop = HeaderData.Loop;
HeaderData.Loop->Nodes.push_back(Index);
LLVM_DEBUG(dbgs() << " - loop = " << getBlockName(Header)
<< ": member = " << getBlockName(Index) << "\n");
}
}
template <class BT> void BlockFrequencyInfoImpl<BT>::computeMassInLoops() {
for (auto L = Loops.rbegin(), E = Loops.rend(); L != E; ++L) {
if (computeMassInLoop(*L))
continue;
auto Next = std::next(L);
computeIrreducibleMass(&*L, L.base());
L = std::prev(Next);
if (computeMassInLoop(*L))
continue;
llvm_unreachable("unhandled irreducible control flow");
}
}
template <class BT>
bool BlockFrequencyInfoImpl<BT>::computeMassInLoop(LoopData &Loop) {
LLVM_DEBUG(dbgs() << "compute-mass-in-loop: " << getLoopName(Loop) << "\n");
if (Loop.isIrreducible()) {
LLVM_DEBUG(dbgs() << "isIrreducible = true\n");
Distribution Dist;
unsigned NumHeadersWithWeight = 0;
Optional<uint64_t> MinHeaderWeight;
DenseSet<uint32_t> HeadersWithoutWeight;
HeadersWithoutWeight.reserve(Loop.NumHeaders);
for (uint32_t H = 0; H < Loop.NumHeaders; ++H) {
auto &HeaderNode = Loop.Nodes[H];
const BlockT *Block = getBlock(HeaderNode);
IsIrrLoopHeader.set(Loop.Nodes[H].Index);
Optional<uint64_t> HeaderWeight = Block->getIrrLoopHeaderWeight();
if (!HeaderWeight) {
LLVM_DEBUG(dbgs() << "Missing irr loop header metadata on "
<< getBlockName(HeaderNode) << "\n");
HeadersWithoutWeight.insert(H);
continue;
}
LLVM_DEBUG(dbgs() << getBlockName(HeaderNode)
<< " has irr loop header weight "
<< HeaderWeight.value() << "\n");
NumHeadersWithWeight++;
uint64_t HeaderWeightValue = HeaderWeight.value();
if (!MinHeaderWeight || HeaderWeightValue < MinHeaderWeight)
MinHeaderWeight = HeaderWeightValue;
if (HeaderWeightValue) {
Dist.addLocal(HeaderNode, HeaderWeightValue);
}
}
if (!MinHeaderWeight)
MinHeaderWeight = 1;
for (uint32_t H : HeadersWithoutWeight) {
auto &HeaderNode = Loop.Nodes[H];
assert(!getBlock(HeaderNode)->getIrrLoopHeaderWeight() &&
"Shouldn't have a weight metadata");
uint64_t MinWeight = *MinHeaderWeight;
LLVM_DEBUG(dbgs() << "Giving weight " << MinWeight << " to "
<< getBlockName(HeaderNode) << "\n");
if (MinWeight)
Dist.addLocal(HeaderNode, MinWeight);
}
distributeIrrLoopHeaderMass(Dist);
for (const BlockNode &M : Loop.Nodes)
if (!propagateMassToSuccessors(&Loop, M))
llvm_unreachable("unhandled irreducible control flow");
if (NumHeadersWithWeight == 0)
adjustLoopHeaderMass(Loop);
} else {
Working[Loop.getHeader().Index].getMass() = BlockMass::getFull();
if (!propagateMassToSuccessors(&Loop, Loop.getHeader()))
llvm_unreachable("irreducible control flow to loop header!?");
for (const BlockNode &M : Loop.members())
if (!propagateMassToSuccessors(&Loop, M))
return false;
}
computeLoopScale(Loop);
packageLoop(Loop);
return true;
}
template <class BT>
bool BlockFrequencyInfoImpl<BT>::tryToComputeMassInFunction() {
LLVM_DEBUG(dbgs() << "compute-mass-in-function\n");
assert(!Working.empty() && "no blocks in function");
assert(!Working[0].isLoopHeader() && "entry block is a loop header");
Working[0].getMass() = BlockMass::getFull();
for (rpot_iterator I = rpot_begin(), IE = rpot_end(); I != IE; ++I) {
BlockNode Node = getNode(I);
if (Working[Node.Index].isPackaged())
continue;
if (!propagateMassToSuccessors(nullptr, Node))
return false;
}
return true;
}
template <class BT> void BlockFrequencyInfoImpl<BT>::computeMassInFunction() {
if (tryToComputeMassInFunction())
return;
computeIrreducibleMass(nullptr, Loops.begin());
if (tryToComputeMassInFunction())
return;
llvm_unreachable("unhandled irreducible control flow");
}
template <class BT>
bool BlockFrequencyInfoImpl<BT>::needIterativeInference() const {
if (!UseIterativeBFIInference)
return false;
if (!F->getFunction().hasProfileData())
return false;
for (auto L = Loops.rbegin(), E = Loops.rend(); L != E; ++L) {
if (L->isIrreducible())
return true;
}
return false;
}
template <class BT> void BlockFrequencyInfoImpl<BT>::applyIterativeInference() {
std::vector<const BlockT *> ReachableBlocks;
findReachableBlocks(ReachableBlocks);
if (ReachableBlocks.empty())
return;
DenseMap<const BlockT *, size_t> BlockIndex;
auto Freq = std::vector<Scaled64>(ReachableBlocks.size());
Scaled64 SumFreq;
for (size_t I = 0; I < ReachableBlocks.size(); I++) {
const BlockT *BB = ReachableBlocks[I];
BlockIndex[BB] = I;
Freq[I] = getFloatingBlockFreq(BB);
SumFreq += Freq[I];
}
assert(!SumFreq.isZero() && "empty initial block frequencies");
LLVM_DEBUG(dbgs() << "Applying iterative inference for " << F->getName()
<< " with " << ReachableBlocks.size() << " blocks\n");
for (auto &Value : Freq) {
Value /= SumFreq;
}
ProbMatrixType ProbMatrix;
initTransitionProbabilities(ReachableBlocks, BlockIndex, ProbMatrix);
iterativeInference(ProbMatrix, Freq);
for (const BlockT &BB : *F) {
auto Node = getNode(&BB);
if (!Node.isValid())
continue;
if (BlockIndex.count(&BB)) {
Freqs[Node.Index].Scaled = Freq[BlockIndex[&BB]];
} else {
Freqs[Node.Index].Scaled = Scaled64::getZero();
}
}
}
template <class BT>
void BlockFrequencyInfoImpl<BT>::iterativeInference(
const ProbMatrixType &ProbMatrix, std::vector<Scaled64> &Freq) const {
assert(0.0 < IterativeBFIPrecision && IterativeBFIPrecision < 1.0 &&
"incorrectly specified precision");
const auto Precision =
Scaled64::getInverse(static_cast<uint64_t>(1.0 / IterativeBFIPrecision));
const size_t MaxIterations = IterativeBFIMaxIterationsPerBlock * Freq.size();
#ifndef NDEBUG
LLVM_DEBUG(dbgs() << " Initial discrepancy = "
<< discrepancy(ProbMatrix, Freq).toString() << "\n");
#endif
auto Successors = std::vector<std::vector<size_t>>(Freq.size());
for (size_t I = 0; I < Freq.size(); I++) {
for (auto &Jump : ProbMatrix[I]) {
Successors[Jump.first].push_back(I);
}
}
auto IsActive = BitVector(Freq.size(), false);
std::queue<size_t> ActiveSet;
for (size_t I = 0; I < Freq.size(); I++) {
if (Freq[I] > 0) {
ActiveSet.push(I);
IsActive[I] = true;
}
}
size_t It = 0;
while (It++ < MaxIterations && !ActiveSet.empty()) {
size_t I = ActiveSet.front();
ActiveSet.pop();
IsActive[I] = false;
Scaled64 NewFreq;
Scaled64 OneMinusSelfProb = Scaled64::getOne();
for (auto &Jump : ProbMatrix[I]) {
if (Jump.first == I) {
OneMinusSelfProb -= Jump.second;
} else {
NewFreq += Freq[Jump.first] * Jump.second;
}
}
if (OneMinusSelfProb != Scaled64::getOne())
NewFreq /= OneMinusSelfProb;
auto Change = Freq[I] >= NewFreq ? Freq[I] - NewFreq : NewFreq - Freq[I];
if (Change > Precision) {
ActiveSet.push(I);
IsActive[I] = true;
for (size_t Succ : Successors[I]) {
if (!IsActive[Succ]) {
ActiveSet.push(Succ);
IsActive[Succ] = true;
}
}
}
Freq[I] = NewFreq;
}
LLVM_DEBUG(dbgs() << " Completed " << It << " inference iterations"
<< format(" (%0.0f per block)", double(It) / Freq.size())
<< "\n");
#ifndef NDEBUG
LLVM_DEBUG(dbgs() << " Final discrepancy = "
<< discrepancy(ProbMatrix, Freq).toString() << "\n");
#endif
}
template <class BT>
void BlockFrequencyInfoImpl<BT>::findReachableBlocks(
std::vector<const BlockT *> &Blocks) const {
std::queue<const BlockT *> Queue;
SmallPtrSet<const BlockT *, 8> Reachable;
const BlockT *Entry = &F->front();
Queue.push(Entry);
Reachable.insert(Entry);
while (!Queue.empty()) {
const BlockT *SrcBB = Queue.front();
Queue.pop();
for (const BlockT *DstBB : children<const BlockT *>(SrcBB)) {
auto EP = BPI->getEdgeProbability(SrcBB, DstBB);
if (EP.isZero())
continue;
if (Reachable.insert(DstBB).second)
Queue.push(DstBB);
}
}
SmallPtrSet<const BlockT *, 8> InverseReachable;
for (const BlockT &BB : *F) {
bool HasSucc = GraphTraits<const BlockT *>::child_begin(&BB) !=
GraphTraits<const BlockT *>::child_end(&BB);
if (!HasSucc && Reachable.count(&BB)) {
Queue.push(&BB);
InverseReachable.insert(&BB);
}
}
while (!Queue.empty()) {
const BlockT *SrcBB = Queue.front();
Queue.pop();
for (const BlockT *DstBB : children<Inverse<const BlockT *>>(SrcBB)) {
auto EP = BPI->getEdgeProbability(DstBB, SrcBB);
if (EP.isZero())
continue;
if (InverseReachable.insert(DstBB).second)
Queue.push(DstBB);
}
}
Blocks.reserve(F->size());
for (const BlockT &BB : *F) {
if (Reachable.count(&BB) && InverseReachable.count(&BB)) {
Blocks.push_back(&BB);
}
}
}
template <class BT>
void BlockFrequencyInfoImpl<BT>::initTransitionProbabilities(
const std::vector<const BlockT *> &Blocks,
const DenseMap<const BlockT *, size_t> &BlockIndex,
ProbMatrixType &ProbMatrix) const {
const size_t NumBlocks = Blocks.size();
auto Succs = std::vector<std::vector<std::pair<size_t, Scaled64>>>(NumBlocks);
auto SumProb = std::vector<Scaled64>(NumBlocks);
for (size_t Src = 0; Src < NumBlocks; Src++) {
const BlockT *BB = Blocks[Src];
SmallPtrSet<const BlockT *, 2> UniqueSuccs;
for (const auto SI : children<const BlockT *>(BB)) {
if (BlockIndex.find(SI) == BlockIndex.end())
continue;
if (!UniqueSuccs.insert(SI).second)
continue;
auto EP = BPI->getEdgeProbability(BB, SI);
if (EP.isZero())
continue;
auto EdgeProb =
Scaled64::getFraction(EP.getNumerator(), EP.getDenominator());
size_t Dst = BlockIndex.find(SI)->second;
Succs[Src].push_back(std::make_pair(Dst, EdgeProb));
SumProb[Src] += EdgeProb;
}
}
ProbMatrix = ProbMatrixType(NumBlocks);
for (size_t Src = 0; Src < NumBlocks; Src++) {
if (Succs[Src].empty())
continue;
assert(!SumProb[Src].isZero() && "Zero sum probability of non-exit block");
for (auto &Jump : Succs[Src]) {
size_t Dst = Jump.first;
Scaled64 Prob = Jump.second;
ProbMatrix[Dst].push_back(std::make_pair(Src, Prob / SumProb[Src]));
}
}
size_t EntryIdx = BlockIndex.find(&F->front())->second;
for (size_t Src = 0; Src < NumBlocks; Src++) {
if (Succs[Src].empty()) {
ProbMatrix[EntryIdx].push_back(std::make_pair(Src, Scaled64::getOne()));
}
}
}
#ifndef NDEBUG
template <class BT>
BlockFrequencyInfoImplBase::Scaled64 BlockFrequencyInfoImpl<BT>::discrepancy(
const ProbMatrixType &ProbMatrix, const std::vector<Scaled64> &Freq) const {
assert(Freq[0] > 0 && "Incorrectly computed frequency of the entry block");
Scaled64 Discrepancy;
for (size_t I = 0; I < ProbMatrix.size(); I++) {
Scaled64 Sum;
for (const auto &Jump : ProbMatrix[I]) {
Sum += Freq[Jump.first] * Jump.second;
}
Discrepancy += Freq[I] >= Sum ? Freq[I] - Sum : Sum - Freq[I];
}
return Discrepancy / Freq[0];
}
#endif
namespace bfi_detail {
template <class BT> struct BlockEdgesAdder {
using BlockT = BT;
using LoopData = BlockFrequencyInfoImplBase::LoopData;
using Successor = GraphTraits<const BlockT *>;
const BlockFrequencyInfoImpl<BT> &BFI;
explicit BlockEdgesAdder(const BlockFrequencyInfoImpl<BT> &BFI)
: BFI(BFI) {}
void operator()(IrreducibleGraph &G, IrreducibleGraph::IrrNode &Irr,
const LoopData *OuterLoop) {
const BlockT *BB = BFI.RPOT[Irr.Node.Index];
for (const auto Succ : children<const BlockT *>(BB))
G.addEdge(Irr, BFI.getNode(Succ), OuterLoop);
}
};
}
template <class BT>
void BlockFrequencyInfoImpl<BT>::computeIrreducibleMass(
LoopData *OuterLoop, std::list<LoopData>::iterator Insert) {
LLVM_DEBUG(dbgs() << "analyze-irreducible-in-";
if (OuterLoop) dbgs()
<< "loop: " << getLoopName(*OuterLoop) << "\n";
else dbgs() << "function\n");
using namespace bfi_detail;
BlockEdgesAdder<BT> addBlockEdges(*this);
IrreducibleGraph G(*this, OuterLoop, addBlockEdges);
for (auto &L : analyzeIrreducible(G, OuterLoop, Insert))
computeMassInLoop(L);
if (!OuterLoop)
return;
updateLoopWithIrreducible(*OuterLoop);
}
inline uint32_t getWeightFromBranchProb(const BranchProbability Prob) {
return Prob.getNumerator();
}
template <class BT>
bool
BlockFrequencyInfoImpl<BT>::propagateMassToSuccessors(LoopData *OuterLoop,
const BlockNode &Node) {
LLVM_DEBUG(dbgs() << " - node: " << getBlockName(Node) << "\n");
Distribution Dist;
if (auto *Loop = Working[Node.Index].getPackagedLoop()) {
assert(Loop != OuterLoop && "Cannot propagate mass in a packaged loop");
if (!addLoopSuccessorsToDist(OuterLoop, *Loop, Dist))
return false;
} else {
const BlockT *BB = getBlock(Node);
for (auto SI = GraphTraits<const BlockT *>::child_begin(BB),
SE = GraphTraits<const BlockT *>::child_end(BB);
SI != SE; ++SI)
if (!addToDist(
Dist, OuterLoop, Node, getNode(*SI),
getWeightFromBranchProb(BPI->getEdgeProbability(BB, SI))))
return false;
}
distributeMass(Node, OuterLoop, Dist);
return true;
}
template <class BT>
raw_ostream &BlockFrequencyInfoImpl<BT>::print(raw_ostream &OS) const {
if (!F)
return OS;
OS << "block-frequency-info: " << F->getName() << "\n";
for (const BlockT &BB : *F) {
OS << " - " << bfi_detail::getBlockName(&BB) << ": float = ";
getFloatingBlockFreq(&BB).print(OS, 5)
<< ", int = " << getBlockFreq(&BB).getFrequency();
if (Optional<uint64_t> ProfileCount =
BlockFrequencyInfoImplBase::getBlockProfileCount(
F->getFunction(), getNode(&BB)))
OS << ", count = " << ProfileCount.value();
if (Optional<uint64_t> IrrLoopHeaderWeight =
BB.getIrrLoopHeaderWeight())
OS << ", irr_loop_header_weight = " << IrrLoopHeaderWeight.value();
OS << "\n";
}
OS << "\n";
return OS;
}
template <class BT>
void BlockFrequencyInfoImpl<BT>::verifyMatch(
BlockFrequencyInfoImpl<BT> &Other) const {
bool Match = true;
DenseMap<const BlockT *, BlockNode> ValidNodes;
DenseMap<const BlockT *, BlockNode> OtherValidNodes;
for (auto &Entry : Nodes) {
const BlockT *BB = Entry.first;
if (BB) {
ValidNodes[BB] = Entry.second.first;
}
}
for (auto &Entry : Other.Nodes) {
const BlockT *BB = Entry.first;
if (BB) {
OtherValidNodes[BB] = Entry.second.first;
}
}
unsigned NumValidNodes = ValidNodes.size();
unsigned NumOtherValidNodes = OtherValidNodes.size();
if (NumValidNodes != NumOtherValidNodes) {
Match = false;
dbgs() << "Number of blocks mismatch: " << NumValidNodes << " vs "
<< NumOtherValidNodes << "\n";
} else {
for (auto &Entry : ValidNodes) {
const BlockT *BB = Entry.first;
BlockNode Node = Entry.second;
if (OtherValidNodes.count(BB)) {
BlockNode OtherNode = OtherValidNodes[BB];
const auto &Freq = Freqs[Node.Index];
const auto &OtherFreq = Other.Freqs[OtherNode.Index];
if (Freq.Integer != OtherFreq.Integer) {
Match = false;
dbgs() << "Freq mismatch: " << bfi_detail::getBlockName(BB) << " "
<< Freq.Integer << " vs " << OtherFreq.Integer << "\n";
}
} else {
Match = false;
dbgs() << "Block " << bfi_detail::getBlockName(BB) << " index "
<< Node.Index << " does not exist in Other.\n";
}
}
}
if (!Match) {
dbgs() << "This\n";
print(dbgs());
dbgs() << "Other\n";
Other.print(dbgs());
}
assert(Match && "BFI mismatch");
}
enum GVDAGType { GVDT_None, GVDT_Fraction, GVDT_Integer, GVDT_Count };
template <class BlockFrequencyInfoT, class BranchProbabilityInfoT>
struct BFIDOTGraphTraitsBase : public DefaultDOTGraphTraits {
using GTraits = GraphTraits<BlockFrequencyInfoT *>;
using NodeRef = typename GTraits::NodeRef;
using EdgeIter = typename GTraits::ChildIteratorType;
using NodeIter = typename GTraits::nodes_iterator;
uint64_t MaxFrequency = 0;
explicit BFIDOTGraphTraitsBase(bool isSimple = false)
: DefaultDOTGraphTraits(isSimple) {}
static StringRef getGraphName(const BlockFrequencyInfoT *G) {
return G->getFunction()->getName();
}
std::string getNodeAttributes(NodeRef Node, const BlockFrequencyInfoT *Graph,
unsigned HotPercentThreshold = 0) {
std::string Result;
if (!HotPercentThreshold)
return Result;
if (!MaxFrequency) {
for (NodeIter I = GTraits::nodes_begin(Graph),
E = GTraits::nodes_end(Graph);
I != E; ++I) {
NodeRef N = *I;
MaxFrequency =
std::max(MaxFrequency, Graph->getBlockFreq(N).getFrequency());
}
}
BlockFrequency Freq = Graph->getBlockFreq(Node);
BlockFrequency HotFreq =
(BlockFrequency(MaxFrequency) *
BranchProbability::getBranchProbability(HotPercentThreshold, 100));
if (Freq < HotFreq)
return Result;
raw_string_ostream OS(Result);
OS << "color=\"red\"";
OS.flush();
return Result;
}
std::string getNodeLabel(NodeRef Node, const BlockFrequencyInfoT *Graph,
GVDAGType GType, int layout_order = -1) {
std::string Result;
raw_string_ostream OS(Result);
if (layout_order != -1)
OS << Node->getName() << "[" << layout_order << "] : ";
else
OS << Node->getName() << " : ";
switch (GType) {
case GVDT_Fraction:
Graph->printBlockFreq(OS, Node);
break;
case GVDT_Integer:
OS << Graph->getBlockFreq(Node).getFrequency();
break;
case GVDT_Count: {
auto Count = Graph->getBlockProfileCount(Node);
if (Count)
OS << *Count;
else
OS << "Unknown";
break;
}
case GVDT_None:
llvm_unreachable("If we are not supposed to render a graph we should "
"never reach this point.");
}
return Result;
}
std::string getEdgeAttributes(NodeRef Node, EdgeIter EI,
const BlockFrequencyInfoT *BFI,
const BranchProbabilityInfoT *BPI,
unsigned HotPercentThreshold = 0) {
std::string Str;
if (!BPI)
return Str;
BranchProbability BP = BPI->getEdgeProbability(Node, EI);
uint32_t N = BP.getNumerator();
uint32_t D = BP.getDenominator();
double Percent = 100.0 * N / D;
raw_string_ostream OS(Str);
OS << format("label=\"%.1f%%\"", Percent);
if (HotPercentThreshold) {
BlockFrequency EFreq = BFI->getBlockFreq(Node) * BP;
BlockFrequency HotFreq = BlockFrequency(MaxFrequency) *
BranchProbability(HotPercentThreshold, 100);
if (EFreq >= HotFreq) {
OS << ",color=\"red\"";
}
}
OS.flush();
return Str;
}
};
}
#undef DEBUG_TYPE
#endif