LLVM Function Instruction Count Pass
This document provides an overview of how to write, build, and use an LLVM pass that counts the number of instructions in each function within a module. This pass is useful for performance analysis, code size estimations, and understanding the structure of functions in LLVM IR.
Prerequisites
Before using this pass, ensure you have the following:
- A working LLVM build environment.
- Basic knowledge of LLVM passes and the LLVM pass pipeline.
- Familiarity with C++ and LLVM's API.
If you're not familiar with building LLVM, please visit the official LLVM documentation and build instruction for guidance on how to build LLVM from source.
Overview
The LLVM Function Instruction Count Pass is designed to count the number of instructions in each function of an LLVM module. The pass iterates over each function and counts the instructions in its basic blocks. The total instruction count for each function is printed to the standard error output.
Key Files
- FunctionCount.h - Defines the header for the
FunctionCountPass
class, which extends theFunctionPass
class. - FunctionCount.cpp - Implements the logic for counting the number of instructions in a function.
- PassRegistry.def - Registers the new pass to make it available for use within the LLVM pass pipeline.
- CMakeLists.txt - Modifies the build system to include and compile the new source files.
- PassBuilder.cpp - Integrates the pass into the LLVM pass builder to ensure it can be used in the pass manager.
Features
- Counts Instructions: The pass counts the number of instructions in each function.
- Integration with LLVM: Easily integrates with the LLVM pipeline for custom optimizations and analyses.
- Customizable Output: The result (number of instructions) is printed to the standard error stream for each function.
Logic Behind the Code
To fully understand the reasoning behind the code, it's important to grasp how different components (such as basic blocks, functions, and modules) interact with each other. For a deeper understanding of these concepts and their relationships, explore the:
How to Create and Build the Pass
1. Create the Pass Header File (FunctionCount.h
)
This file will be created at the location
Path: /path/to/llvm-project/llvm/include/llvm/Transforms/Utils/FunctionName.h
#ifndef LLVM_TRANSFORMS_UTILS_FUNCTIONNAME_H
#define LLVM_TRANSFORMS_UTILS_FUNCTIONNAME_H
#include "llvm/IR/PassManager.h"
namespace llvm {
class FunctionNamePass : public PassInfoMixin<FunctionNamePass> {
public:
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
};
} // namespace llvm
#endif // LLVM_TRANSFORMS_UTILS_FUNCTIONNAME_H
2. Implement the Pass Logic (FunctionCount.cpp
)
This file will be created at the location
Path: /path/to/llvm-project/llvm/lib/Transforms/Utils/FunctionCount.cpp
#include "llvm/Transforms/Utils/FunctionCount.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
PreservedAnalyses FunctionNamePass::run(Function &F, FunctionAnalysisManager &AM) {
static int Counter = 1; // Static counter to number the functions
unsigned int InstructionCount = 0;
for( auto &BB : F){
InstructionCount+=BB.size();
}
errs() << "Function #" << Counter++ << ": " << F.getName() << " has " << InstructionCount << " instructions"<<"\n";
return PreservedAnalyses::all();
}
3. Register the Pass in the Pass Registry (PassRegistry.def
)
This file will be created at the location
PATH: /path/to/llvm-project/llvm/lib/Passes/PassRegistry.def
// Add your pass to the PassRegistry to allow it to be used in the LLVM pipeline
// Add this line to the PassRegistry.def file:
FUNCTION_PASS("countfun",FunctionNamePass())
4. Modify PassBuilder.cpp
to Include Your Pass
This file will be created at the location
PATH: /path/to/llvm-project/llvm/lib/Passes/PassBuilder.cpp
//just include the header
#include "llvm/Transforms/Utils/FunctionCount.h"
5. Update CMakeLists.txt
Ensure your new source files are added to the build system.
This changes should be done in the file
PATH: /path/to/llvm-project/llvm/lib/Transforms/Utils/CMakeLists.txt
+++ b/llvm/lib/Transforms/Utils/CMakeLists.txt
@@ -88,6 +88,7 @@ add_llvm_component_library(LLVMTransformUtils
Utils.cpp
ValueMapper.cpp
VNCoercion.cpp
+ FunctionCount.cpp
ADDITIONAL_HEADER_DIRS
${LLVM_MAIN_INCLUDE_DIR}/llvm/Transforms
6. Build the Pass
Once the code changes are made, recompile LLVM to include the new pass.
cd build
cmake ..
ninja
7. Running the Pass
After building LLVM with the new pass, you can run the pass using the opt
tool. Here's how you would run the pass on a specific LLVM IR file:
/path/to/llvm-project/build/bin/opt -disable-output -passes=countfun hello.ll
8. Test File you can Take as
; ModuleID = 'test_module'
source_filename = "test.ll"
define i32 @main() {
entry:
%retval = alloca i32, align 4
store i32 0, i32* %retval, align 4
%0 = load i32, i32* %retval, align 4
%add = add i32 %0, 1
store i32 %add, i32* %retval, align 4
%1 = load i32, i32* %retval, align 4
ret i32 %1
}
Output
/path/to/llvm-project/llvm/build/bin/opt -disable-output -passes=countfun test.ll
Function #1: main has 7 instructions
You can test your pass with a custom C++ file by following these steps:
-
Generate the LLVM IR from your C++ file using
clang++
:clang++ -S -emit-llvm -o filename.ll file.cpp
-
Run the LLVM pass to count the instructions for each function in the generated LLVM IR file:
/path/to/llvm-project/build/bin/opt -disable-output -passes=countfun filename.ll
This command will output the instruction count for each function in the provided LLVM IR file.
If you encounter any difficulties, feel free to reach out via email at info@compilersutra.com.
Conclusion
This pass provides valuable insights into the instruction counts of functions within an LLVM module. It can be used as part of custom optimizations or analysis within the LLVM framework.