2. IR指令分类统计
任务说明
本案例要求实现一个 LLVM FunctionPass,遍历函数内所有指令,按指令类别(算术、内存、控制流、其他)统计数量,并在每次函数处理结束后输出统计报告。该 Pass 可用于快速了解 IR 中各类操作的分布情况,辅助优化决策或教学演示。
核心实现
// InstCategory.cpp
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/InstVisitor.h"
#include "llvm/Pass.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
namespace {
struct InstCategory : public FunctionPass {
static char ID;
InstCategory() : FunctionPass(ID) {}
bool runOnFunction(Function &F) override {
unsigned arith = 0, mem = 0, ctrl = 0, other = 0;
for (BasicBlock &BB : F) {
for (Instruction &I : BB) {
if (isa<BinaryOperator>(I) || isa<CastInst>(I) ||
isa<CmpInst>(I) || isa<SelectInst>(I) ||
isa<PHINode>(I) || isa<ExtractElementInst>(I) ||
isa<InsertElementInst>(I) || isa<ShuffleVectorInst>(I)) {
++arith;
} else if (isa<LoadInst>(I) || isa<StoreInst>(I) ||
isa<AllocaInst>(I) || isa<GetElementPtrInst>(I) ||
isa<FenceInst>(I) || isa<AtomicCmpXchgInst>(I) ||
isa<AtomicRMWInst>(I)) {
++mem;
} else if (isa<TerminatorInst>(I)) {
++ctrl;
} else {
++other;
}
}
}
errs() << "Function: " << F.getName() << "\n";
errs() << " Arithmetic: " << arith << "\n";
errs() << " Memory: " << mem << "\n";
errs() << " Control: " << ctrl << "\n";
errs() << " Other: " << other << "\n";
errs() << " Total: " << (arith + mem + ctrl + other) << "\n";
return false; // 不修改 IR
}
};
} // namespace
char InstCategory::ID = 0;
static RegisterPass<InstCategory> X("inst-category",
"IR Instruction Category Statistics",
false /* Only looks at CFG */,
false /* Analysis pass */);
构建与运行
- 编译 Pass(以 LLVM 15+ 为例):
clang++ -shared -fPIC -o libInstCategory.so InstCategory.cpp \
$(llvm-config --cxxflags --ldflags --libs)
- 生成待分析的 IR 文件(示例输入
test.c):
int sum(int n) {
int s = 0;
for (int i = 0; i < n; ++i)
s += i;
return s;
}
clang -S -emit-llvm test.c -o test.ll
- 运行 Pass 并观察输出:
opt -load-pass-plugin=./libInstCategory.so -passes=inst-category test.ll -disable-output
验证方法
运行上述命令后,标准错误输出应显示每个函数的分类统计。以 sum 函数为例,预期输出(由代码逻辑直接推出)为:
Function: sum
Arithmetic: 5
Memory: 3
Control: 3
Other: 0
Total: 11
验证要点:
- 算术类包含
add、icmp、zext等指令; - 内存类包含
alloca、load、store; - 控制流类包含
br和ret; - 总数与
opt -passes=inst-count或llvm-dis人工计数一致。
若输出与预期不符,请检查 IR 中实际指令序列(cat test.ll)并核对分类逻辑。
常见问题
- TerminatorInst 已废弃:LLVM 15+ 中应使用
isa<BranchInst>(I) || isa<ReturnInst>(I) || ...或直接判断I.isTerminator()。本代码为兼容旧版使用TerminatorInst,若编译报错请改用I.isTerminator()。 - 统计粒度:本 Pass 按函数统计,如需模块级汇总可在外层 ModulePass 中累加。
- 不修改 IR:返回
false表示未改变函数内容,保证 Pass 可安全用于分析链。