diff --git a/llvm/include/llvm/Transforms/Utils/CountInstructions.h b/llvm/include/llvm/Transforms/Utils/CountInstructions.h new file mode 100644 index 0000000000000..d22c050e9fd81 --- /dev/null +++ b/llvm/include/llvm/Transforms/Utils/CountInstructions.h @@ -0,0 +1,29 @@ +//===- CountInstructions.h --------------------------------------------*- C++ +//-*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_UTILS_COUNTINSTRUCTIONS_H +#define LLVM_TRANSFORMS_UTILS_COUNTINSTRUCTIONS_H + +#include "llvm/ADT/StringMap.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +class Function; + +struct CountInstructionsPass : PassInfoMixin { + PreservedAnalyses run(Function &F, FunctionAnalysisManager &); + +private: + StringMap Counts; +}; + +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_UTILS_COUNTINSTRUCTIONS_H \ No newline at end of file diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp index f5281ea69b512..243d495089065 100644 --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -347,6 +347,7 @@ #include "llvm/Transforms/Utils/BreakCriticalEdges.h" #include "llvm/Transforms/Utils/CanonicalizeAliases.h" #include "llvm/Transforms/Utils/CanonicalizeFreezeInLoops.h" +#include "llvm/Transforms/Utils/CountInstructions.h" #include "llvm/Transforms/Utils/CountVisits.h" #include "llvm/Transforms/Utils/DXILUpgrade.h" #include "llvm/Transforms/Utils/Debugify.h" diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp index 4de527d9ef85e..6e65e347a8af7 100644 --- a/llvm/lib/Passes/PassBuilderPipelines.cpp +++ b/llvm/lib/Passes/PassBuilderPipelines.cpp @@ -135,6 +135,7 @@ #include "llvm/Transforms/Utils/AddDiscriminators.h" #include "llvm/Transforms/Utils/AssumeBundleBuilder.h" #include "llvm/Transforms/Utils/CanonicalizeAliases.h" +#include "llvm/Transforms/Utils/CountInstructions.h" #include "llvm/Transforms/Utils/CountVisits.h" #include "llvm/Transforms/Utils/EntryExitInstrumenter.h" #include "llvm/Transforms/Utils/ExtraPassManager.h" @@ -1737,6 +1738,7 @@ PassBuilder::buildPerModuleDefaultPipeline(OptimizationLevel Level, // Emit annotation remarks. addAnnotationRemarksPass(MPM); + MPM.addPass(createModuleToFunctionPassAdaptor(CountInstructionsPass())); if (isLTOPreLink(Phase)) addRequiredLTOPreLinkPasses(MPM); return MPM; diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def index cf998f29ef38c..3d7c33915b47d 100644 --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -420,6 +420,7 @@ FUNCTION_PASS("consthoist", ConstantHoistingPass()) FUNCTION_PASS("constraint-elimination", ConstraintEliminationPass()) FUNCTION_PASS("coro-elide", CoroElidePass()) FUNCTION_PASS("correlated-propagation", CorrelatedValuePropagationPass()) +FUNCTION_PASS("count-instructions", CountInstructionsPass()) FUNCTION_PASS("count-visits", CountVisitsPass()) FUNCTION_PASS("dce", DCEPass()) FUNCTION_PASS("declare-to-assign", llvm::AssignmentTrackingPass()) diff --git a/llvm/lib/Transforms/Utils/CMakeLists.txt b/llvm/lib/Transforms/Utils/CMakeLists.txt index f367ca2fdf56b..198f84d89279a 100644 --- a/llvm/lib/Transforms/Utils/CMakeLists.txt +++ b/llvm/lib/Transforms/Utils/CMakeLists.txt @@ -18,6 +18,7 @@ add_llvm_component_library(LLVMTransformUtils CodeMoverUtils.cpp ControlFlowUtils.cpp CtorUtils.cpp + CountInstructions.cpp CountVisits.cpp Debugify.cpp DebugSSAUpdater.cpp diff --git a/llvm/lib/Transforms/Utils/CountInstructions.cpp b/llvm/lib/Transforms/Utils/CountInstructions.cpp new file mode 100644 index 0000000000000..ad7290d5d1094 --- /dev/null +++ b/llvm/lib/Transforms/Utils/CountInstructions.cpp @@ -0,0 +1,63 @@ +//===- CountInstructions.cpp +//----------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Utils/CountInstructions.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/PassManager.h" +#include "llvm/Support/Casting.h" +#include + +using namespace llvm; + +#define DEBUG_TYPE "count-instructions" + +STATISTIC(TotalBasicBlocks, "Number of basic blocks"); +STATISTIC(TotalInstructions, "Number of total instructions"); +STATISTIC(TotalBranchInstructions, "Number of branch instructions"); +STATISTIC(TotalSwitchInstructions, "Number of switch instructions"); +STATISTIC(TotalSuccessors, "Number of basic block successors"); +STATISTIC(TotalBranchSuccessors, "Number of branch successors"); +STATISTIC(TotalSwitchSuccessors, "Number of switch successors"); +PreservedAnalyses CountInstructionsPass::run(Function &F, + FunctionAnalysisManager &) { + uint32_t CountBasicBlocks = 0; + uint32_t CountInstructions = 0; + uint32_t CountBranchInstructions = 0; + uint32_t CountSwitchInstructions = 0; + uint32_t CountSuccessors = 0; + uint32_t CountBranchSuccessors = 0; + uint32_t CountSwitchSuccessors = 0; + + for (BasicBlock &BB : F) { + CountBasicBlocks++; + Instruction *I = BB.getTerminator(); + CountSuccessors += I->getNumSuccessors(); + if (isa(I)) { + CountBranchInstructions++; + CountBranchSuccessors += I->getNumSuccessors(); + } else if (isa(I)) { + CountSwitchInstructions++; + CountSwitchSuccessors += I->getNumSuccessors(); + } + CountInstructions += BB.size(); + } + TotalInstructions += CountInstructions; + TotalBasicBlocks += CountBasicBlocks; + TotalBranchInstructions += CountBranchInstructions; + TotalSwitchInstructions += CountSwitchInstructions; + TotalSuccessors += CountSuccessors; + TotalBranchSuccessors += CountBranchSuccessors; + TotalSwitchSuccessors += CountSwitchSuccessors; + + return PreservedAnalyses::all(); +} \ No newline at end of file diff --git a/llvm/test/Other/count-instructions.ll b/llvm/test/Other/count-instructions.ll new file mode 100644 index 0000000000000..db5072e54a0a1 --- /dev/null +++ b/llvm/test/Other/count-instructions.ll @@ -0,0 +1,104 @@ +; REQUIRES: asserts, stats +; RUN: opt -stats -passes=count-instructions < %s + +define dso_local noundef i32 @add(i32 noundef %n) { +entry: + %n.addr = alloca i32, align 4 + store i32 %n, ptr %n.addr, align 4 + %0 = load i32, ptr %n.addr, align 4 + %add = add nsw i32 %0, 1 + ret i32 %add +} + +define dso_local void @f(i32 noundef %i) { +entry: + %i.addr = alloca i32, align 4 + %x = alloca i32, align 4 + store i32 %i, ptr %i.addr, align 4 + store i32 0, ptr %x, align 4 + %0 = load i32, ptr %i.addr, align 4 + switch i32 %0, label %sw.epilog [ + i32 0, label %sw.bb + i32 10, label %sw.bb9 + i32 1, label %sw.bb9 + i32 2, label %sw.bb10 + i32 3, label %sw.bb11 + i32 4, label %sw.bb12 + ] + +sw.bb: + %call = call noundef i32 @add(i32 noundef 9) + store i32 %call, ptr %x, align 4 + %1 = load i32, ptr %x, align 4 + %cmp = icmp eq i32 %1, 0 + br i1 %cmp, label %if.then, label %if.end + +if.then: + store i32 1, ptr %x, align 4 + br label %if.end + +if.end: + %2 = load i32, ptr %x, align 4 + %call1 = call noundef i32 @add(i32 noundef %2) + store i32 %call1, ptr %x, align 4 + %3 = load i32, ptr %x, align 4 + %cmp2 = icmp eq i32 %3, 0 + br i1 %cmp2, label %if.then3, label %if.else + +if.then3: + store i32 1, ptr %x, align 4 + br label %if.end8 + +if.else: + %4 = load i32, ptr %x, align 4 + %cmp4 = icmp eq i32 %4, 1 + br i1 %cmp4, label %if.then5, label %if.else6 + +if.then5: + store i32 0, ptr %x, align 4 + br label %if.end7 + +if.else6: + store i32 2, ptr %x, align 4 + br label %if.end7 + +if.end7: + br label %if.end8 + +if.end8: + br label %sw.epilog + +sw.bb9: + call void @h() + br label %sw.epilog + +sw.bb10: + call void @h() + br label %sw.epilog + +sw.bb11: + call void @j() + br label %sw.bb12 + +sw.bb12: + call void @k() + br label %if.end15 + +sw.epilog: + %5 = load i32, ptr %x, align 4 + %cmp13 = icmp eq i32 %5, 0 + br i1 %cmp13, label %if.then14, label %if.end15 + +if.then14: + store i32 1, ptr %x, align 4 + br label %if.end15 + +if.end15: + ret void +} + +declare void @h() #2 + +declare void @j() #2 + +declare void @k() #2 \ No newline at end of file