第 20 章:最佳实践与贡献指南
第 20 章:最佳实践与贡献指南
“从用户到贡献者,LLVM 社区欢迎每一个愿意参与的人。”
20.1 LLVM 编码规范
20.1.1 命名规范
// 类名: CamelCase
class FunctionPass;
class InstructionCombiningPass;
// 函数名: camelCase
void runOnFunction();
bool isInstructionTriviallyDead();
// 变量名: camelCase
unsigned instCount = 0;
BasicBlock *entry = F.getEntryBlock();
// 成员变量: 带下划线后缀
class MyClass {
unsigned count_;
Function *func_;
};
// 枚举值: CamelCase
enum Result {
Success,
Failure,
Skip
};
// 宏: 大写加下划线
#define LLVM_ENABLE_DEBUG 1
// 命名空间: 全小写
namespace llvm {
namespace detail {
// ...
} // namespace detail
} // namespace llvm
// 常量: 全大写或 camelCase
const unsigned MaxAlignment = 16;
const unsigned defaultThreshold = 100;
// 模板参数: CamelCase
template <typename PassT>
void addPass(PassT Pass);
20.1.2 代码格式
// 缩进: 2 个空格
if (condition) {
doSomething();
}
// 行宽: 80 列
// 好:
if (longCondition1 && longCondition2 &&
longCondition3) {
// ...
}
// 大括号: 函数和类用新行,其他用同行
void MyClass::function() // 函数定义
{
if (condition) { // if 同行
// ...
}
for (auto &I : BB) { // for 同行
// ...
}
}
// 空行: 逻辑块之间用空行分隔
void process() {
// Step 1: 初始化
initialize();
// Step 2: 处理
for (auto &item : items) {
processItem(item);
}
// Step 3: 清理
cleanup();
}
20.1.3 注释规范
// 单行注释: // 开头
// This is a comment.
/// 文档注释: 三个斜杠
/// \brief Brief description.
///
/// Detailed description.
/// \param [in] arg1 Description of arg1
/// \param [out] arg2 Description of arg2
/// \returns Description of return value
int myFunction(int arg1, int *arg2);
// 多行注释
/* This is a multi-line comment
used sparingly */
20.2 LLVM 社区贡献
20.2.1 贡献流程
1. Fork llvm-project 仓库
├── git clone https://github.com/your-username/llvm-project.git
└── git remote add upstream https://github.com/llvm/llvm-project.git
2. 创建分支
└── git checkout -b my-feature
3. 开发和测试
├── 编写代码
├── 编写测试 (test/ 目录)
├── 运行测试: ninja check-llvm
└── 检查格式: clang-format
4. 提交代码
├── git add .
├── git commit -m "[MyComponent] Brief description"
└── git push origin my-feature
5. 创建 Pull Request
├── 在 GitHub 上创建 PR
├── 填写 PR 模板
└── 等待代码审查
6. 代码审查
├── 响应审查意见
├── 修改代码
└── 经过至少一个维护者批准
7. 合并
└── Squash and merge (由维护者操作)
20.2.2 提交信息规范
[Component] Brief description (50 字以内)
Detailed description of the change.
Explain the motivation and context.
- What was the problem?
- How does this change fix it?
- Any side effects?
Fixes #12345
Differential Revision: https://reviews.llvm.org/D12345
示例:
[InstCombine] Add support for fold (add (select ...), (select ...))
This adds a new InstCombine fold for the pattern:
(add (select c, x, y), (select c, z, w))
→ (select c, (add x, z), (add y, w))
This can eliminate redundant selects and enable further
optimizations downstream.
Differential Revision: https://reviews.llvm.org/D12345
20.2.3 测试要求
; test/Transforms/InstCombine/add-select.ll
; RUN: opt -passes='instcombine' -S < %s | FileCheck %s
; CHECK-LABEL: @test_add_select
; CHECK: %result = select i1 %c, i32 5, i32 7
define i32 @test_add_select(i1 %c) {
entry:
%s1 = select i1 %c, i32 2, i32 3
%s2 = select i1 %c, i32 3, i32 4
%result = add i32 %s1, %s2
ret i32 %result
}
20.3 LLVM API 使用最佳实践
20.3.1 IR 操作最佳实践
// ✅ 好: 使用 SSA 形式
Value *Sum = Builder.CreateAdd(A, B, "sum");
Value *Product = Builder.CreateMul(Sum, C, "product");
// ❌ 坏: 使用 alloca + load/store(除非必须)
AllocaInst *A = Builder.CreateAlloca(Int32Ty);
Builder.CreateStore(Val, A);
Value *Loaded = Builder.CreateLoad(Int32Ty, A);
// ✅ 好: 使用 Builder 的当前位置
Builder.SetInsertPoint(BB, BB->begin());
// ✅ 好: 检查 API 返回值
if (Error E = someFunction()) {
errs() << toString(std::move(E));
return;
}
// ✅ 好: 使用 RAII 管理资源
{
// LLVMContext 和 Module 的生命周期管理
LLVMContext Context;
auto M = std::make_unique<Module>("test", Context);
// ... 使用 M
} // 自动清理
// ❌ 坏: 手动管理
LLVMContext *Context = new LLVMContext();
Module *M = new Module("test", *Context);
// 可能忘记 delete
20.3.2 Pass 开发最佳实践
// ✅ 正确设置 PreservedAnalyses
PreservedAnalyses MyPass::run(Function &F, FunctionAnalysisManager &AM) {
// ... 优化逻辑 ...
if (!Changed)
return PreservedAnalyses::all();
PreservedAnalyses PA;
// ✅ 只保留确实未破坏的分析
PA.preserve<DominatorTreeAnalysis>();
PA.preserve<LoopAnalysis>();
return PA;
}
// ✅ 使用 Expected<> 处理错误
Expected<int> parseInput(StringRef Input) {
int Value;
if (Input.getAsInteger(10, Value))
return make_error<StringError>("Invalid input",
inconvertibleErrorCode());
return Value;
}
20.4 生产应用案例
20.4.1 编译器优化
场景: 自研 DSL 编译器
架构:
DSL 源码
↓ 前端 (ANTLR/手写)
AST
↓ IR 生成
LLVM IR
↓ LLVM 优化流水线
优化后 IR
↓ LLVM 后端
可执行文件 / JIT 执行
优势:
· 复用 LLVM 的 100+ 优化 Pass
· 支持多种目标架构
· JIT 编译能力
· 成熟的调试器支持
20.4.2 静态分析工具
场景: 代码安全审计
工具链:
C/C++ 源码
↓ Clang AST
AST
↓ libTooling / AST Matcher
分析结果
典型功能:
· 检测缓冲区溢出
· 检测内存泄漏
· 检测未初始化变量
· 检测 API 使用错误
· 检测安全漏洞
20.4.3 性能分析工具
场景: 运行时 Profile 收集
方案:
1. 编译时插桩 (-fprofile-generate)
2. 运行收集 profile 数据
3. 二进制分析 (BOLT)
4. PGO 优化编译
效果:
· 典型应用 10-30% 性能提升
· 热点路径优化
· 分支预测优化
20.4.4 领域特定加速器
场景: AI/FPGA 加速器编译器
MLIR 方案:
高层 ML 模型 (TensorFlow/PyTorch)
↓ MLIR (tosa/mhlo dialect)
高层 IR
↓ 优化 (算子融合、常量折叠)
优化 IR
↓ 降低 (linalg → scf → affine)
循环 IR
↓ 向量化、并行化
目标 IR
↓ LLVM 后端
硬件代码
20.5 学习路径建议
20.5.1 初学者路径(3-6 个月)
阶段 1: 基础(1-2 个月)
· 阅读 LLVM IR 语言参考 (第 4 章)
· 使用 opt 和 llc 工具
· 理解 SSA 形式和基本指令
· 编写简单的 LLVM IR 文件
阶段 2: 工具使用(1-2 个月)
· 使用 Clang 生成 IR (第 5 章)
· 使用 opt 运行优化 Pass
· 理解优化流水线 (第 8 章)
· 编写第一个自定义 Pass (第 13 章)
阶段 3: 深入理解(1-2 个月)
· 理解 PassManager 框架 (第 7 章)
· 学习代码生成流程 (第 9 章)
· 使用 LLVM C++ API (第 12 章)
20.5.2 进阶路径(6-12 个月)
阶段 4: 高级主题
· JIT 编译 (第 10 章)
· 后端开发 (第 14 章)
· MLIR (第 17 章)
· Sanitizers (第 15 章)
阶段 5: 社区参与
· 阅读 LLVM 源码
· 修复小 bug (标记为 "good first issue")
· 提交第一个 patch
· 参与 LLVM Discourse 讨论
阶段 6: 专业方向
· 选择一个方向深入:
- 后端开发
- 优化 Pass
- MLIR 方言
- Clang 工具
- JIT 编译
20.6 学习资源
20.6.1 官方文档
| 资源 | 链接 | 说明 |
|---|---|---|
| LLVM Language Reference | llvm.org/docs/LangRef.html | IR 完整参考 |
| LLVM Programmer’s Manual | llvm.org/docs/ProgrammersManual.html | 编程指南 |
| Clang Internals | clang.llvm.org/docs/InternalsManual.html | Clang 内部 |
| MLIR Documentation | mlir.llvm.org | MLIR 官方文档 |
| LLVM Tutorial | llvm.org/docs/tutorial/ | Kaleidoscope 教程 |
20.6.2 社区资源
| 资源 | 说明 |
|---|---|
| LLVM Discourse | 官方论坛 discourse.llvm.org |
| LLVM Weekly | 每周新闻 llvmweekly.org |
| LLVM Dev Meeting | 年度开发者大会 |
| Phabricator / GitHub PR | 代码审查平台 |
| LLVM Bug Tracker | Bug 报告 issues.llvm.org |
20.6.3 推荐书籍
| 书籍 | 说明 |
|---|---|
| 《编译器设计》 | 编译原理基础 |
| 《Engineering a Compiler》 | Cooper & Torczon 经典 |
| 《Modern Compiler Implementation》 | Appel 著 |
| 《LLVM Cookbook》 | LLVM 实用指南 |
| 《MLIR: A Compiler Infrastructure》 | MLIR 技术论文 |
20.7 LLVM 的未来
20.7.1 发展方向
| 方向 | 说明 |
|---|---|
| GlobalISel | 新指令选择框架,逐步替代 SelectionDAG |
| MLIR 生态 | 更多方言、更多应用领域 |
| 更好的 C++ 支持 | Clang 对最新 C++ 标准的支持 |
| 硬件协同 | 与新型硬件架构的集成 |
| 安全特性 | 控制流完整性、内存安全 |
| 编译速度 | 持续优化编译性能 |
| 二进制优化 | BOLT 和其他二进制工具 |
20.8 本教程总结
经过 20 章的学习,你已经掌握了:
| 章节 | 核心知识 |
|---|---|
| 1-4 | LLVM 基础:历史、架构、IR |
| 5-6 | 前端:Clang、AST、libTooling |
| 7-8 | 优化:Pass 框架、优化管线 |
| 9-11 | 后端:代码生成、JIT、MC 层 |
| 12-14 | API 与扩展:libLLVM、自定义 Pass、后端开发 |
| 15-16 | 工具:Sanitizers、LLDB |
| 17 | 前沿:MLIR |
| 18-20 | 工程实践:环境、调试、最佳实践 |
下一步行动
初学者 → 继续阅读源码、提交小 patch
编译器开发者 → 深入特定领域(后端/优化/前端)
工具开发者 → libClang/libLLVM 工具开发
研究者 → MLIR、新优化技术
20.9 结语
LLVM 不仅是一个编译器基础设施,更是一个充满活力的开源社区。无论你是编译器新手还是资深工程师,LLVM 都有适合你的位置。
开始贡献:
- 在 LLVM Discourse 上提问和讨论
- 在 GitHub 上提交 PR
- 参加 LLVM 开发者大会
保持学习:
- 订阅 LLVM Weekly
- 关注 LLVM 博客
- 阅读 LLVM 提交日志
“The best way to learn LLVM is to use LLVM, and the best way to contribute is to start small.”
扩展阅读
- LLVM Contributing Guide — 官方贡献指南
- LLVM Code Review — 代码审查流程
- LLVM Developer Policy — 开发者政策
- LLVM Community — 社区资源
恭喜你完成了 LLVM 开发指南的全部 20 章! 🎉
编译器技术的学习是一条漫长但充满收获的道路。愿你在 LLVM 的世界中找到属于自己的方向。