diff --git a/llvm/lib/Transforms/IPO/HotColdSplitting.cpp b/llvm/lib/Transforms/IPO/HotColdSplitting.cpp --- a/llvm/lib/Transforms/IPO/HotColdSplitting.cpp +++ b/llvm/lib/Transforms/IPO/HotColdSplitting.cpp @@ -69,6 +69,7 @@ #include "llvm/Transforms/Utils/ValueMapper.h" #include #include +#include #include #define DEBUG_TYPE "hotcoldsplit" @@ -97,6 +98,11 @@ cl::desc("Name for the section containing cold functions " "extracted by hot-cold splitting.")); +static cl::opt + OutlineEH("hotcoldsplit-outline-eh", cl::init(false), cl::Hidden, + cl::desc("Perform outlining for Itanium ABI-based" + " exception handling blocks.")); + namespace { // Same as blockEndsInUnreachable in CodeGen/BranchFolding.cpp. Do not modify // this function unless you modify the MBB version as well. @@ -116,7 +122,7 @@ bool unlikelyExecuted(BasicBlock &BB, ProfileSummaryInfo *PSI, BlockFrequencyInfo *BFI) { // Exception handling blocks are unlikely executed. - if (BB.isEHPad() || isa(BB.getTerminator())) + if (!OutlineEH && (BB.isEHPad() || isa(BB.getTerminator()))) return true; // The block is cold if it calls/invokes a cold function. However, do not @@ -340,6 +346,10 @@ if (OutliningBenefit <= OutliningPenalty) return nullptr; + LLVM_DEBUG(dbgs() << "Attempting to outline region into function\n"); + LLVM_DEBUG(dbgs() << "Region size = " << Region.size() << "\n"); + LLVM_DEBUG(dbgs() << "Region entry block = " << Region[0]->getName() << "\n"); + Function *OrigF = Region[0]->getParent(); if (Function *OutF = CE.extractCodeRegion(CEAC)) { User *U = *OutF->user_begin(); @@ -370,6 +380,7 @@ return OutF; } + LLVM_DEBUG(dbgs() << "CodeExtractor failed to extract the region\n"); ORE.emit([&]() { return OptimizationRemarkMissed(DEBUG_TYPE, "ExtractFailed", &*Region[0]->begin()) @@ -592,6 +603,70 @@ OptimizationRemarkEmitter &ORE = (*GetORE)(F); AssumptionCache *AC = LookupAC(F); + // For each catch.dispatch block, elevate the + // calls to eh.typeid.for instructions into + // the landingpad block for outlining purposes. + + std::set LPadSuccessors; + + // Split EH pad blocks into a landing pad block and the + // rest. We can start outlining at the first non-landingpad + // instruction. + + // The EH outlining strategy below only works with Itanium-style EH. + // WinEH outlining is not supported. We check if the personality + // function is WinEH's (CxxFrameHandler3), or we try to do EH outlining. + // TODO find better way of finding out if function uses WinEH handling + // or find a way to outling WinEH code. + if (OutlineEH && F.hasPersonalityFn() && + !F.getPersonalityFn()->getName().endswith("CxxFrameHandler3")) { + for (BasicBlock *BB : RPOT) + if (BB->isEHPad()) { + LLVM_DEBUG({ + dbgs() << "Found an EH Basic Block: "; + BB->dump(); + dbgs() << "------------------------\n"; + }); + + if (!DT) + DT = std::make_unique(F); + std::vector EHIntrinsicCalls; + SmallVector Descendants; + DT->getDescendants(BB, Descendants); + for (BasicBlock *SuccBB : Descendants) { + for (Instruction &I : *SuccBB) { + if (isa(&I)) { + const CallInst *CI = dyn_cast(&I); + if (CI->getIntrinsicID() == Intrinsic::eh_typeid_for) + EHIntrinsicCalls.push_back(&I); + } + } + } + Instruction *LPadInst = BB->getLandingPadInst()->getNextNode(); + BasicBlock *NewSuccessorBlock = SplitBlock(BB, LPadInst, DT.get()); + for (size_t I = 0; I < EHIntrinsicCalls.size(); I++) { + EHIntrinsicCalls[I]->removeFromParent(); + // Insert eh.typeid.for call after the landingpad instruction. + // We split \p BB from the next instruction after the landingpad + // instruction, so the landingpad instruction's successor + // must be the terminating unconditional branch. + Instruction *PreBranchInst = BB->getTerminator()->getPrevNode(); + BB->getInstList().insertAfter(PreBranchInst->getIterator(), + EHIntrinsicCalls[I]); + } + LLVM_DEBUG({ + dbgs() + << "EH Outliner: Split BB into lpad and lpad.split, lpad.split: "; + NewSuccessorBlock->dump(); + dbgs() << "---------------------\n"; + dbgs() << "EH Outliner: lpad:"; + BB->dump(); + dbgs() << "---------------------\n"; + }); + LPadSuccessors.insert(NewSuccessorBlock); + } + } + // Find all cold regions. for (BasicBlock *BB : RPOT) { // This block is already part of some outlining region. @@ -600,6 +675,21 @@ bool Cold = (BFI && PSI->isColdBlock(BB, BFI)) || (EnableStaticAnalysis && unlikelyExecuted(*BB, PSI, BFI)); + + if (OutlineEH && EnableStaticAnalysis && BB->getSinglePredecessor() && + BB->getSinglePredecessor()->isEHPad()) { + LLVM_DEBUG(dbgs() << "EH Outliner: block " << BB->getName() + << " has EHPad predecessor and marked as cold\n"); + Cold = true; + } + + // if BB is a split EH-pad block + if (OutlineEH && LPadSuccessors.find(BB) != LPadSuccessors.end()) { + LLVM_DEBUG(dbgs() << "EH Outliner: Found a LPad successor block " + << BB->getName() << "\n"); + Cold = true; + } + if (!Cold) continue; @@ -726,8 +816,8 @@ return HotColdSplitting(PSI, GBFI, GTTI, &GetORE, LookupAC).run(M); } -PreservedAnalyses -HotColdSplittingPass::run(Module &M, ModuleAnalysisManager &AM) { +PreservedAnalyses HotColdSplittingPass::run(Module &M, + ModuleAnalysisManager &AM) { auto &FAM = AM.getResult(M).getManager(); auto LookupAC = [&FAM](Function &F) -> AssumptionCache * {