forked from OSchip/llvm-project
Refactor the SamplePGO profile annotation logic to extract inlineCallInstruction. (NFC)
llvm-svn: 314601
This commit is contained in:
parent
7ae3c3fee3
commit
4f5d830343
|
@ -172,6 +172,7 @@ protected:
|
|||
std::vector<const FunctionSamples *>
|
||||
findIndirectCallFunctionSamples(const Instruction &I) const;
|
||||
const FunctionSamples *findFunctionSamples(const Instruction &I) const;
|
||||
bool inlineCallInstruction(Instruction *I);
|
||||
bool inlineHotFunctions(Function &F,
|
||||
DenseSet<GlobalValue::GUID> &ImportGUIDs);
|
||||
void printEdgeWeight(raw_ostream &OS, Edge E);
|
||||
|
@ -676,6 +677,39 @@ SampleProfileLoader::findFunctionSamples(const Instruction &Inst) const {
|
|||
return FS;
|
||||
}
|
||||
|
||||
bool SampleProfileLoader::inlineCallInstruction(Instruction *I) {
|
||||
assert(isa<CallInst>(I) || isa<InvokeInst>(I));
|
||||
CallSite CS(I);
|
||||
Function *CalledFunction = CS.getCalledFunction();
|
||||
assert(CalledFunction);
|
||||
DebugLoc DLoc = I->getDebugLoc();
|
||||
BasicBlock *BB = I->getParent();
|
||||
InlineParams Params = getInlineParams();
|
||||
Params.ComputeFullInlineCost = true;
|
||||
// Checks if there is anything in the reachable portion of the callee at
|
||||
// this callsite that makes this inlining potentially illegal. Need to
|
||||
// set ComputeFullInlineCost, otherwise getInlineCost may return early
|
||||
// when cost exceeds threshold without checking all IRs in the callee.
|
||||
// The acutal cost does not matter because we only checks isNever() to
|
||||
// see if it is legal to inline the callsite.
|
||||
InlineCost Cost = getInlineCost(CS, Params, GetTTI(*CalledFunction), GetAC,
|
||||
None, nullptr, nullptr);
|
||||
if (Cost.isNever()) {
|
||||
ORE->emit(OptimizationRemark(DEBUG_TYPE, "Not inline", DLoc, BB)
|
||||
<< "incompatible inlining");
|
||||
return false;
|
||||
}
|
||||
InlineFunctionInfo IFI(nullptr, &GetAC);
|
||||
if (InlineFunction(CS, IFI)) {
|
||||
// The call to InlineFunction erases I, so we can't pass it here.
|
||||
ORE->emit(OptimizationRemark(DEBUG_TYPE, "HotInline", DLoc, BB)
|
||||
<< "inlined hot callee '" << ore::NV("Callee", CalledFunction)
|
||||
<< "' into '" << ore::NV("Caller", BB->getParent()) << "'");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \brief Iteratively inline hot callsites of a function.
|
||||
///
|
||||
/// Iteratively traverse all callsites of the function \p F, and find if
|
||||
|
@ -713,82 +747,55 @@ bool SampleProfileLoader::inlineHotFunctions(
|
|||
}
|
||||
}
|
||||
for (auto I : CIS) {
|
||||
InlineFunctionInfo IFI(nullptr, &GetAC);
|
||||
Function *CalledFunction = CallSite(I).getCalledFunction();
|
||||
// Do not inline recursive calls.
|
||||
if (CalledFunction == &F)
|
||||
continue;
|
||||
Instruction *DI = I;
|
||||
if (!CalledFunction && !PromotedInsns.count(I) &&
|
||||
CallSite(I).isIndirectCall()) {
|
||||
if (CallSite(I).isIndirectCall()) {
|
||||
if (PromotedInsns.count(I))
|
||||
continue;
|
||||
for (const auto *FS : findIndirectCallFunctionSamples(*I)) {
|
||||
auto CalleeFunctionName = FS->getName();
|
||||
// If it is a recursive call, we do not inline it as it could bloat
|
||||
// the code exponentially. There is way to better handle this, e.g.
|
||||
// clone the caller first, and inline the cloned caller if it is
|
||||
// recursive. As llvm does not inline recursive calls, we will simply
|
||||
// ignore it instead of handling it explicitly.
|
||||
// recursive. As llvm does not inline recursive calls, we will
|
||||
// simply ignore it instead of handling it explicitly.
|
||||
if (CalleeFunctionName == F.getName())
|
||||
continue;
|
||||
|
||||
const char *Reason = "Callee function not available";
|
||||
auto R = SymbolMap.find(CalleeFunctionName);
|
||||
if (R == SymbolMap.end())
|
||||
continue;
|
||||
CalledFunction = R->getValue();
|
||||
if (CalledFunction && isLegalToPromote(I, CalledFunction, &Reason)) {
|
||||
// The indirect target was promoted and inlined in the profile, as a
|
||||
// result, we do not have profile info for the branch probability.
|
||||
// We set the probability to 80% taken to indicate that the static
|
||||
// call is likely taken.
|
||||
DI = dyn_cast<Instruction>(
|
||||
promoteIndirectCall(I, CalledFunction, 80, 100, false, ORE)
|
||||
if (R != SymbolMap.end() && R->getValue() &&
|
||||
!R->getValue()->isDeclaration() &&
|
||||
R->getValue()->getSubprogram() &&
|
||||
isLegalToPromote(I, R->getValue(), &Reason)) {
|
||||
// The indirect target was promoted and inlined in the profile,
|
||||
// as a result, we do not have profile info for the branch
|
||||
// probability. We set the probability to 80% taken to indicate
|
||||
// that the static call is likely taken.
|
||||
Instruction *DI = dyn_cast<Instruction>(
|
||||
promoteIndirectCall(I, R->getValue(), 80, 100, false, ORE)
|
||||
->stripPointerCasts());
|
||||
PromotedInsns.insert(I);
|
||||
// If profile mismatches, we should not attempt to inline DI.
|
||||
if ((isa<CallInst>(DI) || isa<InvokeInst>(DI)) &&
|
||||
inlineCallInstruction(DI))
|
||||
LocalChanged = true;
|
||||
} else {
|
||||
DEBUG(dbgs() << "\nFailed to promote indirect call to "
|
||||
<< CalleeFunctionName << " because " << Reason
|
||||
<< "\n");
|
||||
continue;
|
||||
FS->findImportedFunctions(ImportGUIDs, F.getParent(),
|
||||
Samples->getTotalSamples() *
|
||||
SampleProfileHotThreshold / 100);
|
||||
}
|
||||
}
|
||||
// If there is profile mismatch, we should not attempt to inline DI.
|
||||
if (!isa<CallInst>(DI) && !isa<InvokeInst>(DI))
|
||||
continue;
|
||||
}
|
||||
if (!CalledFunction || !CalledFunction->getSubprogram()) {
|
||||
// Handles functions that are imported from other modules.
|
||||
for (const FunctionSamples *FS : findIndirectCallFunctionSamples(*I))
|
||||
FS->findImportedFunctions(
|
||||
ImportGUIDs, F.getParent(),
|
||||
Samples->getTotalSamples() * SampleProfileHotThreshold / 100);
|
||||
continue;
|
||||
}
|
||||
assert(isa<CallInst>(DI) || isa<InvokeInst>(DI));
|
||||
CallSite CS(DI);
|
||||
DebugLoc DLoc = I->getDebugLoc();
|
||||
BasicBlock *BB = I->getParent();
|
||||
InlineParams Params = getInlineParams();
|
||||
Params.ComputeFullInlineCost = true;
|
||||
// Checks if there is anything in the reachable portion of the callee at
|
||||
// this callsite that makes this inlining potentially illegal. Need to
|
||||
// set ComputeFullInlineCost, otherwise getInlineCost may return early
|
||||
// when cost exceeds threshold without checking all IRs in the callee.
|
||||
// The acutal cost does not matter because we only checks isNever() to
|
||||
// see if it is legal to inline the callsite.
|
||||
InlineCost Cost = getInlineCost(CS, Params, GetTTI(*CalledFunction), GetAC,
|
||||
None, nullptr, nullptr);
|
||||
if (Cost.isNever()) {
|
||||
ORE->emit(OptimizationRemark(DEBUG_TYPE, "Not inline", DLoc, BB)
|
||||
<< "incompatible inlining");
|
||||
continue;
|
||||
}
|
||||
if (InlineFunction(CS, IFI)) {
|
||||
LocalChanged = true;
|
||||
// The call to InlineFunction erases DI, so we can't pass it here.
|
||||
ORE->emit(OptimizationRemark(DEBUG_TYPE, "HotInline", DLoc, BB)
|
||||
<< "inlined hot callee '"
|
||||
<< ore::NV("Callee", CalledFunction) << "' into '"
|
||||
<< ore::NV("Caller", &F) << "'");
|
||||
} else if (CalledFunction && CalledFunction->getSubprogram() &&
|
||||
!CalledFunction->isDeclaration()) {
|
||||
if (inlineCallInstruction(I))
|
||||
LocalChanged = true;
|
||||
} else {
|
||||
findCalleeFunctionSamples(*I)->findImportedFunctions(
|
||||
ImportGUIDs, F.getParent(),
|
||||
Samples->getTotalSamples() * SampleProfileHotThreshold / 100);
|
||||
}
|
||||
}
|
||||
if (LocalChanged) {
|
||||
|
|
Loading…
Reference in New Issue