diff --git a/llvm/include/llvm/Analysis/FunctionPropertiesAnalysis.h b/llvm/include/llvm/Analysis/FunctionPropertiesAnalysis.h index 3dc241c0124e4..1619671d8f7dc 100644 --- a/llvm/include/llvm/Analysis/FunctionPropertiesAnalysis.h +++ b/llvm/include/llvm/Analysis/FunctionPropertiesAnalysis.h @@ -127,6 +127,11 @@ class FunctionPropertiesInfo { int64_t CriticalEdgeCount = 0; int64_t ControlFlowEdgeCount = 0; int64_t UnconditionalBranchCount = 0; + int64_t ConditionalBranchCount = 0; + int64_t BranchInstructionCount = 0; + int64_t BranchSuccessorCount = 0; + int64_t SwitchInstructionCount = 0; + int64_t SwitchSuccessorCount = 0; // Call related instructions int64_t IntrinsicCount = 0; @@ -179,6 +184,12 @@ class FunctionPropertiesPrinterPass static bool isRequired() { return true; } }; +/// Statistics pass for the FunctionPropertiesAnalysis results. +struct FunctionPropertiesStatisticsPass + : PassInfoMixin { + PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM); +}; + /// Correctly update FunctionPropertiesInfo post-inlining. A /// FunctionPropertiesUpdater keeps the state necessary for tracking the changes /// llvm::InlineFunction makes. The idea is that inlining will at most modify diff --git a/llvm/include/llvm/IR/FunctionProperties.def b/llvm/include/llvm/IR/FunctionProperties.def new file mode 100644 index 0000000000000..a212af4859877 --- /dev/null +++ b/llvm/include/llvm/IR/FunctionProperties.def @@ -0,0 +1,105 @@ +//===-- llvm/FunctionProperties.def - File that describes Function Properties +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains descriptions of the various LLVM function properties. This +// is used as a central place for enumerating the different function properties +// and should eventually be the place to put comments about the function +// properties. +// +//===----------------------------------------------------------------------===// + +// NOTE: NO INCLUDE GUARD DESIRED! + +// Provide definitions of macros so that users of this file do not have to +// define everything to use it. +// + +// Basic/Standard Properties +#ifndef FUNCTION_PROPERTY +#define FUNCTION_PROPERTY(Name, Description) +#endif + +// Detailed Properties (only processed if DETAILED_FUNCTION_PROPERTY is defined) +#ifndef DETAILED_FUNCTION_PROPERTY +#define DETAILED_FUNCTION_PROPERTY(Name, Description) +#endif + +FUNCTION_PROPERTY(BasicBlockCount, "Number of basic blocks") +FUNCTION_PROPERTY(BlocksReachedFromConditionalInstruction, + "Number of blocks reached from a conditional instruction, or " + "that are 'cases' of a SwitchInstr") +FUNCTION_PROPERTY(Uses, "Number of uses of this function, plus 1 if the " + "function is callable outside the module") +FUNCTION_PROPERTY(DirectCallsToDefinedFunctions, + "Number of direct calls made from this function to other " + "functions defined in this module") +FUNCTION_PROPERTY(LoadInstCount, "Load Instruction Count") +FUNCTION_PROPERTY(StoreInstCount, "Store Instruction Count") +FUNCTION_PROPERTY(MaxLoopDepth, "Maximum Loop Depth in the Function") +FUNCTION_PROPERTY(TopLevelLoopCount, + "Number of Top Level Loops in the Function") +FUNCTION_PROPERTY(TotalInstructionCount, + "Number of instructions (of all types)") +DETAILED_FUNCTION_PROPERTY(BasicBlocksWithSingleSuccessor, + "Basic blocks with one successors") +DETAILED_FUNCTION_PROPERTY(BasicBlocksWithTwoSuccessors, + "Basic blocks with two successors") +DETAILED_FUNCTION_PROPERTY(BasicBlocksWithMoreThanTwoSuccessors, + "Basic blocks with more than two successors") +DETAILED_FUNCTION_PROPERTY(BasicBlocksWithSinglePredecessor, + "Basic blocks with one predecessors") +DETAILED_FUNCTION_PROPERTY(BasicBlocksWithTwoPredecessors, + "Basic blocks with two predecessors") +DETAILED_FUNCTION_PROPERTY(BasicBlocksWithMoreThanTwoPredecessors, + "Basic blocks with more than two predecessors") +DETAILED_FUNCTION_PROPERTY(BigBasicBlocks, "Number of big basic blocks") +DETAILED_FUNCTION_PROPERTY(MediumBasicBlocks, "Number of medium basic blocks") +DETAILED_FUNCTION_PROPERTY(SmallBasicBlocks, "Number of small basic blocks") +DETAILED_FUNCTION_PROPERTY(CastInstructionCount, + "The number of cast instructions inside the function") +DETAILED_FUNCTION_PROPERTY( + FloatingPointInstructionCount, + "The number of floating point instructions inside the function") +DETAILED_FUNCTION_PROPERTY(IntegerInstructionCount, + "The number of integer instructions inside the function") +DETAILED_FUNCTION_PROPERTY(ConstantIntOperandCount, "Constant Int Operand Count") +DETAILED_FUNCTION_PROPERTY(ConstantFPOperandCount, "Constant FP Operand Count") +DETAILED_FUNCTION_PROPERTY(ConstantOperandCount, "Constant Operand Count") +DETAILED_FUNCTION_PROPERTY(InstructionOperandCount, "Instruction Operand Count") +DETAILED_FUNCTION_PROPERTY(BasicBlockOperandCount, "Basic Block Operand Count") +DETAILED_FUNCTION_PROPERTY(GlobalValueOperandCount, "Global Value Operand Count") +DETAILED_FUNCTION_PROPERTY(InlineAsmOperandCount, "Inline Asm Operand Count") +DETAILED_FUNCTION_PROPERTY(ArgumentOperandCount, "Argument Operand Count") +DETAILED_FUNCTION_PROPERTY(UnknownOperandCount, "Unknown Operand Count") +DETAILED_FUNCTION_PROPERTY(CriticalEdgeCount, "Critical Edge Count") +DETAILED_FUNCTION_PROPERTY(ControlFlowEdgeCount, "Number of basic block successors") +DETAILED_FUNCTION_PROPERTY(UnconditionalBranchCount, + "Number of unconditional branch instructions") +DETAILED_FUNCTION_PROPERTY(ConditionalBranchCount, + "Number of conditional branch instructions") +DETAILED_FUNCTION_PROPERTY(BranchInstructionCount, "Number of branch instructions") +DETAILED_FUNCTION_PROPERTY(BranchSuccessorCount, "Number of branch successors") +DETAILED_FUNCTION_PROPERTY(SwitchInstructionCount, "Number of switch instructions") +DETAILED_FUNCTION_PROPERTY(SwitchSuccessorCount, "Number of switch successors") +DETAILED_FUNCTION_PROPERTY(IntrinsicCount, "Intrinsic Count") +DETAILED_FUNCTION_PROPERTY(DirectCallCount, "Direct Call Count") +DETAILED_FUNCTION_PROPERTY(IndirectCallCount, "Indirect Call Count") +DETAILED_FUNCTION_PROPERTY(CallReturnsIntegerCount, "Call Returns Integer Count") +DETAILED_FUNCTION_PROPERTY(CallReturnsFloatCount, "Call Returns Float Count") +DETAILED_FUNCTION_PROPERTY(CallReturnsPointerCount, "Call Returns Pointer Count") +DETAILED_FUNCTION_PROPERTY(CallReturnsVectorIntCount, "Call Returns Vector Int Count") +DETAILED_FUNCTION_PROPERTY(CallReturnsVectorFloatCount, + "Call Returns Vector Float Count") +DETAILED_FUNCTION_PROPERTY(CallReturnsVectorPointerCount, + "Call Returns Vector Pointer Count") +DETAILED_FUNCTION_PROPERTY(CallWithManyArgumentsCount, "Call With Many Arguments Count") +DETAILED_FUNCTION_PROPERTY(CallWithPointerArgumentCount, + "Call With Pointer Argument Count") + +#undef FUNCTION_PROPERTY +#undef DETAILED_FUNCTION_PROPERTY diff --git a/llvm/lib/Analysis/FunctionPropertiesAnalysis.cpp b/llvm/lib/Analysis/FunctionPropertiesAnalysis.cpp index c52a6de2bb71e..1f6792dfe30ec 100644 --- a/llvm/lib/Analysis/FunctionPropertiesAnalysis.cpp +++ b/llvm/lib/Analysis/FunctionPropertiesAnalysis.cpp @@ -14,6 +14,7 @@ #include "llvm/Analysis/FunctionPropertiesAnalysis.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SetVector.h" +#include "llvm/ADT/Statistic.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/IR/CFG.h" #include "llvm/IR/Constants.h" @@ -26,6 +27,14 @@ using namespace llvm; +#define DEBUG_TYPE "func-properties-stats" + +#define FUNCTION_PROPERTY(Name, Description) \ + STATISTIC(Total##Name, Description); +#define DETAILED_FUNCTION_PROPERTY(Name, Description) \ + STATISTIC(Total##Name, Description); +#include "llvm/IR/FunctionProperties.def" + namespace llvm { LLVM_ABI cl::opt EnableDetailedFunctionProperties( "enable-detailed-function-properties", cl::Hidden, cl::init(false), @@ -124,9 +133,19 @@ void FunctionPropertiesInfo::updateForBB(const BasicBlock &BB, ControlFlowEdgeCount += Direction * SuccessorCount; - if (const auto *BI = dyn_cast(BB.getTerminator())) { - if (!BI->isConditional()) + const Instruction *TI = BB.getTerminator(); + const int64_t InstructionSuccessorCount = TI->getNumSuccessors(); + if (isa(TI)) { + BranchInstructionCount += Direction; + BranchSuccessorCount += Direction * InstructionSuccessorCount; + const auto *BI = dyn_cast(TI); + if (BI->isConditional()) + ConditionalBranchCount += Direction; + else UnconditionalBranchCount += Direction; + } else if (isa(TI)) { + SwitchInstructionCount += Direction; + SwitchSuccessorCount += Direction * InstructionSuccessorCount; } for (const Instruction &I : BB.instructionsWithoutDebug()) { @@ -325,57 +344,17 @@ bool FunctionPropertiesInfo::operator==( } void FunctionPropertiesInfo::print(raw_ostream &OS) const { -#define PRINT_PROPERTY(PROP_NAME) OS << #PROP_NAME ": " << PROP_NAME << "\n"; - - PRINT_PROPERTY(BasicBlockCount) - PRINT_PROPERTY(BlocksReachedFromConditionalInstruction) - PRINT_PROPERTY(Uses) - PRINT_PROPERTY(DirectCallsToDefinedFunctions) - PRINT_PROPERTY(LoadInstCount) - PRINT_PROPERTY(StoreInstCount) - PRINT_PROPERTY(MaxLoopDepth) - PRINT_PROPERTY(TopLevelLoopCount) - PRINT_PROPERTY(TotalInstructionCount) +#define FUNCTION_PROPERTY(Name, Description) OS << #Name ": " << Name << "\n"; - if (EnableDetailedFunctionProperties) { - PRINT_PROPERTY(BasicBlocksWithSingleSuccessor) - PRINT_PROPERTY(BasicBlocksWithTwoSuccessors) - PRINT_PROPERTY(BasicBlocksWithMoreThanTwoSuccessors) - PRINT_PROPERTY(BasicBlocksWithSinglePredecessor) - PRINT_PROPERTY(BasicBlocksWithTwoPredecessors) - PRINT_PROPERTY(BasicBlocksWithMoreThanTwoPredecessors) - PRINT_PROPERTY(BigBasicBlocks) - PRINT_PROPERTY(MediumBasicBlocks) - PRINT_PROPERTY(SmallBasicBlocks) - PRINT_PROPERTY(CastInstructionCount) - PRINT_PROPERTY(FloatingPointInstructionCount) - PRINT_PROPERTY(IntegerInstructionCount) - PRINT_PROPERTY(ConstantIntOperandCount) - PRINT_PROPERTY(ConstantFPOperandCount) - PRINT_PROPERTY(ConstantOperandCount) - PRINT_PROPERTY(InstructionOperandCount) - PRINT_PROPERTY(BasicBlockOperandCount) - PRINT_PROPERTY(GlobalValueOperandCount) - PRINT_PROPERTY(InlineAsmOperandCount) - PRINT_PROPERTY(ArgumentOperandCount) - PRINT_PROPERTY(UnknownOperandCount) - PRINT_PROPERTY(CriticalEdgeCount) - PRINT_PROPERTY(ControlFlowEdgeCount) - PRINT_PROPERTY(UnconditionalBranchCount) - PRINT_PROPERTY(IntrinsicCount) - PRINT_PROPERTY(DirectCallCount) - PRINT_PROPERTY(IndirectCallCount) - PRINT_PROPERTY(CallReturnsIntegerCount) - PRINT_PROPERTY(CallReturnsFloatCount) - PRINT_PROPERTY(CallReturnsPointerCount) - PRINT_PROPERTY(CallReturnsVectorIntCount) - PRINT_PROPERTY(CallReturnsVectorFloatCount) - PRINT_PROPERTY(CallReturnsVectorPointerCount) - PRINT_PROPERTY(CallWithManyArgumentsCount) - PRINT_PROPERTY(CallWithPointerArgumentCount) +#define DETAILED_FUNCTION_PROPERTY(Name, Description) \ + if (EnableDetailedFunctionProperties) { \ + OS << #Name ": " << Name << "\n"; \ } -#undef PRINT_PROPERTY +#include "llvm/IR/FunctionProperties.def" + +#undef FUNCTION_PROPERTY +#undef DETAILED_FUNCTION_PROPERTY OS << "\n"; } @@ -396,6 +375,22 @@ FunctionPropertiesPrinterPass::run(Function &F, FunctionAnalysisManager &AM) { return PreservedAnalyses::all(); } +PreservedAnalyses +FunctionPropertiesStatisticsPass::run(Function &F, + FunctionAnalysisManager &FAM) { + LLVM_DEBUG(dbgs() << "STATSCOUNT: running on function " << F.getName() + << "\n"); + auto &AnalysisResults = FAM.getResult(F); + +#define FUNCTION_PROPERTY(Name, Description) \ + Total##Name += AnalysisResults.Name; +#define DETAILED_FUNCTION_PROPERTY(Name, Description) \ + Total##Name += AnalysisResults.Name; +#include "llvm/IR/FunctionProperties.def" + + return PreservedAnalyses::all(); +} + FunctionPropertiesUpdater::FunctionPropertiesUpdater( FunctionPropertiesInfo &FPI, CallBase &CB) : FPI(FPI), CallSiteBB(*CB.getParent()), Caller(*CallSiteBB.getParent()) { diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp index 67b9a61cc576f..555d96838d758 100644 --- a/llvm/lib/Passes/PassBuilderPipelines.cpp +++ b/llvm/lib/Passes/PassBuilderPipelines.cpp @@ -19,6 +19,7 @@ #include "llvm/Analysis/BasicAliasAnalysis.h" #include "llvm/Analysis/CGSCCPassManager.h" #include "llvm/Analysis/CtxProfAnalysis.h" +#include "llvm/Analysis/FunctionPropertiesAnalysis.h" #include "llvm/Analysis/GlobalsModRef.h" #include "llvm/Analysis/InlineAdvisor.h" #include "llvm/Analysis/InstCount.h" @@ -412,9 +413,12 @@ void PassBuilder::invokePipelineEarlySimplificationEPCallbacks( // Helper to add AnnotationRemarksPass. static void addAnnotationRemarksPass(ModulePassManager &MPM) { MPM.addPass(createModuleToFunctionPassAdaptor(AnnotationRemarksPass())); - // Count the types of instructions used - if (AreStatisticsEnabled()) + // Count the stats for InstCount and FunctionPropertiesAnalysis + if (AreStatisticsEnabled()) { MPM.addPass(createModuleToFunctionPassAdaptor(InstCountPass())); + MPM.addPass( + createModuleToFunctionPassAdaptor(FunctionPropertiesStatisticsPass())); + } } // Helper to check if the current compilation phase is preparing for LTO diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def index daf6b3d6dbd28..2cfb5b2592601 100644 --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -441,6 +441,7 @@ FUNCTION_PASS("fix-irreducible", FixIrreduciblePass()) FUNCTION_PASS("flatten-cfg", FlattenCFGPass()) FUNCTION_PASS("float2int", Float2IntPass()) FUNCTION_PASS("free-machine-function", FreeMachineFunctionPass()) +FUNCTION_PASS("func-properties-stats", FunctionPropertiesStatisticsPass()) FUNCTION_PASS("gc-lowering", GCLoweringPass()) FUNCTION_PASS("guard-widening", GuardWideningPass()) FUNCTION_PASS("gvn-hoist", GVNHoistPass()) diff --git a/llvm/test/Other/functionpropertiesanalysis.ll b/llvm/test/Other/functionpropertiesanalysis.ll new file mode 100644 index 0000000000000..06da908d63974 --- /dev/null +++ b/llvm/test/Other/functionpropertiesanalysis.ll @@ -0,0 +1,70 @@ +; Testing with all of the below run lines that the pass gets added to the appropriate pipelines +; REQUIRES: asserts +; RUN: opt -stats -enable-detailed-function-properties -disable-output -passes=func-properties-stats < %s 2>&1 | FileCheck %s +; RUN: opt -stats -enable-detailed-function-properties -disable-output -passes='thinlto'< %s 2>&1 | FileCheck %s +; RUN: opt -stats -enable-detailed-function-properties -disable-output -passes='thinlto-pre-link' < %s 2>&1 | FileCheck %s +; RUN: opt -stats -enable-detailed-function-properties -disable-output -passes='lto' < %s 2>&1 | FileCheck %s +; RUN: opt -stats -enable-detailed-function-properties -disable-output -O3 < %s 2>&1 | FileCheck %s +; RUN: opt -stats -enable-detailed-function-properties -disable-output -O0 < %s 2>&1 | FileCheck %s + +; CHECK-DAG: 10 func-properties-stats - Number of basic blocks +; CHECK-DAG: 8 func-properties-stats - Number of branch instructions +; CHECK-DAG: 10 func-properties-stats - Number of branch successors +; CHECK-DAG: 2 func-properties-stats - Number of conditional branch instructions +; CHECK-DAG: 6 func-properties-stats - Number of unconditional branch instructions +; CHECK-DAG: 18 func-properties-stats - Number of instructions (of all types) +; CHECK-DAG: 14 func-properties-stats - Number of basic block successors +; CHECK-DAG: 1 func-properties-stats - Number of switch instructions +; CHECK-DAG: 4 func-properties-stats - Number of switch successors + + +define void @foo(i32 %i, i32 %j, i32 %n) { +entry: + %cmp = icmp slt i32 %i, %j + br i1 %cmp, label %if.then, label %if.end + +if.then: + call void @f() + br label %if.end + +if.end: + switch i32 %i, label %sw.default [ + i32 1, label %sw.bb + i32 2, label %sw.bb1 + i32 3, label %sw.bb1 + ] + +sw.bb: + call void @g() + br label %sw.epilog + +sw.bb1: + call void @h() + br label %sw.epilog + +sw.default: + call void @k() + br label %sw.epilog + +sw.epilog: + %cmp2 = icmp sgt i32 %i, %n + br i1 %cmp2, label %if.then3, label %if.else + +if.then3: + call void @l() + br label %if.end4 + +if.else: + call void @m() + br label %if.end4 + +if.end4: + ret void +} + +declare void @f() +declare void @g() +declare void @h() +declare void @k() +declare void @l() +declare void @m()