【编译与代码分析记录】02 · LLVM Pass 与 ANTLR4
LLVM Pass 与 ANTLR4
整理自博客园旧笔记:《[转]LLVM Pass》《[转]antlr4》(原两篇仅为链接备忘,2022-09-13;2026-09 充实为可读记录)
此内容仅为个人学习记录,非工业界常用技能。
一、LLVM Pass
参考资料:https://llvm.org/docs/WritingAnLLVMPass.html 、https://zhuanlan.zhihu.com/p/122522485
1.1、Pass 是什么
Pass 是 LLVM 优化与分析的基本单元:一个 Pass 遍历 IR( LLVM 中间表示),做一次变换(如死代码消除)或分析(如别名分析)。opt 工具按 Pipeline 串起多个 Pass 处理 .ll/.bc 文件。
.c → clang → IR(.ll/.bc) → [Pass Pipeline via opt] → 优化后 IR → 后端 → 汇编
1.2、Legacy PM 与 New Pass Manager
- Legacy Pass Manager(老教程全是这套):
FunctionPass、RegisterPass<>、INITIALIZE_PASS宏等,代码啰嗦;LLVM 13+ 已逐步移除。 - New Pass Manager(现代写法):类只需实现
run(T &Unit, AnalysisManager &AM),通过PassBuilder注册。写新代码用这套。
看教程时先分清它讲的是哪一套,老教程(含《WritingAnLLVMPass》早期版本)大量使用 legacy API,照抄到新版本 LLVM 会编译失败。
1.3、New Pass Manager 最小示例
#include "llvm/IR/PassManager.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
namespace {
struct HelloPass : PassInfoMixin<HelloPass> {
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {
errs() << "Hello: " << F.getName() << "\n";
return PreservedAnalyses::all(); // 未修改 IR
}
};
} // namespace
// opt 加载插件的入口
extern "C" LLVM_ATTRIBUTE_WEAK PassPluginLibraryInfo llvmGetPassPluginInfo() {
return {LLVM_PLUGIN_API_VERSION, "HelloPass", LLVM_VERSION_STRING,
[](PassBuilder &PB) {
PB.registerPipelineParsingCallback(
[](StringRef Name, FunctionPassManager &FPM,
ArrayRef<PassBuilder::PipelineElement>) {
if (Name == "hello") {
FPM.addPass(HelloPass());
return true;
}
return false;
});
}};
}
编译为动态库并运行:
clang++ -shared -fPIC -o libHelloPass.so HelloPass.cpp $(llvm-config --cxxflags)
opt -load-pass-plugin=./libHelloPass.so -passes=hello -disable-output test.ll
1.4、常用调试/观察手段
clang -O2 -S -emit-llvm test.c -o test.ll:查看优化前 IRopt -passes='default<O2>' -S test.ll:跑标准 O2 流水线opt -passes=print<loops> ...:内置分析结果打印 Pass- 官方 Pass 列表:
opt -print-passes
二、ANTLR4
参考资料:https://github.com/antlr/antlr4 、语法仓库 https://github.com/antlr/grammars-v4
2.1、ANTLR 是什么
ANTLR(ANother Tool for Language Recognition)是一个解析器生成器:写一个 .g4 语法定义,自动生成词法/语法分析器代码(Java、C++、Python、Go、C# 等目标语言),再配合 Visitor/Listener 遍历解析树。和"手写 clang 工具"是两条路——ANTLR 面向自定义 DSL/配置文件解析,LLVM/Clang 面向编译器与已有代码分析。
grammars-v4 仓库收录了上百种现成语法(SQL、JSON、Java、Python、GraphQL……),做 DSL 之前先去抄,别自己从零写。
2.2、最小工作流
语法文件 Expr.g4:
grammar Expr;
prog: expr+ ;
expr: expr ('*'|'/') expr
| expr ('+'|'-') expr
| INT
| '(' expr ')'
;
INT : [0-9]+ ;
WS : [ \t\r\n]+ -> skip ;
生成解析器(以 Java 为例):
antlr4 Expr.g4 # 生成 Lexer/Parser/Visitor/Listener 等
javac *.java
# 测试解析
grun Expr prog -tree # 输入表达式,打印解析树文本
grun Expr prog -gui # 弹出图形化解析树
代码里用 Visitor 处理解析树:
ExprBaseVisitor<Integer> calc = new ExprBaseVisitor<>() { ... };
Integer result = calc.visit(tree); // 自顶向下求值
要点:ANTLR4 处理左递归(上面的 expr: expr ('*'|'/') expr 直接能写)、自动生成 Visitor/Listener 两套遍历接口;语法定义顺序即优先级顺序。
三、记录小结
LLVM Pass 属于"给已有编译器写优化插件",ANTLR 属于"造新的小语言",两者是编译课程/程序分析实验里最常见的搭档。这套东西在工业界主要由编译器组/工具链团队使用,业务开发几乎用不到,仅作留档。

浙公网安备 33010602011771号