18#include "llvm/Config/llvm-config.h"
41#define DEBUG_TYPE "block-freq"
46 cl::desc(
"Apply an iterative post-processing to infer correct BFI counts"));
65#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
77 for (
int Digits = 0; Digits < 16; ++Digits)
110struct DitheringDistributer {
114 DitheringDistributer(Distribution &Dist,
const BlockMass &Mass);
121DitheringDistributer::DitheringDistributer(Distribution &Dist,
124 RemWeight = Dist.Total;
128BlockMass DitheringDistributer::takeMass(uint32_t Weight) {
129 assert(Weight &&
"invalid weight");
130 assert(Weight <= RemWeight);
131 BlockMass Mass = RemMass * BranchProbability(Weight, RemWeight);
139void Distribution::add(
const BlockNode &Node,
uint64_t Amount,
140 Weight::DistType
Type) {
141 assert(Amount &&
"invalid weight of 0");
145 bool IsOverflow = NewTotal <
Total;
146 assert(!(DidOverflow && IsOverflow) &&
"unexpected repeated overflow");
147 DidOverflow |= IsOverflow;
153 Weights.push_back(Weight(
Type, Node, Amount));
157 assert(OtherW.TargetNode.isValid());
162 assert(W.Type == OtherW.Type);
163 assert(W.TargetNode == OtherW.TargetNode);
164 assert(OtherW.Amount &&
"Expected non-zero weight");
165 if (W.Amount > W.Amount + OtherW.Amount)
169 W.Amount += OtherW.Amount;
174 llvm::sort(Weights, [](
const Weight &L,
const Weight &R) {
175 return L.TargetNode < R.TargetNode;
179 WeightList::iterator O = Weights.begin();
180 for (WeightList::const_iterator
I = O, L = O,
E = Weights.end();
I !=
E;
185 for (++L; L !=
E &&
I->TargetNode == L->TargetNode; ++L)
190 Weights.erase(O, Weights.end());
195 Combined.
reserve(Weights.size());
196 for (
const Weight &W : Weights)
200 if (Weights.size() == Combined.
size())
205 for (
const auto &
I : Combined)
206 Weights.push_back(
I.second);
211 if (Weights.size() > 128) {
224 return (
N >> Shift) + (UINT64_C(1) &
N >> (Shift - 1));
250 else if (
Total > UINT32_MAX)
258 [](uint64_t Sum,
const Weight &W) {
259 return Sum + W.Amount;
261 "Expected total to be correct");
273 assert(W.TargetNode.isValid());
275 assert(W.Amount <= UINT32_MAX);
286 std::vector<FrequencyData>().swap(
Freqs);
288 std::vector<WorkingData>().swap(
Working);
297 std::vector<FrequencyData> SavedFreqs(std::move(BFI.
Freqs));
300 BFI.
Freqs = std::move(SavedFreqs);
319 auto debugSuccessor = [&](
const char *
Type) {
322 if (!isLoopHeader(Resolved))
325 if (Resolved != Succ)
329 (void)debugSuccessor;
332 if (isLoopHeader(Resolved)) {
338 if (
Working[Resolved.Index].getContainingLoop() != OuterLoop) {
347 assert(Resolved >= Pred &&
"unhandled irreducible control flow");
356 for (
const auto &
I :
Loop.Exits)
374 const Scaled64 InfiniteLoopScale(1, 12);
389 <<
" - scale = " <<
Loop.Scale <<
"\n");
398 if (
auto *
Loop =
Working[M.Index].getPackagedLoop())
402 Loop.IsPackaged =
true;
407 const DitheringDistributer &
D,
const BlockNode &
T,
409 dbgs() <<
" => assign " << M <<
" (" <<
D.RemMass <<
")";
425 DitheringDistributer
D(Dist, Mass);
431 Working[W.TargetNode.Index].getMass() += Taken;
437 assert(OuterLoop &&
"backedge or exit outside of loop");
454 auto Max = Scaled64::getZero();
455 for (
const FrequencyData &
F : BFI.
Freqs)
456 Max = std::max(Max,
F.Scaled);
465 const unsigned MaxBits =
sizeof(Scaled64::DigitsType) * CHAR_BIT;
469 const unsigned Slack = 10;
470 Scaled64 ScalingFactor = Scaled64(1, MaxBits - Slack) / Max;
474 auto Min = Scaled64::getLargest();
475 for (
const FrequencyData &
F : BFI.
Freqs)
476 Min = std::min(Min,
F.Scaled);
477 dbgs() <<
"float-to-int: min = " << Min <<
", max = " << Max
478 <<
", factor = " << ScalingFactor <<
"\n";
480 for (
size_t Index = 0; Index < BFI.
Freqs.size(); ++Index) {
481 Scaled64
Scaled = BFI.
Freqs[Index].Scaled * ScalingFactor;
484 << BFI.
Freqs[Index].Scaled <<
", scaled = " <<
Scaled
485 <<
", int = " << BFI.
Freqs[Index].Integer <<
"\n");
495 <<
": mass = " <<
Loop.Mass <<
", scale = " <<
Loop.Scale
498 Loop.IsPackaged =
false;
504 for (
const BlockNode &
N :
Loop.Nodes) {
505 const auto &Working = BFI.
Working[
N.Index];
506 Scaled64 &
F = Working.isAPackage() ? Working.getPackagedLoop()->Scale
507 : BFI.
Freqs[
N.Index].Scaled;
508 Scaled64 New =
Loop.Scale *
F;
517 for (
size_t Index = 0; Index <
Working.size(); ++Index)
537 if (!
Node.isValid()) {
551std::optional<uint64_t>
557std::optional<uint64_t>
560 auto EntryCount =
F.getEntryCount();
583 assert(
Node.isValid() &&
"Expected valid node");
601 for (
auto N : OuterLoop.
Nodes)
608 for (
uint32_t Index = 0; Index <
BFI.Working.size(); ++Index)
609 if (!
BFI.Working[Index].isPackaged())
621 if (OuterLoop && OuterLoop->
isHeader(Succ))
627 Irr.
Succs.push_back(&SuccIrr);
648 std::list<LoopData>::iterator Insert,
656 LoopData::NodeList Members;
657 Members.reserve(SCC.size());
658 for (
const auto *
I : SCC) {
659 Members.push_back(
I->Node);
662 bool Header = IsEntry.
test(
G.getIndex(
I)) || Extra.
test(
G.getIndex(
I));
670 auto Loop = BFI.
Loops.emplace(Insert, OuterLoop, std::move(Members));
673 for (
const auto &
N :
Loop->Nodes)
674 if (BFI.
Working[
N.Index].isLoopHeader())
680iterator_range<std::list<LoopData>::iterator>
683 std::list<LoopData>::iterator Insert) {
684 assert((OuterLoop ==
nullptr) == (Insert ==
Loops.begin()));
685 auto Prev = OuterLoop ? std::prev(Insert) :
Loops.end();
693 for (
const auto *
N : *
I)
694 SccId[
G.getIndex(
N)] = Id;
705 for (
const auto &U :
G.Nodes)
706 for (
const auto *V : U.Succs)
707 if (SccId[
G.getIndex(&U)] != SccId[
G.getIndex(V)])
708 IsEntry.
set(
G.getIndex(V));
709 for (
const auto &U :
G.Nodes) {
710 if (IsEntry.
test(
G.getIndex(&U)))
712 for (
const auto *V : U.Succs)
713 if (SccId[
G.getIndex(V)] == SccId[
G.getIndex(&U)] && !(U.Node < V->Node))
714 Extra.
set(
G.getIndex(V));
717 for (
const auto &SCC : SCCs)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
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 implements a map that provides insertion order iteration.
This builds on the llvm/ADT/GraphTraits.h file to find the strongly connected components (SCCs) of a ...
This file defines the SmallString class.
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.
bool CheckUnknownBlockQueries
-check-bfi-unknown-block-queries of the function's context.
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.
This is an important class for using LLVM in a threaded context.
BlockT * getHeader() const
Represents a single loop in the control flow graph.
This class implements a map that also provides access to all stored values in a deterministic order.
void reserve(size_type NumEntries)
Grow the MapVector so that it can contain at least NumEntries items before resizing again.
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.
This is an optimization pass for GlobalISel generic memory operations.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
LLVM_ABI unsigned getIterativeBFIMaxIterationsPerBlock(const LLVMContext &C)
Return -iterative-bfi-max-iterations-per-block.
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.
const AnalysisOptions & getAnalysisOptions(const LLVMContext &C)
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 uint64_t mulDivNearest(uint64_t X, uint64_t Y, uint64_t Z)
Returns (X * Y) / Z rounded by round-half-up, like divideNearest.
LLVM_ABI bool shouldCheckBFIUnknownBlockQueries(const LLVMContext &C)
Return -check-bfi-unknown-block-queries.
LLVM_ABI double getIterativeBFIPrecision(const LLVMContext &C)
Return -iterative-bfi-precision.
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)