xref: /llvm-project/llvm/lib/Analysis/FunctionPropertiesAnalysis.cpp (revision f32e5bdcefcff80f4296f8f4abedc37dcda36d53)
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