#include "bolt/Passes/IndirectCallPromotion.h"
#include "bolt/Core/BinaryFunctionCallGraph.h"
#include "bolt/Passes/DataflowInfoManager.h"
#include "bolt/Passes/Inliner.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/CommandLine.h"
#include <iterator>
#define DEBUG_TYPE …
#define DEBUG_VERBOSE(Level, X) …
usingnamespacellvm;
usingnamespacebolt;
namespace opts {
extern cl::OptionCategory BoltOptCategory;
extern cl::opt<IndirectCallPromotionType> ICP;
extern cl::opt<unsigned> Verbosity;
extern cl::opt<unsigned> ExecutionCountThreshold;
static cl::opt<unsigned> ICPJTRemainingPercentThreshold(
"icp-jt-remaining-percent-threshold",
cl::desc("The percentage threshold against remaining unpromoted indirect "
"call count for the promotion for jump tables"),
cl::init(30), cl::ZeroOrMore, cl::Hidden, cl::cat(BoltOptCategory));
static cl::opt<unsigned> ICPJTTotalPercentThreshold(
"icp-jt-total-percent-threshold",
cl::desc(
"The percentage threshold against total count for the promotion for "
"jump tables"),
cl::init(5), cl::Hidden, cl::cat(BoltOptCategory));
static cl::opt<unsigned> ICPCallsRemainingPercentThreshold(
"icp-calls-remaining-percent-threshold",
cl::desc("The percentage threshold against remaining unpromoted indirect "
"call count for the promotion for calls"),
cl::init(50), cl::Hidden, cl::cat(BoltOptCategory));
static cl::opt<unsigned> ICPCallsTotalPercentThreshold(
"icp-calls-total-percent-threshold",
cl::desc(
"The percentage threshold against total count for the promotion for "
"calls"),
cl::init(30), cl::Hidden, cl::cat(BoltOptCategory));
static cl::opt<unsigned> ICPMispredictThreshold(
"indirect-call-promotion-mispredict-threshold",
cl::desc("misprediction threshold for skipping ICP on an "
"indirect call"),
cl::init(0), cl::cat(BoltOptCategory));
static cl::alias ICPMispredictThresholdAlias(
"icp-mp-threshold",
cl::desc("alias for --indirect-call-promotion-mispredict-threshold"),
cl::aliasopt(ICPMispredictThreshold));
static cl::opt<bool> ICPUseMispredicts(
"indirect-call-promotion-use-mispredicts",
cl::desc("use misprediction frequency for determining whether or not ICP "
"should be applied at a callsite. The "
"-indirect-call-promotion-mispredict-threshold value will be used "
"by this heuristic"),
cl::cat(BoltOptCategory));
static cl::alias ICPUseMispredictsAlias(
"icp-use-mp",
cl::desc("alias for --indirect-call-promotion-use-mispredicts"),
cl::aliasopt(ICPUseMispredicts));
static cl::opt<unsigned>
ICPTopN("indirect-call-promotion-topn",
cl::desc("limit number of targets to consider when doing indirect "
"call promotion. 0 = no limit"),
cl::init(3), cl::cat(BoltOptCategory));
static cl::alias
ICPTopNAlias("icp-topn",
cl::desc("alias for --indirect-call-promotion-topn"),
cl::aliasopt(ICPTopN));
static cl::opt<unsigned> ICPCallsTopN(
"indirect-call-promotion-calls-topn",
cl::desc("limit number of targets to consider when doing indirect "
"call promotion on calls. 0 = no limit"),
cl::init(0), cl::cat(BoltOptCategory));
static cl::alias ICPCallsTopNAlias(
"icp-calls-topn",
cl::desc("alias for --indirect-call-promotion-calls-topn"),
cl::aliasopt(ICPCallsTopN));
static cl::opt<unsigned> ICPJumpTablesTopN(
"indirect-call-promotion-jump-tables-topn",
cl::desc("limit number of targets to consider when doing indirect "
"call promotion on jump tables. 0 = no limit"),
cl::init(0), cl::cat(BoltOptCategory));
static cl::alias ICPJumpTablesTopNAlias(
"icp-jt-topn",
cl::desc("alias for --indirect-call-promotion-jump-tables-topn"),
cl::aliasopt(ICPJumpTablesTopN));
static cl::opt<bool> EliminateLoads(
"icp-eliminate-loads",
cl::desc("enable load elimination using memory profiling data when "
"performing ICP"),
cl::init(true), cl::cat(BoltOptCategory));
static cl::opt<unsigned> ICPTopCallsites(
"icp-top-callsites",
cl::desc("optimize hottest calls until at least this percentage of all "
"indirect calls frequency is covered. 0 = all callsites"),
cl::init(99), cl::Hidden, cl::cat(BoltOptCategory));
static cl::list<std::string>
ICPFuncsList("icp-funcs", cl::CommaSeparated,
cl::desc("list of functions to enable ICP for"),
cl::value_desc("func1,func2,func3,..."), cl::Hidden,
cl::cat(BoltOptCategory));
static cl::opt<bool>
ICPOldCodeSequence("icp-old-code-sequence",
cl::desc("use old code sequence for promoted calls"),
cl::Hidden, cl::cat(BoltOptCategory));
static cl::opt<bool> ICPJumpTablesByTarget(
"icp-jump-tables-targets",
cl::desc(
"for jump tables, optimize indirect jmp targets instead of indices"),
cl::Hidden, cl::cat(BoltOptCategory));
static cl::alias
ICPJumpTablesByTargetAlias("icp-jt-targets",
cl::desc("alias for --icp-jump-tables-targets"),
cl::aliasopt(ICPJumpTablesByTarget));
static cl::opt<bool> ICPPeelForInline(
"icp-inline", cl::desc("only promote call targets eligible for inlining"),
cl::Hidden, cl::cat(BoltOptCategory));
}
#ifndef NDEBUG
static bool verifyProfile(std::map<uint64_t, BinaryFunction> &BFs) {
bool IsValid = true;
for (auto &BFI : BFs) {
BinaryFunction &BF = BFI.second;
if (!BF.isSimple())
continue;
for (const BinaryBasicBlock &BB : BF) {
auto BI = BB.branch_info_begin();
for (BinaryBasicBlock *SuccBB : BB.successors()) {
if (BI->Count != BinaryBasicBlock::COUNT_NO_PROFILE && BI->Count > 0) {
if (BB.getKnownExecutionCount() == 0 ||
SuccBB->getKnownExecutionCount() == 0) {
BF.getBinaryContext().errs()
<< "BOLT-WARNING: profile verification failed after ICP for "
"function "
<< BF << '\n';
IsValid = false;
}
}
++BI;
}
}
}
return IsValid;
}
#endif
namespace llvm {
namespace bolt {
IndirectCallPromotion::Callsite::Callsite(BinaryFunction &BF,
const IndirectCallProfile &ICP)
: … { … }
void IndirectCallPromotion::printDecision(
llvm::raw_ostream &OS,
std::vector<IndirectCallPromotion::Callsite> &Targets, unsigned N) const { … }
std::vector<IndirectCallPromotion::Callsite>
IndirectCallPromotion::getCallTargets(BinaryBasicBlock &BB,
const MCInst &Inst) const { … }
IndirectCallPromotion::JumpTableInfoType
IndirectCallPromotion::maybeGetHotJumpTableTargets(BinaryBasicBlock &BB,
MCInst &CallInst,
MCInst *&TargetFetchInst,
const JumpTable *JT) const { … }
IndirectCallPromotion::SymTargetsType
IndirectCallPromotion::findCallTargetSymbols(std::vector<Callsite> &Targets,
size_t &N, BinaryBasicBlock &BB,
MCInst &CallInst,
MCInst *&TargetFetchInst) const { … }
IndirectCallPromotion::MethodInfoType IndirectCallPromotion::maybeGetVtableSyms(
BinaryBasicBlock &BB, MCInst &Inst,
const SymTargetsType &SymTargets) const { … }
std::vector<std::unique_ptr<BinaryBasicBlock>>
IndirectCallPromotion::rewriteCall(
BinaryBasicBlock &IndCallBlock, const MCInst &CallInst,
MCPlusBuilder::BlocksVectorTy &&ICPcode,
const std::vector<MCInst *> &MethodFetchInsns) const { … }
BinaryBasicBlock *
IndirectCallPromotion::fixCFG(BinaryBasicBlock &IndCallBlock,
const bool IsTailCall, const bool IsJumpTable,
IndirectCallPromotion::BasicBlocksVector &&NewBBs,
const std::vector<Callsite> &Targets) const { … }
size_t IndirectCallPromotion::canPromoteCallsite(
const BinaryBasicBlock &BB, const MCInst &Inst,
const std::vector<Callsite> &Targets, uint64_t NumCalls) { … }
void IndirectCallPromotion::printCallsiteInfo(
const BinaryBasicBlock &BB, const MCInst &Inst,
const std::vector<Callsite> &Targets, const size_t N,
uint64_t NumCalls) const { … }
Error IndirectCallPromotion::runOnFunctions(BinaryContext &BC) { … }
}
}