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