64#define DEBUG_TYPE "partial-inlining"
67 "Number of callsites functions partially inlined into.");
68STATISTIC(NumColdOutlinePartialInlined,
"Number of times functions with "
69 "cold outlined regions were partially "
70 "inlined into its caller(s).");
72 "Number of cold single entry/exit regions found.");
74 "Number of cold single entry/exit regions outlined.");
84 cl::desc(
"Disable multi-region partial inlining"));
90 cl::desc(
"Force outline regions with live exits"));
96 cl::desc(
"Mark outline function calls with ColdCC"));
109 cl::desc(
"Minimum ratio comparing relative sizes of each "
110 "outline candidate and original function"));
115 cl::desc(
"Minimum block executions to consider "
116 "its BranchProbabilityInfo valid"));
121 cl::desc(
"Minimum BranchProbability to consider a region cold."));
125 cl::desc(
"Max number of blocks to be partially inlined"));
131 cl::desc(
"Max number of partial inlining. The default is unlimited"));
139 cl::desc(
"Relative frequency of outline region to "
144 cl::desc(
"A debug option to add additional penalty to the computed one."));
148struct FunctionOutliningInfo {
149 FunctionOutliningInfo() =
default;
153 unsigned getNumInlinedBlocks()
const {
return Entries.size() + 1; }
169struct FunctionOutliningMultiRegionInfo {
170 FunctionOutliningMultiRegionInfo() =
default;
173 struct OutlineRegionInfo {
175 BasicBlock *ExitBlock, BasicBlock *ReturnBlock)
176 : Region(Region), EntryBlock(EntryBlock), ExitBlock(ExitBlock),
177 ReturnBlock(ReturnBlock) {}
178 SmallVector<BasicBlock *, 8> Region;
187struct PartialInlinerImpl {
190 function_ref<AssumptionCache &(Function &)> GetAC,
191 function_ref<AssumptionCache *(Function &)> LookupAC,
192 function_ref<TargetTransformInfo &(Function &)> GTTI,
193 function_ref<
const TargetLibraryInfo &(Function &)> GTLI,
194 ProfileSummaryInfo &ProfSI,
195 function_ref<BlockFrequencyInfo &(Function &)> GBFI =
nullptr)
196 : GetAssumptionCache(GetAC), LookupAssumptionCache(LookupAC),
197 GetTTI(GTTI), GetBFI(GBFI), GetTLI(GTLI), PSI(ProfSI) {}
207 std::pair<bool, Function *> unswitchFunction(Function &
F);
213 struct FunctionCloner {
216 FunctionCloner(Function *
F, FunctionOutliningInfo *OI,
217 OptimizationRemarkEmitter &ORE,
218 function_ref<AssumptionCache *(Function &)> LookupAC,
219 function_ref<TargetTransformInfo &(Function &)> GetTTI);
220 FunctionCloner(Function *
F, FunctionOutliningMultiRegionInfo *OMRI,
221 OptimizationRemarkEmitter &ORE,
222 function_ref<AssumptionCache *(Function &)> LookupAC,
223 function_ref<TargetTransformInfo &(Function &)> GetTTI);
230 void normalizeReturnBlock()
const;
233 bool doMultiRegionFunctionOutlining();
240 Function *doSingleRegionFunctionOutlining();
245 typedef std::pair<Function *, BasicBlock *> FuncBodyCallerPair;
251 bool IsFunctionInlined =
false;
255 std::unique_ptr<FunctionOutliningInfo> ClonedOI =
nullptr;
257 std::unique_ptr<FunctionOutliningMultiRegionInfo> ClonedOMRI =
nullptr;
258 std::unique_ptr<BlockFrequencyInfo> ClonedFuncBFI =
nullptr;
259 OptimizationRemarkEmitter &ORE;
260 function_ref<AssumptionCache *(
Function &)> LookupAC;
261 function_ref<TargetTransformInfo &(
Function &)> GetTTI;
265 int NumPartialInlining = 0;
266 function_ref<AssumptionCache &(
Function &)> GetAssumptionCache;
267 function_ref<AssumptionCache *(
Function &)> LookupAssumptionCache;
268 function_ref<TargetTransformInfo &(
Function &)> GetTTI;
269 function_ref<BlockFrequencyInfo &(
Function &)> GetBFI;
270 function_ref<
const TargetLibraryInfo &(
Function &)> GetTLI;
271 ProfileSummaryInfo &PSI;
278 getOutliningCallBBRelativeFreq(FunctionCloner &Cloner)
const;
282 bool shouldPartialInline(CallBase &CB, FunctionCloner &Cloner,
283 BlockFrequency WeightedOutliningRcost,
284 OptimizationRemarkEmitter &ORE)
const;
289 bool tryPartialInline(FunctionCloner &Cloner);
294 computeCallsiteToProfCountMap(Function *DuplicateFunction,
295 DenseMap<User *, uint64_t> &SiteCountMap)
const;
297 bool isLimitReached()
const {
302 static CallBase *getSupportedCallBase(User *U) {
309 static CallBase *getOneCallSiteTo(Function &
F) {
311 return getSupportedCallBase(User);
314 std::tuple<DebugLoc, BasicBlock *> getOneDebugLoc(Function &
F)
const {
315 CallBase *CB = getOneCallSiteTo(
F);
318 return std::make_tuple(DLoc,
Block);
327 std::tuple<InstructionCost, InstructionCost>
328 computeOutliningCosts(FunctionCloner &Cloner)
const;
334 TargetTransformInfo *
TTI);
336 std::unique_ptr<FunctionOutliningInfo>
337 computeOutliningInfo(Function &
F)
const;
339 std::unique_ptr<FunctionOutliningMultiRegionInfo>
340 computeOutliningColdRegionsInfo(Function &
F,
341 OptimizationRemarkEmitter &ORE)
const;
346std::unique_ptr<FunctionOutliningMultiRegionInfo>
347PartialInlinerImpl::computeOutliningColdRegionsInfo(
355 BranchProbabilityInfo BPI(
F, CI);
356 std::unique_ptr<BlockFrequencyInfo> ScopedBFI;
357 BlockFrequencyInfo *BFI;
359 ScopedBFI.reset(
new BlockFrequencyInfo(
F, BPI, LI));
360 BFI = ScopedBFI.get();
365 if (!PSI.hasInstrumentationProfile())
366 return std::unique_ptr<FunctionOutliningMultiRegionInfo>();
368 std::unique_ptr<FunctionOutliningMultiRegionInfo> OutliningInfo =
369 std::make_unique<FunctionOutliningMultiRegionInfo>();
372 [&ORE](SmallVectorImpl<BasicBlock *> &BlockList) -> BasicBlock * {
374 for (
auto *
Block : BlockList) {
379 return OptimizationRemarkMissed(
DEBUG_TYPE,
"MultiExitRegion",
381 <<
"Region dominated by "
382 <<
ore::NV(
"Block", BlockList.front()->getName())
383 <<
" has more than one region exit edge.";
401 TargetTransformInfo *FTTI = &GetTTI(
F);
404 OverallFunctionCost += computeBBInlineCost(&BB, FTTI);
406 LLVM_DEBUG(
dbgs() <<
"OverallFunctionCost = " << OverallFunctionCost
412 BranchProbability MinBranchProbability(
415 bool ColdCandidateFound =
false;
417 std::vector<BasicBlock *> DFS;
418 SmallPtrSet<BasicBlock *, 8> VisitedSet;
419 DFS.push_back(CurrEntry);
420 VisitedSet.
insert(CurrEntry);
428 while (!DFS.empty()) {
429 auto *ThisBB = DFS.back();
434 if (PSI.isColdBlock(ThisBB, BFI) ||
438 if (!VisitedSet.
insert(*SI).second)
442 BranchProbability SuccProb = BPI.getEdgeProbability(ThisBB, *SI);
443 if (SuccProb > MinBranchProbability)
446 LLVM_DEBUG(
dbgs() <<
"Found cold edge: " << ThisBB->getName() <<
"->"
448 <<
"\nBranch Probability = " << SuccProb <<
"\n";);
450 SmallVector<BasicBlock *, 8> DominateVector;
451 DT.getDescendants(*SI, DominateVector);
453 "SI should be reachable and have at least itself as descendant");
456 if (!DominateVector.
front()->hasNPredecessors(1)) {
458 <<
" doesn't have a single predecessor in the "
459 "dominator tree\n";);
465 if (!(ExitBlock = IsSingleExit(DominateVector))) {
467 <<
" doesn't have a unique successor\n";);
472 for (
auto *BB : DominateVector)
473 OutlineRegionCost += computeBBInlineCost(BB, &GetTTI(*BB->getParent()));
480 return OptimizationRemarkAnalysis(
DEBUG_TYPE,
"TooCostly",
483 <<
" inline cost-savings smaller than "
484 <<
ore::NV(
"Cost", MinOutlineRegionCost);
487 LLVM_DEBUG(
dbgs() <<
"ABORT: Outline region cost is smaller than "
488 << MinOutlineRegionCost <<
"\n";);
500 FunctionOutliningMultiRegionInfo::OutlineRegionInfo RegInfo(
501 DominateVector, DominateVector.front(), ExitBlock, ReturnBlock);
502 OutliningInfo->ORI.push_back(RegInfo);
504 << DominateVector.front()->getName() <<
"\n";);
505 ColdCandidateFound =
true;
506 NumColdRegionsFound++;
510 if (ColdCandidateFound)
511 return OutliningInfo;
513 return std::unique_ptr<FunctionOutliningMultiRegionInfo>();
516std::unique_ptr<FunctionOutliningInfo>
517PartialInlinerImpl::computeOutliningInfo(Function &
F)
const {
521 return std::unique_ptr<FunctionOutliningInfo>();
534 if (IsReturnBlock(Succ1))
535 return std::make_tuple(Succ1, Succ2);
536 if (IsReturnBlock(Succ2))
537 return std::make_tuple(Succ2, Succ1);
539 return std::make_tuple<BasicBlock *, BasicBlock *>(
nullptr,
nullptr);
544 if (IsSuccessor(Succ1, Succ2))
545 return std::make_tuple(Succ1, Succ2);
546 if (IsSuccessor(Succ2, Succ1))
547 return std::make_tuple(Succ2, Succ1);
549 return std::make_tuple<BasicBlock *, BasicBlock *>(
nullptr,
nullptr);
552 std::unique_ptr<FunctionOutliningInfo> OutliningInfo =
553 std::make_unique<FunctionOutliningInfo>();
556 bool CandidateFound =
false;
571 std::tie(ReturnBlock, NonReturnBlock) = GetReturnBlock(Succ1, Succ2);
574 OutliningInfo->Entries.push_back(CurrEntry);
575 OutliningInfo->ReturnBlock = ReturnBlock;
576 OutliningInfo->NonReturnBlock = NonReturnBlock;
577 CandidateFound =
true;
582 std::tie(CommSucc,
OtherSucc) = GetCommonSucc(Succ1, Succ2);
587 OutliningInfo->Entries.push_back(CurrEntry);
592 return std::unique_ptr<FunctionOutliningInfo>();
596 assert(OutliningInfo->Entries[0] == &
F.front() &&
597 "Function Entry must be the first in Entries vector");
602 auto HasNonEntryPred = [Entries](
BasicBlock *BB) {
604 if (!Entries.count(Pred))
609 auto CheckAndNormalizeCandidate =
610 [Entries, HasNonEntryPred](FunctionOutliningInfo *OutliningInfo) {
611 for (BasicBlock *
E : OutliningInfo->Entries) {
613 if (Entries.count(Succ))
615 if (Succ == OutliningInfo->ReturnBlock)
616 OutliningInfo->ReturnBlockPreds.push_back(
E);
617 else if (Succ != OutliningInfo->NonReturnBlock)
621 if (HasNonEntryPred(
E))
627 if (!CheckAndNormalizeCandidate(OutliningInfo.get()))
628 return std::unique_ptr<FunctionOutliningInfo>();
633 BasicBlock *Cand = OutliningInfo->NonReturnBlock;
637 if (HasNonEntryPred(Cand))
644 std::tie(ReturnBlock, NonReturnBlock) = GetReturnBlock(Succ1, Succ2);
645 if (!ReturnBlock || ReturnBlock != OutliningInfo->ReturnBlock)
652 OutliningInfo->Entries.push_back(Cand);
653 OutliningInfo->NonReturnBlock = NonReturnBlock;
654 OutliningInfo->ReturnBlockPreds.push_back(Cand);
655 Entries.insert(Cand);
658 return OutliningInfo;
663 if (
F.hasProfileData())
666 for (
auto *
E : OI.Entries) {
674BranchProbability PartialInlinerImpl::getOutliningCallBBRelativeFreq(
675 FunctionCloner &Cloner)
const {
676 BasicBlock *OutliningCallBB = Cloner.OutlinedFunctions.back().second;
678 Cloner.ClonedFuncBFI->getBlockFreq(&Cloner.ClonedFunc->getEntryBlock());
679 auto OutliningCallFreq =
680 Cloner.ClonedFuncBFI->getBlockFreq(OutliningCallBB);
684 if (OutliningCallFreq.getFrequency() > EntryFreq.getFrequency())
685 OutliningCallFreq = EntryFreq;
688 OutliningCallFreq.getFrequency(), EntryFreq.getFrequency());
691 return OutlineRegionRelFreq;
705 if (OutlineRegionRelFreq < BranchProbability(45, 100))
706 return OutlineRegionRelFreq;
708 OutlineRegionRelFreq = std::max(
711 return OutlineRegionRelFreq;
714bool PartialInlinerImpl::shouldPartialInline(
715 CallBase &CB, FunctionCloner &Cloner, BlockFrequency WeightedOutliningRcost,
716 OptimizationRemarkEmitter &ORE)
const {
720 assert(Callee == Cloner.ClonedFunc);
726 auto &CalleeTTI = GetTTI(*Callee);
727 bool RemarksEnabled =
728 Callee->getContext().getDiagHandlerPtr()->isMissedOptRemarkEnabled(
732 GetTLI, GetBFI, &PSI, RemarksEnabled ? &ORE :
nullptr);
736 return OptimizationRemarkAnalysis(
DEBUG_TYPE,
"AlwaysInline", &CB)
737 <<
NV(
"Callee", Cloner.OrigFunc)
738 <<
" should always be fully inlined, not partially";
745 return OptimizationRemarkMissed(
DEBUG_TYPE,
"NeverInline", &CB)
746 <<
NV(
"Callee", Cloner.OrigFunc) <<
" not partially inlined into "
747 <<
NV(
"Caller", Caller)
748 <<
" because it should never be inlined (cost=never)";
755 return OptimizationRemarkAnalysis(
DEBUG_TYPE,
"TooCostly", &CB)
756 <<
NV(
"Callee", Cloner.OrigFunc) <<
" not partially inlined into "
757 <<
NV(
"Caller", Caller) <<
" because too costly to inline (cost="
758 <<
NV(
"Cost", IC.
getCost()) <<
", threshold="
763 const DataLayout &
DL =
Caller->getDataLayout();
767 BlockFrequency NormWeightedSavings(NonWeightedSavings);
770 if (NormWeightedSavings < WeightedOutliningRcost) {
772 return OptimizationRemarkAnalysis(
DEBUG_TYPE,
"OutliningCallcostTooHigh",
774 <<
NV(
"Callee", Cloner.OrigFunc) <<
" not partially inlined into "
775 <<
NV(
"Caller", Caller) <<
" runtime overhead (overhead="
776 <<
NV(
"Overhead", (
unsigned)WeightedOutliningRcost.
getFrequency())
778 <<
NV(
"Savings", (
unsigned)NormWeightedSavings.getFrequency())
780 <<
" of making the outlined call is too high";
787 return OptimizationRemarkAnalysis(
DEBUG_TYPE,
"CanBePartiallyInlined", &CB)
788 <<
NV(
"Callee", Cloner.OrigFunc) <<
" can be partially inlined into "
789 <<
NV(
"Caller", Caller) <<
" with cost=" <<
NV(
"Cost", IC.
getCost())
800PartialInlinerImpl::computeBBInlineCost(BasicBlock *BB,
801 TargetTransformInfo *
TTI) {
805 for (Instruction &
I : *BB) {
807 switch (
I.getOpcode()) {
808 case Instruction::BitCast:
809 case Instruction::PtrToInt:
810 case Instruction::IntToPtr:
811 case Instruction::Alloca:
812 case Instruction::PHI:
814 case Instruction::GetElementPtr:
822 if (
I.isLifetimeStartOrEnd())
833 FMF = FPMO->getFastMathFlags();
835 IntrinsicCostAttributes ICA(IID,
II->getType(), Tys, FMF);
860std::tuple<InstructionCost, InstructionCost>
861PartialInlinerImpl::computeOutliningCosts(FunctionCloner &Cloner)
const {
863 for (
auto FuncBBPair : Cloner.OutlinedFunctions) {
864 Function *OutlinedFunc = FuncBBPair.first;
865 BasicBlock* OutliningCallBB = FuncBBPair.second;
868 auto *OutlinedFuncTTI = &GetTTI(*OutlinedFunc);
869 OutliningFuncCallCost +=
870 computeBBInlineCost(OutliningCallBB, OutlinedFuncTTI);
873 for (BasicBlock &BB : *OutlinedFunc)
874 OutlinedFunctionCost += computeBBInlineCost(&BB, OutlinedFuncTTI);
876 assert(OutlinedFunctionCost >= Cloner.OutlinedRegionCost &&
877 "Outlined function cost should be no less than the outlined region");
882 OutlinedFunctionCost -=
886 OutliningFuncCallCost +
887 (OutlinedFunctionCost - Cloner.OutlinedRegionCost) +
890 return std::make_tuple(OutliningFuncCallCost, OutliningRuntimeOverhead);
896void PartialInlinerImpl::computeCallsiteToProfCountMap(
897 Function *DuplicateFunction,
898 DenseMap<User *, uint64_t> &CallSiteToProfCountMap)
const {
902 std::unique_ptr<BlockFrequencyInfo> TempBFI;
903 BlockFrequencyInfo *CurrentCallerBFI =
nullptr;
908 DominatorTree DT(*Caller);
912 BranchProbabilityInfo BPI(*Caller, CI);
913 TempBFI.reset(
new BlockFrequencyInfo(*Caller, BPI, LI));
914 CurrentCallerBFI = TempBFI.get();
917 CurrentCallerBFI = &(GetBFI(*Caller));
921 for (User *User :
Users) {
922 CallBase *CB = getSupportedCallBase(User);
924 if (CurrentCaller != Caller) {
926 ComputeCurrBFI(Caller);
928 assert(CurrentCallerBFI &&
"CallerBFI is not set");
935 CallSiteToProfCountMap[
User] = 0;
939PartialInlinerImpl::FunctionCloner::FunctionCloner(
940 Function *
F, FunctionOutliningInfo *OI, OptimizationRemarkEmitter &ORE,
941 function_ref<AssumptionCache *(Function &)> LookupAC,
942 function_ref<TargetTransformInfo &(Function &)> GetTTI)
943 : OrigFunc(
F), ORE(ORE), LookupAC(LookupAC), GetTTI(GetTTI) {
944 ClonedOI = std::make_unique<FunctionOutliningInfo>();
957 ClonedOI->ReturnBlockPreds.push_back(NewE);
961 F->replaceAllUsesWith(ClonedFunc);
964PartialInlinerImpl::FunctionCloner::FunctionCloner(
965 Function *
F, FunctionOutliningMultiRegionInfo *OI,
969 : OrigFunc(
F), ORE(ORE), LookupAC(LookupAC), GetTTI(GetTTI) {
970 ClonedOMRI = std::make_unique<FunctionOutliningMultiRegionInfo>();
978 for (
const FunctionOutliningMultiRegionInfo::OutlineRegionInfo &
RegionInfo :
989 FunctionOutliningMultiRegionInfo::OutlineRegionInfo MappedRegionInfo(
990 Region, NewEntryBlock, NewExitBlock, NewReturnBlock);
991 ClonedOMRI->ORI.push_back(MappedRegionInfo);
995 F->replaceAllUsesWith(ClonedFunc);
998void PartialInlinerImpl::FunctionCloner::normalizeReturnBlock()
const {
1001 PHINode *FirstPhi =
nullptr;
1002 while (
I != BB->end()) {
1023 BasicBlock *PreReturn = ClonedOI->ReturnBlock;
1025 PHINode *FirstPhi = GetFirstPHI(PreReturn);
1026 unsigned NumPredsFromEntries = ClonedOI->ReturnBlockPreds.size();
1031 auto IsTrivialPhi = [](PHINode *PN) ->
Value * {
1033 return PN->getIncomingValue(0);
1037 ClonedOI->ReturnBlock = ClonedOI->ReturnBlock->splitBasicBlock(
1038 ClonedOI->ReturnBlock->getFirstNonPHIIt());
1041 SmallVector<Instruction *, 4> DeadPhis;
1042 while (
I != PreReturn->
end()) {
1051 Ins = ClonedOI->ReturnBlock->getFirstNonPHIIt();
1054 for (BasicBlock *
E : ClonedOI->ReturnBlockPreds) {
1063 if (
auto *OldPhiVal = IsTrivialPhi(OldPhi)) {
1069 for (
auto *DP : DeadPhis)
1070 DP->eraseFromParent();
1072 for (
auto *
E : ClonedOI->ReturnBlockPreds)
1073 E->getTerminator()->replaceUsesOfWith(PreReturn, ClonedOI->ReturnBlock);
1076bool PartialInlinerImpl::FunctionCloner::doMultiRegionFunctionOutlining() {
1078 auto ComputeRegionCost =
1081 for (BasicBlock* BB : Region)
1082 Cost += computeBBInlineCost(BB, &GetTTI(*BB->getParent()));
1086 assert(ClonedOMRI &&
"Expecting OutlineInfo for multi region outline");
1088 if (ClonedOMRI->ORI.empty())
1099 BranchProbabilityInfo BPI(*ClonedFunc, CI);
1100 ClonedFuncBFI.reset(
new BlockFrequencyInfo(*ClonedFunc, BPI, LI));
1103 CodeExtractorAnalysisCache CEAC(*ClonedFunc);
1105 SetVector<Value *> Inputs, Outputs, Sinks;
1106 for (FunctionOutliningMultiRegionInfo::OutlineRegionInfo RegionInfo :
1109 ComputeRegionCost(RegionInfo.Region);
1111 CodeExtractor
CE(RegionInfo.Region, &DT,
false,
1112 ClonedFuncBFI.get(), &BPI,
1113 LookupAC(*RegionInfo.EntryBlock->
getParent()),
1119 CE.findInputsOutputs(Inputs, Outputs, Sinks);
1122 dbgs() <<
"inputs: " << Inputs.
size() <<
"\n";
1123 dbgs() <<
"outputs: " << Outputs.
size() <<
"\n";
1124 for (
Value *value : Inputs)
1125 dbgs() <<
"value used in func: " << *value <<
"\n";
1126 for (
Value *output : Outputs)
1127 dbgs() <<
"instr used in func: " << *output <<
"\n";
1134 if (Function *OutlinedFunc =
CE.extractCodeRegion(CEAC)) {
1135 CallBase *OCS = PartialInlinerImpl::getOneCallSiteTo(*OutlinedFunc);
1138 OutlinedFunctions.push_back(std::make_pair(OutlinedFunc,OutliningCallBB));
1139 NumColdRegionsOutlined++;
1140 OutlinedRegionCost += CurrentOutlinedRegionCost;
1148 return OptimizationRemarkMissed(
DEBUG_TYPE,
"ExtractFailed",
1149 &RegionInfo.Region.
front()->front())
1150 <<
"Failed to extract region at block "
1155 return !OutlinedFunctions.empty();
1159PartialInlinerImpl::FunctionCloner::doSingleRegionFunctionOutlining() {
1162 auto ToBeInlined = [&,
this](
BasicBlock *BB) {
1163 return BB == ClonedOI->ReturnBlock ||
1167 assert(ClonedOI &&
"Expecting OutlineInfo for single region outline");
1176 BranchProbabilityInfo BPI(*ClonedFunc, CI);
1177 ClonedFuncBFI.reset(
new BlockFrequencyInfo(*ClonedFunc, BPI, LI));
1180 std::vector<BasicBlock *> ToExtract;
1181 auto *ClonedFuncTTI = &GetTTI(*ClonedFunc);
1182 ToExtract.push_back(ClonedOI->NonReturnBlock);
1183 OutlinedRegionCost += PartialInlinerImpl::computeBBInlineCost(
1184 ClonedOI->NonReturnBlock, ClonedFuncTTI);
1185 for (BasicBlock *BB :
depth_first(&ClonedFunc->getEntryBlock()))
1186 if (!ToBeInlined(BB) && BB != ClonedOI->NonReturnBlock) {
1187 ToExtract.push_back(BB);
1192 OutlinedRegionCost += computeBBInlineCost(BB, ClonedFuncTTI);
1196 CodeExtractorAnalysisCache CEAC(*ClonedFunc);
1198 CodeExtractor(ToExtract, &DT,
false,
1199 ClonedFuncBFI.get(), &BPI, LookupAC(*ClonedFunc),
1204 .extractCodeRegion(CEAC);
1208 PartialInlinerImpl::getOneCallSiteTo(*OutlinedFunc)->
getParent();
1210 OutlinedFunctions.push_back(std::make_pair(OutlinedFunc, OutliningCallBB));
1213 return OptimizationRemarkMissed(
DEBUG_TYPE,
"ExtractFailed",
1214 &ToExtract.front()->front())
1215 <<
"Failed to extract region at block "
1216 <<
ore::NV(
"Block", ToExtract.front());
1219 return OutlinedFunc;
1222PartialInlinerImpl::FunctionCloner::~FunctionCloner() {
1226 ClonedFunc->eraseFromParent();
1227 if (!IsFunctionInlined) {
1230 for (
auto FuncBBPair : OutlinedFunctions) {
1232 Func->eraseFromParent();
1237std::pair<bool, Function *> PartialInlinerImpl::unswitchFunction(Function &
F) {
1238 if (
F.hasAddressTaken())
1239 return {
false,
nullptr};
1242 if (
F.hasFnAttribute(Attribute::AlwaysInline))
1243 return {
false,
nullptr};
1245 if (
F.hasFnAttribute(Attribute::NoInline))
1246 return {
false,
nullptr};
1248 if (PSI.isFunctionEntryCold(&
F))
1249 return {
false,
nullptr};
1251 if (
F.users().empty())
1252 return {
false,
nullptr};
1254 OptimizationRemarkEmitter ORE(&
F);
1258 if (PSI.hasProfileSummary() &&
F.hasProfileData() &&
1260 std::unique_ptr<FunctionOutliningMultiRegionInfo> OMRI =
1261 computeOutliningColdRegionsInfo(
F, ORE);
1263 FunctionCloner Cloner(&
F, OMRI.get(), ORE, LookupAssumptionCache, GetTTI);
1266 dbgs() <<
"HotCountThreshold = " << PSI.getHotCountThreshold() <<
"\n";
1267 dbgs() <<
"ColdCountThreshold = " << PSI.getColdCountThreshold()
1271 bool DidOutline = Cloner.doMultiRegionFunctionOutlining();
1275 dbgs() <<
">>>>>> Outlined (Cloned) Function >>>>>>\n";
1276 Cloner.ClonedFunc->print(
dbgs());
1277 dbgs() <<
"<<<<<< Outlined (Cloned) Function <<<<<<\n";
1280 if (tryPartialInline(Cloner))
1281 return {
true,
nullptr};
1289 std::unique_ptr<FunctionOutliningInfo> OI = computeOutliningInfo(
F);
1291 return {
false,
nullptr};
1293 FunctionCloner Cloner(&
F, OI.get(), ORE, LookupAssumptionCache, GetTTI);
1294 Cloner.normalizeReturnBlock();
1296 Function *OutlinedFunction = Cloner.doSingleRegionFunctionOutlining();
1298 if (!OutlinedFunction)
1299 return {
false,
nullptr};
1301 if (tryPartialInline(Cloner))
1302 return {
true, OutlinedFunction};
1304 return {
false,
nullptr};
1307bool PartialInlinerImpl::tryPartialInline(FunctionCloner &Cloner) {
1308 if (Cloner.OutlinedFunctions.empty())
1311 auto OutliningCosts = computeOutliningCosts(Cloner);
1317 "Expected valid costs");
1321 BranchProbability RelativeToEntryFreq;
1322 if (Cloner.ClonedOI)
1323 RelativeToEntryFreq = getOutliningCallBBRelativeFreq(Cloner);
1330 RelativeToEntryFreq = BranchProbability(0, 1);
1332 BlockFrequency WeightedRcost =
1333 BlockFrequency(NonWeightedRcost.
getValue()) * RelativeToEntryFreq;
1340 OptimizationRemarkEmitter OrigFuncORE(Cloner.OrigFunc);
1343 std::tie(DLoc,
Block) = getOneDebugLoc(*Cloner.ClonedFunc);
1344 OrigFuncORE.emit([&]() {
1345 return OptimizationRemarkAnalysis(
DEBUG_TYPE,
"OutlineRegionTooSmall",
1347 <<
ore::NV(
"Function", Cloner.OrigFunc)
1348 <<
" not partially inlined into callers (Original Size = "
1349 <<
ore::NV(
"OutlinedRegionOriginalSize", Cloner.OutlinedRegionCost)
1350 <<
", Size of call sequence to outlined function = "
1351 <<
ore::NV(
"NewSize", SizeCost) <<
")";
1356 assert(Cloner.OrigFunc->users().empty() &&
1357 "F's users should all be replaced!");
1359 std::vector<User *>
Users(Cloner.ClonedFunc->user_begin(),
1360 Cloner.ClonedFunc->user_end());
1362 DenseMap<User *, uint64_t> CallSiteToProfCountMap;
1363 auto CalleeEntryCount = Cloner.OrigFunc->getEntryCount();
1364 if (CalleeEntryCount)
1365 computeCallsiteToProfCountMap(Cloner.ClonedFunc, CallSiteToProfCountMap);
1367 uint64_t CalleeEntryCountV = (CalleeEntryCount ? *CalleeEntryCount : 0);
1369 bool AnyInline =
false;
1370 for (User *User :
Users) {
1371 CallBase *CB = getSupportedCallBase(User);
1373 if (isLimitReached())
1376 OptimizationRemarkEmitter CallerORE(CB->
getCaller());
1377 if (!shouldPartialInline(*CB, Cloner, WeightedRcost, CallerORE))
1382 OptimizationRemark
OR(
DEBUG_TYPE,
"PartiallyInlined", CB);
1383 OR <<
ore::NV(
"Callee", Cloner.OrigFunc) <<
" partially inlined into "
1386 InlineFunctionInfo IFI(GetAssumptionCache, &PSI);
1391 (Cloner.ClonedOI ? Cloner.OutlinedFunctions.back().first
1399 if (CalleeEntryCountV) {
1400 if (
auto It = CallSiteToProfCountMap.
find(User);
1401 It != CallSiteToProfCountMap.
end()) {
1402 uint64_t CallSiteCount = It->second;
1403 CalleeEntryCountV -= std::min(CalleeEntryCountV, CallSiteCount);
1408 NumPartialInlining++;
1410 if (Cloner.ClonedOI)
1411 NumPartialInlined++;
1413 NumColdOutlinePartialInlined++;
1417 Cloner.IsFunctionInlined =
true;
1418 if (CalleeEntryCount)
1419 Cloner.OrigFunc->setEntryCount(CalleeEntryCountV);
1420 OptimizationRemarkEmitter OrigFuncORE(Cloner.OrigFunc);
1421 OrigFuncORE.emit([&]() {
1422 return OptimizationRemark(
DEBUG_TYPE,
"PartiallyInlined", Cloner.OrigFunc)
1423 <<
"Partially inlined into at least one caller";
1430bool PartialInlinerImpl::run(
Module &M) {
1434 std::vector<Function *> Worklist;
1435 Worklist.reserve(
M.size());
1436 for (Function &
F : M)
1437 if (!
F.use_empty() && !
F.isDeclaration())
1438 Worklist.push_back(&
F);
1441 while (!Worklist.empty()) {
1442 Function *CurrFunc = Worklist.back();
1443 Worklist.pop_back();
1448 std::pair<bool, Function *>
Result = unswitchFunction(*CurrFunc);
1450 Worklist.push_back(
Result.second);
1483 if (PartialInlinerImpl(GetAssumptionCache, LookupAssumptionCache, GetTTI,
1484 GetTLI, PSI, GetBFI)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static MachineBasicBlock * OtherSucc(MachineBasicBlock *MBB, MachineBasicBlock *Succ)
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
This file contains the simple types necessary to represent the attributes associated with functions a...
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
cl::opt< unsigned > MinBlockCounterExecution
This file declares the LLVM IR specialization of the GenericCycle templates.
This file defines the DenseMap class.
This file defines the DenseSet and SmallDenseSet classes.
This file builds on the ADT/GraphTraits.h file to build generic depth first graph iterator.
This file provides various utilities for inspecting and working with the control flow graph in LLVM I...
Module.h This file contains the declarations for the Module class.
iv Induction Variable Users
static cl::opt< int > InstrCost("inline-instr-cost", cl::Hidden, cl::init(5), cl::desc("Cost of a single instruction when inlining"))
Machine Check Debug Module
uint64_t IntrinsicInst * II
static cl::opt< unsigned > MaxNumInlineBlocks("max-num-inline-blocks", cl::init(5), cl::Hidden, cl::desc("Max number of blocks to be partially inlined"))
static cl::opt< int > OutlineRegionFreqPercent("outline-region-freq-percent", cl::init(75), cl::Hidden, cl::desc("Relative frequency of outline region to " "the entry block"))
static cl::opt< bool > MarkOutlinedColdCC("pi-mark-coldcc", cl::init(false), cl::Hidden, cl::desc("Mark outline function calls with ColdCC"))
static cl::opt< float > MinRegionSizeRatio("min-region-size-ratio", cl::init(0.1), cl::Hidden, cl::desc("Minimum ratio comparing relative sizes of each " "outline candidate and original function"))
static cl::opt< bool > DisableMultiRegionPartialInline("disable-mr-partial-inlining", cl::init(false), cl::Hidden, cl::desc("Disable multi-region partial inlining"))
cl::opt< unsigned > MinBlockCounterExecution("min-block-execution", cl::init(100), cl::Hidden, cl::desc("Minimum block executions to consider " "its BranchProbabilityInfo valid"))
static cl::opt< int > MaxNumPartialInlining("max-partial-inlining", cl::init(-1), cl::Hidden, cl::desc("Max number of partial inlining. The default is unlimited"))
static cl::opt< bool > DisablePartialInlining("disable-partial-inlining", cl::init(false), cl::Hidden, cl::desc("Disable partial inlining"))
static bool hasProfileData(const Function &F, const FunctionOutliningInfo &OI)
static cl::opt< float > ColdBranchRatio("cold-branch-ratio", cl::init(0.1), cl::Hidden, cl::desc("Minimum BranchProbability to consider a region cold."))
static cl::opt< bool > ForceLiveExit("pi-force-live-exit-outline", cl::init(false), cl::Hidden, cl::desc("Force outline regions with live exits"))
static cl::opt< unsigned > ExtraOutliningPenalty("partial-inlining-extra-penalty", cl::init(0), cl::Hidden, cl::desc("A debug option to add additional penalty to the computed one."))
static cl::opt< bool > SkipCostAnalysis("skip-partial-inlining-cost-analysis", cl::ReallyHidden, cl::desc("Skip Cost Analysis"))
FunctionAnalysisManager FAM
This file contains the declarations for profiling metadata utility functions.
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
A function analysis which provides an AssumptionCache.
A cache of @llvm.assume calls within a function.
LLVM Basic Block Representation.
iterator begin()
Instruction iterator methods.
const Function * getParent() const
Return the enclosing method, or null if none.
LLVM_ABI const BasicBlock * getSinglePredecessor() const
Return the predecessor of this block if it has a single predecessor block.
const Instruction & front() const
LLVM_ABI const BasicBlock * getSingleSuccessor() const
Return the successor of this block if it has a single successor.
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this basic block belongs to.
InstListType::iterator iterator
Instruction iterators...
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
Analysis pass which computes BlockFrequencyInfo.
BlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation to estimate IR basic block frequen...
LLVM_ABI std::optional< uint64_t > getBlockProfileCount(const BasicBlock *BB, bool AllowSynthetic=false) const
Returns the estimated profile count of BB.
uint64_t getFrequency() const
Returns the frequency as a fixpoint number scaled by the entry frequency.
static LLVM_ABI BranchProbability getBranchProbability(uint64_t Numerator, uint64_t Denominator)
void setCallingConv(CallingConv::ID CC)
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
LLVM_ABI Function * getCaller()
Helper to get the caller (the parent function).
Conditional Branch instruction.
iterator find(const_arg_type_t< KeyT > Val)
void recalculate(ParentType &Func)
recalculate - compute a dominator tree for the given function
void setCallingConv(CallingConv::ID CC)
void compute(FunctionT &F)
Compute the cycle info for a function.
int getCost() const
Get the inline cost estimate.
int getCostDelta() const
Get the cost delta from the threshold for inlining.
auto map(const Function &F) const -> InstructionCost
CostType getValue() const
This function is intended to be used as sparingly as possible, since the class provides the full rang...
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
LLVM_ABI void insertBefore(InstListType::iterator InsertPos)
Insert an unlinked instruction into a basic block immediately before the specified position.
A Module instance is used to store all the information related to an LLVM module.
void addIncoming(Value *V, BasicBlock *BB)
Add an incoming value to the end of the PHI list.
LLVM_ABI Value * removeIncomingValue(unsigned Idx, bool DeletePHIIfEmpty=true)
Remove an incoming value.
Value * getIncomingValueForBlock(const BasicBlock *BB) const
unsigned getNumIncomingValues() const
Return the number of incoming edges.
static PHINode * Create(Type *Ty, unsigned NumReservedValues, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
Constructors - NumReservedValues is a hint for the number of incoming edges that this phi node will h...
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &)
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
An analysis pass based on the new PM to deliver ProfileSummaryInfo.
Analysis providing profile information.
size_type size() const
Determine the number of elements in the SetVector.
void insert_range(Range &&R)
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Analysis pass providing the TargetTransformInfo.
Analysis pass providing the TargetLibraryInfo.
Provides information about what library functions are available for the current target.
Type * getType() const
All values are typed, get the type of this value.
user_iterator user_begin()
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
An efficient, type-erasing, non-owning reference to a callable.
const ParentTy * getParent() const
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ BR
Control flow instructions. These all have token chains.
@ BasicBlock
Various leaf nodes.
LLVM_ABI int getInstrCost()
@ CE
Windows NT (Windows on ARM)
initializer< Ty > init(const Ty &Val)
DXILDebugInfoMap run(Module &M)
@ User
could "use" a pointer
DiagnosticInfoOptimizationBase::Argument NV
NodeAddr< PhiNode * > Phi
NodeAddr< FuncNode * > Func
friend class Instruction
Iterator for Instructions in a `BasicBlock.
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
auto successors(const MachineBasicBlock *BB)
constexpr from_range_t from_range
InnerAnalysisManagerProxy< FunctionAnalysisManager, Module > FunctionAnalysisManagerModuleProxy
Provide the FunctionAnalysisManager to Module proxy.
LLVM_ABI InlineResult InlineFunction(CallBase &CB, InlineFunctionInfo &IFI, bool MergeAttributes=false, AAResults *CalleeAAR=nullptr, bool InsertLifetime=true, bool TrackInlineHistory=false, Function *ForwardVarArgsTo=nullptr, OptimizationRemarkEmitter *ORE=nullptr)
This function inlines the called function into the basic block of the caller.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
LLVM_ABI InlineResult isInlineViable(Function &Callee)
Check if it is mechanically possible to inline the function Callee, based on the contents of the func...
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
auto succ_size(const MachineBasicBlock *BB)
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
RNSuccIterator< NodeRef, BlockT, RegionT > succ_begin(NodeRef Node)
LLVM_ABI InlineCost getInlineCost(CallBase &Call, const InlineParams &Params, TargetTransformInfo &CalleeTTI, function_ref< AssumptionCache &(Function &)> GetAssumptionCache, function_ref< const TargetLibraryInfo &(Function &)> GetTLI, function_ref< BlockFrequencyInfo &(Function &)> GetBFI=nullptr, ProfileSummaryInfo *PSI=nullptr, OptimizationRemarkEmitter *ORE=nullptr, function_ref< EphemeralValuesCache &(Function &)> GetEphValuesCache=nullptr)
Get an InlineCost object representing the cost of inlining this callsite.
RNSuccIterator< NodeRef, BlockT, RegionT > succ_end(NodeRef Node)
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
ArrayRef(const T &OneElt) -> ArrayRef< T >
LLVM_ABI InlineParams getInlineParams()
Generate the parameters to tune the inline cost analysis based only on the commandline options.
LLVM_ABI int getCallsiteCost(const TargetTransformInfo &TTI, const CallBase &Call, const DataLayout &DL)
Return the cost associated with a callsite, including parameter passing and the call/return instructi...
ValueMap< const Value *, WeakTrackingVH > ValueToValueMapTy
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
auto predecessors(const MachineBasicBlock *BB)
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
iterator_range< df_iterator< T > > depth_first(const T &G)
bool all_equal(std::initializer_list< T > Values)
Returns true if all Values in the initializer lists are equal or the list.
LLVM_ABI bool hasBranchWeightMD(const Instruction &I)
Checks if an instructions has Branch Weight Metadata.
LLVM_ABI Function * CloneFunction(Function *F, ValueToValueMapTy &VMap, ClonedCodeInfo *CodeInfo=nullptr)
Return a copy of the specified function and add it to that function's module.
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.