Refactor the SamplePGO profile annotation logic to extract inlineCallInstruction. (NFC)

llvm-svn: 314601
This commit is contained in:
Dehao Chen 2017-09-30 20:46:15 +00:00
parent 7ae3c3fee3
commit 4f5d830343
1 changed files with 65 additions and 58 deletions

View File

@ -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(
} else if (CalledFunction && CalledFunction->getSubprogram() &&
!CalledFunction->isDeclaration()) {
if (inlineCallInstruction(I))
LocalChanged = true;
} else {
findCalleeFunctionSamples(*I)->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) << "'");
}
}
if (LocalChanged) {