1e8d8bef9SDimitry Andric //===- FunctionPropertiesAnalysis.cpp - Function Properties Analysis ------===// 2e8d8bef9SDimitry Andric // 3e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e8d8bef9SDimitry Andric // 7e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 8e8d8bef9SDimitry Andric // 9e8d8bef9SDimitry Andric // This file defines the FunctionPropertiesInfo and FunctionPropertiesAnalysis 10e8d8bef9SDimitry Andric // classes used to extract function properties. 11e8d8bef9SDimitry Andric // 12e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 13e8d8bef9SDimitry Andric 14e8d8bef9SDimitry Andric #include "llvm/Analysis/FunctionPropertiesAnalysis.h" 1581ad6265SDimitry Andric #include "llvm/ADT/STLExtras.h" 1681ad6265SDimitry Andric #include "llvm/ADT/SetVector.h" 1781ad6265SDimitry Andric #include "llvm/Analysis/LoopInfo.h" 1881ad6265SDimitry Andric #include "llvm/IR/CFG.h" 195f757f3fSDimitry Andric #include "llvm/IR/Constants.h" 2081ad6265SDimitry Andric #include "llvm/IR/Dominators.h" 21e8d8bef9SDimitry Andric #include "llvm/IR/Instructions.h" 225f757f3fSDimitry Andric #include "llvm/IR/IntrinsicInst.h" 235f757f3fSDimitry Andric #include "llvm/Support/CommandLine.h" 2481ad6265SDimitry Andric #include <deque> 25e8d8bef9SDimitry Andric 26e8d8bef9SDimitry Andric using namespace llvm; 27e8d8bef9SDimitry Andric 285f757f3fSDimitry Andric namespace llvm { 295f757f3fSDimitry Andric cl::opt<bool> EnableDetailedFunctionProperties( 305f757f3fSDimitry Andric "enable-detailed-function-properties", cl::Hidden, cl::init(false), 315f757f3fSDimitry Andric cl::desc("Whether or not to compute detailed function properties.")); 325f757f3fSDimitry Andric 335f757f3fSDimitry Andric cl::opt<unsigned> BigBasicBlockInstructionThreshold( 345f757f3fSDimitry Andric "big-basic-block-instruction-threshold", cl::Hidden, cl::init(500), 355f757f3fSDimitry Andric cl::desc("The minimum number of instructions a basic block should contain " 365f757f3fSDimitry Andric "before being considered big.")); 375f757f3fSDimitry Andric 385f757f3fSDimitry Andric cl::opt<unsigned> MediumBasicBlockInstructionThreshold( 395f757f3fSDimitry Andric "medium-basic-block-instruction-threshold", cl::Hidden, cl::init(15), 405f757f3fSDimitry Andric cl::desc("The minimum number of instructions a basic block should contain " 415f757f3fSDimitry Andric "before being considered medium-sized.")); 42*0fca6ea1SDimitry Andric } // namespace llvm 435f757f3fSDimitry Andric 445f757f3fSDimitry Andric static cl::opt<unsigned> CallWithManyArgumentsThreshold( 455f757f3fSDimitry Andric "call-with-many-arguments-threshold", cl::Hidden, cl::init(4), 465f757f3fSDimitry Andric cl::desc("The minimum number of arguments a function call must have before " 475f757f3fSDimitry Andric "it is considered having many arguments.")); 485f757f3fSDimitry Andric 4981ad6265SDimitry Andric namespace { 5081ad6265SDimitry Andric int64_t getNrBlocksFromCond(const BasicBlock &BB) { 5181ad6265SDimitry Andric int64_t Ret = 0; 52e8d8bef9SDimitry Andric if (const auto *BI = dyn_cast<BranchInst>(BB.getTerminator())) { 53e8d8bef9SDimitry Andric if (BI->isConditional()) 5481ad6265SDimitry Andric Ret += BI->getNumSuccessors(); 55e8d8bef9SDimitry Andric } else if (const auto *SI = dyn_cast<SwitchInst>(BB.getTerminator())) { 5681ad6265SDimitry Andric Ret += (SI->getNumCases() + (nullptr != SI->getDefaultDest())); 5781ad6265SDimitry Andric } 5881ad6265SDimitry Andric return Ret; 59e8d8bef9SDimitry Andric } 60e8d8bef9SDimitry Andric 6181ad6265SDimitry Andric int64_t getUses(const Function &F) { 6281ad6265SDimitry Andric return ((!F.hasLocalLinkage()) ? 1 : 0) + F.getNumUses(); 6381ad6265SDimitry Andric } 6481ad6265SDimitry Andric } // namespace 6581ad6265SDimitry Andric 6681ad6265SDimitry Andric void FunctionPropertiesInfo::reIncludeBB(const BasicBlock &BB) { 6781ad6265SDimitry Andric updateForBB(BB, +1); 6881ad6265SDimitry Andric } 6981ad6265SDimitry Andric 7081ad6265SDimitry Andric void FunctionPropertiesInfo::updateForBB(const BasicBlock &BB, 7181ad6265SDimitry Andric int64_t Direction) { 7281ad6265SDimitry Andric assert(Direction == 1 || Direction == -1); 7381ad6265SDimitry Andric BasicBlockCount += Direction; 7481ad6265SDimitry Andric BlocksReachedFromConditionalInstruction += 7581ad6265SDimitry Andric (Direction * getNrBlocksFromCond(BB)); 76e8d8bef9SDimitry Andric for (const auto &I : BB) { 77e8d8bef9SDimitry Andric if (auto *CS = dyn_cast<CallBase>(&I)) { 78e8d8bef9SDimitry Andric const auto *Callee = CS->getCalledFunction(); 79e8d8bef9SDimitry Andric if (Callee && !Callee->isIntrinsic() && !Callee->isDeclaration()) 8081ad6265SDimitry Andric DirectCallsToDefinedFunctions += Direction; 81e8d8bef9SDimitry Andric } 82e8d8bef9SDimitry Andric if (I.getOpcode() == Instruction::Load) { 8381ad6265SDimitry Andric LoadInstCount += Direction; 84e8d8bef9SDimitry Andric } else if (I.getOpcode() == Instruction::Store) { 8581ad6265SDimitry Andric StoreInstCount += Direction; 86e8d8bef9SDimitry Andric } 87e8d8bef9SDimitry Andric } 8881ad6265SDimitry Andric TotalInstructionCount += Direction * BB.sizeWithoutDebug(); 895f757f3fSDimitry Andric 905f757f3fSDimitry Andric if (EnableDetailedFunctionProperties) { 915f757f3fSDimitry Andric unsigned SuccessorCount = succ_size(&BB); 925f757f3fSDimitry Andric if (SuccessorCount == 1) 935f757f3fSDimitry Andric BasicBlocksWithSingleSuccessor += Direction; 945f757f3fSDimitry Andric else if (SuccessorCount == 2) 955f757f3fSDimitry Andric BasicBlocksWithTwoSuccessors += Direction; 965f757f3fSDimitry Andric else if (SuccessorCount > 2) 975f757f3fSDimitry Andric BasicBlocksWithMoreThanTwoSuccessors += Direction; 985f757f3fSDimitry Andric 995f757f3fSDimitry Andric unsigned PredecessorCount = pred_size(&BB); 1005f757f3fSDimitry Andric if (PredecessorCount == 1) 1015f757f3fSDimitry Andric BasicBlocksWithSinglePredecessor += Direction; 1025f757f3fSDimitry Andric else if (PredecessorCount == 2) 1035f757f3fSDimitry Andric BasicBlocksWithTwoPredecessors += Direction; 1045f757f3fSDimitry Andric else if (PredecessorCount > 2) 1055f757f3fSDimitry Andric BasicBlocksWithMoreThanTwoPredecessors += Direction; 1065f757f3fSDimitry Andric 1075f757f3fSDimitry Andric if (TotalInstructionCount > BigBasicBlockInstructionThreshold) 1085f757f3fSDimitry Andric BigBasicBlocks += Direction; 1095f757f3fSDimitry Andric else if (TotalInstructionCount > MediumBasicBlockInstructionThreshold) 1105f757f3fSDimitry Andric MediumBasicBlocks += Direction; 1115f757f3fSDimitry Andric else 1125f757f3fSDimitry Andric SmallBasicBlocks += Direction; 1135f757f3fSDimitry Andric 1145f757f3fSDimitry Andric // Calculate critical edges by looking through all successors of a basic 1155f757f3fSDimitry Andric // block that has multiple successors and finding ones that have multiple 1165f757f3fSDimitry Andric // predecessors, which represent critical edges. 1175f757f3fSDimitry Andric if (SuccessorCount > 1) { 1185f757f3fSDimitry Andric for (const auto *Successor : successors(&BB)) { 1195f757f3fSDimitry Andric if (pred_size(Successor) > 1) 1205f757f3fSDimitry Andric CriticalEdgeCount += Direction; 1215f757f3fSDimitry Andric } 1225f757f3fSDimitry Andric } 1235f757f3fSDimitry Andric 1245f757f3fSDimitry Andric ControlFlowEdgeCount += Direction * SuccessorCount; 1255f757f3fSDimitry Andric 1265f757f3fSDimitry Andric if (const auto *BI = dyn_cast<BranchInst>(BB.getTerminator())) { 1275f757f3fSDimitry Andric if (!BI->isConditional()) 1285f757f3fSDimitry Andric UnconditionalBranchCount += Direction; 1295f757f3fSDimitry Andric } 1305f757f3fSDimitry Andric 1315f757f3fSDimitry Andric for (const Instruction &I : BB.instructionsWithoutDebug()) { 1325f757f3fSDimitry Andric if (I.isCast()) 1335f757f3fSDimitry Andric CastInstructionCount += Direction; 1345f757f3fSDimitry Andric 1355f757f3fSDimitry Andric if (I.getType()->isFloatTy()) 1365f757f3fSDimitry Andric FloatingPointInstructionCount += Direction; 1375f757f3fSDimitry Andric else if (I.getType()->isIntegerTy()) 1385f757f3fSDimitry Andric IntegerInstructionCount += Direction; 1395f757f3fSDimitry Andric 1405f757f3fSDimitry Andric if (isa<IntrinsicInst>(I)) 1415f757f3fSDimitry Andric ++IntrinsicCount; 1425f757f3fSDimitry Andric 1435f757f3fSDimitry Andric if (const auto *Call = dyn_cast<CallInst>(&I)) { 1445f757f3fSDimitry Andric if (Call->isIndirectCall()) 1455f757f3fSDimitry Andric IndirectCallCount += Direction; 1465f757f3fSDimitry Andric else 1475f757f3fSDimitry Andric DirectCallCount += Direction; 1485f757f3fSDimitry Andric 1495f757f3fSDimitry Andric if (Call->getType()->isIntegerTy()) 1505f757f3fSDimitry Andric CallReturnsIntegerCount += Direction; 1515f757f3fSDimitry Andric else if (Call->getType()->isFloatingPointTy()) 1525f757f3fSDimitry Andric CallReturnsFloatCount += Direction; 1535f757f3fSDimitry Andric else if (Call->getType()->isPointerTy()) 1545f757f3fSDimitry Andric CallReturnsPointerCount += Direction; 1555f757f3fSDimitry Andric else if (Call->getType()->isVectorTy()) { 1565f757f3fSDimitry Andric if (Call->getType()->getScalarType()->isIntegerTy()) 1575f757f3fSDimitry Andric CallReturnsVectorIntCount += Direction; 1585f757f3fSDimitry Andric else if (Call->getType()->getScalarType()->isFloatingPointTy()) 1595f757f3fSDimitry Andric CallReturnsVectorFloatCount += Direction; 1605f757f3fSDimitry Andric else if (Call->getType()->getScalarType()->isPointerTy()) 1615f757f3fSDimitry Andric CallReturnsVectorPointerCount += Direction; 1625f757f3fSDimitry Andric } 1635f757f3fSDimitry Andric 1645f757f3fSDimitry Andric if (Call->arg_size() > CallWithManyArgumentsThreshold) 1655f757f3fSDimitry Andric CallWithManyArgumentsCount += Direction; 1665f757f3fSDimitry Andric 1675f757f3fSDimitry Andric for (const auto &Arg : Call->args()) { 1685f757f3fSDimitry Andric if (Arg->getType()->isPointerTy()) { 1695f757f3fSDimitry Andric CallWithPointerArgumentCount += Direction; 1705f757f3fSDimitry Andric break; 1715f757f3fSDimitry Andric } 1725f757f3fSDimitry Andric } 1735f757f3fSDimitry Andric } 1745f757f3fSDimitry Andric 1755f757f3fSDimitry Andric #define COUNT_OPERAND(OPTYPE) \ 1765f757f3fSDimitry Andric if (isa<OPTYPE>(Operand)) { \ 1775f757f3fSDimitry Andric OPTYPE##OperandCount += Direction; \ 1785f757f3fSDimitry Andric continue; \ 1795f757f3fSDimitry Andric } 1805f757f3fSDimitry Andric 1815f757f3fSDimitry Andric for (unsigned int OperandIndex = 0; OperandIndex < I.getNumOperands(); 1825f757f3fSDimitry Andric ++OperandIndex) { 1835f757f3fSDimitry Andric Value *Operand = I.getOperand(OperandIndex); 1845f757f3fSDimitry Andric COUNT_OPERAND(GlobalValue) 1855f757f3fSDimitry Andric COUNT_OPERAND(ConstantInt) 1865f757f3fSDimitry Andric COUNT_OPERAND(ConstantFP) 1875f757f3fSDimitry Andric COUNT_OPERAND(Constant) 1885f757f3fSDimitry Andric COUNT_OPERAND(Instruction) 1895f757f3fSDimitry Andric COUNT_OPERAND(BasicBlock) 1905f757f3fSDimitry Andric COUNT_OPERAND(InlineAsm) 1915f757f3fSDimitry Andric COUNT_OPERAND(Argument) 1925f757f3fSDimitry Andric 1935f757f3fSDimitry Andric // We only get to this point if we haven't matched any of the other 1945f757f3fSDimitry Andric // operand types. 1955f757f3fSDimitry Andric UnknownOperandCount += Direction; 1965f757f3fSDimitry Andric } 1975f757f3fSDimitry Andric 1985f757f3fSDimitry Andric #undef CHECK_OPERAND 1995f757f3fSDimitry Andric } 2005f757f3fSDimitry Andric } 201e8d8bef9SDimitry Andric } 20281ad6265SDimitry Andric 20381ad6265SDimitry Andric void FunctionPropertiesInfo::updateAggregateStats(const Function &F, 20481ad6265SDimitry Andric const LoopInfo &LI) { 20581ad6265SDimitry Andric 20681ad6265SDimitry Andric Uses = getUses(F); 20781ad6265SDimitry Andric TopLevelLoopCount = llvm::size(LI); 20881ad6265SDimitry Andric MaxLoopDepth = 0; 20981ad6265SDimitry Andric std::deque<const Loop *> Worklist; 21081ad6265SDimitry Andric llvm::append_range(Worklist, LI); 21181ad6265SDimitry Andric while (!Worklist.empty()) { 21281ad6265SDimitry Andric const auto *L = Worklist.front(); 21381ad6265SDimitry Andric MaxLoopDepth = 21481ad6265SDimitry Andric std::max(MaxLoopDepth, static_cast<int64_t>(L->getLoopDepth())); 21581ad6265SDimitry Andric Worklist.pop_front(); 21681ad6265SDimitry Andric llvm::append_range(Worklist, L->getSubLoops()); 21781ad6265SDimitry Andric } 21881ad6265SDimitry Andric } 21981ad6265SDimitry Andric 22081ad6265SDimitry Andric FunctionPropertiesInfo FunctionPropertiesInfo::getFunctionPropertiesInfo( 22106c3fb27SDimitry Andric Function &F, FunctionAnalysisManager &FAM) { 22206c3fb27SDimitry Andric return getFunctionPropertiesInfo(F, FAM.getResult<DominatorTreeAnalysis>(F), 22306c3fb27SDimitry Andric FAM.getResult<LoopAnalysis>(F)); 22406c3fb27SDimitry Andric } 22506c3fb27SDimitry Andric 22606c3fb27SDimitry Andric FunctionPropertiesInfo FunctionPropertiesInfo::getFunctionPropertiesInfo( 22706c3fb27SDimitry Andric const Function &F, const DominatorTree &DT, const LoopInfo &LI) { 22881ad6265SDimitry Andric 22981ad6265SDimitry Andric FunctionPropertiesInfo FPI; 23081ad6265SDimitry Andric for (const auto &BB : F) 23181ad6265SDimitry Andric if (DT.isReachableFromEntry(&BB)) 23281ad6265SDimitry Andric FPI.reIncludeBB(BB); 23381ad6265SDimitry Andric FPI.updateAggregateStats(F, LI); 234e8d8bef9SDimitry Andric return FPI; 235e8d8bef9SDimitry Andric } 236e8d8bef9SDimitry Andric 237e8d8bef9SDimitry Andric void FunctionPropertiesInfo::print(raw_ostream &OS) const { 2385f757f3fSDimitry Andric #define PRINT_PROPERTY(PROP_NAME) OS << #PROP_NAME ": " << PROP_NAME << "\n"; 2395f757f3fSDimitry Andric 2405f757f3fSDimitry Andric PRINT_PROPERTY(BasicBlockCount) 2415f757f3fSDimitry Andric PRINT_PROPERTY(BlocksReachedFromConditionalInstruction) 2425f757f3fSDimitry Andric PRINT_PROPERTY(Uses) 2435f757f3fSDimitry Andric PRINT_PROPERTY(DirectCallsToDefinedFunctions) 2445f757f3fSDimitry Andric PRINT_PROPERTY(LoadInstCount) 2455f757f3fSDimitry Andric PRINT_PROPERTY(StoreInstCount) 2465f757f3fSDimitry Andric PRINT_PROPERTY(MaxLoopDepth) 2475f757f3fSDimitry Andric PRINT_PROPERTY(TopLevelLoopCount) 2485f757f3fSDimitry Andric PRINT_PROPERTY(TotalInstructionCount) 2495f757f3fSDimitry Andric 2505f757f3fSDimitry Andric if (EnableDetailedFunctionProperties) { 2515f757f3fSDimitry Andric PRINT_PROPERTY(BasicBlocksWithSingleSuccessor) 2525f757f3fSDimitry Andric PRINT_PROPERTY(BasicBlocksWithTwoSuccessors) 2535f757f3fSDimitry Andric PRINT_PROPERTY(BasicBlocksWithMoreThanTwoSuccessors) 2545f757f3fSDimitry Andric PRINT_PROPERTY(BasicBlocksWithSinglePredecessor) 2555f757f3fSDimitry Andric PRINT_PROPERTY(BasicBlocksWithTwoPredecessors) 2565f757f3fSDimitry Andric PRINT_PROPERTY(BasicBlocksWithMoreThanTwoPredecessors) 2575f757f3fSDimitry Andric PRINT_PROPERTY(BigBasicBlocks) 2585f757f3fSDimitry Andric PRINT_PROPERTY(MediumBasicBlocks) 2595f757f3fSDimitry Andric PRINT_PROPERTY(SmallBasicBlocks) 2605f757f3fSDimitry Andric PRINT_PROPERTY(CastInstructionCount) 2615f757f3fSDimitry Andric PRINT_PROPERTY(FloatingPointInstructionCount) 2625f757f3fSDimitry Andric PRINT_PROPERTY(IntegerInstructionCount) 2635f757f3fSDimitry Andric PRINT_PROPERTY(ConstantIntOperandCount) 2645f757f3fSDimitry Andric PRINT_PROPERTY(ConstantFPOperandCount) 2655f757f3fSDimitry Andric PRINT_PROPERTY(ConstantOperandCount) 2665f757f3fSDimitry Andric PRINT_PROPERTY(InstructionOperandCount) 2675f757f3fSDimitry Andric PRINT_PROPERTY(BasicBlockOperandCount) 2685f757f3fSDimitry Andric PRINT_PROPERTY(GlobalValueOperandCount) 2695f757f3fSDimitry Andric PRINT_PROPERTY(InlineAsmOperandCount) 2705f757f3fSDimitry Andric PRINT_PROPERTY(ArgumentOperandCount) 2715f757f3fSDimitry Andric PRINT_PROPERTY(UnknownOperandCount) 2725f757f3fSDimitry Andric PRINT_PROPERTY(CriticalEdgeCount) 2735f757f3fSDimitry Andric PRINT_PROPERTY(ControlFlowEdgeCount) 2745f757f3fSDimitry Andric PRINT_PROPERTY(UnconditionalBranchCount) 2755f757f3fSDimitry Andric PRINT_PROPERTY(IntrinsicCount) 2765f757f3fSDimitry Andric PRINT_PROPERTY(DirectCallCount) 2775f757f3fSDimitry Andric PRINT_PROPERTY(IndirectCallCount) 2785f757f3fSDimitry Andric PRINT_PROPERTY(CallReturnsIntegerCount) 2795f757f3fSDimitry Andric PRINT_PROPERTY(CallReturnsFloatCount) 2805f757f3fSDimitry Andric PRINT_PROPERTY(CallReturnsPointerCount) 2815f757f3fSDimitry Andric PRINT_PROPERTY(CallReturnsVectorIntCount) 2825f757f3fSDimitry Andric PRINT_PROPERTY(CallReturnsVectorFloatCount) 2835f757f3fSDimitry Andric PRINT_PROPERTY(CallReturnsVectorPointerCount) 2845f757f3fSDimitry Andric PRINT_PROPERTY(CallWithManyArgumentsCount) 2855f757f3fSDimitry Andric PRINT_PROPERTY(CallWithPointerArgumentCount) 2865f757f3fSDimitry Andric } 2875f757f3fSDimitry Andric 2885f757f3fSDimitry Andric #undef PRINT_PROPERTY 2895f757f3fSDimitry Andric 2905f757f3fSDimitry Andric OS << "\n"; 291e8d8bef9SDimitry Andric } 292e8d8bef9SDimitry Andric 293e8d8bef9SDimitry Andric AnalysisKey FunctionPropertiesAnalysis::Key; 294e8d8bef9SDimitry Andric 295e8d8bef9SDimitry Andric FunctionPropertiesInfo 296e8d8bef9SDimitry Andric FunctionPropertiesAnalysis::run(Function &F, FunctionAnalysisManager &FAM) { 29781ad6265SDimitry Andric return FunctionPropertiesInfo::getFunctionPropertiesInfo(F, FAM); 298e8d8bef9SDimitry Andric } 299e8d8bef9SDimitry Andric 300e8d8bef9SDimitry Andric PreservedAnalyses 301e8d8bef9SDimitry Andric FunctionPropertiesPrinterPass::run(Function &F, FunctionAnalysisManager &AM) { 302e8d8bef9SDimitry Andric OS << "Printing analysis results of CFA for function " 303e8d8bef9SDimitry Andric << "'" << F.getName() << "':" 304e8d8bef9SDimitry Andric << "\n"; 305e8d8bef9SDimitry Andric AM.getResult<FunctionPropertiesAnalysis>(F).print(OS); 306e8d8bef9SDimitry Andric return PreservedAnalyses::all(); 307e8d8bef9SDimitry Andric } 30881ad6265SDimitry Andric 30981ad6265SDimitry Andric FunctionPropertiesUpdater::FunctionPropertiesUpdater( 31006c3fb27SDimitry Andric FunctionPropertiesInfo &FPI, CallBase &CB) 31181ad6265SDimitry Andric : FPI(FPI), CallSiteBB(*CB.getParent()), Caller(*CallSiteBB.getParent()) { 31281ad6265SDimitry Andric assert(isa<CallInst>(CB) || isa<InvokeInst>(CB)); 31381ad6265SDimitry Andric // For BBs that are likely to change, we subtract from feature totals their 31481ad6265SDimitry Andric // contribution. Some features, like max loop counts or depths, are left 31581ad6265SDimitry Andric // invalid, as they will be updated post-inlining. 31681ad6265SDimitry Andric SmallPtrSet<const BasicBlock *, 4> LikelyToChangeBBs; 31781ad6265SDimitry Andric // The CB BB will change - it'll either be split or the callee's body (single 31881ad6265SDimitry Andric // BB) will be pasted in. 31981ad6265SDimitry Andric LikelyToChangeBBs.insert(&CallSiteBB); 32081ad6265SDimitry Andric 32181ad6265SDimitry Andric // The caller's entry BB may change due to new alloca instructions. 32281ad6265SDimitry Andric LikelyToChangeBBs.insert(&*Caller.begin()); 32381ad6265SDimitry Andric 32481ad6265SDimitry Andric // The successors may become unreachable in the case of `invoke` inlining. 32581ad6265SDimitry Andric // We track successors separately, too, because they form a boundary, together 32681ad6265SDimitry Andric // with the CB BB ('Entry') between which the inlined callee will be pasted. 32781ad6265SDimitry Andric Successors.insert(succ_begin(&CallSiteBB), succ_end(&CallSiteBB)); 32881ad6265SDimitry Andric 32981ad6265SDimitry Andric // Inlining only handles invoke and calls. If this is an invoke, and inlining 33081ad6265SDimitry Andric // it pulls another invoke, the original landing pad may get split, so as to 33181ad6265SDimitry Andric // share its content with other potential users. So the edge up to which we 33281ad6265SDimitry Andric // need to invalidate and then re-account BB data is the successors of the 33381ad6265SDimitry Andric // current landing pad. We can leave the current lp, too - if it doesn't get 33481ad6265SDimitry Andric // split, then it will be the place traversal stops. Either way, the 33581ad6265SDimitry Andric // discounted BBs will be checked if reachable and re-added. 33681ad6265SDimitry Andric if (const auto *II = dyn_cast<InvokeInst>(&CB)) { 33781ad6265SDimitry Andric const auto *UnwindDest = II->getUnwindDest(); 33881ad6265SDimitry Andric Successors.insert(succ_begin(UnwindDest), succ_end(UnwindDest)); 33981ad6265SDimitry Andric } 34081ad6265SDimitry Andric 34181ad6265SDimitry Andric // Exclude the CallSiteBB, if it happens to be its own successor (1-BB loop). 34281ad6265SDimitry Andric // We are only interested in BBs the graph moves past the callsite BB to 34381ad6265SDimitry Andric // define the frontier past which we don't want to re-process BBs. Including 34481ad6265SDimitry Andric // the callsite BB in this case would prematurely stop the traversal in 34581ad6265SDimitry Andric // finish(). 34681ad6265SDimitry Andric Successors.erase(&CallSiteBB); 34781ad6265SDimitry Andric 34881ad6265SDimitry Andric for (const auto *BB : Successors) 34981ad6265SDimitry Andric LikelyToChangeBBs.insert(BB); 35081ad6265SDimitry Andric 35181ad6265SDimitry Andric // Commit the change. While some of the BBs accounted for above may play dual 35281ad6265SDimitry Andric // role - e.g. caller's entry BB may be the same as the callsite BB - set 35381ad6265SDimitry Andric // insertion semantics make sure we account them once. This needs to be 35481ad6265SDimitry Andric // followed in `finish`, too. 35581ad6265SDimitry Andric for (const auto *BB : LikelyToChangeBBs) 35681ad6265SDimitry Andric FPI.updateForBB(*BB, -1); 35781ad6265SDimitry Andric } 35881ad6265SDimitry Andric 35981ad6265SDimitry Andric void FunctionPropertiesUpdater::finish(FunctionAnalysisManager &FAM) const { 36081ad6265SDimitry Andric // Update feature values from the BBs that were copied from the callee, or 36181ad6265SDimitry Andric // might have been modified because of inlining. The latter have been 36281ad6265SDimitry Andric // subtracted in the FunctionPropertiesUpdater ctor. 36381ad6265SDimitry Andric // There could be successors that were reached before but now are only 36481ad6265SDimitry Andric // reachable from elsewhere in the CFG. 36581ad6265SDimitry Andric // One example is the following diamond CFG (lines are arrows pointing down): 36681ad6265SDimitry Andric // A 36781ad6265SDimitry Andric // / \ 36881ad6265SDimitry Andric // B C 36981ad6265SDimitry Andric // | | 37081ad6265SDimitry Andric // | D 37181ad6265SDimitry Andric // | | 37281ad6265SDimitry Andric // | E 37381ad6265SDimitry Andric // \ / 37481ad6265SDimitry Andric // F 37581ad6265SDimitry Andric // There's a call site in C that is inlined. Upon doing that, it turns out 37681ad6265SDimitry Andric // it expands to 37781ad6265SDimitry Andric // call void @llvm.trap() 37881ad6265SDimitry Andric // unreachable 37981ad6265SDimitry Andric // F isn't reachable from C anymore, but we did discount it when we set up 38081ad6265SDimitry Andric // FunctionPropertiesUpdater, so we need to re-include it here. 38181ad6265SDimitry Andric // At the same time, D and E were reachable before, but now are not anymore, 38281ad6265SDimitry Andric // so we need to leave D out (we discounted it at setup), and explicitly 38381ad6265SDimitry Andric // remove E. 38481ad6265SDimitry Andric SetVector<const BasicBlock *> Reinclude; 38581ad6265SDimitry Andric SetVector<const BasicBlock *> Unreachable; 38681ad6265SDimitry Andric const auto &DT = 38781ad6265SDimitry Andric FAM.getResult<DominatorTreeAnalysis>(const_cast<Function &>(Caller)); 38881ad6265SDimitry Andric 38981ad6265SDimitry Andric if (&CallSiteBB != &*Caller.begin()) 39081ad6265SDimitry Andric Reinclude.insert(&*Caller.begin()); 39181ad6265SDimitry Andric 39281ad6265SDimitry Andric // Distribute the successors to the 2 buckets. 39381ad6265SDimitry Andric for (const auto *Succ : Successors) 39481ad6265SDimitry Andric if (DT.isReachableFromEntry(Succ)) 39581ad6265SDimitry Andric Reinclude.insert(Succ); 39681ad6265SDimitry Andric else 39781ad6265SDimitry Andric Unreachable.insert(Succ); 39881ad6265SDimitry Andric 39981ad6265SDimitry Andric // For reinclusion, we want to stop at the reachable successors, who are at 40081ad6265SDimitry Andric // the beginning of the worklist; but, starting from the callsite bb and 40181ad6265SDimitry Andric // ending at those successors, we also want to perform a traversal. 40281ad6265SDimitry Andric // IncludeSuccessorsMark is the index after which we include successors. 40381ad6265SDimitry Andric const auto IncludeSuccessorsMark = Reinclude.size(); 40481ad6265SDimitry Andric bool CSInsertion = Reinclude.insert(&CallSiteBB); 40581ad6265SDimitry Andric (void)CSInsertion; 40681ad6265SDimitry Andric assert(CSInsertion); 40781ad6265SDimitry Andric for (size_t I = 0; I < Reinclude.size(); ++I) { 40881ad6265SDimitry Andric const auto *BB = Reinclude[I]; 40981ad6265SDimitry Andric FPI.reIncludeBB(*BB); 41081ad6265SDimitry Andric if (I >= IncludeSuccessorsMark) 41181ad6265SDimitry Andric Reinclude.insert(succ_begin(BB), succ_end(BB)); 41281ad6265SDimitry Andric } 41381ad6265SDimitry Andric 41481ad6265SDimitry Andric // For exclusion, we don't need to exclude the set of BBs that were successors 41581ad6265SDimitry Andric // before and are now unreachable, because we already did that at setup. For 41681ad6265SDimitry Andric // the rest, as long as a successor is unreachable, we want to explicitly 41781ad6265SDimitry Andric // exclude it. 41881ad6265SDimitry Andric const auto AlreadyExcludedMark = Unreachable.size(); 41981ad6265SDimitry Andric for (size_t I = 0; I < Unreachable.size(); ++I) { 42081ad6265SDimitry Andric const auto *U = Unreachable[I]; 42181ad6265SDimitry Andric if (I >= AlreadyExcludedMark) 42281ad6265SDimitry Andric FPI.updateForBB(*U, -1); 42381ad6265SDimitry Andric for (const auto *Succ : successors(U)) 42481ad6265SDimitry Andric if (!DT.isReachableFromEntry(Succ)) 42581ad6265SDimitry Andric Unreachable.insert(Succ); 42681ad6265SDimitry Andric } 42781ad6265SDimitry Andric 42881ad6265SDimitry Andric const auto &LI = FAM.getResult<LoopAnalysis>(const_cast<Function &>(Caller)); 42981ad6265SDimitry Andric FPI.updateAggregateStats(Caller, LI); 43006c3fb27SDimitry Andric } 43106c3fb27SDimitry Andric 43206c3fb27SDimitry Andric bool FunctionPropertiesUpdater::isUpdateValid(Function &F, 43306c3fb27SDimitry Andric const FunctionPropertiesInfo &FPI, 43406c3fb27SDimitry Andric FunctionAnalysisManager &FAM) { 43506c3fb27SDimitry Andric DominatorTree DT(F); 43606c3fb27SDimitry Andric LoopInfo LI(DT); 43706c3fb27SDimitry Andric auto Fresh = FunctionPropertiesInfo::getFunctionPropertiesInfo(F, DT, LI); 43806c3fb27SDimitry Andric return FPI == Fresh; 43981ad6265SDimitry Andric } 440