Path: blob/main/contrib/llvm-project/llvm/lib/Analysis/FunctionPropertiesAnalysis.cpp
35232 views
//===- FunctionPropertiesAnalysis.cpp - Function Properties Analysis ------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file defines the FunctionPropertiesInfo and FunctionPropertiesAnalysis9// classes used to extract function properties.10//11//===----------------------------------------------------------------------===//1213#include "llvm/Analysis/FunctionPropertiesAnalysis.h"14#include "llvm/ADT/STLExtras.h"15#include "llvm/ADT/SetVector.h"16#include "llvm/Analysis/LoopInfo.h"17#include "llvm/IR/CFG.h"18#include "llvm/IR/Constants.h"19#include "llvm/IR/Dominators.h"20#include "llvm/IR/Instructions.h"21#include "llvm/IR/IntrinsicInst.h"22#include "llvm/Support/CommandLine.h"23#include <deque>2425using namespace llvm;2627namespace llvm {28cl::opt<bool> EnableDetailedFunctionProperties(29"enable-detailed-function-properties", cl::Hidden, cl::init(false),30cl::desc("Whether or not to compute detailed function properties."));3132cl::opt<unsigned> BigBasicBlockInstructionThreshold(33"big-basic-block-instruction-threshold", cl::Hidden, cl::init(500),34cl::desc("The minimum number of instructions a basic block should contain "35"before being considered big."));3637cl::opt<unsigned> MediumBasicBlockInstructionThreshold(38"medium-basic-block-instruction-threshold", cl::Hidden, cl::init(15),39cl::desc("The minimum number of instructions a basic block should contain "40"before being considered medium-sized."));41} // namespace llvm4243static cl::opt<unsigned> CallWithManyArgumentsThreshold(44"call-with-many-arguments-threshold", cl::Hidden, cl::init(4),45cl::desc("The minimum number of arguments a function call must have before "46"it is considered having many arguments."));4748namespace {49int64_t getNrBlocksFromCond(const BasicBlock &BB) {50int64_t Ret = 0;51if (const auto *BI = dyn_cast<BranchInst>(BB.getTerminator())) {52if (BI->isConditional())53Ret += BI->getNumSuccessors();54} else if (const auto *SI = dyn_cast<SwitchInst>(BB.getTerminator())) {55Ret += (SI->getNumCases() + (nullptr != SI->getDefaultDest()));56}57return Ret;58}5960int64_t getUses(const Function &F) {61return ((!F.hasLocalLinkage()) ? 1 : 0) + F.getNumUses();62}63} // namespace6465void FunctionPropertiesInfo::reIncludeBB(const BasicBlock &BB) {66updateForBB(BB, +1);67}6869void FunctionPropertiesInfo::updateForBB(const BasicBlock &BB,70int64_t Direction) {71assert(Direction == 1 || Direction == -1);72BasicBlockCount += Direction;73BlocksReachedFromConditionalInstruction +=74(Direction * getNrBlocksFromCond(BB));75for (const auto &I : BB) {76if (auto *CS = dyn_cast<CallBase>(&I)) {77const auto *Callee = CS->getCalledFunction();78if (Callee && !Callee->isIntrinsic() && !Callee->isDeclaration())79DirectCallsToDefinedFunctions += Direction;80}81if (I.getOpcode() == Instruction::Load) {82LoadInstCount += Direction;83} else if (I.getOpcode() == Instruction::Store) {84StoreInstCount += Direction;85}86}87TotalInstructionCount += Direction * BB.sizeWithoutDebug();8889if (EnableDetailedFunctionProperties) {90unsigned SuccessorCount = succ_size(&BB);91if (SuccessorCount == 1)92BasicBlocksWithSingleSuccessor += Direction;93else if (SuccessorCount == 2)94BasicBlocksWithTwoSuccessors += Direction;95else if (SuccessorCount > 2)96BasicBlocksWithMoreThanTwoSuccessors += Direction;9798unsigned PredecessorCount = pred_size(&BB);99if (PredecessorCount == 1)100BasicBlocksWithSinglePredecessor += Direction;101else if (PredecessorCount == 2)102BasicBlocksWithTwoPredecessors += Direction;103else if (PredecessorCount > 2)104BasicBlocksWithMoreThanTwoPredecessors += Direction;105106if (TotalInstructionCount > BigBasicBlockInstructionThreshold)107BigBasicBlocks += Direction;108else if (TotalInstructionCount > MediumBasicBlockInstructionThreshold)109MediumBasicBlocks += Direction;110else111SmallBasicBlocks += Direction;112113// Calculate critical edges by looking through all successors of a basic114// block that has multiple successors and finding ones that have multiple115// predecessors, which represent critical edges.116if (SuccessorCount > 1) {117for (const auto *Successor : successors(&BB)) {118if (pred_size(Successor) > 1)119CriticalEdgeCount += Direction;120}121}122123ControlFlowEdgeCount += Direction * SuccessorCount;124125if (const auto *BI = dyn_cast<BranchInst>(BB.getTerminator())) {126if (!BI->isConditional())127UnconditionalBranchCount += Direction;128}129130for (const Instruction &I : BB.instructionsWithoutDebug()) {131if (I.isCast())132CastInstructionCount += Direction;133134if (I.getType()->isFloatTy())135FloatingPointInstructionCount += Direction;136else if (I.getType()->isIntegerTy())137IntegerInstructionCount += Direction;138139if (isa<IntrinsicInst>(I))140++IntrinsicCount;141142if (const auto *Call = dyn_cast<CallInst>(&I)) {143if (Call->isIndirectCall())144IndirectCallCount += Direction;145else146DirectCallCount += Direction;147148if (Call->getType()->isIntegerTy())149CallReturnsIntegerCount += Direction;150else if (Call->getType()->isFloatingPointTy())151CallReturnsFloatCount += Direction;152else if (Call->getType()->isPointerTy())153CallReturnsPointerCount += Direction;154else if (Call->getType()->isVectorTy()) {155if (Call->getType()->getScalarType()->isIntegerTy())156CallReturnsVectorIntCount += Direction;157else if (Call->getType()->getScalarType()->isFloatingPointTy())158CallReturnsVectorFloatCount += Direction;159else if (Call->getType()->getScalarType()->isPointerTy())160CallReturnsVectorPointerCount += Direction;161}162163if (Call->arg_size() > CallWithManyArgumentsThreshold)164CallWithManyArgumentsCount += Direction;165166for (const auto &Arg : Call->args()) {167if (Arg->getType()->isPointerTy()) {168CallWithPointerArgumentCount += Direction;169break;170}171}172}173174#define COUNT_OPERAND(OPTYPE) \175if (isa<OPTYPE>(Operand)) { \176OPTYPE##OperandCount += Direction; \177continue; \178}179180for (unsigned int OperandIndex = 0; OperandIndex < I.getNumOperands();181++OperandIndex) {182Value *Operand = I.getOperand(OperandIndex);183COUNT_OPERAND(GlobalValue)184COUNT_OPERAND(ConstantInt)185COUNT_OPERAND(ConstantFP)186COUNT_OPERAND(Constant)187COUNT_OPERAND(Instruction)188COUNT_OPERAND(BasicBlock)189COUNT_OPERAND(InlineAsm)190COUNT_OPERAND(Argument)191192// We only get to this point if we haven't matched any of the other193// operand types.194UnknownOperandCount += Direction;195}196197#undef CHECK_OPERAND198}199}200}201202void FunctionPropertiesInfo::updateAggregateStats(const Function &F,203const LoopInfo &LI) {204205Uses = getUses(F);206TopLevelLoopCount = llvm::size(LI);207MaxLoopDepth = 0;208std::deque<const Loop *> Worklist;209llvm::append_range(Worklist, LI);210while (!Worklist.empty()) {211const auto *L = Worklist.front();212MaxLoopDepth =213std::max(MaxLoopDepth, static_cast<int64_t>(L->getLoopDepth()));214Worklist.pop_front();215llvm::append_range(Worklist, L->getSubLoops());216}217}218219FunctionPropertiesInfo FunctionPropertiesInfo::getFunctionPropertiesInfo(220Function &F, FunctionAnalysisManager &FAM) {221return getFunctionPropertiesInfo(F, FAM.getResult<DominatorTreeAnalysis>(F),222FAM.getResult<LoopAnalysis>(F));223}224225FunctionPropertiesInfo FunctionPropertiesInfo::getFunctionPropertiesInfo(226const Function &F, const DominatorTree &DT, const LoopInfo &LI) {227228FunctionPropertiesInfo FPI;229for (const auto &BB : F)230if (DT.isReachableFromEntry(&BB))231FPI.reIncludeBB(BB);232FPI.updateAggregateStats(F, LI);233return FPI;234}235236void FunctionPropertiesInfo::print(raw_ostream &OS) const {237#define PRINT_PROPERTY(PROP_NAME) OS << #PROP_NAME ": " << PROP_NAME << "\n";238239PRINT_PROPERTY(BasicBlockCount)240PRINT_PROPERTY(BlocksReachedFromConditionalInstruction)241PRINT_PROPERTY(Uses)242PRINT_PROPERTY(DirectCallsToDefinedFunctions)243PRINT_PROPERTY(LoadInstCount)244PRINT_PROPERTY(StoreInstCount)245PRINT_PROPERTY(MaxLoopDepth)246PRINT_PROPERTY(TopLevelLoopCount)247PRINT_PROPERTY(TotalInstructionCount)248249if (EnableDetailedFunctionProperties) {250PRINT_PROPERTY(BasicBlocksWithSingleSuccessor)251PRINT_PROPERTY(BasicBlocksWithTwoSuccessors)252PRINT_PROPERTY(BasicBlocksWithMoreThanTwoSuccessors)253PRINT_PROPERTY(BasicBlocksWithSinglePredecessor)254PRINT_PROPERTY(BasicBlocksWithTwoPredecessors)255PRINT_PROPERTY(BasicBlocksWithMoreThanTwoPredecessors)256PRINT_PROPERTY(BigBasicBlocks)257PRINT_PROPERTY(MediumBasicBlocks)258PRINT_PROPERTY(SmallBasicBlocks)259PRINT_PROPERTY(CastInstructionCount)260PRINT_PROPERTY(FloatingPointInstructionCount)261PRINT_PROPERTY(IntegerInstructionCount)262PRINT_PROPERTY(ConstantIntOperandCount)263PRINT_PROPERTY(ConstantFPOperandCount)264PRINT_PROPERTY(ConstantOperandCount)265PRINT_PROPERTY(InstructionOperandCount)266PRINT_PROPERTY(BasicBlockOperandCount)267PRINT_PROPERTY(GlobalValueOperandCount)268PRINT_PROPERTY(InlineAsmOperandCount)269PRINT_PROPERTY(ArgumentOperandCount)270PRINT_PROPERTY(UnknownOperandCount)271PRINT_PROPERTY(CriticalEdgeCount)272PRINT_PROPERTY(ControlFlowEdgeCount)273PRINT_PROPERTY(UnconditionalBranchCount)274PRINT_PROPERTY(IntrinsicCount)275PRINT_PROPERTY(DirectCallCount)276PRINT_PROPERTY(IndirectCallCount)277PRINT_PROPERTY(CallReturnsIntegerCount)278PRINT_PROPERTY(CallReturnsFloatCount)279PRINT_PROPERTY(CallReturnsPointerCount)280PRINT_PROPERTY(CallReturnsVectorIntCount)281PRINT_PROPERTY(CallReturnsVectorFloatCount)282PRINT_PROPERTY(CallReturnsVectorPointerCount)283PRINT_PROPERTY(CallWithManyArgumentsCount)284PRINT_PROPERTY(CallWithPointerArgumentCount)285}286287#undef PRINT_PROPERTY288289OS << "\n";290}291292AnalysisKey FunctionPropertiesAnalysis::Key;293294FunctionPropertiesInfo295FunctionPropertiesAnalysis::run(Function &F, FunctionAnalysisManager &FAM) {296return FunctionPropertiesInfo::getFunctionPropertiesInfo(F, FAM);297}298299PreservedAnalyses300FunctionPropertiesPrinterPass::run(Function &F, FunctionAnalysisManager &AM) {301OS << "Printing analysis results of CFA for function "302<< "'" << F.getName() << "':"303<< "\n";304AM.getResult<FunctionPropertiesAnalysis>(F).print(OS);305return PreservedAnalyses::all();306}307308FunctionPropertiesUpdater::FunctionPropertiesUpdater(309FunctionPropertiesInfo &FPI, CallBase &CB)310: FPI(FPI), CallSiteBB(*CB.getParent()), Caller(*CallSiteBB.getParent()) {311assert(isa<CallInst>(CB) || isa<InvokeInst>(CB));312// For BBs that are likely to change, we subtract from feature totals their313// contribution. Some features, like max loop counts or depths, are left314// invalid, as they will be updated post-inlining.315SmallPtrSet<const BasicBlock *, 4> LikelyToChangeBBs;316// The CB BB will change - it'll either be split or the callee's body (single317// BB) will be pasted in.318LikelyToChangeBBs.insert(&CallSiteBB);319320// The caller's entry BB may change due to new alloca instructions.321LikelyToChangeBBs.insert(&*Caller.begin());322323// The successors may become unreachable in the case of `invoke` inlining.324// We track successors separately, too, because they form a boundary, together325// with the CB BB ('Entry') between which the inlined callee will be pasted.326Successors.insert(succ_begin(&CallSiteBB), succ_end(&CallSiteBB));327328// Inlining only handles invoke and calls. If this is an invoke, and inlining329// it pulls another invoke, the original landing pad may get split, so as to330// share its content with other potential users. So the edge up to which we331// need to invalidate and then re-account BB data is the successors of the332// current landing pad. We can leave the current lp, too - if it doesn't get333// split, then it will be the place traversal stops. Either way, the334// discounted BBs will be checked if reachable and re-added.335if (const auto *II = dyn_cast<InvokeInst>(&CB)) {336const auto *UnwindDest = II->getUnwindDest();337Successors.insert(succ_begin(UnwindDest), succ_end(UnwindDest));338}339340// Exclude the CallSiteBB, if it happens to be its own successor (1-BB loop).341// We are only interested in BBs the graph moves past the callsite BB to342// define the frontier past which we don't want to re-process BBs. Including343// the callsite BB in this case would prematurely stop the traversal in344// finish().345Successors.erase(&CallSiteBB);346347for (const auto *BB : Successors)348LikelyToChangeBBs.insert(BB);349350// Commit the change. While some of the BBs accounted for above may play dual351// role - e.g. caller's entry BB may be the same as the callsite BB - set352// insertion semantics make sure we account them once. This needs to be353// followed in `finish`, too.354for (const auto *BB : LikelyToChangeBBs)355FPI.updateForBB(*BB, -1);356}357358void FunctionPropertiesUpdater::finish(FunctionAnalysisManager &FAM) const {359// Update feature values from the BBs that were copied from the callee, or360// might have been modified because of inlining. The latter have been361// subtracted in the FunctionPropertiesUpdater ctor.362// There could be successors that were reached before but now are only363// reachable from elsewhere in the CFG.364// One example is the following diamond CFG (lines are arrows pointing down):365// A366// / \367// B C368// | |369// | D370// | |371// | E372// \ /373// F374// There's a call site in C that is inlined. Upon doing that, it turns out375// it expands to376// call void @llvm.trap()377// unreachable378// F isn't reachable from C anymore, but we did discount it when we set up379// FunctionPropertiesUpdater, so we need to re-include it here.380// At the same time, D and E were reachable before, but now are not anymore,381// so we need to leave D out (we discounted it at setup), and explicitly382// remove E.383SetVector<const BasicBlock *> Reinclude;384SetVector<const BasicBlock *> Unreachable;385const auto &DT =386FAM.getResult<DominatorTreeAnalysis>(const_cast<Function &>(Caller));387388if (&CallSiteBB != &*Caller.begin())389Reinclude.insert(&*Caller.begin());390391// Distribute the successors to the 2 buckets.392for (const auto *Succ : Successors)393if (DT.isReachableFromEntry(Succ))394Reinclude.insert(Succ);395else396Unreachable.insert(Succ);397398// For reinclusion, we want to stop at the reachable successors, who are at399// the beginning of the worklist; but, starting from the callsite bb and400// ending at those successors, we also want to perform a traversal.401// IncludeSuccessorsMark is the index after which we include successors.402const auto IncludeSuccessorsMark = Reinclude.size();403bool CSInsertion = Reinclude.insert(&CallSiteBB);404(void)CSInsertion;405assert(CSInsertion);406for (size_t I = 0; I < Reinclude.size(); ++I) {407const auto *BB = Reinclude[I];408FPI.reIncludeBB(*BB);409if (I >= IncludeSuccessorsMark)410Reinclude.insert(succ_begin(BB), succ_end(BB));411}412413// For exclusion, we don't need to exclude the set of BBs that were successors414// before and are now unreachable, because we already did that at setup. For415// the rest, as long as a successor is unreachable, we want to explicitly416// exclude it.417const auto AlreadyExcludedMark = Unreachable.size();418for (size_t I = 0; I < Unreachable.size(); ++I) {419const auto *U = Unreachable[I];420if (I >= AlreadyExcludedMark)421FPI.updateForBB(*U, -1);422for (const auto *Succ : successors(U))423if (!DT.isReachableFromEntry(Succ))424Unreachable.insert(Succ);425}426427const auto &LI = FAM.getResult<LoopAnalysis>(const_cast<Function &>(Caller));428FPI.updateAggregateStats(Caller, LI);429}430431bool FunctionPropertiesUpdater::isUpdateValid(Function &F,432const FunctionPropertiesInfo &FPI,433FunctionAnalysisManager &FAM) {434DominatorTree DT(F);435LoopInfo LI(DT);436auto Fresh = FunctionPropertiesInfo::getFunctionPropertiesInfo(F, DT, LI);437return FPI == Fresh;438}439440441