1ee6f0e10STarindu Jayatilaka //===- FunctionPropertiesAnalysis.cpp - Function Properties Analysis ------===// 2418121c3STarindu Jayatilaka // 3418121c3STarindu Jayatilaka // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4418121c3STarindu Jayatilaka // See https://llvm.org/LICENSE.txt for license information. 5418121c3STarindu Jayatilaka // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6418121c3STarindu Jayatilaka // 7418121c3STarindu Jayatilaka //===----------------------------------------------------------------------===// 8418121c3STarindu Jayatilaka // 9ee6f0e10STarindu Jayatilaka // This file defines the FunctionPropertiesInfo and FunctionPropertiesAnalysis 10ee6f0e10STarindu Jayatilaka // classes used to extract function properties. 11418121c3STarindu Jayatilaka // 12418121c3STarindu Jayatilaka //===----------------------------------------------------------------------===// 13418121c3STarindu Jayatilaka 14418121c3STarindu Jayatilaka #include "llvm/Analysis/FunctionPropertiesAnalysis.h" 15f46dd19bSMircea Trofin #include "llvm/ADT/STLExtras.h" 1622a1f998SMircea Trofin #include "llvm/ADT/SetVector.h" 1771c3a551Sserge-sans-paille #include "llvm/Analysis/LoopInfo.h" 18f46dd19bSMircea Trofin #include "llvm/IR/CFG.h" 19b8f191e0SAiden Grossman #include "llvm/IR/Constants.h" 2022a1f998SMircea Trofin #include "llvm/IR/Dominators.h" 21418121c3STarindu Jayatilaka #include "llvm/IR/Instructions.h" 22aad3641eSAiden Grossman #include "llvm/IR/IntrinsicInst.h" 23fe6bb84cSAiden Grossman #include "llvm/Support/CommandLine.h" 24f46dd19bSMircea Trofin #include <deque> 25418121c3STarindu Jayatilaka 26418121c3STarindu Jayatilaka using namespace llvm; 27418121c3STarindu Jayatilaka 282d854dd3SFangrui Song namespace llvm { 29fe6bb84cSAiden Grossman cl::opt<bool> EnableDetailedFunctionProperties( 30fe6bb84cSAiden Grossman "enable-detailed-function-properties", cl::Hidden, cl::init(false), 31fe6bb84cSAiden Grossman cl::desc("Whether or not to compute detailed function properties.")); 32fe6bb84cSAiden Grossman 33fe6bb84cSAiden Grossman cl::opt<unsigned> BigBasicBlockInstructionThreshold( 34fe6bb84cSAiden Grossman "big-basic-block-instruction-threshold", cl::Hidden, cl::init(500), 35fe6bb84cSAiden Grossman cl::desc("The minimum number of instructions a basic block should contain " 36fe6bb84cSAiden Grossman "before being considered big.")); 37fe6bb84cSAiden Grossman 38fe6bb84cSAiden Grossman cl::opt<unsigned> MediumBasicBlockInstructionThreshold( 39fe6bb84cSAiden Grossman "medium-basic-block-instruction-threshold", cl::Hidden, cl::init(15), 40fe6bb84cSAiden Grossman cl::desc("The minimum number of instructions a basic block should contain " 41fe6bb84cSAiden Grossman "before being considered medium-sized.")); 427b57a1b4SMohammed Keyvanzadeh } // namespace llvm 43fe6bb84cSAiden Grossman 442d854dd3SFangrui Song static cl::opt<unsigned> CallWithManyArgumentsThreshold( 45aad3641eSAiden Grossman "call-with-many-arguments-threshold", cl::Hidden, cl::init(4), 46aad3641eSAiden Grossman cl::desc("The minimum number of arguments a function call must have before " 47aad3641eSAiden Grossman "it is considered having many arguments.")); 48aad3641eSAiden Grossman 49f46dd19bSMircea Trofin namespace { 50*f32e5bdcSMircea Trofin int64_t getNumBlocksFromCond(const BasicBlock &BB) { 51f46dd19bSMircea Trofin int64_t Ret = 0; 52f46dd19bSMircea Trofin if (const auto *BI = dyn_cast<BranchInst>(BB.getTerminator())) { 53f46dd19bSMircea Trofin if (BI->isConditional()) 54f46dd19bSMircea Trofin Ret += BI->getNumSuccessors(); 55f46dd19bSMircea Trofin } else if (const auto *SI = dyn_cast<SwitchInst>(BB.getTerminator())) { 56f46dd19bSMircea Trofin Ret += (SI->getNumCases() + (nullptr != SI->getDefaultDest())); 57f46dd19bSMircea Trofin } 58f46dd19bSMircea Trofin return Ret; 59f46dd19bSMircea Trofin } 60f46dd19bSMircea Trofin 61f46dd19bSMircea Trofin int64_t getUses(const Function &F) { 62f46dd19bSMircea Trofin return ((!F.hasLocalLinkage()) ? 1 : 0) + F.getNumUses(); 63f46dd19bSMircea Trofin } 64f46dd19bSMircea Trofin } // namespace 65f46dd19bSMircea Trofin 6622a1f998SMircea Trofin void FunctionPropertiesInfo::reIncludeBB(const BasicBlock &BB) { 67f46dd19bSMircea Trofin updateForBB(BB, +1); 68f46dd19bSMircea Trofin } 69f46dd19bSMircea Trofin 70f46dd19bSMircea Trofin void FunctionPropertiesInfo::updateForBB(const BasicBlock &BB, 71f46dd19bSMircea Trofin int64_t Direction) { 72f46dd19bSMircea Trofin assert(Direction == 1 || Direction == -1); 73f46dd19bSMircea Trofin BasicBlockCount += Direction; 74f46dd19bSMircea Trofin BlocksReachedFromConditionalInstruction += 75*f32e5bdcSMircea Trofin (Direction * getNumBlocksFromCond(BB)); 76f46dd19bSMircea Trofin for (const auto &I : BB) { 77f46dd19bSMircea Trofin if (auto *CS = dyn_cast<CallBase>(&I)) { 78f46dd19bSMircea Trofin const auto *Callee = CS->getCalledFunction(); 79f46dd19bSMircea Trofin if (Callee && !Callee->isIntrinsic() && !Callee->isDeclaration()) 80f46dd19bSMircea Trofin DirectCallsToDefinedFunctions += Direction; 81f46dd19bSMircea Trofin } 82f46dd19bSMircea Trofin if (I.getOpcode() == Instruction::Load) { 83f46dd19bSMircea Trofin LoadInstCount += Direction; 84f46dd19bSMircea Trofin } else if (I.getOpcode() == Instruction::Store) { 85f46dd19bSMircea Trofin StoreInstCount += Direction; 86f46dd19bSMircea Trofin } 87f46dd19bSMircea Trofin } 88f46dd19bSMircea Trofin TotalInstructionCount += Direction * BB.sizeWithoutDebug(); 89fe6bb84cSAiden Grossman 90fe6bb84cSAiden Grossman if (EnableDetailedFunctionProperties) { 91fe6bb84cSAiden Grossman unsigned SuccessorCount = succ_size(&BB); 92fe6bb84cSAiden Grossman if (SuccessorCount == 1) 93fe6bb84cSAiden Grossman BasicBlocksWithSingleSuccessor += Direction; 94fe6bb84cSAiden Grossman else if (SuccessorCount == 2) 95fe6bb84cSAiden Grossman BasicBlocksWithTwoSuccessors += Direction; 96fe6bb84cSAiden Grossman else if (SuccessorCount > 2) 97fe6bb84cSAiden Grossman BasicBlocksWithMoreThanTwoSuccessors += Direction; 98fe6bb84cSAiden Grossman 99fe6bb84cSAiden Grossman unsigned PredecessorCount = pred_size(&BB); 100fe6bb84cSAiden Grossman if (PredecessorCount == 1) 101fe6bb84cSAiden Grossman BasicBlocksWithSinglePredecessor += Direction; 102fe6bb84cSAiden Grossman else if (PredecessorCount == 2) 103fe6bb84cSAiden Grossman BasicBlocksWithTwoPredecessors += Direction; 104fe6bb84cSAiden Grossman else if (PredecessorCount > 2) 105fe6bb84cSAiden Grossman BasicBlocksWithMoreThanTwoPredecessors += Direction; 106fe6bb84cSAiden Grossman 107fe6bb84cSAiden Grossman if (TotalInstructionCount > BigBasicBlockInstructionThreshold) 108fe6bb84cSAiden Grossman BigBasicBlocks += Direction; 109fe6bb84cSAiden Grossman else if (TotalInstructionCount > MediumBasicBlockInstructionThreshold) 110fe6bb84cSAiden Grossman MediumBasicBlocks += Direction; 111fe6bb84cSAiden Grossman else 112fe6bb84cSAiden Grossman SmallBasicBlocks += Direction; 113fe6bb84cSAiden Grossman 114aad3641eSAiden Grossman // Calculate critical edges by looking through all successors of a basic 115aad3641eSAiden Grossman // block that has multiple successors and finding ones that have multiple 116aad3641eSAiden Grossman // predecessors, which represent critical edges. 117aad3641eSAiden Grossman if (SuccessorCount > 1) { 118aad3641eSAiden Grossman for (const auto *Successor : successors(&BB)) { 119aad3641eSAiden Grossman if (pred_size(Successor) > 1) 120aad3641eSAiden Grossman CriticalEdgeCount += Direction; 121aad3641eSAiden Grossman } 122aad3641eSAiden Grossman } 123aad3641eSAiden Grossman 124aad3641eSAiden Grossman ControlFlowEdgeCount += Direction * SuccessorCount; 125aad3641eSAiden Grossman 126aad3641eSAiden Grossman if (const auto *BI = dyn_cast<BranchInst>(BB.getTerminator())) { 127aad3641eSAiden Grossman if (!BI->isConditional()) 128aad3641eSAiden Grossman UnconditionalBranchCount += Direction; 129aad3641eSAiden Grossman } 130aad3641eSAiden Grossman 131fe6bb84cSAiden Grossman for (const Instruction &I : BB.instructionsWithoutDebug()) { 132fe6bb84cSAiden Grossman if (I.isCast()) 133fe6bb84cSAiden Grossman CastInstructionCount += Direction; 134fe6bb84cSAiden Grossman 135fe6bb84cSAiden Grossman if (I.getType()->isFloatTy()) 136fe6bb84cSAiden Grossman FloatingPointInstructionCount += Direction; 137fe6bb84cSAiden Grossman else if (I.getType()->isIntegerTy()) 138fe6bb84cSAiden Grossman IntegerInstructionCount += Direction; 139fe6bb84cSAiden Grossman 140aad3641eSAiden Grossman if (isa<IntrinsicInst>(I)) 141aad3641eSAiden Grossman ++IntrinsicCount; 142aad3641eSAiden Grossman 143aad3641eSAiden Grossman if (const auto *Call = dyn_cast<CallInst>(&I)) { 144aad3641eSAiden Grossman if (Call->isIndirectCall()) 145aad3641eSAiden Grossman IndirectCallCount += Direction; 146aad3641eSAiden Grossman else 147aad3641eSAiden Grossman DirectCallCount += Direction; 148aad3641eSAiden Grossman 149aad3641eSAiden Grossman if (Call->getType()->isIntegerTy()) 150aad3641eSAiden Grossman CallReturnsIntegerCount += Direction; 151aad3641eSAiden Grossman else if (Call->getType()->isFloatingPointTy()) 152aad3641eSAiden Grossman CallReturnsFloatCount += Direction; 153aad3641eSAiden Grossman else if (Call->getType()->isPointerTy()) 154aad3641eSAiden Grossman CallReturnsPointerCount += Direction; 155aad3641eSAiden Grossman else if (Call->getType()->isVectorTy()) { 156aad3641eSAiden Grossman if (Call->getType()->getScalarType()->isIntegerTy()) 157aad3641eSAiden Grossman CallReturnsVectorIntCount += Direction; 158aad3641eSAiden Grossman else if (Call->getType()->getScalarType()->isFloatingPointTy()) 159aad3641eSAiden Grossman CallReturnsVectorFloatCount += Direction; 160aad3641eSAiden Grossman else if (Call->getType()->getScalarType()->isPointerTy()) 161aad3641eSAiden Grossman CallReturnsVectorPointerCount += Direction; 162aad3641eSAiden Grossman } 163aad3641eSAiden Grossman 164aad3641eSAiden Grossman if (Call->arg_size() > CallWithManyArgumentsThreshold) 165aad3641eSAiden Grossman CallWithManyArgumentsCount += Direction; 166aad3641eSAiden Grossman 167aad3641eSAiden Grossman for (const auto &Arg : Call->args()) { 168aad3641eSAiden Grossman if (Arg->getType()->isPointerTy()) { 169aad3641eSAiden Grossman CallWithPointerArgumentCount += Direction; 170aad3641eSAiden Grossman break; 171aad3641eSAiden Grossman } 172aad3641eSAiden Grossman } 173aad3641eSAiden Grossman } 174aad3641eSAiden Grossman 175b8f191e0SAiden Grossman #define COUNT_OPERAND(OPTYPE) \ 176b8f191e0SAiden Grossman if (isa<OPTYPE>(Operand)) { \ 177b8f191e0SAiden Grossman OPTYPE##OperandCount += Direction; \ 178b8f191e0SAiden Grossman continue; \ 179b8f191e0SAiden Grossman } 180b8f191e0SAiden Grossman 181fe6bb84cSAiden Grossman for (unsigned int OperandIndex = 0; OperandIndex < I.getNumOperands(); 182fe6bb84cSAiden Grossman ++OperandIndex) { 183b8f191e0SAiden Grossman Value *Operand = I.getOperand(OperandIndex); 184b8f191e0SAiden Grossman COUNT_OPERAND(GlobalValue) 185b8f191e0SAiden Grossman COUNT_OPERAND(ConstantInt) 186b8f191e0SAiden Grossman COUNT_OPERAND(ConstantFP) 187b8f191e0SAiden Grossman COUNT_OPERAND(Constant) 188b8f191e0SAiden Grossman COUNT_OPERAND(Instruction) 189b8f191e0SAiden Grossman COUNT_OPERAND(BasicBlock) 190b8f191e0SAiden Grossman COUNT_OPERAND(InlineAsm) 191b8f191e0SAiden Grossman COUNT_OPERAND(Argument) 192b8f191e0SAiden Grossman 193b8f191e0SAiden Grossman // We only get to this point if we haven't matched any of the other 194b8f191e0SAiden Grossman // operand types. 195b8f191e0SAiden Grossman UnknownOperandCount += Direction; 196fe6bb84cSAiden Grossman } 197b8f191e0SAiden Grossman 198b8f191e0SAiden Grossman #undef CHECK_OPERAND 199fe6bb84cSAiden Grossman } 200fe6bb84cSAiden Grossman } 201f46dd19bSMircea Trofin } 202f46dd19bSMircea Trofin 203f46dd19bSMircea Trofin void FunctionPropertiesInfo::updateAggregateStats(const Function &F, 204f46dd19bSMircea Trofin const LoopInfo &LI) { 205f46dd19bSMircea Trofin 206f46dd19bSMircea Trofin Uses = getUses(F); 207f46dd19bSMircea Trofin TopLevelLoopCount = llvm::size(LI); 20822a1f998SMircea Trofin MaxLoopDepth = 0; 20922a1f998SMircea Trofin std::deque<const Loop *> Worklist; 21022a1f998SMircea Trofin llvm::append_range(Worklist, LI); 21122a1f998SMircea Trofin while (!Worklist.empty()) { 21222a1f998SMircea Trofin const auto *L = Worklist.front(); 21322a1f998SMircea Trofin MaxLoopDepth = 21422a1f998SMircea Trofin std::max(MaxLoopDepth, static_cast<int64_t>(L->getLoopDepth())); 21522a1f998SMircea Trofin Worklist.pop_front(); 21622a1f998SMircea Trofin llvm::append_range(Worklist, L->getSubLoops()); 21722a1f998SMircea Trofin } 218f46dd19bSMircea Trofin } 219f46dd19bSMircea Trofin 22022a1f998SMircea Trofin FunctionPropertiesInfo FunctionPropertiesInfo::getFunctionPropertiesInfo( 22101c5ec3dSMircea Trofin Function &F, FunctionAnalysisManager &FAM) { 22201c5ec3dSMircea Trofin return getFunctionPropertiesInfo(F, FAM.getResult<DominatorTreeAnalysis>(F), 22301c5ec3dSMircea Trofin FAM.getResult<LoopAnalysis>(F)); 22401c5ec3dSMircea Trofin } 22501c5ec3dSMircea Trofin 22601c5ec3dSMircea Trofin FunctionPropertiesInfo FunctionPropertiesInfo::getFunctionPropertiesInfo( 22701c5ec3dSMircea Trofin const Function &F, const DominatorTree &DT, const LoopInfo &LI) { 228418121c3STarindu Jayatilaka 2292f56046dSTarindu Jayatilaka FunctionPropertiesInfo FPI; 230f46dd19bSMircea Trofin for (const auto &BB : F) 23122a1f998SMircea Trofin if (DT.isReachableFromEntry(&BB)) 23222a1f998SMircea Trofin FPI.reIncludeBB(BB); 233f46dd19bSMircea Trofin FPI.updateAggregateStats(F, LI); 2342f56046dSTarindu Jayatilaka return FPI; 2352f56046dSTarindu Jayatilaka } 2362f56046dSTarindu Jayatilaka 237ee6f0e10STarindu Jayatilaka void FunctionPropertiesInfo::print(raw_ostream &OS) const { 238b8f191e0SAiden Grossman #define PRINT_PROPERTY(PROP_NAME) OS << #PROP_NAME ": " << PROP_NAME << "\n"; 239b8f191e0SAiden Grossman 240b8f191e0SAiden Grossman PRINT_PROPERTY(BasicBlockCount) 241b8f191e0SAiden Grossman PRINT_PROPERTY(BlocksReachedFromConditionalInstruction) 242b8f191e0SAiden Grossman PRINT_PROPERTY(Uses) 243b8f191e0SAiden Grossman PRINT_PROPERTY(DirectCallsToDefinedFunctions) 244b8f191e0SAiden Grossman PRINT_PROPERTY(LoadInstCount) 245b8f191e0SAiden Grossman PRINT_PROPERTY(StoreInstCount) 246b8f191e0SAiden Grossman PRINT_PROPERTY(MaxLoopDepth) 247b8f191e0SAiden Grossman PRINT_PROPERTY(TopLevelLoopCount) 248b8f191e0SAiden Grossman PRINT_PROPERTY(TotalInstructionCount) 249b8f191e0SAiden Grossman 250fe6bb84cSAiden Grossman if (EnableDetailedFunctionProperties) { 251b8f191e0SAiden Grossman PRINT_PROPERTY(BasicBlocksWithSingleSuccessor) 252b8f191e0SAiden Grossman PRINT_PROPERTY(BasicBlocksWithTwoSuccessors) 253b8f191e0SAiden Grossman PRINT_PROPERTY(BasicBlocksWithMoreThanTwoSuccessors) 254b8f191e0SAiden Grossman PRINT_PROPERTY(BasicBlocksWithSinglePredecessor) 255b8f191e0SAiden Grossman PRINT_PROPERTY(BasicBlocksWithTwoPredecessors) 256b8f191e0SAiden Grossman PRINT_PROPERTY(BasicBlocksWithMoreThanTwoPredecessors) 257b8f191e0SAiden Grossman PRINT_PROPERTY(BigBasicBlocks) 258b8f191e0SAiden Grossman PRINT_PROPERTY(MediumBasicBlocks) 259b8f191e0SAiden Grossman PRINT_PROPERTY(SmallBasicBlocks) 260b8f191e0SAiden Grossman PRINT_PROPERTY(CastInstructionCount) 261b8f191e0SAiden Grossman PRINT_PROPERTY(FloatingPointInstructionCount) 262b8f191e0SAiden Grossman PRINT_PROPERTY(IntegerInstructionCount) 263b8f191e0SAiden Grossman PRINT_PROPERTY(ConstantIntOperandCount) 264b8f191e0SAiden Grossman PRINT_PROPERTY(ConstantFPOperandCount) 265b8f191e0SAiden Grossman PRINT_PROPERTY(ConstantOperandCount) 266b8f191e0SAiden Grossman PRINT_PROPERTY(InstructionOperandCount) 267b8f191e0SAiden Grossman PRINT_PROPERTY(BasicBlockOperandCount) 268b8f191e0SAiden Grossman PRINT_PROPERTY(GlobalValueOperandCount) 269b8f191e0SAiden Grossman PRINT_PROPERTY(InlineAsmOperandCount) 270b8f191e0SAiden Grossman PRINT_PROPERTY(ArgumentOperandCount) 271b8f191e0SAiden Grossman PRINT_PROPERTY(UnknownOperandCount) 272aad3641eSAiden Grossman PRINT_PROPERTY(CriticalEdgeCount) 273aad3641eSAiden Grossman PRINT_PROPERTY(ControlFlowEdgeCount) 274aad3641eSAiden Grossman PRINT_PROPERTY(UnconditionalBranchCount) 275aad3641eSAiden Grossman PRINT_PROPERTY(IntrinsicCount) 276aad3641eSAiden Grossman PRINT_PROPERTY(DirectCallCount) 277aad3641eSAiden Grossman PRINT_PROPERTY(IndirectCallCount) 278aad3641eSAiden Grossman PRINT_PROPERTY(CallReturnsIntegerCount) 279aad3641eSAiden Grossman PRINT_PROPERTY(CallReturnsFloatCount) 280aad3641eSAiden Grossman PRINT_PROPERTY(CallReturnsPointerCount) 281aad3641eSAiden Grossman PRINT_PROPERTY(CallReturnsVectorIntCount) 282aad3641eSAiden Grossman PRINT_PROPERTY(CallReturnsVectorFloatCount) 283aad3641eSAiden Grossman PRINT_PROPERTY(CallReturnsVectorPointerCount) 284aad3641eSAiden Grossman PRINT_PROPERTY(CallWithManyArgumentsCount) 285aad3641eSAiden Grossman PRINT_PROPERTY(CallWithPointerArgumentCount) 286fe6bb84cSAiden Grossman } 287b8f191e0SAiden Grossman 288b8f191e0SAiden Grossman #undef PRINT_PROPERTY 289b8f191e0SAiden Grossman 290fe6bb84cSAiden Grossman OS << "\n"; 291ee6f0e10STarindu Jayatilaka } 292ee6f0e10STarindu Jayatilaka 2932f56046dSTarindu Jayatilaka AnalysisKey FunctionPropertiesAnalysis::Key; 2942f56046dSTarindu Jayatilaka 29549942d59SMircea Trofin FunctionPropertiesInfo 2962f56046dSTarindu Jayatilaka FunctionPropertiesAnalysis::run(Function &F, FunctionAnalysisManager &FAM) { 29722a1f998SMircea Trofin return FunctionPropertiesInfo::getFunctionPropertiesInfo(F, FAM); 298418121c3STarindu Jayatilaka } 299ee6f0e10STarindu Jayatilaka 300ee6f0e10STarindu Jayatilaka PreservedAnalyses 301ee6f0e10STarindu Jayatilaka FunctionPropertiesPrinterPass::run(Function &F, FunctionAnalysisManager &AM) { 302ee6f0e10STarindu Jayatilaka OS << "Printing analysis results of CFA for function " 303ee6f0e10STarindu Jayatilaka << "'" << F.getName() << "':" 304ee6f0e10STarindu Jayatilaka << "\n"; 305ee6f0e10STarindu Jayatilaka AM.getResult<FunctionPropertiesAnalysis>(F).print(OS); 306ee6f0e10STarindu Jayatilaka return PreservedAnalyses::all(); 307ee6f0e10STarindu Jayatilaka } 308f46dd19bSMircea Trofin 309f46dd19bSMircea Trofin FunctionPropertiesUpdater::FunctionPropertiesUpdater( 31001c5ec3dSMircea Trofin FunctionPropertiesInfo &FPI, CallBase &CB) 311f46dd19bSMircea Trofin : FPI(FPI), CallSiteBB(*CB.getParent()), Caller(*CallSiteBB.getParent()) { 3123f8e4169SMircea Trofin assert(isa<CallInst>(CB) || isa<InvokeInst>(CB)); 313f46dd19bSMircea Trofin // For BBs that are likely to change, we subtract from feature totals their 314f46dd19bSMircea Trofin // contribution. Some features, like max loop counts or depths, are left 315f46dd19bSMircea Trofin // invalid, as they will be updated post-inlining. 316f46dd19bSMircea Trofin SmallPtrSet<const BasicBlock *, 4> LikelyToChangeBBs; 317f46dd19bSMircea Trofin // The CB BB will change - it'll either be split or the callee's body (single 318f46dd19bSMircea Trofin // BB) will be pasted in. 319f46dd19bSMircea Trofin LikelyToChangeBBs.insert(&CallSiteBB); 320f46dd19bSMircea Trofin 321f46dd19bSMircea Trofin // The caller's entry BB may change due to new alloca instructions. 322f46dd19bSMircea Trofin LikelyToChangeBBs.insert(&*Caller.begin()); 323f46dd19bSMircea Trofin 324f46dd19bSMircea Trofin // The successors may become unreachable in the case of `invoke` inlining. 325f46dd19bSMircea Trofin // We track successors separately, too, because they form a boundary, together 326f46dd19bSMircea Trofin // with the CB BB ('Entry') between which the inlined callee will be pasted. 327f46dd19bSMircea Trofin Successors.insert(succ_begin(&CallSiteBB), succ_end(&CallSiteBB)); 328b8c39eb2SMircea Trofin 3291991aa6bSMircea Trofin // the outcome of the inlining may be that some edges get lost (DCEd BBs 3301991aa6bSMircea Trofin // because inlining brought some constant, for example). We don't know which 3311991aa6bSMircea Trofin // edges will be removed, so we list all of them as potentially removable. 3321991aa6bSMircea Trofin // Some BBs have (at this point) duplicate edges. Remove duplicates, otherwise 3331991aa6bSMircea Trofin // the DT updater will not apply changes correctly. 3341991aa6bSMircea Trofin DenseSet<const BasicBlock *> Inserted; 3351991aa6bSMircea Trofin for (auto *Succ : successors(&CallSiteBB)) 3361991aa6bSMircea Trofin if (Inserted.insert(Succ).second) 3371991aa6bSMircea Trofin DomTreeUpdates.emplace_back(DominatorTree::UpdateKind::Delete, 3381991aa6bSMircea Trofin const_cast<BasicBlock *>(&CallSiteBB), 3391991aa6bSMircea Trofin const_cast<BasicBlock *>(Succ)); 3401991aa6bSMircea Trofin // Reuse Inserted (which has some allocated capacity at this point) below, if 3411991aa6bSMircea Trofin // we have an invoke. 3421991aa6bSMircea Trofin Inserted.clear(); 3433f8e4169SMircea Trofin // Inlining only handles invoke and calls. If this is an invoke, and inlining 3443f8e4169SMircea Trofin // it pulls another invoke, the original landing pad may get split, so as to 3453f8e4169SMircea Trofin // share its content with other potential users. So the edge up to which we 3463f8e4169SMircea Trofin // need to invalidate and then re-account BB data is the successors of the 3473f8e4169SMircea Trofin // current landing pad. We can leave the current lp, too - if it doesn't get 3483f8e4169SMircea Trofin // split, then it will be the place traversal stops. Either way, the 3493f8e4169SMircea Trofin // discounted BBs will be checked if reachable and re-added. 3503f8e4169SMircea Trofin if (const auto *II = dyn_cast<InvokeInst>(&CB)) { 3513f8e4169SMircea Trofin const auto *UnwindDest = II->getUnwindDest(); 3523f8e4169SMircea Trofin Successors.insert(succ_begin(UnwindDest), succ_end(UnwindDest)); 3531991aa6bSMircea Trofin // Same idea as above, we pretend we lose all these edges. 3541991aa6bSMircea Trofin for (auto *Succ : successors(UnwindDest)) 3551991aa6bSMircea Trofin if (Inserted.insert(Succ).second) 3561991aa6bSMircea Trofin DomTreeUpdates.emplace_back(DominatorTree::UpdateKind::Delete, 3571991aa6bSMircea Trofin const_cast<BasicBlock *>(UnwindDest), 3581991aa6bSMircea Trofin const_cast<BasicBlock *>(Succ)); 3593f8e4169SMircea Trofin } 3603f8e4169SMircea Trofin 361b8c39eb2SMircea Trofin // Exclude the CallSiteBB, if it happens to be its own successor (1-BB loop). 362b8c39eb2SMircea Trofin // We are only interested in BBs the graph moves past the callsite BB to 363b8c39eb2SMircea Trofin // define the frontier past which we don't want to re-process BBs. Including 364b8c39eb2SMircea Trofin // the callsite BB in this case would prematurely stop the traversal in 365b8c39eb2SMircea Trofin // finish(). 366b8c39eb2SMircea Trofin Successors.erase(&CallSiteBB); 367b8c39eb2SMircea Trofin 368f46dd19bSMircea Trofin for (const auto *BB : Successors) 369f46dd19bSMircea Trofin LikelyToChangeBBs.insert(BB); 370f46dd19bSMircea Trofin 371f46dd19bSMircea Trofin // Commit the change. While some of the BBs accounted for above may play dual 372f46dd19bSMircea Trofin // role - e.g. caller's entry BB may be the same as the callsite BB - set 373f46dd19bSMircea Trofin // insertion semantics make sure we account them once. This needs to be 374f46dd19bSMircea Trofin // followed in `finish`, too. 375f46dd19bSMircea Trofin for (const auto *BB : LikelyToChangeBBs) 376f46dd19bSMircea Trofin FPI.updateForBB(*BB, -1); 377f46dd19bSMircea Trofin } 378f46dd19bSMircea Trofin 3791991aa6bSMircea Trofin DominatorTree &FunctionPropertiesUpdater::getUpdatedDominatorTree( 3801991aa6bSMircea Trofin FunctionAnalysisManager &FAM) const { 3811991aa6bSMircea Trofin auto &DT = 3821991aa6bSMircea Trofin FAM.getResult<DominatorTreeAnalysis>(const_cast<Function &>(Caller)); 3831991aa6bSMircea Trofin 3841991aa6bSMircea Trofin SmallVector<DominatorTree::UpdateType, 2> FinalDomTreeUpdates; 3851991aa6bSMircea Trofin 3861991aa6bSMircea Trofin DenseSet<const BasicBlock *> Inserted; 3871991aa6bSMircea Trofin for (auto *Succ : successors(&CallSiteBB)) 3881991aa6bSMircea Trofin if (Inserted.insert(Succ).second) 3891991aa6bSMircea Trofin FinalDomTreeUpdates.push_back({DominatorTree::UpdateKind::Insert, 3901991aa6bSMircea Trofin const_cast<BasicBlock *>(&CallSiteBB), 3911991aa6bSMircea Trofin const_cast<BasicBlock *>(Succ)}); 3921991aa6bSMircea Trofin 3931991aa6bSMircea Trofin // Perform the deletes last, so that any new nodes connected to nodes 3941991aa6bSMircea Trofin // participating in the edge deletion are known to the DT. 3951991aa6bSMircea Trofin for (auto &Upd : DomTreeUpdates) 3961991aa6bSMircea Trofin if (!llvm::is_contained(successors(Upd.getFrom()), Upd.getTo())) 3971991aa6bSMircea Trofin FinalDomTreeUpdates.push_back(Upd); 3981991aa6bSMircea Trofin 3991991aa6bSMircea Trofin DT.applyUpdates(FinalDomTreeUpdates); 4001991aa6bSMircea Trofin #ifdef EXPENSIVE_CHECKS 4011991aa6bSMircea Trofin assert(DT.verify(DominatorTree::VerificationLevel::Full)); 4021991aa6bSMircea Trofin #endif 4031991aa6bSMircea Trofin return DT; 4041991aa6bSMircea Trofin } 4051991aa6bSMircea Trofin 40622a1f998SMircea Trofin void FunctionPropertiesUpdater::finish(FunctionAnalysisManager &FAM) const { 407f46dd19bSMircea Trofin // Update feature values from the BBs that were copied from the callee, or 408f46dd19bSMircea Trofin // might have been modified because of inlining. The latter have been 409f46dd19bSMircea Trofin // subtracted in the FunctionPropertiesUpdater ctor. 41022a1f998SMircea Trofin // There could be successors that were reached before but now are only 41122a1f998SMircea Trofin // reachable from elsewhere in the CFG. 4123f8e4169SMircea Trofin // One example is the following diamond CFG (lines are arrows pointing down): 41322a1f998SMircea Trofin // A 41422a1f998SMircea Trofin // / \ 41522a1f998SMircea Trofin // B C 4163f8e4169SMircea Trofin // | | 4173f8e4169SMircea Trofin // | D 4183f8e4169SMircea Trofin // | | 4193f8e4169SMircea Trofin // | E 42022a1f998SMircea Trofin // \ / 4213f8e4169SMircea Trofin // F 42222a1f998SMircea Trofin // There's a call site in C that is inlined. Upon doing that, it turns out 42322a1f998SMircea Trofin // it expands to 42422a1f998SMircea Trofin // call void @llvm.trap() 42522a1f998SMircea Trofin // unreachable 4263f8e4169SMircea Trofin // F isn't reachable from C anymore, but we did discount it when we set up 42722a1f998SMircea Trofin // FunctionPropertiesUpdater, so we need to re-include it here. 4283f8e4169SMircea Trofin // At the same time, D and E were reachable before, but now are not anymore, 4293f8e4169SMircea Trofin // so we need to leave D out (we discounted it at setup), and explicitly 4303f8e4169SMircea Trofin // remove E. 4313f8e4169SMircea Trofin SetVector<const BasicBlock *> Reinclude; 4323f8e4169SMircea Trofin SetVector<const BasicBlock *> Unreachable; 4331991aa6bSMircea Trofin auto &DT = getUpdatedDominatorTree(FAM); 43422a1f998SMircea Trofin 4353f8e4169SMircea Trofin if (&CallSiteBB != &*Caller.begin()) 4363f8e4169SMircea Trofin Reinclude.insert(&*Caller.begin()); 4373f8e4169SMircea Trofin 4383f8e4169SMircea Trofin // Distribute the successors to the 2 buckets. 4393f8e4169SMircea Trofin for (const auto *Succ : Successors) 4403f8e4169SMircea Trofin if (DT.isReachableFromEntry(Succ)) 4413f8e4169SMircea Trofin Reinclude.insert(Succ); 4423f8e4169SMircea Trofin else 4433f8e4169SMircea Trofin Unreachable.insert(Succ); 4443f8e4169SMircea Trofin 4453f8e4169SMircea Trofin // For reinclusion, we want to stop at the reachable successors, who are at 4463f8e4169SMircea Trofin // the beginning of the worklist; but, starting from the callsite bb and 4473f8e4169SMircea Trofin // ending at those successors, we also want to perform a traversal. 4483f8e4169SMircea Trofin // IncludeSuccessorsMark is the index after which we include successors. 4493f8e4169SMircea Trofin const auto IncludeSuccessorsMark = Reinclude.size(); 4503f8e4169SMircea Trofin bool CSInsertion = Reinclude.insert(&CallSiteBB); 45122a1f998SMircea Trofin (void)CSInsertion; 45222a1f998SMircea Trofin assert(CSInsertion); 4533f8e4169SMircea Trofin for (size_t I = 0; I < Reinclude.size(); ++I) { 4543f8e4169SMircea Trofin const auto *BB = Reinclude[I]; 45522a1f998SMircea Trofin FPI.reIncludeBB(*BB); 4563f8e4169SMircea Trofin if (I >= IncludeSuccessorsMark) 4573f8e4169SMircea Trofin Reinclude.insert(succ_begin(BB), succ_end(BB)); 4583f8e4169SMircea Trofin } 4593f8e4169SMircea Trofin 4603f8e4169SMircea Trofin // For exclusion, we don't need to exclude the set of BBs that were successors 4613f8e4169SMircea Trofin // before and are now unreachable, because we already did that at setup. For 4623f8e4169SMircea Trofin // the rest, as long as a successor is unreachable, we want to explicitly 4633f8e4169SMircea Trofin // exclude it. 4643f8e4169SMircea Trofin const auto AlreadyExcludedMark = Unreachable.size(); 4653f8e4169SMircea Trofin for (size_t I = 0; I < Unreachable.size(); ++I) { 4663f8e4169SMircea Trofin const auto *U = Unreachable[I]; 4673f8e4169SMircea Trofin if (I >= AlreadyExcludedMark) 4683f8e4169SMircea Trofin FPI.updateForBB(*U, -1); 4693f8e4169SMircea Trofin for (const auto *Succ : successors(U)) 4703f8e4169SMircea Trofin if (!DT.isReachableFromEntry(Succ)) 4713f8e4169SMircea Trofin Unreachable.insert(Succ); 472f46dd19bSMircea Trofin } 47322a1f998SMircea Trofin 47422a1f998SMircea Trofin const auto &LI = FAM.getResult<LoopAnalysis>(const_cast<Function &>(Caller)); 475f46dd19bSMircea Trofin FPI.updateAggregateStats(Caller, LI); 4761991aa6bSMircea Trofin #ifdef EXPENSIVE_CHECKS 4771991aa6bSMircea Trofin assert(isUpdateValid(Caller, FPI, FAM)); 4781991aa6bSMircea Trofin #endif 47901c5ec3dSMircea Trofin } 48001c5ec3dSMircea Trofin 48101c5ec3dSMircea Trofin bool FunctionPropertiesUpdater::isUpdateValid(Function &F, 48201c5ec3dSMircea Trofin const FunctionPropertiesInfo &FPI, 48301c5ec3dSMircea Trofin FunctionAnalysisManager &FAM) { 4841991aa6bSMircea Trofin if (!FAM.getResult<DominatorTreeAnalysis>(F).verify( 4851991aa6bSMircea Trofin DominatorTree::VerificationLevel::Full)) 4861991aa6bSMircea Trofin return false; 48701c5ec3dSMircea Trofin DominatorTree DT(F); 48801c5ec3dSMircea Trofin LoopInfo LI(DT); 48901c5ec3dSMircea Trofin auto Fresh = FunctionPropertiesInfo::getFunctionPropertiesInfo(F, DT, LI); 49001c5ec3dSMircea Trofin return FPI == Fresh; 491f46dd19bSMircea Trofin } 492