强曰为道

与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

第 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 Referencellvm.org/docs/LangRef.htmlIR 完整参考
LLVM Programmer’s Manualllvm.org/docs/ProgrammersManual.html编程指南
Clang Internalsclang.llvm.org/docs/InternalsManual.htmlClang 内部
MLIR Documentationmlir.llvm.orgMLIR 官方文档
LLVM Tutorialllvm.org/docs/tutorial/Kaleidoscope 教程

20.6.2 社区资源

资源说明
LLVM Discourse官方论坛 discourse.llvm.org
LLVM Weekly每周新闻 llvmweekly.org
LLVM Dev Meeting年度开发者大会
Phabricator / GitHub PR代码审查平台
LLVM Bug TrackerBug 报告 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-4LLVM 基础:历史、架构、IR
5-6前端:Clang、AST、libTooling
7-8优化:Pass 框架、优化管线
9-11后端:代码生成、JIT、MC 层
12-14API 与扩展:libLLVM、自定义 Pass、后端开发
15-16工具:Sanitizers、LLDB
17前沿:MLIR
18-20工程实践:环境、调试、最佳实践

下一步行动

初学者 → 继续阅读源码、提交小 patch
编译器开发者 → 深入特定领域(后端/优化/前端)
工具开发者 → libClang/libLLVM 工具开发
研究者 → MLIR、新优化技术

20.9 结语

LLVM 不仅是一个编译器基础设施,更是一个充满活力的开源社区。无论你是编译器新手还是资深工程师,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.”


扩展阅读

  1. LLVM Contributing Guide — 官方贡献指南
  2. LLVM Code Review — 代码审查流程
  3. LLVM Developer Policy — 开发者政策
  4. LLVM Community — 社区资源

恭喜你完成了 LLVM 开发指南的全部 20 章! 🎉

编译器技术的学习是一条漫长但充满收获的道路。愿你在 LLVM 的世界中找到属于自己的方向。