xref: /src/contrib/llvm-project/llvm/lib/Analysis/FunctionPropertiesAnalysis.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1b60736ecSDimitry Andric //===- FunctionPropertiesAnalysis.cpp - Function Properties Analysis ------===//
2b60736ecSDimitry Andric //
3b60736ecSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4b60736ecSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5b60736ecSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b60736ecSDimitry Andric //
7b60736ecSDimitry Andric //===----------------------------------------------------------------------===//
8b60736ecSDimitry Andric //
9b60736ecSDimitry Andric // This file defines the FunctionPropertiesInfo and FunctionPropertiesAnalysis
10b60736ecSDimitry Andric // classes used to extract function properties.
11b60736ecSDimitry Andric //
12b60736ecSDimitry Andric //===----------------------------------------------------------------------===//
13b60736ecSDimitry Andric 
14b60736ecSDimitry Andric #include "llvm/Analysis/FunctionPropertiesAnalysis.h"
15145449b1SDimitry Andric #include "llvm/ADT/STLExtras.h"
16145449b1SDimitry Andric #include "llvm/ADT/SetVector.h"
17145449b1SDimitry Andric #include "llvm/Analysis/LoopInfo.h"
18145449b1SDimitry Andric #include "llvm/IR/CFG.h"
19b1c73532SDimitry Andric #include "llvm/IR/Constants.h"
20145449b1SDimitry Andric #include "llvm/IR/Dominators.h"
21b60736ecSDimitry Andric #include "llvm/IR/Instructions.h"
22b1c73532SDimitry Andric #include "llvm/IR/IntrinsicInst.h"
23b1c73532SDimitry Andric #include "llvm/Support/CommandLine.h"
24145449b1SDimitry Andric #include <deque>
25b60736ecSDimitry Andric 
26b60736ecSDimitry Andric using namespace llvm;
27b60736ecSDimitry Andric 
28b1c73532SDimitry Andric namespace llvm {
29b1c73532SDimitry Andric cl::opt<bool> EnableDetailedFunctionProperties(
30b1c73532SDimitry Andric     "enable-detailed-function-properties", cl::Hidden, cl::init(false),
31b1c73532SDimitry Andric     cl::desc("Whether or not to compute detailed function properties."));
32b1c73532SDimitry Andric 
33b1c73532SDimitry Andric cl::opt<unsigned> BigBasicBlockInstructionThreshold(
34b1c73532SDimitry Andric     "big-basic-block-instruction-threshold", cl::Hidden, cl::init(500),
35b1c73532SDimitry Andric     cl::desc("The minimum number of instructions a basic block should contain "
36b1c73532SDimitry Andric              "before being considered big."));
37b1c73532SDimitry Andric 
38b1c73532SDimitry Andric cl::opt<unsigned> MediumBasicBlockInstructionThreshold(
39b1c73532SDimitry Andric     "medium-basic-block-instruction-threshold", cl::Hidden, cl::init(15),
40b1c73532SDimitry Andric     cl::desc("The minimum number of instructions a basic block should contain "
41b1c73532SDimitry Andric              "before being considered medium-sized."));
42ac9a064cSDimitry Andric } // namespace llvm
43b1c73532SDimitry Andric 
44b1c73532SDimitry Andric static cl::opt<unsigned> CallWithManyArgumentsThreshold(
45b1c73532SDimitry Andric     "call-with-many-arguments-threshold", cl::Hidden, cl::init(4),
46b1c73532SDimitry Andric     cl::desc("The minimum number of arguments a function call must have before "
47b1c73532SDimitry Andric              "it is considered having many arguments."));
48b1c73532SDimitry Andric 
49145449b1SDimitry Andric namespace {
getNrBlocksFromCond(const BasicBlock & BB)50145449b1SDimitry Andric int64_t getNrBlocksFromCond(const BasicBlock &BB) {
51145449b1SDimitry Andric   int64_t Ret = 0;
52b60736ecSDimitry Andric   if (const auto *BI = dyn_cast<BranchInst>(BB.getTerminator())) {
53b60736ecSDimitry Andric     if (BI->isConditional())
54145449b1SDimitry Andric       Ret += BI->getNumSuccessors();
55b60736ecSDimitry Andric   } else if (const auto *SI = dyn_cast<SwitchInst>(BB.getTerminator())) {
56145449b1SDimitry Andric     Ret += (SI->getNumCases() + (nullptr != SI->getDefaultDest()));
57145449b1SDimitry Andric   }
58145449b1SDimitry Andric   return Ret;
59b60736ecSDimitry Andric }
60b60736ecSDimitry Andric 
getUses(const Function & F)61145449b1SDimitry Andric int64_t getUses(const Function &F) {
62145449b1SDimitry Andric   return ((!F.hasLocalLinkage()) ? 1 : 0) + F.getNumUses();
63145449b1SDimitry Andric }
64145449b1SDimitry Andric } // namespace
65145449b1SDimitry Andric 
reIncludeBB(const BasicBlock & BB)66145449b1SDimitry Andric void FunctionPropertiesInfo::reIncludeBB(const BasicBlock &BB) {
67145449b1SDimitry Andric   updateForBB(BB, +1);
68145449b1SDimitry Andric }
69145449b1SDimitry Andric 
updateForBB(const BasicBlock & BB,int64_t Direction)70145449b1SDimitry Andric void FunctionPropertiesInfo::updateForBB(const BasicBlock &BB,
71145449b1SDimitry Andric                                          int64_t Direction) {
72145449b1SDimitry Andric   assert(Direction == 1 || Direction == -1);
73145449b1SDimitry Andric   BasicBlockCount += Direction;
74145449b1SDimitry Andric   BlocksReachedFromConditionalInstruction +=
75145449b1SDimitry Andric       (Direction * getNrBlocksFromCond(BB));
76b60736ecSDimitry Andric   for (const auto &I : BB) {
77b60736ecSDimitry Andric     if (auto *CS = dyn_cast<CallBase>(&I)) {
78b60736ecSDimitry Andric       const auto *Callee = CS->getCalledFunction();
79b60736ecSDimitry Andric       if (Callee && !Callee->isIntrinsic() && !Callee->isDeclaration())
80145449b1SDimitry Andric         DirectCallsToDefinedFunctions += Direction;
81b60736ecSDimitry Andric     }
82b60736ecSDimitry Andric     if (I.getOpcode() == Instruction::Load) {
83145449b1SDimitry Andric       LoadInstCount += Direction;
84b60736ecSDimitry Andric     } else if (I.getOpcode() == Instruction::Store) {
85145449b1SDimitry Andric       StoreInstCount += Direction;
86b60736ecSDimitry Andric     }
87b60736ecSDimitry Andric   }
88145449b1SDimitry Andric   TotalInstructionCount += Direction * BB.sizeWithoutDebug();
89b1c73532SDimitry Andric 
90b1c73532SDimitry Andric   if (EnableDetailedFunctionProperties) {
91b1c73532SDimitry Andric     unsigned SuccessorCount = succ_size(&BB);
92b1c73532SDimitry Andric     if (SuccessorCount == 1)
93b1c73532SDimitry Andric       BasicBlocksWithSingleSuccessor += Direction;
94b1c73532SDimitry Andric     else if (SuccessorCount == 2)
95b1c73532SDimitry Andric       BasicBlocksWithTwoSuccessors += Direction;
96b1c73532SDimitry Andric     else if (SuccessorCount > 2)
97b1c73532SDimitry Andric       BasicBlocksWithMoreThanTwoSuccessors += Direction;
98b1c73532SDimitry Andric 
99b1c73532SDimitry Andric     unsigned PredecessorCount = pred_size(&BB);
100b1c73532SDimitry Andric     if (PredecessorCount == 1)
101b1c73532SDimitry Andric       BasicBlocksWithSinglePredecessor += Direction;
102b1c73532SDimitry Andric     else if (PredecessorCount == 2)
103b1c73532SDimitry Andric       BasicBlocksWithTwoPredecessors += Direction;
104b1c73532SDimitry Andric     else if (PredecessorCount > 2)
105b1c73532SDimitry Andric       BasicBlocksWithMoreThanTwoPredecessors += Direction;
106b1c73532SDimitry Andric 
107b1c73532SDimitry Andric     if (TotalInstructionCount > BigBasicBlockInstructionThreshold)
108b1c73532SDimitry Andric       BigBasicBlocks += Direction;
109b1c73532SDimitry Andric     else if (TotalInstructionCount > MediumBasicBlockInstructionThreshold)
110b1c73532SDimitry Andric       MediumBasicBlocks += Direction;
111b1c73532SDimitry Andric     else
112b1c73532SDimitry Andric       SmallBasicBlocks += Direction;
113b1c73532SDimitry Andric 
114b1c73532SDimitry Andric     // Calculate critical edges by looking through all successors of a basic
115b1c73532SDimitry Andric     // block that has multiple successors and finding ones that have multiple
116b1c73532SDimitry Andric     // predecessors, which represent critical edges.
117b1c73532SDimitry Andric     if (SuccessorCount > 1) {
118b1c73532SDimitry Andric       for (const auto *Successor : successors(&BB)) {
119b1c73532SDimitry Andric         if (pred_size(Successor) > 1)
120b1c73532SDimitry Andric           CriticalEdgeCount += Direction;
121b1c73532SDimitry Andric       }
122b1c73532SDimitry Andric     }
123b1c73532SDimitry Andric 
124b1c73532SDimitry Andric     ControlFlowEdgeCount += Direction * SuccessorCount;
125b1c73532SDimitry Andric 
126b1c73532SDimitry Andric     if (const auto *BI = dyn_cast<BranchInst>(BB.getTerminator())) {
127b1c73532SDimitry Andric       if (!BI->isConditional())
128b1c73532SDimitry Andric         UnconditionalBranchCount += Direction;
129b1c73532SDimitry Andric     }
130b1c73532SDimitry Andric 
131b1c73532SDimitry Andric     for (const Instruction &I : BB.instructionsWithoutDebug()) {
132b1c73532SDimitry Andric       if (I.isCast())
133b1c73532SDimitry Andric         CastInstructionCount += Direction;
134b1c73532SDimitry Andric 
135b1c73532SDimitry Andric       if (I.getType()->isFloatTy())
136b1c73532SDimitry Andric         FloatingPointInstructionCount += Direction;
137b1c73532SDimitry Andric       else if (I.getType()->isIntegerTy())
138b1c73532SDimitry Andric         IntegerInstructionCount += Direction;
139b1c73532SDimitry Andric 
140b1c73532SDimitry Andric       if (isa<IntrinsicInst>(I))
141b1c73532SDimitry Andric         ++IntrinsicCount;
142b1c73532SDimitry Andric 
143b1c73532SDimitry Andric       if (const auto *Call = dyn_cast<CallInst>(&I)) {
144b1c73532SDimitry Andric         if (Call->isIndirectCall())
145b1c73532SDimitry Andric           IndirectCallCount += Direction;
146b1c73532SDimitry Andric         else
147b1c73532SDimitry Andric           DirectCallCount += Direction;
148b1c73532SDimitry Andric 
149b1c73532SDimitry Andric         if (Call->getType()->isIntegerTy())
150b1c73532SDimitry Andric           CallReturnsIntegerCount += Direction;
151b1c73532SDimitry Andric         else if (Call->getType()->isFloatingPointTy())
152b1c73532SDimitry Andric           CallReturnsFloatCount += Direction;
153b1c73532SDimitry Andric         else if (Call->getType()->isPointerTy())
154b1c73532SDimitry Andric           CallReturnsPointerCount += Direction;
155b1c73532SDimitry Andric         else if (Call->getType()->isVectorTy()) {
156b1c73532SDimitry Andric           if (Call->getType()->getScalarType()->isIntegerTy())
157b1c73532SDimitry Andric             CallReturnsVectorIntCount += Direction;
158b1c73532SDimitry Andric           else if (Call->getType()->getScalarType()->isFloatingPointTy())
159b1c73532SDimitry Andric             CallReturnsVectorFloatCount += Direction;
160b1c73532SDimitry Andric           else if (Call->getType()->getScalarType()->isPointerTy())
161b1c73532SDimitry Andric             CallReturnsVectorPointerCount += Direction;
162b1c73532SDimitry Andric         }
163b1c73532SDimitry Andric 
164b1c73532SDimitry Andric         if (Call->arg_size() > CallWithManyArgumentsThreshold)
165b1c73532SDimitry Andric           CallWithManyArgumentsCount += Direction;
166b1c73532SDimitry Andric 
167b1c73532SDimitry Andric         for (const auto &Arg : Call->args()) {
168b1c73532SDimitry Andric           if (Arg->getType()->isPointerTy()) {
169b1c73532SDimitry Andric             CallWithPointerArgumentCount += Direction;
170b1c73532SDimitry Andric             break;
171b1c73532SDimitry Andric           }
172b1c73532SDimitry Andric         }
173b1c73532SDimitry Andric       }
174b1c73532SDimitry Andric 
175b1c73532SDimitry Andric #define COUNT_OPERAND(OPTYPE)                                                  \
176b1c73532SDimitry Andric   if (isa<OPTYPE>(Operand)) {                                                  \
177b1c73532SDimitry Andric     OPTYPE##OperandCount += Direction;                                         \
178b1c73532SDimitry Andric     continue;                                                                  \
179b1c73532SDimitry Andric   }
180b1c73532SDimitry Andric 
181b1c73532SDimitry Andric       for (unsigned int OperandIndex = 0; OperandIndex < I.getNumOperands();
182b1c73532SDimitry Andric            ++OperandIndex) {
183b1c73532SDimitry Andric         Value *Operand = I.getOperand(OperandIndex);
184b1c73532SDimitry Andric         COUNT_OPERAND(GlobalValue)
185b1c73532SDimitry Andric         COUNT_OPERAND(ConstantInt)
186b1c73532SDimitry Andric         COUNT_OPERAND(ConstantFP)
187b1c73532SDimitry Andric         COUNT_OPERAND(Constant)
188b1c73532SDimitry Andric         COUNT_OPERAND(Instruction)
189b1c73532SDimitry Andric         COUNT_OPERAND(BasicBlock)
190b1c73532SDimitry Andric         COUNT_OPERAND(InlineAsm)
191b1c73532SDimitry Andric         COUNT_OPERAND(Argument)
192b1c73532SDimitry Andric 
193b1c73532SDimitry Andric         // We only get to this point if we haven't matched any of the other
194b1c73532SDimitry Andric         // operand types.
195b1c73532SDimitry Andric         UnknownOperandCount += Direction;
196b1c73532SDimitry Andric       }
197b1c73532SDimitry Andric 
198b1c73532SDimitry Andric #undef CHECK_OPERAND
199b1c73532SDimitry Andric     }
200b1c73532SDimitry Andric   }
201b60736ecSDimitry Andric }
202145449b1SDimitry Andric 
updateAggregateStats(const Function & F,const LoopInfo & LI)203145449b1SDimitry Andric void FunctionPropertiesInfo::updateAggregateStats(const Function &F,
204145449b1SDimitry Andric                                                   const LoopInfo &LI) {
205145449b1SDimitry Andric 
206145449b1SDimitry Andric   Uses = getUses(F);
207145449b1SDimitry Andric   TopLevelLoopCount = llvm::size(LI);
208145449b1SDimitry Andric   MaxLoopDepth = 0;
209145449b1SDimitry Andric   std::deque<const Loop *> Worklist;
210145449b1SDimitry Andric   llvm::append_range(Worklist, LI);
211145449b1SDimitry Andric   while (!Worklist.empty()) {
212145449b1SDimitry Andric     const auto *L = Worklist.front();
213145449b1SDimitry Andric     MaxLoopDepth =
214145449b1SDimitry Andric         std::max(MaxLoopDepth, static_cast<int64_t>(L->getLoopDepth()));
215145449b1SDimitry Andric     Worklist.pop_front();
216145449b1SDimitry Andric     llvm::append_range(Worklist, L->getSubLoops());
217145449b1SDimitry Andric   }
218145449b1SDimitry Andric }
219145449b1SDimitry Andric 
getFunctionPropertiesInfo(Function & F,FunctionAnalysisManager & FAM)220145449b1SDimitry Andric FunctionPropertiesInfo FunctionPropertiesInfo::getFunctionPropertiesInfo(
2217fa27ce4SDimitry Andric     Function &F, FunctionAnalysisManager &FAM) {
2227fa27ce4SDimitry Andric   return getFunctionPropertiesInfo(F, FAM.getResult<DominatorTreeAnalysis>(F),
2237fa27ce4SDimitry Andric                                    FAM.getResult<LoopAnalysis>(F));
2247fa27ce4SDimitry Andric }
2257fa27ce4SDimitry Andric 
getFunctionPropertiesInfo(const Function & F,const DominatorTree & DT,const LoopInfo & LI)2267fa27ce4SDimitry Andric FunctionPropertiesInfo FunctionPropertiesInfo::getFunctionPropertiesInfo(
2277fa27ce4SDimitry Andric     const Function &F, const DominatorTree &DT, const LoopInfo &LI) {
228145449b1SDimitry Andric 
229145449b1SDimitry Andric   FunctionPropertiesInfo FPI;
230145449b1SDimitry Andric   for (const auto &BB : F)
231145449b1SDimitry Andric     if (DT.isReachableFromEntry(&BB))
232145449b1SDimitry Andric       FPI.reIncludeBB(BB);
233145449b1SDimitry Andric   FPI.updateAggregateStats(F, LI);
234b60736ecSDimitry Andric   return FPI;
235b60736ecSDimitry Andric }
236b60736ecSDimitry Andric 
print(raw_ostream & OS) const237b60736ecSDimitry Andric void FunctionPropertiesInfo::print(raw_ostream &OS) const {
238b1c73532SDimitry Andric #define PRINT_PROPERTY(PROP_NAME) OS << #PROP_NAME ": " << PROP_NAME << "\n";
239b1c73532SDimitry Andric 
240b1c73532SDimitry Andric   PRINT_PROPERTY(BasicBlockCount)
241b1c73532SDimitry Andric   PRINT_PROPERTY(BlocksReachedFromConditionalInstruction)
242b1c73532SDimitry Andric   PRINT_PROPERTY(Uses)
243b1c73532SDimitry Andric   PRINT_PROPERTY(DirectCallsToDefinedFunctions)
244b1c73532SDimitry Andric   PRINT_PROPERTY(LoadInstCount)
245b1c73532SDimitry Andric   PRINT_PROPERTY(StoreInstCount)
246b1c73532SDimitry Andric   PRINT_PROPERTY(MaxLoopDepth)
247b1c73532SDimitry Andric   PRINT_PROPERTY(TopLevelLoopCount)
248b1c73532SDimitry Andric   PRINT_PROPERTY(TotalInstructionCount)
249b1c73532SDimitry Andric 
250b1c73532SDimitry Andric   if (EnableDetailedFunctionProperties) {
251b1c73532SDimitry Andric     PRINT_PROPERTY(BasicBlocksWithSingleSuccessor)
252b1c73532SDimitry Andric     PRINT_PROPERTY(BasicBlocksWithTwoSuccessors)
253b1c73532SDimitry Andric     PRINT_PROPERTY(BasicBlocksWithMoreThanTwoSuccessors)
254b1c73532SDimitry Andric     PRINT_PROPERTY(BasicBlocksWithSinglePredecessor)
255b1c73532SDimitry Andric     PRINT_PROPERTY(BasicBlocksWithTwoPredecessors)
256b1c73532SDimitry Andric     PRINT_PROPERTY(BasicBlocksWithMoreThanTwoPredecessors)
257b1c73532SDimitry Andric     PRINT_PROPERTY(BigBasicBlocks)
258b1c73532SDimitry Andric     PRINT_PROPERTY(MediumBasicBlocks)
259b1c73532SDimitry Andric     PRINT_PROPERTY(SmallBasicBlocks)
260b1c73532SDimitry Andric     PRINT_PROPERTY(CastInstructionCount)
261b1c73532SDimitry Andric     PRINT_PROPERTY(FloatingPointInstructionCount)
262b1c73532SDimitry Andric     PRINT_PROPERTY(IntegerInstructionCount)
263b1c73532SDimitry Andric     PRINT_PROPERTY(ConstantIntOperandCount)
264b1c73532SDimitry Andric     PRINT_PROPERTY(ConstantFPOperandCount)
265b1c73532SDimitry Andric     PRINT_PROPERTY(ConstantOperandCount)
266b1c73532SDimitry Andric     PRINT_PROPERTY(InstructionOperandCount)
267b1c73532SDimitry Andric     PRINT_PROPERTY(BasicBlockOperandCount)
268b1c73532SDimitry Andric     PRINT_PROPERTY(GlobalValueOperandCount)
269b1c73532SDimitry Andric     PRINT_PROPERTY(InlineAsmOperandCount)
270b1c73532SDimitry Andric     PRINT_PROPERTY(ArgumentOperandCount)
271b1c73532SDimitry Andric     PRINT_PROPERTY(UnknownOperandCount)
272b1c73532SDimitry Andric     PRINT_PROPERTY(CriticalEdgeCount)
273b1c73532SDimitry Andric     PRINT_PROPERTY(ControlFlowEdgeCount)
274b1c73532SDimitry Andric     PRINT_PROPERTY(UnconditionalBranchCount)
275b1c73532SDimitry Andric     PRINT_PROPERTY(IntrinsicCount)
276b1c73532SDimitry Andric     PRINT_PROPERTY(DirectCallCount)
277b1c73532SDimitry Andric     PRINT_PROPERTY(IndirectCallCount)
278b1c73532SDimitry Andric     PRINT_PROPERTY(CallReturnsIntegerCount)
279b1c73532SDimitry Andric     PRINT_PROPERTY(CallReturnsFloatCount)
280b1c73532SDimitry Andric     PRINT_PROPERTY(CallReturnsPointerCount)
281b1c73532SDimitry Andric     PRINT_PROPERTY(CallReturnsVectorIntCount)
282b1c73532SDimitry Andric     PRINT_PROPERTY(CallReturnsVectorFloatCount)
283b1c73532SDimitry Andric     PRINT_PROPERTY(CallReturnsVectorPointerCount)
284b1c73532SDimitry Andric     PRINT_PROPERTY(CallWithManyArgumentsCount)
285b1c73532SDimitry Andric     PRINT_PROPERTY(CallWithPointerArgumentCount)
286b1c73532SDimitry Andric   }
287b1c73532SDimitry Andric 
288b1c73532SDimitry Andric #undef PRINT_PROPERTY
289b1c73532SDimitry Andric 
290b1c73532SDimitry Andric   OS << "\n";
291b60736ecSDimitry Andric }
292b60736ecSDimitry Andric 
293b60736ecSDimitry Andric AnalysisKey FunctionPropertiesAnalysis::Key;
294b60736ecSDimitry Andric 
295b60736ecSDimitry Andric FunctionPropertiesInfo
run(Function & F,FunctionAnalysisManager & FAM)296b60736ecSDimitry Andric FunctionPropertiesAnalysis::run(Function &F, FunctionAnalysisManager &FAM) {
297145449b1SDimitry Andric   return FunctionPropertiesInfo::getFunctionPropertiesInfo(F, FAM);
298b60736ecSDimitry Andric }
299b60736ecSDimitry Andric 
300b60736ecSDimitry Andric PreservedAnalyses
run(Function & F,FunctionAnalysisManager & AM)301b60736ecSDimitry Andric FunctionPropertiesPrinterPass::run(Function &F, FunctionAnalysisManager &AM) {
302b60736ecSDimitry Andric   OS << "Printing analysis results of CFA for function "
303b60736ecSDimitry Andric      << "'" << F.getName() << "':"
304b60736ecSDimitry Andric      << "\n";
305b60736ecSDimitry Andric   AM.getResult<FunctionPropertiesAnalysis>(F).print(OS);
306b60736ecSDimitry Andric   return PreservedAnalyses::all();
307b60736ecSDimitry Andric }
308145449b1SDimitry Andric 
FunctionPropertiesUpdater(FunctionPropertiesInfo & FPI,CallBase & CB)309145449b1SDimitry Andric FunctionPropertiesUpdater::FunctionPropertiesUpdater(
3107fa27ce4SDimitry Andric     FunctionPropertiesInfo &FPI, CallBase &CB)
311145449b1SDimitry Andric     : FPI(FPI), CallSiteBB(*CB.getParent()), Caller(*CallSiteBB.getParent()) {
312145449b1SDimitry Andric   assert(isa<CallInst>(CB) || isa<InvokeInst>(CB));
313145449b1SDimitry Andric   // For BBs that are likely to change, we subtract from feature totals their
314145449b1SDimitry Andric   // contribution. Some features, like max loop counts or depths, are left
315145449b1SDimitry Andric   // invalid, as they will be updated post-inlining.
316145449b1SDimitry Andric   SmallPtrSet<const BasicBlock *, 4> LikelyToChangeBBs;
317145449b1SDimitry Andric   // The CB BB will change - it'll either be split or the callee's body (single
318145449b1SDimitry Andric   // BB) will be pasted in.
319145449b1SDimitry Andric   LikelyToChangeBBs.insert(&CallSiteBB);
320145449b1SDimitry Andric 
321145449b1SDimitry Andric   // The caller's entry BB may change due to new alloca instructions.
322145449b1SDimitry Andric   LikelyToChangeBBs.insert(&*Caller.begin());
323145449b1SDimitry Andric 
324145449b1SDimitry Andric   // The successors may become unreachable in the case of `invoke` inlining.
325145449b1SDimitry Andric   // We track successors separately, too, because they form a boundary, together
326145449b1SDimitry Andric   // with the CB BB ('Entry') between which the inlined callee will be pasted.
327145449b1SDimitry Andric   Successors.insert(succ_begin(&CallSiteBB), succ_end(&CallSiteBB));
328145449b1SDimitry Andric 
329145449b1SDimitry Andric   // Inlining only handles invoke and calls. If this is an invoke, and inlining
330145449b1SDimitry Andric   // it pulls another invoke, the original landing pad may get split, so as to
331145449b1SDimitry Andric   // share its content with other potential users. So the edge up to which we
332145449b1SDimitry Andric   // need to invalidate and then re-account BB data is the successors of the
333145449b1SDimitry Andric   // current landing pad. We can leave the current lp, too - if it doesn't get
334145449b1SDimitry Andric   // split, then it will be the place traversal stops. Either way, the
335145449b1SDimitry Andric   // discounted BBs will be checked if reachable and re-added.
336145449b1SDimitry Andric   if (const auto *II = dyn_cast<InvokeInst>(&CB)) {
337145449b1SDimitry Andric     const auto *UnwindDest = II->getUnwindDest();
338145449b1SDimitry Andric     Successors.insert(succ_begin(UnwindDest), succ_end(UnwindDest));
339145449b1SDimitry Andric   }
340145449b1SDimitry Andric 
341145449b1SDimitry Andric   // Exclude the CallSiteBB, if it happens to be its own successor (1-BB loop).
342145449b1SDimitry Andric   // We are only interested in BBs the graph moves past the callsite BB to
343145449b1SDimitry Andric   // define the frontier past which we don't want to re-process BBs. Including
344145449b1SDimitry Andric   // the callsite BB in this case would prematurely stop the traversal in
345145449b1SDimitry Andric   // finish().
346145449b1SDimitry Andric   Successors.erase(&CallSiteBB);
347145449b1SDimitry Andric 
348145449b1SDimitry Andric   for (const auto *BB : Successors)
349145449b1SDimitry Andric     LikelyToChangeBBs.insert(BB);
350145449b1SDimitry Andric 
351145449b1SDimitry Andric   // Commit the change. While some of the BBs accounted for above may play dual
352145449b1SDimitry Andric   // role - e.g. caller's entry BB may be the same as the callsite BB - set
353145449b1SDimitry Andric   // insertion semantics make sure we account them once. This needs to be
354145449b1SDimitry Andric   // followed in `finish`, too.
355145449b1SDimitry Andric   for (const auto *BB : LikelyToChangeBBs)
356145449b1SDimitry Andric     FPI.updateForBB(*BB, -1);
357145449b1SDimitry Andric }
358145449b1SDimitry Andric 
finish(FunctionAnalysisManager & FAM) const359145449b1SDimitry Andric void FunctionPropertiesUpdater::finish(FunctionAnalysisManager &FAM) const {
360145449b1SDimitry Andric   // Update feature values from the BBs that were copied from the callee, or
361145449b1SDimitry Andric   // might have been modified because of inlining. The latter have been
362145449b1SDimitry Andric   // subtracted in the FunctionPropertiesUpdater ctor.
363145449b1SDimitry Andric   // There could be successors that were reached before but now are only
364145449b1SDimitry Andric   // reachable from elsewhere in the CFG.
365145449b1SDimitry Andric   // One example is the following diamond CFG (lines are arrows pointing down):
366145449b1SDimitry Andric   //    A
367145449b1SDimitry Andric   //  /   \
368145449b1SDimitry Andric   // B     C
369145449b1SDimitry Andric   // |     |
370145449b1SDimitry Andric   // |     D
371145449b1SDimitry Andric   // |     |
372145449b1SDimitry Andric   // |     E
373145449b1SDimitry Andric   //  \   /
374145449b1SDimitry Andric   //    F
375145449b1SDimitry Andric   // There's a call site in C that is inlined. Upon doing that, it turns out
376145449b1SDimitry Andric   // it expands to
377145449b1SDimitry Andric   //   call void @llvm.trap()
378145449b1SDimitry Andric   //   unreachable
379145449b1SDimitry Andric   // F isn't reachable from C anymore, but we did discount it when we set up
380145449b1SDimitry Andric   // FunctionPropertiesUpdater, so we need to re-include it here.
381145449b1SDimitry Andric   // At the same time, D and E were reachable before, but now are not anymore,
382145449b1SDimitry Andric   // so we need to leave D out (we discounted it at setup), and explicitly
383145449b1SDimitry Andric   // remove E.
384145449b1SDimitry Andric   SetVector<const BasicBlock *> Reinclude;
385145449b1SDimitry Andric   SetVector<const BasicBlock *> Unreachable;
386145449b1SDimitry Andric   const auto &DT =
387145449b1SDimitry Andric       FAM.getResult<DominatorTreeAnalysis>(const_cast<Function &>(Caller));
388145449b1SDimitry Andric 
389145449b1SDimitry Andric   if (&CallSiteBB != &*Caller.begin())
390145449b1SDimitry Andric     Reinclude.insert(&*Caller.begin());
391145449b1SDimitry Andric 
392145449b1SDimitry Andric   // Distribute the successors to the 2 buckets.
393145449b1SDimitry Andric   for (const auto *Succ : Successors)
394145449b1SDimitry Andric     if (DT.isReachableFromEntry(Succ))
395145449b1SDimitry Andric       Reinclude.insert(Succ);
396145449b1SDimitry Andric     else
397145449b1SDimitry Andric       Unreachable.insert(Succ);
398145449b1SDimitry Andric 
399145449b1SDimitry Andric   // For reinclusion, we want to stop at the reachable successors, who are at
400145449b1SDimitry Andric   // the beginning of the worklist; but, starting from the callsite bb and
401145449b1SDimitry Andric   // ending at those successors, we also want to perform a traversal.
402145449b1SDimitry Andric   // IncludeSuccessorsMark is the index after which we include successors.
403145449b1SDimitry Andric   const auto IncludeSuccessorsMark = Reinclude.size();
404145449b1SDimitry Andric   bool CSInsertion = Reinclude.insert(&CallSiteBB);
405145449b1SDimitry Andric   (void)CSInsertion;
406145449b1SDimitry Andric   assert(CSInsertion);
407145449b1SDimitry Andric   for (size_t I = 0; I < Reinclude.size(); ++I) {
408145449b1SDimitry Andric     const auto *BB = Reinclude[I];
409145449b1SDimitry Andric     FPI.reIncludeBB(*BB);
410145449b1SDimitry Andric     if (I >= IncludeSuccessorsMark)
411145449b1SDimitry Andric       Reinclude.insert(succ_begin(BB), succ_end(BB));
412145449b1SDimitry Andric   }
413145449b1SDimitry Andric 
414145449b1SDimitry Andric   // For exclusion, we don't need to exclude the set of BBs that were successors
415145449b1SDimitry Andric   // before and are now unreachable, because we already did that at setup. For
416145449b1SDimitry Andric   // the rest, as long as a successor is unreachable, we want to explicitly
417145449b1SDimitry Andric   // exclude it.
418145449b1SDimitry Andric   const auto AlreadyExcludedMark = Unreachable.size();
419145449b1SDimitry Andric   for (size_t I = 0; I < Unreachable.size(); ++I) {
420145449b1SDimitry Andric     const auto *U = Unreachable[I];
421145449b1SDimitry Andric     if (I >= AlreadyExcludedMark)
422145449b1SDimitry Andric       FPI.updateForBB(*U, -1);
423145449b1SDimitry Andric     for (const auto *Succ : successors(U))
424145449b1SDimitry Andric       if (!DT.isReachableFromEntry(Succ))
425145449b1SDimitry Andric         Unreachable.insert(Succ);
426145449b1SDimitry Andric   }
427145449b1SDimitry Andric 
428145449b1SDimitry Andric   const auto &LI = FAM.getResult<LoopAnalysis>(const_cast<Function &>(Caller));
429145449b1SDimitry Andric   FPI.updateAggregateStats(Caller, LI);
4307fa27ce4SDimitry Andric }
4317fa27ce4SDimitry Andric 
isUpdateValid(Function & F,const FunctionPropertiesInfo & FPI,FunctionAnalysisManager & FAM)4327fa27ce4SDimitry Andric bool FunctionPropertiesUpdater::isUpdateValid(Function &F,
4337fa27ce4SDimitry Andric                                               const FunctionPropertiesInfo &FPI,
4347fa27ce4SDimitry Andric                                               FunctionAnalysisManager &FAM) {
4357fa27ce4SDimitry Andric   DominatorTree DT(F);
4367fa27ce4SDimitry Andric   LoopInfo LI(DT);
4377fa27ce4SDimitry Andric   auto Fresh = FunctionPropertiesInfo::getFunctionPropertiesInfo(F, DT, LI);
4387fa27ce4SDimitry Andric   return FPI == Fresh;
439145449b1SDimitry Andric }
440