#include "llvm/Transforms/Instrumentation/PGOInstrumentation.h"
#include "ValueProfileCollector.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/ADT/iterator.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Analysis/BlockFrequencyInfo.h"
#include "llvm/Analysis/BranchProbabilityInfo.h"
#include "llvm/Analysis/CFG.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/Analysis/ProfileSummaryInfo.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Comdat.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/EHPersonalities.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalAlias.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/InstVisitor.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/ProfDataUtils.h"
#include "llvm/IR/ProfileSummary.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Value.h"
#include "llvm/ProfileData/InstrProf.h"
#include "llvm/ProfileData/InstrProfReader.h"
#include "llvm/Support/BranchProbability.h"
#include "llvm/Support/CRC.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/DOTGraphTraits.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/GraphWriter.h"
#include "llvm/Support/VirtualFileSystem.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TargetParser/Triple.h"
#include "llvm/Transforms/Instrumentation/BlockCoverageInference.h"
#include "llvm/Transforms/Instrumentation/CFGMST.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/Instrumentation.h"
#include "llvm/Transforms/Utils/MisExpect.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <memory>
#include <numeric>
#include <optional>
#include <stack>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
usingnamespacellvm;
ProfileCount;
VPCandidateInfo;
#define DEBUG_TYPE …
STATISTIC(NumOfPGOInstrument, "Number of edges instrumented.");
STATISTIC(NumOfPGOSelectInsts, "Number of select instruction instrumented.");
STATISTIC(NumOfPGOMemIntrinsics, "Number of mem intrinsics instrumented.");
STATISTIC(NumOfPGOEdge, "Number of edges.");
STATISTIC(NumOfPGOBB, "Number of basic-blocks.");
STATISTIC(NumOfPGOSplit, "Number of critical edge splits.");
STATISTIC(NumOfPGOFunc, "Number of functions having valid profile counts.");
STATISTIC(NumOfPGOMismatch, "Number of functions having mismatch profile.");
STATISTIC(NumOfPGOMissing, "Number of functions without profile.");
STATISTIC(NumOfPGOICall, "Number of indirect call value instrumentations.");
STATISTIC(NumOfCSPGOInstrument, "Number of edges instrumented in CSPGO.");
STATISTIC(NumOfCSPGOSelectInsts,
"Number of select instruction instrumented in CSPGO.");
STATISTIC(NumOfCSPGOMemIntrinsics,
"Number of mem intrinsics instrumented in CSPGO.");
STATISTIC(NumOfCSPGOEdge, "Number of edges in CSPGO.");
STATISTIC(NumOfCSPGOBB, "Number of basic-blocks in CSPGO.");
STATISTIC(NumOfCSPGOSplit, "Number of critical edge splits in CSPGO.");
STATISTIC(NumOfCSPGOFunc,
"Number of functions having valid profile counts in CSPGO.");
STATISTIC(NumOfCSPGOMismatch,
"Number of functions having mismatch profile in CSPGO.");
STATISTIC(NumOfCSPGOMissing, "Number of functions without profile in CSPGO.");
STATISTIC(NumCoveredBlocks, "Number of basic blocks that were executed");
static cl::opt<std::string>
PGOTestProfileFile("pgo-test-profile-file", cl::init(""), cl::Hidden,
cl::value_desc("filename"),
cl::desc("Specify the path of profile data file. This is"
"mainly for test purpose."));
static cl::opt<std::string> PGOTestProfileRemappingFile(
"pgo-test-profile-remapping-file", cl::init(""), cl::Hidden,
cl::value_desc("filename"),
cl::desc("Specify the path of profile remapping file. This is mainly for "
"test purpose."));
static cl::opt<bool> DisableValueProfiling("disable-vp", cl::init(false),
cl::Hidden,
cl::desc("Disable Value Profiling"));
static cl::opt<unsigned> MaxNumAnnotations(
"icp-max-annotations", cl::init(3), cl::Hidden,
cl::desc("Max number of annotations for a single indirect "
"call callsite"));
static cl::opt<unsigned> MaxNumMemOPAnnotations(
"memop-max-annotations", cl::init(4), cl::Hidden,
cl::desc("Max number of preicise value annotations for a single memop"
"intrinsic"));
static cl::opt<bool> DoComdatRenaming(
"do-comdat-renaming", cl::init(false), cl::Hidden,
cl::desc("Append function hash to the name of COMDAT function to avoid "
"function hash mismatch due to the preinliner"));
namespace llvm {
cl::opt<bool> PGOWarnMissing("pgo-warn-missing-function", cl::init(false),
cl::Hidden,
cl::desc("Use this option to turn on/off "
"warnings about missing profile data for "
"functions."));
cl::opt<bool>
NoPGOWarnMismatch("no-pgo-warn-mismatch", cl::init(false), cl::Hidden,
cl::desc("Use this option to turn off/on "
"warnings about profile cfg mismatch."));
cl::opt<bool> NoPGOWarnMismatchComdatWeak(
"no-pgo-warn-mismatch-comdat-weak", cl::init(true), cl::Hidden,
cl::desc("The option is used to turn on/off "
"warnings about hash mismatch for comdat "
"or weak functions."));
}
static cl::opt<bool>
PGOInstrSelect("pgo-instr-select", cl::init(true), cl::Hidden,
cl::desc("Use this option to turn on/off SELECT "
"instruction instrumentation. "));
static cl::opt<PGOViewCountsType> PGOViewRawCounts(
"pgo-view-raw-counts", cl::Hidden,
cl::desc("A boolean option to show CFG dag or text "
"with raw profile counts from "
"profile data. See also option "
"-pgo-view-counts. To limit graph "
"display to only one function, use "
"filtering option -view-bfi-func-name."),
cl::values(clEnumValN(PGOVCT_None, "none", "do not show."),
clEnumValN(PGOVCT_Graph, "graph", "show a graph."),
clEnumValN(PGOVCT_Text, "text", "show in text.")));
static cl::opt<bool>
PGOInstrMemOP("pgo-instr-memop", cl::init(true), cl::Hidden,
cl::desc("Use this option to turn on/off "
"memory intrinsic size profiling."));
static cl::opt<bool>
EmitBranchProbability("pgo-emit-branch-prob", cl::init(false), cl::Hidden,
cl::desc("When this option is on, the annotated "
"branch probability will be emitted as "
"optimization remarks: -{Rpass|"
"pass-remarks}=pgo-instrumentation"));
static cl::opt<bool> PGOInstrumentEntry(
"pgo-instrument-entry", cl::init(false), cl::Hidden,
cl::desc("Force to instrument function entry basicblock."));
static cl::opt<bool> PGOFunctionEntryCoverage(
"pgo-function-entry-coverage", cl::Hidden,
cl::desc(
"Use this option to enable function entry coverage instrumentation."));
static cl::opt<bool> PGOBlockCoverage(
"pgo-block-coverage",
cl::desc("Use this option to enable basic block coverage instrumentation"));
static cl::opt<bool>
PGOViewBlockCoverageGraph("pgo-view-block-coverage-graph",
cl::desc("Create a dot file of CFGs with block "
"coverage inference information"));
static cl::opt<bool> PGOTemporalInstrumentation(
"pgo-temporal-instrumentation",
cl::desc("Use this option to enable temporal instrumentation"));
static cl::opt<bool>
PGOFixEntryCount("pgo-fix-entry-count", cl::init(true), cl::Hidden,
cl::desc("Fix function entry count in profile use."));
static cl::opt<bool> PGOVerifyHotBFI(
"pgo-verify-hot-bfi", cl::init(false), cl::Hidden,
cl::desc("Print out the non-match BFI count if a hot raw profile count "
"becomes non-hot, or a cold raw profile count becomes hot. "
"The print is enabled under -Rpass-analysis=pgo, or "
"internal option -pass-remakrs-analysis=pgo."));
static cl::opt<bool> PGOVerifyBFI(
"pgo-verify-bfi", cl::init(false), cl::Hidden,
cl::desc("Print out mismatched BFI counts after setting profile metadata "
"The print is enabled under -Rpass-analysis=pgo, or "
"internal option -pass-remakrs-analysis=pgo."));
static cl::opt<unsigned> PGOVerifyBFIRatio(
"pgo-verify-bfi-ratio", cl::init(2), cl::Hidden,
cl::desc("Set the threshold for pgo-verify-bfi: only print out "
"mismatched BFI if the difference percentage is greater than "
"this value (in percentage)."));
static cl::opt<unsigned> PGOVerifyBFICutoff(
"pgo-verify-bfi-cutoff", cl::init(5), cl::Hidden,
cl::desc("Set the threshold for pgo-verify-bfi: skip the counts whose "
"profile count value is below."));
static cl::opt<std::string> PGOTraceFuncHash(
"pgo-trace-func-hash", cl::init("-"), cl::Hidden,
cl::value_desc("function name"),
cl::desc("Trace the hash of the function with this name."));
static cl::opt<unsigned> PGOFunctionSizeThreshold(
"pgo-function-size-threshold", cl::Hidden,
cl::desc("Do not instrument functions smaller than this threshold."));
static cl::opt<unsigned> PGOFunctionCriticalEdgeThreshold(
"pgo-critical-edge-threshold", cl::init(20000), cl::Hidden,
cl::desc("Do not instrument functions with the number of critical edges "
" greater than this threshold."));
extern cl::opt<unsigned> MaxNumVTableAnnotations;
namespace llvm {
extern cl::opt<PGOViewCountsType> PGOViewCounts;
extern cl::opt<std::string> ViewBlockFreqFuncName;
extern cl::opt<bool> EnableVTableValueProfiling;
extern cl::opt<bool> EnableVTableProfileUse;
extern cl::opt<InstrProfCorrelator::ProfCorrelatorKind> ProfileCorrelate;
}
namespace {
class FunctionInstrumenter final { … };
}
static std::string getBranchCondString(Instruction *TI) { … }
static const char *ValueProfKindDescr[] = …;
static GlobalVariable *
createIRLevelProfileFlagVar(Module &M,
PGOInstrumentationType InstrumentationType) { … }
namespace {
enum VisitMode { … };
class PGOUseFunc;
struct SelectInstVisitor : public InstVisitor<SelectInstVisitor> { … };
struct PGOEdge { … };
struct PGOBBInfo { … };
template <class Edge, class BBInfo> class FuncPGOInstrumentation { … };
}
template <class Edge, class BBInfo>
void FuncPGOInstrumentation<Edge, BBInfo>::computeCFGHash() { … }
static bool canRenameComdat(
Function &F,
std::unordered_multimap<Comdat *, GlobalValue *> &ComdatMembers) { … }
template <class Edge, class BBInfo>
void FuncPGOInstrumentation<Edge, BBInfo>::renameComdatFunction() { … }
template <class Edge, class BBInfo>
void FuncPGOInstrumentation<Edge, BBInfo>::getInstrumentBBs(
std::vector<BasicBlock *> &InstrumentBBs) { … }
template <class Edge, class BBInfo>
BasicBlock *FuncPGOInstrumentation<Edge, BBInfo>::getInstrBB(Edge *E) { … }
static void
populateEHOperandBundle(VPCandidateInfo &Cand,
DenseMap<BasicBlock *, ColorVector> &BlockColors,
SmallVectorImpl<OperandBundleDef> &OpBundles) { … }
void FunctionInstrumenter::instrument() { … }
namespace {
struct PGOUseEdge : public PGOEdge { … };
DirectEdges;
struct PGOUseBBInfo : public PGOBBInfo { … };
}
static uint64_t sumEdgeCount(const ArrayRef<PGOUseEdge *> Edges) { … }
namespace {
class PGOUseFunc { … };
}
static void setupBBInfoEdges(
const FuncPGOInstrumentation<PGOUseEdge, PGOUseBBInfo> &FuncInfo) { … }
bool PGOUseFunc::setInstrumentedCounts(
const std::vector<uint64_t> &CountFromProfile) { … }
void PGOUseFunc::setEdgeCount(DirectEdges &Edges, uint64_t Value) { … }
static void annotateFunctionWithHashMismatch(Function &F, LLVMContext &ctx) { … }
void PGOUseFunc::handleInstrProfError(Error Err, uint64_t MismatchedFuncSum) { … }
bool PGOUseFunc::readCounters(IndexedInstrProfReader *PGOReader, bool &AllZeros,
InstrProfRecord::CountPseudoKind &PseudoKind) { … }
void PGOUseFunc::populateCoverage(IndexedInstrProfReader *PGOReader) { … }
void PGOUseFunc::populateCounters() { … }
void PGOUseFunc::setBranchWeights() { … }
static bool isIndirectBrTarget(BasicBlock *BB) { … }
void PGOUseFunc::annotateIrrLoopHeaderWeights() { … }
void SelectInstVisitor::instrumentOneSelectInst(SelectInst &SI) { … }
void SelectInstVisitor::annotateOneSelectInst(SelectInst &SI) { … }
void SelectInstVisitor::visitSelectInst(SelectInst &SI) { … }
static uint32_t getMaxNumAnnotations(InstrProfValueKind ValueProfKind) { … }
void PGOUseFunc::annotateValueSites() { … }
void PGOUseFunc::annotateValueSites(uint32_t Kind) { … }
static void collectComdatMembers(
Module &M,
std::unordered_multimap<Comdat *, GlobalValue *> &ComdatMembers) { … }
static bool skipPGOUse(const Function &F) { … }
static bool skipPGOGen(const Function &F) { … }
static bool InstrumentAllFunctions(
Module &M, function_ref<TargetLibraryInfo &(Function &)> LookupTLI,
function_ref<BranchProbabilityInfo *(Function &)> LookupBPI,
function_ref<BlockFrequencyInfo *(Function &)> LookupBFI,
PGOInstrumentationType InstrumentationType) { … }
PreservedAnalyses
PGOInstrumentationGenCreateVar::run(Module &M, ModuleAnalysisManager &MAM) { … }
PreservedAnalyses PGOInstrumentationGen::run(Module &M,
ModuleAnalysisManager &MAM) { … }
static void fixFuncEntryCount(PGOUseFunc &Func, LoopInfo &LI,
BranchProbabilityInfo &NBPI) { … }
static void verifyFuncBFI(PGOUseFunc &Func, LoopInfo &LI,
BranchProbabilityInfo &NBPI,
uint64_t HotCountThreshold,
uint64_t ColdCountThreshold) { … }
static bool annotateAllFunctions(
Module &M, StringRef ProfileFileName, StringRef ProfileRemappingFileName,
vfs::FileSystem &FS,
function_ref<TargetLibraryInfo &(Function &)> LookupTLI,
function_ref<BranchProbabilityInfo *(Function &)> LookupBPI,
function_ref<BlockFrequencyInfo *(Function &)> LookupBFI,
ProfileSummaryInfo *PSI, bool IsCS) { … }
PGOInstrumentationUse::PGOInstrumentationUse(
std::string Filename, std::string RemappingFilename, bool IsCS,
IntrusiveRefCntPtr<vfs::FileSystem> VFS)
: … { … }
PreservedAnalyses PGOInstrumentationUse::run(Module &M,
ModuleAnalysisManager &MAM) { … }
static std::string getSimpleNodeName(const BasicBlock *Node) { … }
void llvm::setProfMetadata(Module *M, Instruction *TI,
ArrayRef<uint64_t> EdgeCounts, uint64_t MaxCount) { … }
namespace llvm {
void setIrrLoopHeaderMetadata(Module *M, Instruction *TI, uint64_t Count) { … }
template <> struct GraphTraits<PGOUseFunc *> { … };
template <> struct DOTGraphTraits<PGOUseFunc *> : DefaultDOTGraphTraits { … };
}