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 *>
|
std::vector<const FunctionSamples *>
|
||||||
findIndirectCallFunctionSamples(const Instruction &I) const;
|
findIndirectCallFunctionSamples(const Instruction &I) const;
|
||||||
const FunctionSamples *findFunctionSamples(const Instruction &I) const;
|
const FunctionSamples *findFunctionSamples(const Instruction &I) const;
|
||||||
|
bool inlineCallInstruction(Instruction *I);
|
||||||
bool inlineHotFunctions(Function &F,
|
bool inlineHotFunctions(Function &F,
|
||||||
DenseSet<GlobalValue::GUID> &ImportGUIDs);
|
DenseSet<GlobalValue::GUID> &ImportGUIDs);
|
||||||
void printEdgeWeight(raw_ostream &OS, Edge E);
|
void printEdgeWeight(raw_ostream &OS, Edge E);
|
||||||
|
@ -676,6 +677,39 @@ SampleProfileLoader::findFunctionSamples(const Instruction &Inst) const {
|
||||||
return FS;
|
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.
|
/// \brief Iteratively inline hot callsites of a function.
|
||||||
///
|
///
|
||||||
/// Iteratively traverse all callsites of the function \p F, and find if
|
/// Iteratively traverse all callsites of the function \p F, and find if
|
||||||
|
@ -713,82 +747,55 @@ bool SampleProfileLoader::inlineHotFunctions(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (auto I : CIS) {
|
for (auto I : CIS) {
|
||||||
InlineFunctionInfo IFI(nullptr, &GetAC);
|
|
||||||
Function *CalledFunction = CallSite(I).getCalledFunction();
|
Function *CalledFunction = CallSite(I).getCalledFunction();
|
||||||
// Do not inline recursive calls.
|
// Do not inline recursive calls.
|
||||||
if (CalledFunction == &F)
|
if (CalledFunction == &F)
|
||||||
continue;
|
continue;
|
||||||
Instruction *DI = I;
|
if (CallSite(I).isIndirectCall()) {
|
||||||
if (!CalledFunction && !PromotedInsns.count(I) &&
|
if (PromotedInsns.count(I))
|
||||||
CallSite(I).isIndirectCall()) {
|
continue;
|
||||||
for (const auto *FS : findIndirectCallFunctionSamples(*I)) {
|
for (const auto *FS : findIndirectCallFunctionSamples(*I)) {
|
||||||
auto CalleeFunctionName = FS->getName();
|
auto CalleeFunctionName = FS->getName();
|
||||||
// If it is a recursive call, we do not inline it as it could bloat
|
// 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.
|
// the code exponentially. There is way to better handle this, e.g.
|
||||||
// clone the caller first, and inline the cloned caller if it is
|
// clone the caller first, and inline the cloned caller if it is
|
||||||
// recursive. As llvm does not inline recursive calls, we will simply
|
// recursive. As llvm does not inline recursive calls, we will
|
||||||
// ignore it instead of handling it explicitly.
|
// simply ignore it instead of handling it explicitly.
|
||||||
if (CalleeFunctionName == F.getName())
|
if (CalleeFunctionName == F.getName())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const char *Reason = "Callee function not available";
|
const char *Reason = "Callee function not available";
|
||||||
auto R = SymbolMap.find(CalleeFunctionName);
|
auto R = SymbolMap.find(CalleeFunctionName);
|
||||||
if (R == SymbolMap.end())
|
if (R != SymbolMap.end() && R->getValue() &&
|
||||||
continue;
|
!R->getValue()->isDeclaration() &&
|
||||||
CalledFunction = R->getValue();
|
R->getValue()->getSubprogram() &&
|
||||||
if (CalledFunction && isLegalToPromote(I, CalledFunction, &Reason)) {
|
isLegalToPromote(I, R->getValue(), &Reason)) {
|
||||||
// The indirect target was promoted and inlined in the profile, as a
|
// The indirect target was promoted and inlined in the profile,
|
||||||
// result, we do not have profile info for the branch probability.
|
// as a result, we do not have profile info for the branch
|
||||||
// We set the probability to 80% taken to indicate that the static
|
// probability. We set the probability to 80% taken to indicate
|
||||||
// call is likely taken.
|
// that the static call is likely taken.
|
||||||
DI = dyn_cast<Instruction>(
|
Instruction *DI = dyn_cast<Instruction>(
|
||||||
promoteIndirectCall(I, CalledFunction, 80, 100, false, ORE)
|
promoteIndirectCall(I, R->getValue(), 80, 100, false, ORE)
|
||||||
->stripPointerCasts());
|
->stripPointerCasts());
|
||||||
PromotedInsns.insert(I);
|
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 {
|
} else {
|
||||||
DEBUG(dbgs() << "\nFailed to promote indirect call to "
|
FS->findImportedFunctions(ImportGUIDs, F.getParent(),
|
||||||
<< CalleeFunctionName << " because " << Reason
|
Samples->getTotalSamples() *
|
||||||
<< "\n");
|
SampleProfileHotThreshold / 100);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If there is profile mismatch, we should not attempt to inline DI.
|
} else if (CalledFunction && CalledFunction->getSubprogram() &&
|
||||||
if (!isa<CallInst>(DI) && !isa<InvokeInst>(DI))
|
!CalledFunction->isDeclaration()) {
|
||||||
continue;
|
if (inlineCallInstruction(I))
|
||||||
}
|
LocalChanged = true;
|
||||||
if (!CalledFunction || !CalledFunction->getSubprogram()) {
|
} else {
|
||||||
// Handles functions that are imported from other modules.
|
findCalleeFunctionSamples(*I)->findImportedFunctions(
|
||||||
for (const FunctionSamples *FS : findIndirectCallFunctionSamples(*I))
|
ImportGUIDs, F.getParent(),
|
||||||
FS->findImportedFunctions(
|
Samples->getTotalSamples() * SampleProfileHotThreshold / 100);
|
||||||
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) {
|
if (LocalChanged) {
|
||||||
|
|
Loading…
Reference in New Issue