18#include "llvm/Config/llvm-config.h"
41#define DEBUG_TYPE "block-freq"
45 "check-bfi-unknown-block-queries",
47 cl::desc(
"Check if block frequency is queried for an unknown block "
48 "for debugging missed BFI updates"));
52 cl::desc(
"Apply an iterative post-processing to infer correct BFI counts"));
56 cl::desc(
"Iterative inference: maximum number of update iterations "
61 cl::desc(
"Iterative inference: delta convergence precision; smaller values "
62 "typically lead to better results at the cost of worsen runtime"));
71#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
83 for (
int Digits = 0; Digits < 16; ++Digits)
116struct DitheringDistributer {
120 DitheringDistributer(Distribution &Dist,
const BlockMass &Mass);
127DitheringDistributer::DitheringDistributer(Distribution &Dist,
130 RemWeight = Dist.Total;
134BlockMass DitheringDistributer::takeMass(uint32_t Weight) {
135 assert(Weight &&
"invalid weight");
136 assert(Weight <= RemWeight);
137 BlockMass Mass = RemMass * BranchProbability(Weight, RemWeight);
145void Distribution::add(
const BlockNode &Node,
uint64_t Amount,
146 Weight::DistType
Type) {
147 assert(Amount &&
"invalid weight of 0");
151 bool IsOverflow = NewTotal <
Total;
152 assert(!(DidOverflow && IsOverflow) &&
"unexpected repeated overflow");
153 DidOverflow |= IsOverflow;
159 Weights.push_back(Weight(
Type, Node, Amount));
163 assert(OtherW.TargetNode.isValid());
168 assert(W.Type == OtherW.Type);
169 assert(W.TargetNode == OtherW.TargetNode);
170 assert(OtherW.Amount &&
"Expected non-zero weight");
171 if (W.Amount > W.Amount + OtherW.Amount)
175 W.Amount += OtherW.Amount;
180 llvm::sort(Weights, [](
const Weight &L,
const Weight &R) {
181 return L.TargetNode < R.TargetNode;
185 WeightList::iterator O = Weights.begin();
186 for (WeightList::const_iterator
I = O, L = O,
E = Weights.end();
I !=
E;
191 for (++L; L !=
E &&
I->TargetNode == L->TargetNode; ++L)
196 Weights.erase(O, Weights.end());
204 for (
const Weight &W : Weights)
208 if (Weights.size() == Combined.size())
213 Weights.reserve(Combined.size());
214 for (
const auto &
I : Combined)
215 Weights.push_back(
I.second);
220 if (Weights.size() > 128) {
233 return (
N >> Shift) + (UINT64_C(1) &
N >> (Shift - 1));
259 else if (
Total > UINT32_MAX)
267 [](uint64_t Sum,
const Weight &W) {
268 return Sum + W.Amount;
270 "Expected total to be correct");
282 assert(W.TargetNode.isValid());
284 assert(W.Amount <= UINT32_MAX);
295 std::vector<FrequencyData>().swap(
Freqs);
297 std::vector<WorkingData>().swap(
Working);
306 std::vector<FrequencyData> SavedFreqs(std::move(BFI.
Freqs));
309 BFI.
Freqs = std::move(SavedFreqs);
328 auto debugSuccessor = [&](
const char *
Type) {
331 if (!isLoopHeader(Resolved))
334 if (Resolved != Succ)
338 (void)debugSuccessor;
341 if (isLoopHeader(Resolved)) {
347 if (
Working[Resolved.Index].getContainingLoop() != OuterLoop) {
356 assert(Resolved >= Pred &&
"unhandled irreducible control flow");
365 for (
const auto &
I :
Loop.Exits)
383 const Scaled64 InfiniteLoopScale(1, 12);
398 <<
" - scale = " <<
Loop.Scale <<
"\n");
407 if (
auto *
Loop =
Working[M.Index].getPackagedLoop())
411 Loop.IsPackaged =
true;
416 const DitheringDistributer &
D,
const BlockNode &
T,
418 dbgs() <<
" => assign " << M <<
" (" <<
D.RemMass <<
")";
434 DitheringDistributer
D(Dist, Mass);
440 Working[W.TargetNode.Index].getMass() += Taken;
446 assert(OuterLoop &&
"backedge or exit outside of loop");
463 auto Max = Scaled64::getZero();
464 for (
const FrequencyData &
F : BFI.
Freqs)
465 Max = std::max(Max,
F.Scaled);
474 const unsigned MaxBits =
sizeof(Scaled64::DigitsType) * CHAR_BIT;
478 const unsigned Slack = 10;
479 Scaled64 ScalingFactor = Scaled64(1, MaxBits - Slack) / Max;
483 auto Min = Scaled64::getLargest();
484 for (
const FrequencyData &
F : BFI.
Freqs)
485 Min = std::min(Min,
F.Scaled);
486 dbgs() <<
"float-to-int: min = " << Min <<
", max = " << Max
487 <<
", factor = " << ScalingFactor <<
"\n";
489 for (
size_t Index = 0; Index < BFI.
Freqs.size(); ++Index) {
490 Scaled64
Scaled = BFI.
Freqs[Index].Scaled * ScalingFactor;
493 << BFI.
Freqs[Index].Scaled <<
", scaled = " <<
Scaled
494 <<
", int = " << BFI.
Freqs[Index].Integer <<
"\n");
504 <<
": mass = " <<
Loop.Mass <<
", scale = " <<
Loop.Scale
507 Loop.IsPackaged =
false;
513 for (
const BlockNode &
N :
Loop.Nodes) {
514 const auto &Working = BFI.
Working[
N.Index];
515 Scaled64 &
F = Working.isAPackage() ? Working.getPackagedLoop()->Scale
516 : BFI.
Freqs[
N.Index].Scaled;
517 Scaled64 New =
Loop.Scale *
F;
526 for (
size_t Index = 0; Index <
Working.size(); ++Index)
546 if (!
Node.isValid()) {
560std::optional<uint64_t>
566std::optional<uint64_t>
569 auto EntryCount =
F.getEntryCount();
573 APInt BlockCount(128, *EntryCount);
576 BlockCount *= BlockFreq;
579 BlockCount = (BlockCount + EntryFreq.
lshr(1)).
udiv(EntryFreq);
599 assert(
Node.isValid() &&
"Expected valid node");
617 for (
auto N : OuterLoop.
Nodes)
624 for (
uint32_t Index = 0; Index <
BFI.Working.size(); ++Index)
625 if (!
BFI.Working[Index].isPackaged())
637 if (OuterLoop && OuterLoop->
isHeader(Succ))
643 Irr.
Succs.push_back(&SuccIrr);
664 std::list<LoopData>::iterator Insert,
672 LoopData::NodeList Members;
673 Members.reserve(SCC.size());
674 for (
const auto *
I : SCC) {
675 Members.push_back(
I->Node);
678 bool Header = IsEntry.
test(
G.getIndex(
I)) || Extra.
test(
G.getIndex(
I));
686 auto Loop = BFI.
Loops.emplace(Insert, OuterLoop, std::move(Members));
689 for (
const auto &
N :
Loop->Nodes)
690 if (BFI.
Working[
N.Index].isLoopHeader())
696iterator_range<std::list<LoopData>::iterator>
699 std::list<LoopData>::iterator Insert) {
700 assert((OuterLoop ==
nullptr) == (Insert ==
Loops.begin()));
701 auto Prev = OuterLoop ? std::prev(Insert) :
Loops.end();
709 for (
const auto *
N : *
I)
710 SccId[
G.getIndex(
N)] = Id;
721 for (
const auto &U :
G.Nodes)
722 for (
const auto *V : U.Succs)
723 if (SccId[
G.getIndex(&U)] != SccId[
G.getIndex(V)])
724 IsEntry.
set(
G.getIndex(V));
725 for (
const auto &U :
G.Nodes) {
726 if (IsEntry.
test(
G.getIndex(&U)))
728 for (
const auto *V : U.Succs)
729 if (SccId[
G.getIndex(V)] == SccId[
G.getIndex(&U)] && !(U.Node < V->Node))
730 Extra.
set(
G.getIndex(V));
733 for (
const auto &SCC : SCCs)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file implements a class to represent arbitrary precision integral constant values and operations...
static void combineWeightsBySorting(WeightList &Weights)
static void convertFloatingToInteger(BlockFrequencyInfoImplBase &BFI)
static void cleanup(BlockFrequencyInfoImplBase &BFI)
Clear all memory not needed downstream.
static void combineWeightsByHashing(WeightList &Weights)
static void unwrapLoop(BlockFrequencyInfoImplBase &BFI, LoopData &Loop)
Unwrap a loop package.
static void combineWeight(Weight &W, const Weight &OtherW)
static void debugAssign(const BlockFrequencyInfoImplBase &BFI, const DitheringDistributer &D, const BlockNode &T, const BlockMass &M, const char *Desc)
static void combineWeights(WeightList &Weights)
static char getHexDigit(int N)
static void createIrreducibleLoop(BlockFrequencyInfoImplBase &BFI, const IrreducibleGraph &G, LoopData *OuterLoop, std::list< LoopData >::iterator Insert, ArrayRef< const IrreducibleGraph::IrrNode * > SCC, const BitVector &IsEntry, const BitVector &Extra)
Package SCC into a loop represented by its lowest-RPO member.
static uint64_t shiftRightAndRound(uint64_t N, int Shift)
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
This file defines the DenseMap class.
This builds on the llvm/ADT/GraphTraits.h file to find the strongly connected components (SCCs) of a ...
This file defines the SmallString class.
Class for arbitrary precision integers.
LLVM_ABI APInt udiv(const APInt &RHS) const
Unsigned division operation.
uint64_t getLimitedValue(uint64_t Limit=UINT64_MAX) const
If this value is smaller than the specified limit, return it, otherwise return the limit value.
APInt lshr(unsigned shiftAmt) const
Logical right-shift function.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
bool test(unsigned Idx) const
Returns true if bit Idx is set.
BitVector & set()
Set all bits in the bitvector.
Base class for BlockFrequencyInfoImpl.
std::vector< WorkingData > Working
Loop data: see initializeLoops().
std::optional< uint64_t > getProfileCountFromFreq(const Function &F, BlockFrequency Freq) const
std::list< LoopData > Loops
Indexed information about loops.
void addToDist(Distribution &Dist, const LoopData *OuterLoop, const BlockNode &Pred, const BlockNode &Succ, uint64_t Weight)
Add an edge to the distribution.
std::optional< uint64_t > getBlockProfileCount(const Function &F, const BlockNode &Node) const
ScaledNumber< uint64_t > Scaled64
std::string getLoopName(const LoopData &Loop) const
bool TopContainsIrreducible
Has an irreducible SCC outside every loop.
bool isIrrLoopHeader(const BlockNode &Node)
void computeLoopScale(LoopData &Loop)
Compute the loop scale for a loop.
bfi_detail::BlockMass BlockMass
void packageLoop(LoopData &Loop)
Package up a loop.
virtual std::string getBlockName(const BlockNode &Node) const
void finalizeMetrics()
Finalize frequency metrics.
void setBlockFreq(const BlockNode &Node, BlockFrequency Freq)
BlockFrequency getEntryFreq() const
void clear()
Clear all memory.
BlockFrequency getBlockFreq(const BlockNode &Node) const
iterator_range< std::list< LoopData >::iterator > analyzeIrreducible(const bfi_detail::IrreducibleGraph &G, LoopData *OuterLoop, std::list< LoopData >::iterator Insert)
Analyze irreducible SCCs.
void unwrapLoops()
Unwrap loops.
Scaled64 getFloatingBlockFreq(const BlockNode &Node) const
void distributeMass(const BlockNode &Source, LoopData *OuterLoop, Distribution &Dist)
Distribute mass according to a distribution.
SparseBitVector IsIrrLoopHeader
Whether each block is an irreducible loop header.
void addLoopSuccessorsToDist(const LoopData *OuterLoop, LoopData &Loop, Distribution &Dist)
Add all edges out of a packaged loop to the distribution.
std::vector< FrequencyData > Freqs
Data about each block. This is used downstream.
uint64_t getFrequency() const
Returns the frequency as a fixpoint number scaled by the entry frequency.
BlockT * getHeader() const
Represents a single loop in the control flow graph.
Simple representation of a scaled number.
ScaledNumber inverse() const
static ScaledNumber getZero()
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
The instances of the Type class are immutable: once they are created, they are never changed.
LLVM_ABI raw_ostream & print(raw_ostream &OS) const
LLVM_ABI void dump() const
static BlockMass getFull()
LLVM_ABI ScaledNumber< uint64_t > toScaled() const
Convert to scaled number.
This class implements an extremely fast bulk output stream that can only output to a stream.
A raw_ostream that writes to an SmallVector or SmallString.
StringRef str() const
Return a StringRef for the vector contents.
std::string getBlockName(const BlockT *BB)
Get the name of a MachineBasicBlock.
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
scc_iterator< T > scc_begin(const T &G)
Construct the begin iterator for a deduced graph type T.
LLVM_ABI llvm::cl::opt< unsigned > IterativeBFIMaxIterationsPerBlock
int countl_zero(T Val)
Count number of 0's from the most significant bit to the least stopping at the first 1.
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI llvm::cl::opt< bool > UseIterativeBFIInference
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
LLVM_ABI llvm::cl::opt< bool > CheckBFIUnknownBlockQueries
LLVM_ABI llvm::cl::opt< double > IterativeBFIPrecision
constexpr uint64_t NextPowerOf2(uint64_t A)
Returns the next power of two (in 64-bits) that is strictly greater than A.
Representative of a block.
Distribution of unscaled probability weight.
void addBackedge(const BlockNode &Node, uint64_t Amount)
SmallVector< Weight, 4 > WeightList
WeightList Weights
Individual successor weights.
uint64_t Total
Sum of all weights.
LLVM_ABI void normalize()
Normalize the distribution.
void addExit(const BlockNode &Node, uint64_t Amount)
bool DidOverflow
Whether Total did overflow.
void addLocal(const BlockNode &Node, uint64_t Amount)
Stats about a block itself.
bool isHeader(const BlockNode &Node) const
ExitMap Exits
Successor edges (and weights).
BlockMass BackedgeMass
Mass that circulates, not exits.
BlockNode getHeader() const
NodeList Nodes
Header and the members of the loop.
Unscaled probability weight.
const GraphT::IrrNode * NodeRef
static ChildIteratorType child_begin(NodeRef N)
static ChildIteratorType child_end(NodeRef N)
bfi_detail::IrreducibleGraph GraphT
GraphT::IrrNode::iterator ChildIteratorType
static NodeRef getEntryNode(const GraphT &G)
SmallVector< const IrrNode *, 4 > Succs
Graph of irreducible control flow.
LLVM_ABI void addNodesInFunction()
LLVM_ABI void indexNodes()
LLVM_ABI void addEdge(IrrNode &Irr, const BlockNode &Succ, const BFIBase::LoopData *OuterLoop)
BFIBase::BlockNode BlockNode
std::vector< IrrNode > Nodes
SmallDenseMap< uint32_t, IrrNode *, 4 > Lookup
void addNode(const BlockNode &Node)
LLVM_ABI void addNodesInLoop(const BFIBase::LoopData &OuterLoop)