Path: blob/main/contrib/llvm-project/llvm/lib/Transforms/IPO/HotColdSplitting.cpp
35294 views
//===- HotColdSplitting.cpp -- Outline Cold Regions -------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7///8/// \file9/// The goal of hot/cold splitting is to improve the memory locality of code.10/// The splitting pass does this by identifying cold blocks and moving them into11/// separate functions.12///13/// When the splitting pass finds a cold block (referred to as "the sink"), it14/// grows a maximal cold region around that block. The maximal region contains15/// all blocks (post-)dominated by the sink [*]. In theory, these blocks are as16/// cold as the sink. Once a region is found, it's split out of the original17/// function provided it's profitable to do so.18///19/// [*] In practice, there is some added complexity because some blocks are not20/// safe to extract.21///22/// TODO: Use the PM to get domtrees, and preserve BFI/BPI.23/// TODO: Reorder outlined functions.24///25//===----------------------------------------------------------------------===//2627#include "llvm/Transforms/IPO/HotColdSplitting.h"28#include "llvm/ADT/PostOrderIterator.h"29#include "llvm/ADT/SmallVector.h"30#include "llvm/ADT/Statistic.h"31#include "llvm/Analysis/AssumptionCache.h"32#include "llvm/Analysis/BlockFrequencyInfo.h"33#include "llvm/Analysis/OptimizationRemarkEmitter.h"34#include "llvm/Analysis/PostDominators.h"35#include "llvm/Analysis/ProfileSummaryInfo.h"36#include "llvm/Analysis/TargetTransformInfo.h"37#include "llvm/IR/BasicBlock.h"38#include "llvm/IR/CFG.h"39#include "llvm/IR/DiagnosticInfo.h"40#include "llvm/IR/Dominators.h"41#include "llvm/IR/EHPersonalities.h"42#include "llvm/IR/Function.h"43#include "llvm/IR/Instruction.h"44#include "llvm/IR/Instructions.h"45#include "llvm/IR/Module.h"46#include "llvm/IR/PassManager.h"47#include "llvm/IR/ProfDataUtils.h"48#include "llvm/IR/User.h"49#include "llvm/IR/Value.h"50#include "llvm/Support/CommandLine.h"51#include "llvm/Support/Debug.h"52#include "llvm/Support/raw_ostream.h"53#include "llvm/Transforms/IPO.h"54#include "llvm/Transforms/Utils/CodeExtractor.h"55#include <algorithm>56#include <cassert>57#include <limits>58#include <string>5960#define DEBUG_TYPE "hotcoldsplit"6162STATISTIC(NumColdRegionsFound, "Number of cold regions found.");63STATISTIC(NumColdRegionsOutlined, "Number of cold regions outlined.");6465using namespace llvm;6667static cl::opt<bool> EnableStaticAnalysis("hot-cold-static-analysis",68cl::init(true), cl::Hidden);6970static cl::opt<int>71SplittingThreshold("hotcoldsplit-threshold", cl::init(2), cl::Hidden,72cl::desc("Base penalty for splitting cold code (as a "73"multiple of TCC_Basic)"));7475static cl::opt<bool> EnableColdSection(76"enable-cold-section", cl::init(false), cl::Hidden,77cl::desc("Enable placement of extracted cold functions"78" into a separate section after hot-cold splitting."));7980static cl::opt<std::string>81ColdSectionName("hotcoldsplit-cold-section-name", cl::init("__llvm_cold"),82cl::Hidden,83cl::desc("Name for the section containing cold functions "84"extracted by hot-cold splitting."));8586static cl::opt<int> MaxParametersForSplit(87"hotcoldsplit-max-params", cl::init(4), cl::Hidden,88cl::desc("Maximum number of parameters for a split function"));8990static cl::opt<int> ColdBranchProbDenom(91"hotcoldsplit-cold-probability-denom", cl::init(100), cl::Hidden,92cl::desc("Divisor of cold branch probability."93"BranchProbability = 1/ColdBranchProbDenom"));9495namespace {96// Same as blockEndsInUnreachable in CodeGen/BranchFolding.cpp. Do not modify97// this function unless you modify the MBB version as well.98//99/// A no successor, non-return block probably ends in unreachable and is cold.100/// Also consider a block that ends in an indirect branch to be a return block,101/// since many targets use plain indirect branches to return.102bool blockEndsInUnreachable(const BasicBlock &BB) {103if (!succ_empty(&BB))104return false;105if (BB.empty())106return true;107const Instruction *I = BB.getTerminator();108return !(isa<ReturnInst>(I) || isa<IndirectBrInst>(I));109}110111void analyzeProfMetadata(BasicBlock *BB,112BranchProbability ColdProbThresh,113SmallPtrSetImpl<BasicBlock *> &AnnotatedColdBlocks) {114// TODO: Handle branches with > 2 successors.115BranchInst *CondBr = dyn_cast<BranchInst>(BB->getTerminator());116if (!CondBr)117return;118119uint64_t TrueWt, FalseWt;120if (!extractBranchWeights(*CondBr, TrueWt, FalseWt))121return;122123auto SumWt = TrueWt + FalseWt;124if (SumWt == 0)125return;126127auto TrueProb = BranchProbability::getBranchProbability(TrueWt, SumWt);128auto FalseProb = BranchProbability::getBranchProbability(FalseWt, SumWt);129130if (TrueProb <= ColdProbThresh)131AnnotatedColdBlocks.insert(CondBr->getSuccessor(0));132133if (FalseProb <= ColdProbThresh)134AnnotatedColdBlocks.insert(CondBr->getSuccessor(1));135}136137bool unlikelyExecuted(BasicBlock &BB) {138// Exception handling blocks are unlikely executed.139if (BB.isEHPad() || isa<ResumeInst>(BB.getTerminator()))140return true;141142// The block is cold if it calls/invokes a cold function. However, do not143// mark sanitizer traps as cold.144for (Instruction &I : BB)145if (auto *CB = dyn_cast<CallBase>(&I))146if (CB->hasFnAttr(Attribute::Cold) &&147!CB->getMetadata(LLVMContext::MD_nosanitize))148return true;149150// The block is cold if it has an unreachable terminator, unless it's151// preceded by a call to a (possibly warm) noreturn call (e.g. longjmp).152if (blockEndsInUnreachable(BB)) {153if (auto *CI =154dyn_cast_or_null<CallInst>(BB.getTerminator()->getPrevNode()))155if (CI->hasFnAttr(Attribute::NoReturn))156return false;157return true;158}159160return false;161}162163/// Check whether it's safe to outline \p BB.164static bool mayExtractBlock(const BasicBlock &BB) {165// EH pads are unsafe to outline because doing so breaks EH type tables. It166// follows that invoke instructions cannot be extracted, because CodeExtractor167// requires unwind destinations to be within the extraction region.168//169// Resumes that are not reachable from a cleanup landing pad are considered to170// be unreachable. It’s not safe to split them out either.171172if (BB.hasAddressTaken() || BB.isEHPad())173return false;174auto Term = BB.getTerminator();175if (isa<InvokeInst>(Term) || isa<ResumeInst>(Term))176return false;177178// Do not outline basic blocks that have token type instructions. e.g.,179// exception:180// %0 = cleanuppad within none []181// call void @"?terminate@@YAXXZ"() [ "funclet"(token %0) ]182// br label %continue-exception183if (llvm::any_of(184BB, [](const Instruction &I) { return I.getType()->isTokenTy(); })) {185return false;186}187188return true;189}190191/// Mark \p F cold. Based on this assumption, also optimize it for minimum size.192/// If \p UpdateEntryCount is true (set when this is a new split function and193/// module has profile data), set entry count to 0 to ensure treated as cold.194/// Return true if the function is changed.195static bool markFunctionCold(Function &F, bool UpdateEntryCount = false) {196assert(!F.hasOptNone() && "Can't mark this cold");197bool Changed = false;198if (!F.hasFnAttribute(Attribute::Cold)) {199F.addFnAttr(Attribute::Cold);200Changed = true;201}202if (!F.hasFnAttribute(Attribute::MinSize)) {203F.addFnAttr(Attribute::MinSize);204Changed = true;205}206if (UpdateEntryCount) {207// Set the entry count to 0 to ensure it is placed in the unlikely text208// section when function sections are enabled.209F.setEntryCount(0);210Changed = true;211}212213return Changed;214}215216} // end anonymous namespace217218/// Check whether \p F is inherently cold.219bool HotColdSplitting::isFunctionCold(const Function &F) const {220if (F.hasFnAttribute(Attribute::Cold))221return true;222223if (F.getCallingConv() == CallingConv::Cold)224return true;225226if (PSI->isFunctionEntryCold(&F))227return true;228229return false;230}231232bool HotColdSplitting::isBasicBlockCold(233BasicBlock *BB, BranchProbability ColdProbThresh,234SmallPtrSetImpl<BasicBlock *> &AnnotatedColdBlocks,235BlockFrequencyInfo *BFI) const {236if (BFI) {237if (PSI->isColdBlock(BB, BFI))238return true;239} else {240// Find cold blocks of successors of BB during a reverse postorder traversal.241analyzeProfMetadata(BB, ColdProbThresh, AnnotatedColdBlocks);242243// A statically cold BB would be known before it is visited244// because the prof-data of incoming edges are 'analyzed' as part of RPOT.245if (AnnotatedColdBlocks.count(BB))246return true;247}248249if (EnableStaticAnalysis && unlikelyExecuted(*BB))250return true;251252return false;253}254255// Returns false if the function should not be considered for hot-cold split256// optimization.257bool HotColdSplitting::shouldOutlineFrom(const Function &F) const {258if (F.hasFnAttribute(Attribute::AlwaysInline))259return false;260261if (F.hasFnAttribute(Attribute::NoInline))262return false;263264// A function marked `noreturn` may contain unreachable terminators: these265// should not be considered cold, as the function may be a trampoline.266if (F.hasFnAttribute(Attribute::NoReturn))267return false;268269if (F.hasFnAttribute(Attribute::SanitizeAddress) ||270F.hasFnAttribute(Attribute::SanitizeHWAddress) ||271F.hasFnAttribute(Attribute::SanitizeThread) ||272F.hasFnAttribute(Attribute::SanitizeMemory))273return false;274275// Do not outline scoped EH personality functions.276if (F.hasPersonalityFn())277if (isScopedEHPersonality(classifyEHPersonality(F.getPersonalityFn())))278return false;279280return true;281}282283/// Get the benefit score of outlining \p Region.284static InstructionCost getOutliningBenefit(ArrayRef<BasicBlock *> Region,285TargetTransformInfo &TTI) {286// Sum up the code size costs of non-terminator instructions. Tight coupling287// with \ref getOutliningPenalty is needed to model the costs of terminators.288InstructionCost Benefit = 0;289for (BasicBlock *BB : Region)290for (Instruction &I : BB->instructionsWithoutDebug())291if (&I != BB->getTerminator())292Benefit +=293TTI.getInstructionCost(&I, TargetTransformInfo::TCK_CodeSize);294295return Benefit;296}297298/// Get the penalty score for outlining \p Region.299static int getOutliningPenalty(ArrayRef<BasicBlock *> Region,300unsigned NumInputs, unsigned NumOutputs) {301int Penalty = SplittingThreshold;302LLVM_DEBUG(dbgs() << "Applying penalty for splitting: " << Penalty << "\n");303304// If the splitting threshold is set at or below zero, skip the usual305// profitability check.306if (SplittingThreshold <= 0)307return Penalty;308309// Find the number of distinct exit blocks for the region. Use a conservative310// check to determine whether control returns from the region.311bool NoBlocksReturn = true;312SmallPtrSet<BasicBlock *, 2> SuccsOutsideRegion;313for (BasicBlock *BB : Region) {314// If a block has no successors, only assume it does not return if it's315// unreachable.316if (succ_empty(BB)) {317NoBlocksReturn &= isa<UnreachableInst>(BB->getTerminator());318continue;319}320321for (BasicBlock *SuccBB : successors(BB)) {322if (!is_contained(Region, SuccBB)) {323NoBlocksReturn = false;324SuccsOutsideRegion.insert(SuccBB);325}326}327}328329// Count the number of phis in exit blocks with >= 2 incoming values from the330// outlining region. These phis are split (\ref severSplitPHINodesOfExits),331// and new outputs are created to supply the split phis. CodeExtractor can't332// report these new outputs until extraction begins, but it's important to333// factor the cost of the outputs into the cost calculation.334unsigned NumSplitExitPhis = 0;335for (BasicBlock *ExitBB : SuccsOutsideRegion) {336for (PHINode &PN : ExitBB->phis()) {337// Find all incoming values from the outlining region.338int NumIncomingVals = 0;339for (unsigned i = 0; i < PN.getNumIncomingValues(); ++i)340if (llvm::is_contained(Region, PN.getIncomingBlock(i))) {341++NumIncomingVals;342if (NumIncomingVals > 1) {343++NumSplitExitPhis;344break;345}346}347}348}349350// Apply a penalty for calling the split function. Factor in the cost of351// materializing all of the parameters.352int NumOutputsAndSplitPhis = NumOutputs + NumSplitExitPhis;353int NumParams = NumInputs + NumOutputsAndSplitPhis;354if (NumParams > MaxParametersForSplit) {355LLVM_DEBUG(dbgs() << NumInputs << " inputs and " << NumOutputsAndSplitPhis356<< " outputs exceeds parameter limit ("357<< MaxParametersForSplit << ")\n");358return std::numeric_limits<int>::max();359}360const int CostForArgMaterialization = 2 * TargetTransformInfo::TCC_Basic;361LLVM_DEBUG(dbgs() << "Applying penalty for: " << NumParams << " params\n");362Penalty += CostForArgMaterialization * NumParams;363364// Apply the typical code size cost for an output alloca and its associated365// reload in the caller. Also penalize the associated store in the callee.366LLVM_DEBUG(dbgs() << "Applying penalty for: " << NumOutputsAndSplitPhis367<< " outputs/split phis\n");368const int CostForRegionOutput = 3 * TargetTransformInfo::TCC_Basic;369Penalty += CostForRegionOutput * NumOutputsAndSplitPhis;370371// Apply a `noreturn` bonus.372if (NoBlocksReturn) {373LLVM_DEBUG(dbgs() << "Applying bonus for: " << Region.size()374<< " non-returning terminators\n");375Penalty -= Region.size();376}377378// Apply a penalty for having more than one successor outside of the region.379// This penalty accounts for the switch needed in the caller.380if (SuccsOutsideRegion.size() > 1) {381LLVM_DEBUG(dbgs() << "Applying penalty for: " << SuccsOutsideRegion.size()382<< " non-region successors\n");383Penalty += (SuccsOutsideRegion.size() - 1) * TargetTransformInfo::TCC_Basic;384}385386return Penalty;387}388389// Determine if it is beneficial to split the \p Region.390bool HotColdSplitting::isSplittingBeneficial(CodeExtractor &CE,391const BlockSequence &Region,392TargetTransformInfo &TTI) {393assert(!Region.empty());394395// Perform a simple cost/benefit analysis to decide whether or not to permit396// splitting.397SetVector<Value *> Inputs, Outputs, Sinks;398CE.findInputsOutputs(Inputs, Outputs, Sinks);399InstructionCost OutliningBenefit = getOutliningBenefit(Region, TTI);400int OutliningPenalty =401getOutliningPenalty(Region, Inputs.size(), Outputs.size());402LLVM_DEBUG(dbgs() << "Split profitability: benefit = " << OutliningBenefit403<< ", penalty = " << OutliningPenalty << "\n");404if (!OutliningBenefit.isValid() || OutliningBenefit <= OutliningPenalty)405return false;406407return true;408}409410// Split the single \p EntryPoint cold region. \p CE is the region code411// extractor.412Function *HotColdSplitting::extractColdRegion(413BasicBlock &EntryPoint, CodeExtractor &CE,414const CodeExtractorAnalysisCache &CEAC, BlockFrequencyInfo *BFI,415TargetTransformInfo &TTI, OptimizationRemarkEmitter &ORE) {416Function *OrigF = EntryPoint.getParent();417if (Function *OutF = CE.extractCodeRegion(CEAC)) {418User *U = *OutF->user_begin();419CallInst *CI = cast<CallInst>(U);420NumColdRegionsOutlined++;421if (TTI.useColdCCForColdCall(*OutF)) {422OutF->setCallingConv(CallingConv::Cold);423CI->setCallingConv(CallingConv::Cold);424}425CI->setIsNoInline();426427if (EnableColdSection)428OutF->setSection(ColdSectionName);429else {430if (OrigF->hasSection())431OutF->setSection(OrigF->getSection());432}433434markFunctionCold(*OutF, BFI != nullptr);435436LLVM_DEBUG(llvm::dbgs() << "Outlined Region: " << *OutF);437ORE.emit([&]() {438return OptimizationRemark(DEBUG_TYPE, "HotColdSplit",439&*EntryPoint.begin())440<< ore::NV("Original", OrigF) << " split cold code into "441<< ore::NV("Split", OutF);442});443return OutF;444}445446ORE.emit([&]() {447return OptimizationRemarkMissed(DEBUG_TYPE, "ExtractFailed",448&*EntryPoint.begin())449<< "Failed to extract region at block "450<< ore::NV("Block", &EntryPoint);451});452return nullptr;453}454455/// A pair of (basic block, score).456using BlockTy = std::pair<BasicBlock *, unsigned>;457458namespace {459/// A maximal outlining region. This contains all blocks post-dominated by a460/// sink block, the sink block itself, and all blocks dominated by the sink.461/// If sink-predecessors and sink-successors cannot be extracted in one region,462/// the static constructor returns a list of suitable extraction regions.463class OutliningRegion {464/// A list of (block, score) pairs. A block's score is non-zero iff it's a465/// viable sub-region entry point. Blocks with higher scores are better entry466/// points (i.e. they are more distant ancestors of the sink block).467SmallVector<BlockTy, 0> Blocks = {};468469/// The suggested entry point into the region. If the region has multiple470/// entry points, all blocks within the region may not be reachable from this471/// entry point.472BasicBlock *SuggestedEntryPoint = nullptr;473474/// Whether the entire function is cold.475bool EntireFunctionCold = false;476477/// If \p BB is a viable entry point, return \p Score. Return 0 otherwise.478static unsigned getEntryPointScore(BasicBlock &BB, unsigned Score) {479return mayExtractBlock(BB) ? Score : 0;480}481482/// These scores should be lower than the score for predecessor blocks,483/// because regions starting at predecessor blocks are typically larger.484static constexpr unsigned ScoreForSuccBlock = 1;485static constexpr unsigned ScoreForSinkBlock = 1;486487OutliningRegion(const OutliningRegion &) = delete;488OutliningRegion &operator=(const OutliningRegion &) = delete;489490public:491OutliningRegion() = default;492OutliningRegion(OutliningRegion &&) = default;493OutliningRegion &operator=(OutliningRegion &&) = default;494495static std::vector<OutliningRegion> create(BasicBlock &SinkBB,496const DominatorTree &DT,497const PostDominatorTree &PDT) {498std::vector<OutliningRegion> Regions;499SmallPtrSet<BasicBlock *, 4> RegionBlocks;500501Regions.emplace_back();502OutliningRegion *ColdRegion = &Regions.back();503504auto addBlockToRegion = [&](BasicBlock *BB, unsigned Score) {505RegionBlocks.insert(BB);506ColdRegion->Blocks.emplace_back(BB, Score);507};508509// The ancestor farthest-away from SinkBB, and also post-dominated by it.510unsigned SinkScore = getEntryPointScore(SinkBB, ScoreForSinkBlock);511ColdRegion->SuggestedEntryPoint = (SinkScore > 0) ? &SinkBB : nullptr;512unsigned BestScore = SinkScore;513514// Visit SinkBB's ancestors using inverse DFS.515auto PredIt = ++idf_begin(&SinkBB);516auto PredEnd = idf_end(&SinkBB);517while (PredIt != PredEnd) {518BasicBlock &PredBB = **PredIt;519bool SinkPostDom = PDT.dominates(&SinkBB, &PredBB);520521// If the predecessor is cold and has no predecessors, the entire522// function must be cold.523if (SinkPostDom && pred_empty(&PredBB)) {524ColdRegion->EntireFunctionCold = true;525return Regions;526}527528// If SinkBB does not post-dominate a predecessor, do not mark the529// predecessor (or any of its predecessors) cold.530if (!SinkPostDom || !mayExtractBlock(PredBB)) {531PredIt.skipChildren();532continue;533}534535// Keep track of the post-dominated ancestor farthest away from the sink.536// The path length is always >= 2, ensuring that predecessor blocks are537// considered as entry points before the sink block.538unsigned PredScore = getEntryPointScore(PredBB, PredIt.getPathLength());539if (PredScore > BestScore) {540ColdRegion->SuggestedEntryPoint = &PredBB;541BestScore = PredScore;542}543544addBlockToRegion(&PredBB, PredScore);545++PredIt;546}547548// If the sink can be added to the cold region, do so. It's considered as549// an entry point before any sink-successor blocks.550//551// Otherwise, split cold sink-successor blocks using a separate region.552// This satisfies the requirement that all extraction blocks other than the553// first have predecessors within the extraction region.554if (mayExtractBlock(SinkBB)) {555addBlockToRegion(&SinkBB, SinkScore);556if (pred_empty(&SinkBB)) {557ColdRegion->EntireFunctionCold = true;558return Regions;559}560} else {561Regions.emplace_back();562ColdRegion = &Regions.back();563BestScore = 0;564}565566// Find all successors of SinkBB dominated by SinkBB using DFS.567auto SuccIt = ++df_begin(&SinkBB);568auto SuccEnd = df_end(&SinkBB);569while (SuccIt != SuccEnd) {570BasicBlock &SuccBB = **SuccIt;571bool SinkDom = DT.dominates(&SinkBB, &SuccBB);572573// Don't allow the backwards & forwards DFSes to mark the same block.574bool DuplicateBlock = RegionBlocks.count(&SuccBB);575576// If SinkBB does not dominate a successor, do not mark the successor (or577// any of its successors) cold.578if (DuplicateBlock || !SinkDom || !mayExtractBlock(SuccBB)) {579SuccIt.skipChildren();580continue;581}582583unsigned SuccScore = getEntryPointScore(SuccBB, ScoreForSuccBlock);584if (SuccScore > BestScore) {585ColdRegion->SuggestedEntryPoint = &SuccBB;586BestScore = SuccScore;587}588589addBlockToRegion(&SuccBB, SuccScore);590++SuccIt;591}592593return Regions;594}595596/// Whether this region has nothing to extract.597bool empty() const { return !SuggestedEntryPoint; }598599/// The blocks in this region.600ArrayRef<std::pair<BasicBlock *, unsigned>> blocks() const { return Blocks; }601602/// Whether the entire function containing this region is cold.603bool isEntireFunctionCold() const { return EntireFunctionCold; }604605/// Remove a sub-region from this region and return it as a block sequence.606BlockSequence takeSingleEntrySubRegion(DominatorTree &DT) {607assert(!empty() && !isEntireFunctionCold() && "Nothing to extract");608609// Remove blocks dominated by the suggested entry point from this region.610// During the removal, identify the next best entry point into the region.611// Ensure that the first extracted block is the suggested entry point.612BlockSequence SubRegion = {SuggestedEntryPoint};613BasicBlock *NextEntryPoint = nullptr;614unsigned NextScore = 0;615auto RegionEndIt = Blocks.end();616auto RegionStartIt = remove_if(Blocks, [&](const BlockTy &Block) {617BasicBlock *BB = Block.first;618unsigned Score = Block.second;619bool InSubRegion =620BB == SuggestedEntryPoint || DT.dominates(SuggestedEntryPoint, BB);621if (!InSubRegion && Score > NextScore) {622NextEntryPoint = BB;623NextScore = Score;624}625if (InSubRegion && BB != SuggestedEntryPoint)626SubRegion.push_back(BB);627return InSubRegion;628});629Blocks.erase(RegionStartIt, RegionEndIt);630631// Update the suggested entry point.632SuggestedEntryPoint = NextEntryPoint;633634return SubRegion;635}636};637} // namespace638639bool HotColdSplitting::outlineColdRegions(Function &F, bool HasProfileSummary) {640// The set of cold blocks outlined.641SmallPtrSet<BasicBlock *, 4> ColdBlocks;642643// The set of cold blocks cannot be outlined.644SmallPtrSet<BasicBlock *, 4> CannotBeOutlinedColdBlocks;645646// Set of cold blocks obtained with RPOT.647SmallPtrSet<BasicBlock *, 4> AnnotatedColdBlocks;648649// The worklist of non-intersecting regions left to outline. The first member650// of the pair is the entry point into the region to be outlined.651SmallVector<std::pair<BasicBlock *, CodeExtractor>, 2> OutliningWorklist;652653// Set up an RPO traversal. Experimentally, this performs better (outlines654// more) than a PO traversal, because we prevent region overlap by keeping655// the first region to contain a block.656ReversePostOrderTraversal<Function *> RPOT(&F);657658// Calculate domtrees lazily. This reduces compile-time significantly.659std::unique_ptr<DominatorTree> DT;660std::unique_ptr<PostDominatorTree> PDT;661662// Calculate BFI lazily (it's only used to query ProfileSummaryInfo). This663// reduces compile-time significantly. TODO: When we *do* use BFI, we should664// be able to salvage its domtrees instead of recomputing them.665BlockFrequencyInfo *BFI = nullptr;666if (HasProfileSummary)667BFI = GetBFI(F);668669TargetTransformInfo &TTI = GetTTI(F);670OptimizationRemarkEmitter &ORE = (*GetORE)(F);671AssumptionCache *AC = LookupAC(F);672auto ColdProbThresh = TTI.getPredictableBranchThreshold().getCompl();673674if (ColdBranchProbDenom.getNumOccurrences())675ColdProbThresh = BranchProbability(1, ColdBranchProbDenom.getValue());676677unsigned OutlinedFunctionID = 1;678// Find all cold regions.679for (BasicBlock *BB : RPOT) {680// This block is already part of some outlining region.681if (ColdBlocks.count(BB))682continue;683684// This block is already part of some region cannot be outlined.685if (CannotBeOutlinedColdBlocks.count(BB))686continue;687688if (!isBasicBlockCold(BB, ColdProbThresh, AnnotatedColdBlocks, BFI))689continue;690691LLVM_DEBUG({692dbgs() << "Found a cold block:\n";693BB->dump();694});695696if (!DT)697DT = std::make_unique<DominatorTree>(F);698if (!PDT)699PDT = std::make_unique<PostDominatorTree>(F);700701auto Regions = OutliningRegion::create(*BB, *DT, *PDT);702for (OutliningRegion &Region : Regions) {703if (Region.empty())704continue;705706if (Region.isEntireFunctionCold()) {707LLVM_DEBUG(dbgs() << "Entire function is cold\n");708return markFunctionCold(F);709}710711do {712BlockSequence SubRegion = Region.takeSingleEntrySubRegion(*DT);713LLVM_DEBUG({714dbgs() << "Hot/cold splitting attempting to outline these blocks:\n";715for (BasicBlock *BB : SubRegion)716BB->dump();717});718719// TODO: Pass BFI and BPI to update profile information.720CodeExtractor CE(721SubRegion, &*DT, /* AggregateArgs */ false, /* BFI */ nullptr,722/* BPI */ nullptr, AC, /* AllowVarArgs */ false,723/* AllowAlloca */ false, /* AllocaBlock */ nullptr,724/* Suffix */ "cold." + std::to_string(OutlinedFunctionID));725726if (CE.isEligible() && isSplittingBeneficial(CE, SubRegion, TTI) &&727// If this outlining region intersects with another, drop the new728// region.729//730// TODO: It's theoretically possible to outline more by only keeping731// the largest region which contains a block, but the extra732// bookkeeping to do this is tricky/expensive.733none_of(SubRegion, [&](BasicBlock *Block) {734return ColdBlocks.contains(Block);735})) {736ColdBlocks.insert(SubRegion.begin(), SubRegion.end());737738LLVM_DEBUG({739for (auto *Block : SubRegion)740dbgs() << " contains cold block:" << Block->getName() << "\n";741});742743OutliningWorklist.emplace_back(744std::make_pair(SubRegion[0], std::move(CE)));745++OutlinedFunctionID;746} else {747// The cold block region cannot be outlined.748for (auto *Block : SubRegion)749if ((DT->dominates(BB, Block) && PDT->dominates(Block, BB)) ||750(PDT->dominates(BB, Block) && DT->dominates(Block, BB)))751// Will skip this cold block in the loop to save the compile time752CannotBeOutlinedColdBlocks.insert(Block);753}754} while (!Region.empty());755756++NumColdRegionsFound;757}758}759760if (OutliningWorklist.empty())761return false;762763// Outline single-entry cold regions, splitting up larger regions as needed.764// Cache and recycle the CodeExtractor analysis to avoid O(n^2) compile-time.765CodeExtractorAnalysisCache CEAC(F);766for (auto &BCE : OutliningWorklist) {767Function *Outlined =768extractColdRegion(*BCE.first, BCE.second, CEAC, BFI, TTI, ORE);769assert(Outlined && "Should be outlined");770(void)Outlined;771}772773return true;774}775776bool HotColdSplitting::run(Module &M) {777bool Changed = false;778bool HasProfileSummary = (M.getProfileSummary(/* IsCS */ false) != nullptr);779for (Function &F : M) {780// Do not touch declarations.781if (F.isDeclaration())782continue;783784// Do not modify `optnone` functions.785if (F.hasOptNone())786continue;787788// Detect inherently cold functions and mark them as such.789if (isFunctionCold(F)) {790Changed |= markFunctionCold(F);791continue;792}793794if (!shouldOutlineFrom(F)) {795LLVM_DEBUG(llvm::dbgs() << "Skipping " << F.getName() << "\n");796continue;797}798799LLVM_DEBUG(llvm::dbgs() << "Outlining in " << F.getName() << "\n");800Changed |= outlineColdRegions(F, HasProfileSummary);801}802return Changed;803}804805PreservedAnalyses806HotColdSplittingPass::run(Module &M, ModuleAnalysisManager &AM) {807auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();808809auto LookupAC = [&FAM](Function &F) -> AssumptionCache * {810return FAM.getCachedResult<AssumptionAnalysis>(F);811};812813auto GBFI = [&FAM](Function &F) {814return &FAM.getResult<BlockFrequencyAnalysis>(F);815};816817std::function<TargetTransformInfo &(Function &)> GTTI =818[&FAM](Function &F) -> TargetTransformInfo & {819return FAM.getResult<TargetIRAnalysis>(F);820};821822std::unique_ptr<OptimizationRemarkEmitter> ORE;823std::function<OptimizationRemarkEmitter &(Function &)> GetORE =824[&ORE](Function &F) -> OptimizationRemarkEmitter & {825ORE.reset(new OptimizationRemarkEmitter(&F));826return *ORE;827};828829ProfileSummaryInfo *PSI = &AM.getResult<ProfileSummaryAnalysis>(M);830831if (HotColdSplitting(PSI, GBFI, GTTI, &GetORE, LookupAC).run(M))832return PreservedAnalyses::none();833return PreservedAnalyses::all();834}835836837