1. 理解LLVM IR基础结构
任务目标
编写一个基于LLVM的C++工具,读取指定的LLVM IR文本文件(.ll),解析后统计并打印模块、函数、基本块和指令的数量。该工具用于建立对LLVM IR层级结构(Module → Function → BasicBlock → Instruction)的直观认识。
环境与依赖
- LLVM(≥ 15.0),需包含核心库与IR读取库
- C++17 编译器
- CMake ≥ 3.13
核心实现
// ir_stats.cpp
#include <llvm/IR/Module.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/BasicBlock.h>
#include <llvm/IR/Instruction.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IRReader/IRReader.h>
#include <llvm/Support/SourceMgr.h>
#include <llvm/Support/raw_ostream.h>
#include <llvm/Support/CommandLine.h>
using namespace llvm;
static cl::opt<std::string> InputFile(cl::Positional, cl::desc("<input .ll file>"), cl::init("-"));
int main(int argc, char **argv) {
cl::ParseCommandLineOptions(argc, argv, "LLVM IR structure statistics tool\n");
LLVMContext Context;
SMDiagnostic Err;
// 从 .ll 文件解析 IR
std::unique_ptr<Module> M = parseIRFile(InputFile, Err, Context);
if (!M) {
Err.print("ir_stats", errs());
return 1;
}
unsigned func_count = 0, bb_count = 0, inst_count = 0;
for (Function &F : *M) {
if (F.isDeclaration()) continue; // 跳过声明,只统计有实现的函数
func_count++;
for (BasicBlock &BB : F) {
bb_count++;
inst_count += BB.size();
}
}
// 输出统计结果
outs() << "Module: " << M->getName() << "\n";
outs() << "Functions (with body): " << func_count << "\n";
outs() << "Basic Blocks: " << bb_count << "\n";
outs() << "Instructions: " << inst_count << "\n";
return 0;
}
构建与运行
# CMakeLists.txt
cmake_minimum_required(VERSION 3.13)
project(ir_stats)
find_package(LLVM REQUIRED CONFIG)
add_executable(ir_stats ir_stats.cpp)
target_include_directories(ir_stats PRIVATE ${LLVM_INCLUDE_DIRS})
target_compile_definitions(ir_stats PRIVATE ${LLVM_DEFINITIONS})
target_link_libraries(ir_stats PRIVATE LLVMIRReader LLVMCore LLVMSupport)
# 构建
mkdir build && cd build
cmake ..
make
# 运行(假设已有 test.ll)
./ir_stats test.ll
验证方法
准备一个简单的测试文件 test.ll:
define i32 @add(i32 %a, i32 %b) {
entry:
%sum = add i32 %a, %b
ret i32 %sum
}
define void @main() {
entry:
%r = call i32 @add(i32 1, i32 2)
ret void
}
运行 ./ir_stats test.ll,预期输出:
Module: test.ll
Functions (with body): 2
Basic Blocks: 2
Instructions: 4
判定标准:输出与上述预期一致(模块名可能包含路径前缀),说明工具正确解析了IR的层级结构。若将 F.isDeclaration() 的过滤移除,则声明函数也会被计入,可自行对比观察差异。