xref: /llvm-project/llvm/include/llvm/Analysis/FunctionPropertiesAnalysis.h (revision 1991aa6b48845f31ff4e69a960b04086ff68ce3e)
1 //=- FunctionPropertiesAnalysis.h - Function Properties Analysis --*- C++ -*-=//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines the FunctionPropertiesInfo and FunctionPropertiesAnalysis
10 // classes used to extract function properties.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_ANALYSIS_FUNCTIONPROPERTIESANALYSIS_H
15 #define LLVM_ANALYSIS_FUNCTIONPROPERTIESANALYSIS_H
16 
17 #include "llvm/ADT/DenseSet.h"
18 #include "llvm/IR/Dominators.h"
19 #include "llvm/IR/PassManager.h"
20 
21 namespace llvm {
22 class BasicBlock;
23 class CallBase;
24 class DominatorTree;
25 class Function;
26 class LoopInfo;
27 
28 class FunctionPropertiesInfo {
29   friend class FunctionPropertiesUpdater;
30   void updateForBB(const BasicBlock &BB, int64_t Direction);
31   void updateAggregateStats(const Function &F, const LoopInfo &LI);
32   void reIncludeBB(const BasicBlock &BB);
33 
34 public:
35   static FunctionPropertiesInfo
36   getFunctionPropertiesInfo(const Function &F, const DominatorTree &DT,
37                             const LoopInfo &LI);
38 
39   static FunctionPropertiesInfo
40   getFunctionPropertiesInfo(Function &F, FunctionAnalysisManager &FAM);
41 
42   bool operator==(const FunctionPropertiesInfo &FPI) const {
43     return std::memcmp(this, &FPI, sizeof(FunctionPropertiesInfo)) == 0;
44   }
45 
46   bool operator!=(const FunctionPropertiesInfo &FPI) const {
47     return !(*this == FPI);
48   }
49 
50   void print(raw_ostream &OS) const;
51 
52   /// Number of basic blocks
53   int64_t BasicBlockCount = 0;
54 
55   /// Number of blocks reached from a conditional instruction, or that are
56   /// 'cases' of a SwitchInstr.
57   // FIXME: We may want to replace this with a more meaningful metric, like
58   // number of conditionally executed blocks:
59   // 'if (a) s();' would be counted here as 2 blocks, just like
60   // 'if (a) s(); else s2(); s3();' would.
61   int64_t BlocksReachedFromConditionalInstruction = 0;
62 
63   /// Number of uses of this function, plus 1 if the function is callable
64   /// outside the module.
65   int64_t Uses = 0;
66 
67   /// Number of direct calls made from this function to other functions
68   /// defined in this module.
69   int64_t DirectCallsToDefinedFunctions = 0;
70 
71   // Load Instruction Count
72   int64_t LoadInstCount = 0;
73 
74   // Store Instruction Count
75   int64_t StoreInstCount = 0;
76 
77   // Maximum Loop Depth in the Function
78   int64_t MaxLoopDepth = 0;
79 
80   // Number of Top Level Loops in the Function
81   int64_t TopLevelLoopCount = 0;
82 
83   // All non-debug instructions
84   int64_t TotalInstructionCount = 0;
85 
86   // Basic blocks grouped by number of successors.
87   int64_t BasicBlocksWithSingleSuccessor = 0;
88   int64_t BasicBlocksWithTwoSuccessors = 0;
89   int64_t BasicBlocksWithMoreThanTwoSuccessors = 0;
90 
91   // Basic blocks grouped by number of predecessors.
92   int64_t BasicBlocksWithSinglePredecessor = 0;
93   int64_t BasicBlocksWithTwoPredecessors = 0;
94   int64_t BasicBlocksWithMoreThanTwoPredecessors = 0;
95 
96   // Basic blocks grouped by size as determined by the number of non-debug
97   // instructions that they contain.
98   int64_t BigBasicBlocks = 0;
99   int64_t MediumBasicBlocks = 0;
100   int64_t SmallBasicBlocks = 0;
101 
102   // The number of cast instructions inside the function.
103   int64_t CastInstructionCount = 0;
104 
105   // The number of floating point instructions inside the function.
106   int64_t FloatingPointInstructionCount = 0;
107 
108   // The number of integer instructions inside the function.
109   int64_t IntegerInstructionCount = 0;
110 
111   // Operand type couns
112   int64_t ConstantIntOperandCount = 0;
113   int64_t ConstantFPOperandCount = 0;
114   int64_t ConstantOperandCount = 0;
115   int64_t InstructionOperandCount = 0;
116   int64_t BasicBlockOperandCount = 0;
117   int64_t GlobalValueOperandCount = 0;
118   int64_t InlineAsmOperandCount = 0;
119   int64_t ArgumentOperandCount = 0;
120   int64_t UnknownOperandCount = 0;
121 
122   // Additional CFG Properties
123   int64_t CriticalEdgeCount = 0;
124   int64_t ControlFlowEdgeCount = 0;
125   int64_t UnconditionalBranchCount = 0;
126 
127   // Call related instructions
128   int64_t IntrinsicCount = 0;
129   int64_t DirectCallCount = 0;
130   int64_t IndirectCallCount = 0;
131   int64_t CallReturnsIntegerCount = 0;
132   int64_t CallReturnsFloatCount = 0;
133   int64_t CallReturnsPointerCount = 0;
134   int64_t CallReturnsVectorIntCount = 0;
135   int64_t CallReturnsVectorFloatCount = 0;
136   int64_t CallReturnsVectorPointerCount = 0;
137   int64_t CallWithManyArgumentsCount = 0;
138   int64_t CallWithPointerArgumentCount = 0;
139 };
140 
141 // Analysis pass
142 class FunctionPropertiesAnalysis
143     : public AnalysisInfoMixin<FunctionPropertiesAnalysis> {
144 
145 public:
146   static AnalysisKey Key;
147 
148   using Result = const FunctionPropertiesInfo;
149 
150   FunctionPropertiesInfo run(Function &F, FunctionAnalysisManager &FAM);
151 };
152 
153 /// Printer pass for the FunctionPropertiesAnalysis results.
154 class FunctionPropertiesPrinterPass
155     : public PassInfoMixin<FunctionPropertiesPrinterPass> {
156   raw_ostream &OS;
157 
158 public:
159   explicit FunctionPropertiesPrinterPass(raw_ostream &OS) : OS(OS) {}
160 
161   PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
162 
163   static bool isRequired() { return true; }
164 };
165 
166 /// Correctly update FunctionPropertiesInfo post-inlining. A
167 /// FunctionPropertiesUpdater keeps the state necessary for tracking the changes
168 /// llvm::InlineFunction makes. The idea is that inlining will at most modify
169 /// a few BBs of the Caller (maybe the entry BB and definitely the callsite BB)
170 /// and potentially affect exception handling BBs in the case of invoke
171 /// inlining.
172 class FunctionPropertiesUpdater {
173 public:
174   FunctionPropertiesUpdater(FunctionPropertiesInfo &FPI, CallBase &CB);
175 
176   void finish(FunctionAnalysisManager &FAM) const;
177   bool finishAndTest(FunctionAnalysisManager &FAM) const {
178     finish(FAM);
179     return isUpdateValid(Caller, FPI, FAM);
180   }
181 
182 private:
183   FunctionPropertiesInfo &FPI;
184   BasicBlock &CallSiteBB;
185   Function &Caller;
186 
187   static bool isUpdateValid(Function &F, const FunctionPropertiesInfo &FPI,
188                             FunctionAnalysisManager &FAM);
189 
190   DominatorTree &getUpdatedDominatorTree(FunctionAnalysisManager &FAM) const;
191 
192   DenseSet<const BasicBlock *> Successors;
193 
194   // Edges we might potentially need to remove from the dominator tree.
195   SmallVector<DominatorTree::UpdateType, 2> DomTreeUpdates;
196 };
197 } // namespace llvm
198 #endif // LLVM_ANALYSIS_FUNCTIONPROPERTIESANALYSIS_H
199