63#define DEBUG_TYPE "partial-inlining"
66 "Number of callsites functions partially inlined into.");
67STATISTIC(NumColdOutlinePartialInlined,
"Number of times functions with "
68 "cold outlined regions were partially "
69 "inlined into its caller(s).");
71 "Number of cold single entry/exit regions found.");
73 "Number of cold single entry/exit regions outlined.");
77struct FunctionOutliningInfo {
78 FunctionOutliningInfo() =
default;
82 unsigned getNumInlinedBlocks()
const {
return Entries.size() + 1; }
98struct FunctionOutliningMultiRegionInfo {
99 FunctionOutliningMultiRegionInfo() =
default;
102 struct OutlineRegionInfo {
104 BasicBlock *ExitBlock, BasicBlock *ReturnBlock)
105 : Region(Region), EntryBlock(EntryBlock), ExitBlock(ExitBlock),
106 ReturnBlock(ReturnBlock) {}
107 SmallVector<BasicBlock *, 8> Region;
116struct PartialInlinerImpl {
119 const IPOOptions &Opts, function_ref<AssumptionCache &(
Function &)> GetAC,
120 function_ref<AssumptionCache *(
Function &)> LookupAC,
121 function_ref<TargetTransformInfo &(
Function &)> GTTI,
122 function_ref<
const TargetLibraryInfo &(
Function &)> GTLI,
123 ProfileSummaryInfo &ProfSI,
124 function_ref<BlockFrequencyInfo &(
Function &)> GBFI =
nullptr)
125 : Opts(Opts), GetAssumptionCache(GetAC), LookupAssumptionCache(LookupAC),
126 GetTTI(GTTI), GetBFI(GBFI), GetTLI(GTLI), PSI(ProfSI) {}
136 std::pair<bool, Function *> unswitchFunction(
Function &
F);
142 struct FunctionCloner {
145 FunctionCloner(
Function *
F, FunctionOutliningInfo *OI,
146 OptimizationRemarkEmitter &ORE,
147 function_ref<AssumptionCache *(
Function &)> LookupAC,
148 function_ref<TargetTransformInfo &(
Function &)> GetTTI);
149 FunctionCloner(
Function *
F, FunctionOutliningMultiRegionInfo *OMRI,
150 OptimizationRemarkEmitter &ORE,
151 function_ref<AssumptionCache *(
Function &)> LookupAC,
152 function_ref<TargetTransformInfo &(
Function &)> GetTTI);
159 void normalizeReturnBlock()
const;
162 bool doMultiRegionFunctionOutlining(
const IPOOptions &Opts);
169 Function *doSingleRegionFunctionOutlining();
174 typedef std::pair<Function *, BasicBlock *> FuncBodyCallerPair;
180 bool IsFunctionInlined =
false;
184 std::unique_ptr<FunctionOutliningInfo> ClonedOI =
nullptr;
186 std::unique_ptr<FunctionOutliningMultiRegionInfo> ClonedOMRI =
nullptr;
187 std::unique_ptr<BlockFrequencyInfo> ClonedFuncBFI =
nullptr;
188 OptimizationRemarkEmitter &ORE;
189 function_ref<AssumptionCache *(
Function &)> LookupAC;
190 function_ref<TargetTransformInfo &(
Function &)> GetTTI;
194 const IPOOptions &Opts;
195 int NumPartialInlining = 0;
196 function_ref<AssumptionCache &(
Function &)> GetAssumptionCache;
197 function_ref<AssumptionCache *(
Function &)> LookupAssumptionCache;
198 function_ref<TargetTransformInfo &(
Function &)> GetTTI;
199 function_ref<BlockFrequencyInfo &(
Function &)> GetBFI;
200 function_ref<
const TargetLibraryInfo &(
Function &)> GetTLI;
201 ProfileSummaryInfo &PSI;
208 getOutliningCallBBRelativeFreq(FunctionCloner &Cloner)
const;
212 bool shouldPartialInline(CallBase &CB, FunctionCloner &Cloner,
213 BlockFrequency WeightedOutliningRcost,
214 OptimizationRemarkEmitter &ORE)
const;
219 bool tryPartialInline(FunctionCloner &Cloner);
224 computeCallsiteToProfCountMap(
Function *DuplicateFunction,
225 DenseMap<User *, uint64_t> &SiteCountMap)
const;
227 bool isLimitReached()
const {
228 return (Opts.max_partial_inlining != -1 &&
229 NumPartialInlining >= Opts.max_partial_inlining);
232 static CallBase *getSupportedCallBase(User *U) {
239 static CallBase *getOneCallSiteTo(
Function &
F) {
241 return getSupportedCallBase(User);
244 std::tuple<DebugLoc, BasicBlock *> getOneDebugLoc(
Function &
F)
const {
245 CallBase *CB = getOneCallSiteTo(
F);
248 return std::make_tuple(DLoc,
Block);
257 std::tuple<InstructionCost, InstructionCost>
258 computeOutliningCosts(FunctionCloner &Cloner)
const;
264 TargetTransformInfo *
TTI);
266 std::unique_ptr<FunctionOutliningInfo>
269 std::unique_ptr<FunctionOutliningMultiRegionInfo>
270 computeOutliningColdRegionsInfo(
Function &
F,
271 OptimizationRemarkEmitter &ORE)
const;
276std::unique_ptr<FunctionOutliningMultiRegionInfo>
277PartialInlinerImpl::computeOutliningColdRegionsInfo(
284 BranchProbabilityInfo BPI(
F, CI);
285 std::unique_ptr<BlockFrequencyInfo> ScopedBFI;
286 BlockFrequencyInfo *BFI;
288 ScopedBFI.reset(
new BlockFrequencyInfo(
F, BPI, CI));
289 BFI = ScopedBFI.get();
294 if (!PSI.hasInstrumentationProfile())
295 return std::unique_ptr<FunctionOutliningMultiRegionInfo>();
297 std::unique_ptr<FunctionOutliningMultiRegionInfo> OutliningInfo =
298 std::make_unique<FunctionOutliningMultiRegionInfo>();
301 [&ORE](SmallVectorImpl<BasicBlock *> &BlockList) -> BasicBlock * {
303 for (
auto *
Block : BlockList) {
308 return OptimizationRemarkMissed(
DEBUG_TYPE,
"MultiExitRegion",
310 <<
"Region dominated by "
311 <<
ore::NV(
"Block", BlockList.front()->getName())
312 <<
" has more than one region exit edge.";
330 TargetTransformInfo *FTTI = &GetTTI(
F);
333 OverallFunctionCost += computeBBInlineCost(&BB, FTTI);
335 LLVM_DEBUG(
dbgs() <<
"OverallFunctionCost = " << OverallFunctionCost
339 [&](
auto Cost) {
return Cost * Opts.min_region_size_ratio; });
341 BranchProbability MinBranchProbability(
342 static_cast<int>(Opts.cold_branch_ratio * Opts.min_block_execution),
343 Opts.min_block_execution);
344 bool ColdCandidateFound =
false;
346 std::vector<BasicBlock *> DFS;
347 SmallPtrSet<BasicBlock *, 8> VisitedSet;
348 DFS.push_back(CurrEntry);
349 VisitedSet.
insert(CurrEntry);
357 while (!DFS.empty()) {
358 auto *ThisBB = DFS.back();
363 if (PSI.isColdBlock(ThisBB, BFI) ||
364 BBProfileCount(ThisBB) < Opts.min_block_execution)
367 if (!VisitedSet.
insert(*SI).second)
371 BranchProbability SuccProb = BPI.getEdgeProbability(ThisBB, *SI);
372 if (SuccProb > MinBranchProbability)
375 LLVM_DEBUG(
dbgs() <<
"Found cold edge: " << ThisBB->getName() <<
"->"
377 <<
"\nBranch Probability = " << SuccProb <<
"\n";);
379 SmallVector<BasicBlock *, 8> DominateVector;
380 DT.getDescendants(*SI, DominateVector);
382 "SI should be reachable and have at least itself as descendant");
385 if (!DominateVector.
front()->hasNPredecessors(1)) {
387 <<
" doesn't have a single predecessor in the "
388 "dominator tree\n";);
394 if (!(ExitBlock = IsSingleExit(DominateVector))) {
396 <<
" doesn't have a unique successor\n";);
401 for (
auto *BB : DominateVector)
402 OutlineRegionCost += computeBBInlineCost(BB, &GetTTI(*BB->getParent()));
407 if (!Opts.skip_partial_inlining_cost_analysis &&
408 OutlineRegionCost < MinOutlineRegionCost) {
410 return OptimizationRemarkAnalysis(
DEBUG_TYPE,
"TooCostly",
413 <<
" inline cost-savings smaller than "
414 <<
ore::NV(
"Cost", MinOutlineRegionCost);
417 LLVM_DEBUG(
dbgs() <<
"ABORT: Outline region cost is smaller than "
418 << MinOutlineRegionCost <<
"\n";);
430 FunctionOutliningMultiRegionInfo::OutlineRegionInfo RegInfo(
431 DominateVector, DominateVector.front(), ExitBlock, ReturnBlock);
432 OutliningInfo->ORI.push_back(RegInfo);
434 << DominateVector.front()->getName() <<
"\n";);
435 ColdCandidateFound =
true;
436 NumColdRegionsFound++;
440 if (ColdCandidateFound)
441 return OutliningInfo;
443 return std::unique_ptr<FunctionOutliningMultiRegionInfo>();
446std::unique_ptr<FunctionOutliningInfo>
447PartialInlinerImpl::computeOutliningInfo(
Function &
F)
const {
451 return std::unique_ptr<FunctionOutliningInfo>();
464 if (IsReturnBlock(Succ1))
465 return std::make_tuple(Succ1, Succ2);
466 if (IsReturnBlock(Succ2))
467 return std::make_tuple(Succ2, Succ1);
469 return std::make_tuple<BasicBlock *, BasicBlock *>(
nullptr,
nullptr);
474 if (IsSuccessor(Succ1, Succ2))
475 return std::make_tuple(Succ1, Succ2);
476 if (IsSuccessor(Succ2, Succ1))
477 return std::make_tuple(Succ2, Succ1);
479 return std::make_tuple<BasicBlock *, BasicBlock *>(
nullptr,
nullptr);
482 std::unique_ptr<FunctionOutliningInfo> OutliningInfo =
483 std::make_unique<FunctionOutliningInfo>();
486 bool CandidateFound =
false;
491 if (OutliningInfo->getNumInlinedBlocks() >= Opts.max_num_inline_blocks)
501 std::tie(ReturnBlock, NonReturnBlock) = GetReturnBlock(Succ1, Succ2);
504 OutliningInfo->Entries.push_back(CurrEntry);
505 OutliningInfo->ReturnBlock = ReturnBlock;
506 OutliningInfo->NonReturnBlock = NonReturnBlock;
507 CandidateFound =
true;
512 std::tie(CommSucc,
OtherSucc) = GetCommonSucc(Succ1, Succ2);
517 OutliningInfo->Entries.push_back(CurrEntry);
522 return std::unique_ptr<FunctionOutliningInfo>();
526 assert(OutliningInfo->Entries[0] == &
F.front() &&
527 "Function Entry must be the first in Entries vector");
532 auto HasNonEntryPred = [Entries](
BasicBlock *BB) {
534 if (!Entries.count(
Pred))
539 auto CheckAndNormalizeCandidate =
540 [Entries, HasNonEntryPred](FunctionOutliningInfo *OutliningInfo) {
541 for (BasicBlock *
E : OutliningInfo->Entries) {
543 if (Entries.count(Succ))
545 if (Succ == OutliningInfo->ReturnBlock)
546 OutliningInfo->ReturnBlockPreds.push_back(
E);
547 else if (Succ != OutliningInfo->NonReturnBlock)
551 if (HasNonEntryPred(
E))
557 if (!CheckAndNormalizeCandidate(OutliningInfo.get()))
558 return std::unique_ptr<FunctionOutliningInfo>();
562 while (OutliningInfo->getNumInlinedBlocks() < Opts.max_num_inline_blocks) {
563 BasicBlock *Cand = OutliningInfo->NonReturnBlock;
567 if (HasNonEntryPred(Cand))
574 std::tie(ReturnBlock, NonReturnBlock) = GetReturnBlock(Succ1, Succ2);
575 if (!ReturnBlock || ReturnBlock != OutliningInfo->ReturnBlock)
582 OutliningInfo->Entries.push_back(Cand);
583 OutliningInfo->NonReturnBlock = NonReturnBlock;
584 OutliningInfo->ReturnBlockPreds.push_back(Cand);
585 Entries.insert(Cand);
588 return OutliningInfo;
593 if (
F.hasProfileData())
596 for (
auto *
E : OI.Entries) {
604BranchProbability PartialInlinerImpl::getOutliningCallBBRelativeFreq(
605 FunctionCloner &Cloner)
const {
606 BasicBlock *OutliningCallBB = Cloner.OutlinedFunctions.back().second;
608 Cloner.ClonedFuncBFI->getBlockFreq(&Cloner.ClonedFunc->getEntryBlock());
609 auto OutliningCallFreq =
610 Cloner.ClonedFuncBFI->getBlockFreq(OutliningCallBB);
614 if (OutliningCallFreq.getFrequency() > EntryFreq.getFrequency())
615 OutliningCallFreq = EntryFreq;
618 OutliningCallFreq.getFrequency(), EntryFreq.getFrequency());
621 return OutlineRegionRelFreq;
635 if (OutlineRegionRelFreq < BranchProbability(45, 100))
636 return OutlineRegionRelFreq;
638 OutlineRegionRelFreq =
639 std::max(OutlineRegionRelFreq,
640 BranchProbability(Opts.outline_region_freq_percent, 100));
642 return OutlineRegionRelFreq;
645bool PartialInlinerImpl::shouldPartialInline(
646 CallBase &CB, FunctionCloner &Cloner, BlockFrequency WeightedOutliningRcost,
647 OptimizationRemarkEmitter &ORE)
const {
651 assert(Callee == Cloner.ClonedFunc);
653 if (Opts.skip_partial_inlining_cost_analysis)
657 auto &CallerTTI = GetTTI(*Caller);
658 bool RemarksEnabled =
659 Callee->getContext().getDiagHandlerPtr()->isMissedOptRemarkEnabled(
662 GetAssumptionCache, GetTLI, GetBFI, &PSI,
663 RemarksEnabled ? &ORE :
nullptr);
667 return OptimizationRemarkAnalysis(
DEBUG_TYPE,
"AlwaysInline", &CB)
668 <<
NV(
"Callee", Cloner.OrigFunc)
669 <<
" should always be fully inlined, not partially";
676 return OptimizationRemarkMissed(
DEBUG_TYPE,
"NeverInline", &CB)
677 <<
NV(
"Callee", Cloner.OrigFunc) <<
" not partially inlined into "
678 <<
NV(
"Caller", Caller)
679 <<
" because it should never be inlined (cost=never)";
686 return OptimizationRemarkAnalysis(
DEBUG_TYPE,
"TooCostly", &CB)
687 <<
NV(
"Callee", Cloner.OrigFunc) <<
" not partially inlined into "
688 <<
NV(
"Caller", Caller) <<
" because too costly to inline (cost="
689 <<
NV(
"Cost", IC.
getCost()) <<
", threshold="
694 const DataLayout &
DL =
Caller->getDataLayout();
698 BlockFrequency NormWeightedSavings(NonWeightedSavings);
701 if (NormWeightedSavings < WeightedOutliningRcost) {
703 return OptimizationRemarkAnalysis(
DEBUG_TYPE,
"OutliningCallcostTooHigh",
705 <<
NV(
"Callee", Cloner.OrigFunc) <<
" not partially inlined into "
706 <<
NV(
"Caller", Caller) <<
" runtime overhead (overhead="
707 <<
NV(
"Overhead", (
unsigned)WeightedOutliningRcost.
getFrequency())
709 <<
NV(
"Savings", (
unsigned)NormWeightedSavings.getFrequency())
711 <<
" of making the outlined call is too high";
718 return OptimizationRemarkAnalysis(
DEBUG_TYPE,
"CanBePartiallyInlined", &CB)
719 <<
NV(
"Callee", Cloner.OrigFunc) <<
" can be partially inlined into "
720 <<
NV(
"Caller", Caller) <<
" with cost=" <<
NV(
"Cost", IC.
getCost())
731PartialInlinerImpl::computeBBInlineCost(BasicBlock *BB,
732 TargetTransformInfo *
TTI) {
736 for (Instruction &
I : *BB) {
738 switch (
I.getOpcode()) {
739 case Instruction::BitCast:
740 case Instruction::PtrToInt:
741 case Instruction::IntToPtr:
742 case Instruction::Alloca:
743 case Instruction::PHI:
745 case Instruction::GetElementPtr:
753 if (
I.isLifetimeStartOrEnd())
764 FMF = FPMO->getFastMathFlags();
766 IntrinsicCostAttributes ICA(IID,
II->getType(), Tys, FMF);
782 InlineCost += (
SI->getNumCases() + 1) * InstrCost;
785 InlineCost += InstrCost;
791std::tuple<InstructionCost, InstructionCost>
792PartialInlinerImpl::computeOutliningCosts(FunctionCloner &Cloner)
const {
794 for (
auto FuncBBPair : Cloner.OutlinedFunctions) {
795 Function *OutlinedFunc = FuncBBPair.first;
796 BasicBlock* OutliningCallBB = FuncBBPair.second;
799 auto *OutlinedFuncTTI = &GetTTI(*OutlinedFunc);
800 OutliningFuncCallCost +=
801 computeBBInlineCost(OutliningCallBB, OutlinedFuncTTI);
804 for (BasicBlock &BB : *OutlinedFunc)
805 OutlinedFunctionCost += computeBBInlineCost(&BB, OutlinedFuncTTI);
807 assert(OutlinedFunctionCost >= Cloner.OutlinedRegionCost &&
808 "Outlined function cost should be no less than the outlined region");
813 OutlinedFunctionCost -=
815 Cloner.OutlinedFunctions.size();
818 OutliningFuncCallCost +
819 (OutlinedFunctionCost - Cloner.OutlinedRegionCost) +
820 Opts.partial_inlining_extra_penalty;
822 return std::make_tuple(OutliningFuncCallCost, OutliningRuntimeOverhead);
828void PartialInlinerImpl::computeCallsiteToProfCountMap(
830 DenseMap<User *, uint64_t> &CallSiteToProfCountMap)
const {
834 std::unique_ptr<BlockFrequencyInfo> TempBFI;
835 BlockFrequencyInfo *CurrentCallerBFI =
nullptr;
842 BranchProbabilityInfo BPI(*Caller, CI);
843 TempBFI.reset(
new BlockFrequencyInfo(*Caller, BPI, CI));
844 CurrentCallerBFI = TempBFI.get();
847 CurrentCallerBFI = &(GetBFI(*Caller));
851 for (User *User :
Users) {
852 CallBase *CB = getSupportedCallBase(User);
854 if (CurrentCaller != Caller) {
856 ComputeCurrBFI(Caller);
858 assert(CurrentCallerBFI &&
"CallerBFI is not set");
865 CallSiteToProfCountMap[
User] = 0;
869PartialInlinerImpl::FunctionCloner::FunctionCloner(
870 Function *
F, FunctionOutliningInfo *OI, OptimizationRemarkEmitter &ORE,
871 function_ref<AssumptionCache *(
Function &)> LookupAC,
872 function_ref<TargetTransformInfo &(
Function &)> GetTTI)
873 : OrigFunc(
F), ORE(ORE), LookupAC(LookupAC), GetTTI(GetTTI) {
874 ClonedOI = std::make_unique<FunctionOutliningInfo>();
887 ClonedOI->ReturnBlockPreds.push_back(NewE);
891 F->replaceAllUsesWith(ClonedFunc);
894PartialInlinerImpl::FunctionCloner::FunctionCloner(
895 Function *
F, FunctionOutliningMultiRegionInfo *OI,
899 : OrigFunc(
F), ORE(ORE), LookupAC(LookupAC), GetTTI(GetTTI) {
900 ClonedOMRI = std::make_unique<FunctionOutliningMultiRegionInfo>();
908 for (
const FunctionOutliningMultiRegionInfo::OutlineRegionInfo &
RegionInfo :
919 FunctionOutliningMultiRegionInfo::OutlineRegionInfo MappedRegionInfo(
920 Region, NewEntryBlock, NewExitBlock, NewReturnBlock);
921 ClonedOMRI->ORI.push_back(MappedRegionInfo);
925 F->replaceAllUsesWith(ClonedFunc);
928void PartialInlinerImpl::FunctionCloner::normalizeReturnBlock()
const {
931 PHINode *FirstPhi =
nullptr;
932 while (
I != BB->end()) {
953 BasicBlock *PreReturn = ClonedOI->ReturnBlock;
955 PHINode *FirstPhi = GetFirstPHI(PreReturn);
956 unsigned NumPredsFromEntries = ClonedOI->ReturnBlockPreds.size();
961 auto IsTrivialPhi = [](PHINode *PN) ->
Value * {
963 return PN->getIncomingValue(0);
967 ClonedOI->ReturnBlock = ClonedOI->ReturnBlock->splitBasicBlock(
968 ClonedOI->ReturnBlock->getFirstNonPHIIt());
971 SmallVector<Instruction *, 4> DeadPhis;
972 while (
I != PreReturn->
end()) {
981 Ins = ClonedOI->ReturnBlock->getFirstNonPHIIt();
984 for (BasicBlock *
E : ClonedOI->ReturnBlockPreds) {
993 if (
auto *OldPhiVal = IsTrivialPhi(OldPhi)) {
999 for (
auto *DP : DeadPhis)
1000 DP->eraseFromParent();
1002 for (
auto *
E : ClonedOI->ReturnBlockPreds)
1003 E->getTerminator()->replaceUsesOfWith(PreReturn, ClonedOI->ReturnBlock);
1006bool PartialInlinerImpl::FunctionCloner::doMultiRegionFunctionOutlining(
1007 const IPOOptions &Opts) {
1008 auto ComputeRegionCost =
1011 for (BasicBlock* BB : Region)
1012 Cost += computeBBInlineCost(BB, &GetTTI(*BB->getParent()));
1016 assert(ClonedOMRI &&
"Expecting OutlineInfo for multi region outline");
1018 if (ClonedOMRI->ORI.empty())
1028 BranchProbabilityInfo BPI(*ClonedFunc, CI);
1029 ClonedFuncBFI.reset(
new BlockFrequencyInfo(*ClonedFunc, BPI, CI));
1032 CodeExtractorAnalysisCache CEAC(*ClonedFunc);
1034 SetVector<Value *> Inputs, Outputs, Sinks;
1035 for (FunctionOutliningMultiRegionInfo::OutlineRegionInfo RegionInfo :
1038 ComputeRegionCost(RegionInfo.Region);
1040 CodeExtractor
CE(RegionInfo.Region, &DT,
false,
1041 ClonedFuncBFI.get(), &BPI,
1042 LookupAC(*RegionInfo.EntryBlock->
getParent()),
1048 CE.findInputsOutputs(Inputs, Outputs, Sinks);
1051 dbgs() <<
"inputs: " << Inputs.
size() <<
"\n";
1052 dbgs() <<
"outputs: " << Outputs.
size() <<
"\n";
1053 for (
Value *value : Inputs)
1054 dbgs() <<
"value used in func: " << *value <<
"\n";
1055 for (
Value *output : Outputs)
1056 dbgs() <<
"instr used in func: " << *output <<
"\n";
1060 if (Outputs.
size() > 0 && !Opts.pi_force_live_exit_outline)
1063 if (
Function *OutlinedFunc =
CE.extractCodeRegion(CEAC)) {
1064 CallBase *OCS = PartialInlinerImpl::getOneCallSiteTo(*OutlinedFunc);
1067 OutlinedFunctions.push_back(std::make_pair(OutlinedFunc,OutliningCallBB));
1068 NumColdRegionsOutlined++;
1069 OutlinedRegionCost += CurrentOutlinedRegionCost;
1071 if (Opts.pi_mark_coldcc) {
1072 OutlinedFunc->setCallingConv(CallingConv::Cold);
1077 return OptimizationRemarkMissed(
DEBUG_TYPE,
"ExtractFailed",
1078 &RegionInfo.Region.
front()->front())
1079 <<
"Failed to extract region at block "
1084 return !OutlinedFunctions.empty();
1088PartialInlinerImpl::FunctionCloner::doSingleRegionFunctionOutlining() {
1091 auto ToBeInlined = [&,
this](
BasicBlock *BB) {
1092 return BB == ClonedOI->ReturnBlock ||
1096 assert(ClonedOI &&
"Expecting OutlineInfo for single region outline");
1104 BranchProbabilityInfo BPI(*ClonedFunc, CI);
1105 ClonedFuncBFI.reset(
new BlockFrequencyInfo(*ClonedFunc, BPI, CI));
1108 std::vector<BasicBlock *> ToExtract;
1109 auto *ClonedFuncTTI = &GetTTI(*ClonedFunc);
1110 ToExtract.push_back(ClonedOI->NonReturnBlock);
1111 OutlinedRegionCost += PartialInlinerImpl::computeBBInlineCost(
1112 ClonedOI->NonReturnBlock, ClonedFuncTTI);
1113 for (BasicBlock *BB :
depth_first(&ClonedFunc->getEntryBlock()))
1114 if (!ToBeInlined(BB) && BB != ClonedOI->NonReturnBlock) {
1115 ToExtract.push_back(BB);
1120 OutlinedRegionCost += computeBBInlineCost(BB, ClonedFuncTTI);
1124 CodeExtractorAnalysisCache CEAC(*ClonedFunc);
1126 CodeExtractor(ToExtract, &DT,
false,
1127 ClonedFuncBFI.get(), &BPI, LookupAC(*ClonedFunc),
1132 .extractCodeRegion(CEAC);
1136 PartialInlinerImpl::getOneCallSiteTo(*OutlinedFunc)->
getParent();
1138 OutlinedFunctions.push_back(std::make_pair(OutlinedFunc, OutliningCallBB));
1141 return OptimizationRemarkMissed(
DEBUG_TYPE,
"ExtractFailed",
1142 &ToExtract.front()->front())
1143 <<
"Failed to extract region at block "
1144 <<
ore::NV(
"Block", ToExtract.front());
1147 return OutlinedFunc;
1150PartialInlinerImpl::FunctionCloner::~FunctionCloner() {
1154 ClonedFunc->eraseFromParent();
1155 if (!IsFunctionInlined) {
1158 for (
auto FuncBBPair : OutlinedFunctions) {
1160 Func->eraseFromParent();
1165std::pair<bool, Function *> PartialInlinerImpl::unswitchFunction(
Function &
F) {
1166 if (
F.hasAddressTaken())
1167 return {
false,
nullptr};
1170 if (
F.hasFnAttribute(Attribute::AlwaysInline))
1171 return {
false,
nullptr};
1174 return {
false,
nullptr};
1176 if (PSI.isFunctionEntryCold(&
F))
1177 return {
false,
nullptr};
1179 if (
F.users().empty())
1180 return {
false,
nullptr};
1182 OptimizationRemarkEmitter ORE(&
F);
1186 if (PSI.hasProfileSummary() &&
F.hasProfileData() &&
1187 Opts.mr_partial_inlining) {
1188 std::unique_ptr<FunctionOutliningMultiRegionInfo> OMRI =
1189 computeOutliningColdRegionsInfo(
F, ORE);
1191 FunctionCloner Cloner(&
F, OMRI.get(), ORE, LookupAssumptionCache, GetTTI);
1194 dbgs() <<
"HotCountThreshold = " << PSI.getHotCountThreshold() <<
"\n";
1195 dbgs() <<
"ColdCountThreshold = " << PSI.getColdCountThreshold()
1199 bool DidOutline = Cloner.doMultiRegionFunctionOutlining(Opts);
1203 dbgs() <<
">>>>>> Outlined (Cloned) Function >>>>>>\n";
1204 Cloner.ClonedFunc->print(
dbgs());
1205 dbgs() <<
"<<<<<< Outlined (Cloned) Function <<<<<<\n";
1208 if (tryPartialInline(Cloner))
1209 return {
true,
nullptr};
1217 std::unique_ptr<FunctionOutliningInfo> OI = computeOutliningInfo(
F);
1219 return {
false,
nullptr};
1221 FunctionCloner Cloner(&
F, OI.get(), ORE, LookupAssumptionCache, GetTTI);
1222 Cloner.normalizeReturnBlock();
1224 Function *OutlinedFunction = Cloner.doSingleRegionFunctionOutlining();
1226 if (!OutlinedFunction)
1227 return {
false,
nullptr};
1229 if (tryPartialInline(Cloner))
1230 return {
true, OutlinedFunction};
1232 return {
false,
nullptr};
1235bool PartialInlinerImpl::tryPartialInline(FunctionCloner &Cloner) {
1236 if (Cloner.OutlinedFunctions.empty())
1239 auto OutliningCosts = computeOutliningCosts(Cloner);
1245 "Expected valid costs");
1249 BranchProbability RelativeToEntryFreq;
1250 if (Cloner.ClonedOI)
1251 RelativeToEntryFreq = getOutliningCallBBRelativeFreq(Cloner);
1258 RelativeToEntryFreq = BranchProbability(0, 1);
1260 BlockFrequency WeightedRcost =
1261 BlockFrequency(NonWeightedRcost.
getValue()) * RelativeToEntryFreq;
1267 if (!Opts.skip_partial_inlining_cost_analysis &&
1268 Cloner.OutlinedRegionCost < SizeCost) {
1269 OptimizationRemarkEmitter OrigFuncORE(Cloner.OrigFunc);
1272 std::tie(DLoc,
Block) = getOneDebugLoc(*Cloner.ClonedFunc);
1273 OrigFuncORE.emit([&]() {
1274 return OptimizationRemarkAnalysis(
DEBUG_TYPE,
"OutlineRegionTooSmall",
1276 <<
ore::NV(
"Function", Cloner.OrigFunc)
1277 <<
" not partially inlined into callers (Original Size = "
1278 <<
ore::NV(
"OutlinedRegionOriginalSize", Cloner.OutlinedRegionCost)
1279 <<
", Size of call sequence to outlined function = "
1280 <<
ore::NV(
"NewSize", SizeCost) <<
")";
1285 assert(Cloner.OrigFunc->users().empty() &&
1286 "F's users should all be replaced!");
1288 std::vector<User *>
Users(Cloner.ClonedFunc->user_begin(),
1289 Cloner.ClonedFunc->user_end());
1291 DenseMap<User *, uint64_t> CallSiteToProfCountMap;
1292 auto CalleeEntryCount = Cloner.OrigFunc->getEntryCount();
1293 if (CalleeEntryCount)
1294 computeCallsiteToProfCountMap(Cloner.ClonedFunc, CallSiteToProfCountMap);
1296 uint64_t CalleeEntryCountV = (CalleeEntryCount ? *CalleeEntryCount : 0);
1298 bool AnyInline =
false;
1299 for (User *User :
Users) {
1300 CallBase *CB = getSupportedCallBase(User);
1302 if (isLimitReached())
1305 OptimizationRemarkEmitter CallerORE(CB->
getCaller());
1306 if (!shouldPartialInline(*CB, Cloner, WeightedRcost, CallerORE))
1311 OptimizationRemark
OR(
DEBUG_TYPE,
"PartiallyInlined", CB);
1312 OR <<
ore::NV(
"Callee", Cloner.OrigFunc) <<
" partially inlined into "
1315 InlineFunctionInfo IFI(GetAssumptionCache, &PSI);
1320 (Cloner.ClonedOI ? Cloner.OutlinedFunctions.back().first
1328 if (CalleeEntryCountV) {
1329 if (
auto It = CallSiteToProfCountMap.
find(User);
1330 It != CallSiteToProfCountMap.
end()) {
1331 uint64_t CallSiteCount = It->second;
1332 CalleeEntryCountV -= std::min(CalleeEntryCountV, CallSiteCount);
1337 NumPartialInlining++;
1339 if (Cloner.ClonedOI)
1340 NumPartialInlined++;
1342 NumColdOutlinePartialInlined++;
1346 Cloner.IsFunctionInlined =
true;
1347 if (CalleeEntryCount)
1348 Cloner.OrigFunc->setEntryCount(CalleeEntryCountV);
1349 OptimizationRemarkEmitter OrigFuncORE(Cloner.OrigFunc);
1350 OrigFuncORE.emit([&]() {
1351 return OptimizationRemark(
DEBUG_TYPE,
"PartiallyInlined", Cloner.OrigFunc)
1352 <<
"Partially inlined into at least one caller";
1359bool PartialInlinerImpl::run(
Module &M) {
1360 if (!Opts.partial_inlining)
1363 std::vector<Function *> Worklist;
1364 Worklist.reserve(
M.size());
1366 if (!
F.use_empty() && !
F.isDeclaration())
1367 Worklist.push_back(&
F);
1370 while (!Worklist.empty()) {
1371 Function *CurrFunc = Worklist.back();
1372 Worklist.pop_back();
1377 std::pair<bool, Function *>
Result = unswitchFunction(*CurrFunc);
1379 Worklist.push_back(
Result.second);
1412 if (PartialInlinerImpl(
getIPOOptions(M), GetAssumptionCache,
1413 LookupAssumptionCache, GetTTI, 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")
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
Machine Check Debug Module
uint64_t IntrinsicInst * II
static bool hasProfileData(const Function &F, const FunctionOutliningInfo &OI)
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...
LLVM_ABI LLVMContext & getContext() const
Get the context in which this basic block lives.
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) 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 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.
LLVMContext & getContext() const
All values hold a context through their type.
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(const LLVMContext &C)
Return -inline-instr-cost.
@ CE
Windows NT (Windows on ARM)
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the 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.
LLVM_ABI InlineCost getInlineCost(CallBase &Call, const InlineParams &Params, TargetTransformInfo &CallerTTI, 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.
LLVM_ABI InlineParams getInlineParams(const LLVMContext &C)
Generate the parameters to tune the inline cost analysis based only on the commandline options.
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...
const IPOOptions & getIPOOptions(const LLVMContext &C)
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)
RNSuccIterator< NodeRef, BlockT, RegionT > succ_end(NodeRef Node)
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
ArrayRef(const T &OneElt) -> ArrayRef< T >
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.