[llvm] [LLVM] Successor count added to InstCount (PR #171670)
IƱaki V Arrechea via llvm-commits
llvm-commits at lists.llvm.org
Thu Dec 18 08:59:08 PST 2025
https://github.com/InakiVA updated https://github.com/llvm/llvm-project/pull/171670
>From d8cbcdc56a918d7d584b12a6c4fb36eb65bc1d0f Mon Sep 17 00:00:00 2001
From: Inaki Arrechea <inakiarrechea at google.com>
Date: Wed, 17 Dec 2025 19:16:24 +0000
Subject: [PATCH] Pass implementation of Function Properties Analysis - stats
---
.../Analysis/FunctionPropertiesAnalysis.h | 11 ++++
.../Analysis/FunctionPropertiesAnalysis.cpp | 51 ++++++++++++++++++-
llvm/lib/Passes/PassBuilderPipelines.cpp | 24 +++++----
llvm/lib/Passes/PassRegistry.def | 45 ++++++++++------
llvm/test/Other/instcount.ll | 33 ++++++------
5 files changed, 119 insertions(+), 45 deletions(-)
diff --git a/llvm/include/llvm/Analysis/FunctionPropertiesAnalysis.h b/llvm/include/llvm/Analysis/FunctionPropertiesAnalysis.h
index 3dc241c0124e4..a2923f74805da 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<FunctionPropertiesStatisticsPass> {
+ PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
+};
+
/// 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/lib/Analysis/FunctionPropertiesAnalysis.cpp b/llvm/lib/Analysis/FunctionPropertiesAnalysis.cpp
index c52a6de2bb71e..9f7bf6b6387d2 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,19 @@
using namespace llvm;
+#define DEBUG_TYPE "statscount"
+
+STATISTIC(TotalBlocks, "Number of basic blocks");
+STATISTIC(TotalInsts, "Number of instructions (of all types)");
+STATISTIC(TotalSuccs, "Number of basic block successors");
+STATISTIC(TotalUncondBranchInsts,
+ "Number of unconditional branch instructions");
+STATISTIC(TotalCondBranchInsts, "Number of conditional branch instructions");
+STATISTIC(TotalBranchInsts, "Number of branch instructions");
+STATISTIC(TotalBranchSuccs, "Number of branch successors");
+STATISTIC(TotalSwitchInsts, "Number of switch instructions");
+STATISTIC(TotalSwitchSuccs, "Number of switch successors");
+
namespace llvm {
LLVM_ABI cl::opt<bool> EnableDetailedFunctionProperties(
"enable-detailed-function-properties", cl::Hidden, cl::init(false),
@@ -124,9 +138,19 @@ void FunctionPropertiesInfo::updateForBB(const BasicBlock &BB,
ControlFlowEdgeCount += Direction * SuccessorCount;
- if (const auto *BI = dyn_cast<BranchInst>(BB.getTerminator())) {
- if (!BI->isConditional())
+ const Instruction *TI = BB.getTerminator();
+ const int64_t InstructionSuccessorCount = TI->getNumSuccessors();
+ if (isa<BranchInst>(TI)) {
+ BranchInstructionCount += Direction;
+ BranchSuccessorCount += Direction * InstructionSuccessorCount;
+ const auto *BI = dyn_cast<BranchInst>(TI);
+ if (BI->isConditional())
+ ConditionalBranchCount += Direction;
+ else
UnconditionalBranchCount += Direction;
+ } else if (isa<SwitchInst>(TI)) {
+ SwitchInstructionCount += Direction;
+ SwitchSuccessorCount += Direction * InstructionSuccessorCount;
}
for (const Instruction &I : BB.instructionsWithoutDebug()) {
@@ -362,6 +386,11 @@ void FunctionPropertiesInfo::print(raw_ostream &OS) const {
PRINT_PROPERTY(CriticalEdgeCount)
PRINT_PROPERTY(ControlFlowEdgeCount)
PRINT_PROPERTY(UnconditionalBranchCount)
+ PRINT_PROPERTY(ConditionalBranchCount)
+ PRINT_PROPERTY(BranchInstructionCount)
+ PRINT_PROPERTY(BranchSuccessorCount)
+ PRINT_PROPERTY(SwitchInstructionCount)
+ PRINT_PROPERTY(SwitchSuccessorCount)
PRINT_PROPERTY(IntrinsicCount)
PRINT_PROPERTY(DirectCallCount)
PRINT_PROPERTY(IndirectCallCount)
@@ -396,6 +425,24 @@ FunctionPropertiesPrinterPass::run(Function &F, FunctionAnalysisManager &AM) {
return PreservedAnalyses::all();
}
+PreservedAnalyses
+FunctionPropertiesStatisticsPass::run(Function &F,
+ FunctionAnalysisManager &AM) {
+ LLVM_DEBUG(dbgs() << "STATSCOUNT: running on function " << F.getName()
+ << "\n");
+ auto AnalysisResults = AM.getResult<FunctionPropertiesAnalysis>(F);
+ TotalBlocks += AnalysisResults.BasicBlockCount;
+ TotalInsts += AnalysisResults.TotalInstructionCount;
+ TotalSuccs += AnalysisResults.ControlFlowEdgeCount;
+ TotalUncondBranchInsts += AnalysisResults.UnconditionalBranchCount;
+ TotalCondBranchInsts += AnalysisResults.ConditionalBranchCount;
+ TotalBranchInsts += AnalysisResults.BranchInstructionCount;
+ TotalBranchSuccs += AnalysisResults.BranchSuccessorCount;
+ TotalSwitchInsts += AnalysisResults.SwitchInstructionCount;
+ TotalSwitchSuccs += AnalysisResults.SwitchSuccessorCount;
+ 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..16fa233c6a727 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"
@@ -30,6 +31,7 @@
#include "llvm/Passes/OptimizationLevel.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/PGOOptions.h"
#include "llvm/Support/VirtualFileSystem.h"
@@ -191,9 +193,9 @@ static cl::opt<bool> EnablePostPGOLoopRotation(
"enable-post-pgo-loop-rotation", cl::init(true), cl::Hidden,
cl::desc("Run the loop rotation transformation after PGO instrumentation"));
-static cl::opt<bool> EnableGlobalAnalyses(
- "enable-global-analyses", cl::init(true), cl::Hidden,
- cl::desc("Enable inter-procedural analyses"));
+static cl::opt<bool>
+ EnableGlobalAnalyses("enable-global-analyses", cl::init(true), cl::Hidden,
+ cl::desc("Enable inter-procedural analyses"));
static cl::opt<bool> RunPartialInlining("enable-partial-inlining",
cl::init(false), cl::Hidden,
@@ -413,8 +415,11 @@ void PassBuilder::invokePipelineEarlySimplificationEPCallbacks(
static void addAnnotationRemarksPass(ModulePassManager &MPM) {
MPM.addPass(createModuleToFunctionPassAdaptor(AnnotationRemarksPass()));
// Count the types of instructions used
- if (AreStatisticsEnabled())
- MPM.addPass(createModuleToFunctionPassAdaptor(InstCountPass()));
+ if (AreStatisticsEnabled()) {
+ // MPM.addPass(createModuleToFunctionPassAdaptor(InstCountPass()));
+ MPM.addPass(
+ createModuleToFunctionPassAdaptor(FunctionPropertiesStatisticsPass()));
+ }
}
// Helper to check if the current compilation phase is preparing for LTO
@@ -1181,11 +1186,10 @@ PassBuilder::buildModuleSimplificationPipeline(OptimizationLevel Level,
// and prior to optimizing globals.
// FIXME: This position in the pipeline hasn't been carefully considered in
// years, it should be re-analyzed.
- MPM.addPass(IPSCCPPass(
- IPSCCPOptions(/*AllowFuncSpec=*/
- Level != OptimizationLevel::Os &&
- Level != OptimizationLevel::Oz &&
- !isLTOPreLink(Phase))));
+ MPM.addPass(IPSCCPPass(IPSCCPOptions(/*AllowFuncSpec=*/
+ Level != OptimizationLevel::Os &&
+ Level != OptimizationLevel::Oz &&
+ !isLTOPreLink(Phase))));
// Attach metadata to indirect call sites indicating the set of functions
// they may target at run-time. This should follow IPSCCP.
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index cf998f29ef38c..ce5436a5417fd 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -257,25 +257,29 @@ MODULE_PASS_WITH_PARAMS(
parseStructuralHashPrinterPassOptions, "detailed;call-target-ignored")
MODULE_PASS_WITH_PARAMS(
- "default", "", [&](OptimizationLevel L) {
+ "default", "",
+ [&](OptimizationLevel L) {
setupOptionsForPipelineAlias(PTO, L);
return buildPerModuleDefaultPipeline(L);
},
parseOptLevelParam, "O0;O1;O2;O3;Os;Oz")
MODULE_PASS_WITH_PARAMS(
- "thinlto-pre-link", "", [&](OptimizationLevel L) {
+ "thinlto-pre-link", "",
+ [&](OptimizationLevel L) {
setupOptionsForPipelineAlias(PTO, L);
return buildThinLTOPreLinkDefaultPipeline(L);
},
parseOptLevelParam, "O0;O1;O2;O3;Os;Oz")
MODULE_PASS_WITH_PARAMS(
- "thinlto", "", [&](OptimizationLevel L) {
+ "thinlto", "",
+ [&](OptimizationLevel L) {
setupOptionsForPipelineAlias(PTO, L);
return buildThinLTODefaultPipeline(L, nullptr);
},
parseOptLevelParam, "O0;O1;O2;O3;Os;Oz")
MODULE_PASS_WITH_PARAMS(
- "lto-pre-link", "", [&](OptimizationLevel L) {
+ "lto-pre-link", "",
+ [&](OptimizationLevel L) {
setupOptionsForPipelineAlias(PTO, L);
if (PTO.UnifiedLTO) {
// When UnifiedLTO is enabled, use the ThinLTO pre-link pipeline. This
@@ -287,13 +291,15 @@ MODULE_PASS_WITH_PARAMS(
},
parseOptLevelParam, "O0;O1;O2;O3;Os;Oz")
MODULE_PASS_WITH_PARAMS(
- "lto", "", [&](OptimizationLevel L) {
+ "lto", "",
+ [&](OptimizationLevel L) {
setupOptionsForPipelineAlias(PTO, L);
return buildLTODefaultPipeline(L, nullptr);
},
parseOptLevelParam, "O0;O1;O2;O3;Os;Oz")
MODULE_PASS_WITH_PARAMS(
- "fatlto-pre-link", "", [&](FatLTOOptions Opts) {
+ "fatlto-pre-link", "",
+ [&](FatLTOOptions Opts) {
setupOptionsForPipelineAlias(PTO, Opts.OptLevel);
return buildFatLTODefaultPipeline(Opts.OptLevel, Opts.ThinLTO,
Opts.EmitSummary);
@@ -543,6 +549,7 @@ FUNCTION_PASS("sjlj-eh-prepare", SjLjEHPreparePass(TM))
FUNCTION_PASS("slp-vectorizer", SLPVectorizerPass())
FUNCTION_PASS("slsr", StraightLineStrengthReducePass())
FUNCTION_PASS("stack-protector", StackProtectorPass(*TM))
+FUNCTION_PASS("statscount", FunctionPropertiesStatisticsPass())
FUNCTION_PASS("strip-gc-relocates", StripGCRelocates())
FUNCTION_PASS("tailcallelim", TailCallElimPass())
FUNCTION_PASS("transform-warning", WarnMissedTransformationsPass())
@@ -583,7 +590,9 @@ FUNCTION_PASS_WITH_PARAMS(
parseEarlyCSEPassOptions, "memssa")
FUNCTION_PASS_WITH_PARAMS(
"drop-unnecessary-assumes", "DropUnnecessaryAssumesPass",
- [](bool DropDereferenceable) { return DropUnnecessaryAssumesPass(DropDereferenceable); },
+ [](bool DropDereferenceable) {
+ return DropUnnecessaryAssumesPass(DropDereferenceable);
+ },
parseDropUnnecessaryAssumesPassOptions, "drop-deref")
FUNCTION_PASS_WITH_PARAMS(
"ee-instrument", "EntryExitInstrumenterPass",
@@ -731,9 +740,7 @@ FUNCTION_PASS_WITH_PARAMS(
"trap;rt;rt-abort;min-rt;min-rt-abort;merge;guard=N")
FUNCTION_PASS_WITH_PARAMS(
"expand-fp", "ExpandFpPass",
- [TM = TM](CodeGenOptLevel OL) {
- return ExpandFpPass(*TM, OL);
- },
+ [TM = TM](CodeGenOptLevel OL) { return ExpandFpPass(*TM, OL); },
parseExpandFpOptions, "O0;O1;O2;O3")
#undef FUNCTION_PASS_WITH_PARAMS
@@ -821,27 +828,33 @@ MODULE_CALLBACK("pipeline-start-callbacks", invokePipelineStartEPCallbacks)
// There are some full lto specific ones that are ignored here for now
#ifdef MODULE_LTO_CALLBACK
-MODULE_LTO_CALLBACK("pipeline-early-simplification-callbacks", invokePipelineEarlySimplificationEPCallbacks)
-MODULE_LTO_CALLBACK("optimizer-early-callbacks", invokeOptimizerEarlyEPCallbacks)
+MODULE_LTO_CALLBACK("pipeline-early-simplification-callbacks",
+ invokePipelineEarlySimplificationEPCallbacks)
+MODULE_LTO_CALLBACK("optimizer-early-callbacks",
+ invokeOptimizerEarlyEPCallbacks)
MODULE_LTO_CALLBACK("optimizer-last-callbacks", invokeOptimizerLastEPCallbacks)
#endif
#undef MODULE_LTO_CALLBACK
#ifdef FUNCTION_CALLBACK
FUNCTION_CALLBACK("peephole-callbacks", invokePeepholeEPCallbacks)
-FUNCTION_CALLBACK("scalar-optimizer-late-callbacks", invokeScalarOptimizerLateEPCallbacks)
-FUNCTION_CALLBACK("vectorizer-start-callbacks", invokeVectorizerStartEPCallbacks)
+FUNCTION_CALLBACK("scalar-optimizer-late-callbacks",
+ invokeScalarOptimizerLateEPCallbacks)
+FUNCTION_CALLBACK("vectorizer-start-callbacks",
+ invokeVectorizerStartEPCallbacks)
FUNCTION_CALLBACK("vectorizer-end-callbacks", invokeVectorizerEndEPCallbacks)
#endif
#undef FUNCTION_CALLBACK
#ifdef CGSCC_CALLBACK
-CGSCC_CALLBACK("cgscc-optimizer-late-callbacks", invokeCGSCCOptimizerLateEPCallbacks)
+CGSCC_CALLBACK("cgscc-optimizer-late-callbacks",
+ invokeCGSCCOptimizerLateEPCallbacks)
#endif
#undef CGSCC_CALLBACK
#ifdef LOOP_CALLBACK
-LOOP_CALLBACK("late-loop-optimizations-callbacks", invokeLateLoopOptimizationsEPCallbacks)
+LOOP_CALLBACK("late-loop-optimizations-callbacks",
+ invokeLateLoopOptimizationsEPCallbacks)
LOOP_CALLBACK("loop-optimizer-end-callbacks", invokeLoopOptimizerEndEPCallbacks)
#endif
#undef LOOP_CALLBACK
diff --git a/llvm/test/Other/instcount.ll b/llvm/test/Other/instcount.ll
index 931d547371958..2a8c196445e34 100644
--- a/llvm/test/Other/instcount.ll
+++ b/llvm/test/Other/instcount.ll
@@ -1,21 +1,20 @@
-; REQUIRES: asserts
-; RUN: opt -stats -passes=instcount -disable-output < %s 2>&1 | FileCheck %s
-; RUN: opt -stats -passes='thinlto<O3>' -disable-output < %s 2>&1 | FileCheck %s
-; RUN: opt -stats -passes='thinlto-pre-link<O2>' -disable-output < %s 2>&1 | FileCheck %s
-; RUN: opt -stats -passes='lto<O1>' -disable-output < %s 2>&1 | FileCheck %s
-; RUN: opt -stats -passes='lto-pre-link<Os>' -disable-output < %s 2>&1 | FileCheck %s
-; RUN: opt -stats -O3 -disable-output < %s 2>&1 | FileCheck %s
-; RUN: opt -stats -O0 -disable-output < %s 2>&1 | FileCheck %s
-
-; CHECK-DAG: 8 instcount - Number of Br insts
-; CHECK-DAG: 6 instcount - Number of Call insts
-; CHECK-DAG: 2 instcount - Number of ICmp insts
-; CHECK-DAG: 1 instcount - Number of Ret insts
-; CHECK-DAG: 1 instcount - Number of Switch insts
-; CHECK-DAG: 10 instcount - Number of basic blocks
-; CHECK-DAG: 1 instcount - Number of non-external functions
-; CHECK-DAG: 18 instcount - Number of instructions (of all types)
+; REQUIRES asserts
+; RUN: opt -stats -enable-detailed-function-properties -disable-output -passes=statscount < %s 2>&1 | FileCheck %s
+; RUN: opt -stats -enable-detailed-function-properties -disable-output -passes='thinlto<O3>'< %s 2>&1 | FileCheck %s
+; RUN: opt -stats -enable-detailed-function-properties -disable-output -passes='thinlto-pre-link<O2>' < %s 2>&1 | FileCheck %s
+; RUN: opt -stats -enable-detailed-function-properties -disable-output -passes='lto<O1>' < %s 2>&1 | FileCheck %s
+; RUN: opt -stats -enable-detailed-function-properties -disable-output -passes='default<O3>' < %s 2>&1 | FileCheck %s
+; RUN: opt -stats -enable-detailed-function-properties -disable-output -passes='default<O0>' < %s 2>&1 | FileCheck %s
+; CHECK-DAG: 10 statscount - Number of basic blocks
+; CHECK-DAG: 8 statscount - Number of branch instructions
+; CHECK-DAG: 10 statscount - Number of branch successors
+; CHECK-DAG: 2 statscount - Number of conditional branch instructions
+; CHECK-DAG: 18 statscount - Number of instructions (of all types)
+; CHECK-DAG: 14 statscount - Number of basic block successors
+; CHECK-DAG: 1 statscount - Number of switch instructions
+; CHECK-DAG: 4 statscount - Number of switch successors
+; CHECK-DAG: 6 statscount - Number of unconditional branch instructions
define void @foo(i32 %i, i32 %j, i32 %n) {
entry:
More information about the llvm-commits
mailing list