【GitHub】 LLVM Project 深度解析:现代编译器基础设施的基石

项目地址:https://github.com/llvm/llvm-project

官方网站:https://llvm.org/

当前最新稳定版:LLVM 22.1.8(2026 年 6 月发布)

许可证:Apache 2.0 License with LLVM exceptions

一、项目概述

LLVM 是一个模块化、可复用的编译器与工具链技术集合。尽管名字中带有 "VM",但它与传统的虚拟机毫无关系------"LLVM" 本身就是项目的全称,并非缩写。

项目起源于伊利诺伊大学厄巴纳-香槟分校(UIUC)的一个研究项目,目标是构建一种基于 SSA(静态单赋值)的现代编译策略,能够同时支持静态和动态编译,适用于任意编程语言。经过二十余年的发展,LLVM 已成长为一个庞大的伞形项目,包含十余个子项目,被大量商业和开源项目用于生产环境,同时也是学术研究的重镇。

LLVM 于 2012 年荣获 ACM 软件系统奖------该奖项每年仅授予全球一个软件系统,与 LLVM 同列的包括 Unix、Java、Mosaic 浏览器等。

二、整体架构:三层式编译器设计

LLVM 的核心设计哲学是模块化的三段式架构

复制代码
┌──────────────┐     ┌──────────────────┐     ┌──────────────┐
│   前端        │ ──→ │  优化器 (LLVM IR) │ ──→ │  后端 (代码生成) │
│ (Frontend)   │     │  (Optimizer)      │     │ (CodeGen)    │
└──────────────┘     └──────────────────┘     └──────────────┘
  Clang/Flang          LLVM Core               Target Backends
  Rustc/Swift           Pass Framework          X86/ARM/RISC-V
  等语言前端            IR 优化                 GPU/...

这种架构的关键在于:

  1. 前端将源代码解析为抽象语法树(AST),再翻译为 LLVM IR(中间表示)
  2. 优化器对 LLVM IR 进行一系列与源语言和目标平台无关的优化
  3. 后端将优化后的 IR 转换为目标平台的机器码

三阶段之间通过明确定义的接口隔离,任意一端都可以被独立替换。这意味着:

  • 新语言只需实现前端,即可复用全部优化器和后端能力
  • 新硬件平台只需实现后端,即可支持所有已有前端语言
  • 优化器中的每个 Pass 都是独立的,可以自由组合

三、LLVM IR:一切的核心枢纽

LLVM IR(Intermediate Representation)是整个架构的枢纽。它是一种类型化、低级别、类似 RISC 的指令集,具有以下特性:

  • 基于 SSA 形式:每个值只被赋值一次,简化了数据流分析和优化
  • 类型安全:拥有完整的类型系统(整数、浮点、指针、向量、结构体、数组等)
  • 三种表示形式 :人类可读的文本形式(.ll 文件)、二进制位码形式(.bc 文件)和内存中的 C++ 对象表示

一个简单的 LLVM IR 示例------计算两个整数之和:

llvm 复制代码
; 定义函数:i32 @add(i32 %a, i32 %b)
define i32 @add(i32 %a, i32 %b) {
entry:
  %result = add i32 %a, %b
  ret i32 %result
}

对应的 C 代码仅为 int add(int a, int b) { return a + b; },但 IR 显式表达了每个操作。

LLVM IR 的指令体系覆盖了:

指令类别 代表指令 说明
终结指令 ret, br, switch, invoke 控制流转移
二元运算 add, sub, mul, sdiv, udiv 整数算术
浮点运算 fadd, fsub, fmul, fdiv 浮点算术
位运算 shl, lshr, ashr, and, or, xor 位级操作
内存访问 alloca, load, store, getelementptr 栈分配与内存读写
类型转换 trunc, zext, sext, bitcast, fptosi 类型间转换
比较运算 icmp, fcmp 整数/浮点比较
向量运算 extractelement, insertelement, shufflevector SIMD 向量操作
其他 phi, select, call SSA 节点、条件选择、函数调用

LLVM IR 还包含丰富的内联函数(Intrinsics) ,如 llvm.memcpyllvm.sqrtllvm.ctlz 等,这些在 IR 层面提供了语义明确的高级操作,由后端负责映射到目标平台的最优实现。

四、代码生成流水线

后端代码生成是 LLVM 最复杂的部分之一。从 LLVM IR 到目标机器码,需要经过以下阶段:

复制代码
LLVM IR
  │
  ▼
① 指令选择 (Instruction Selection)
  │  SelectionDAG / GlobalISel:将 IR 操作匹配为目标指令
  ▼
② 调度与形成 (Scheduling & Formation)
  │  确定指令顺序,生成 MachineInstr
  ▼
③ SSA 机器码优化 (SSA Machine Code Optimizations)
  │  在 SSA 形式上进行窥孔优化等
  ▼
④ 寄存器分配 (Register Allocation)
  │  将无限虚拟寄存器映射到有限物理寄存器,插入溢出代码
  ▼
⑤ 序言/尾声插入 (Prolog/Epilog Insertion)
  │  插入栈帧管理代码,实现帧指针消除等
  ▼
⑥ 后期机器码优化 (Late Machine Code Optimizations)
  │  溢出代码调度、最终窥孔优化
  ▼
⑦ 代码发射 (Code Emission)
  │  输出汇编文件或二进制目标文件
  ▼
机器码 / 目标文件

4.1 指令选择:SelectionDAG

SelectionDAG 是 LLVM 最成熟的指令选择框架。它将 LLVM IR 转换为有向无环图(DAG),节点是 SDNode,然后通过以下步骤处理:

  1. 构建初始 DAG:将 IR 翻译为目标无关的 DAG 节点
  2. 第一次优化:简化 DAG,识别旋转、div/rem 配对等元指令
  3. 类型合法化:将不支持的数据类型转换为支持的类型(如将 i1 提升为 i32)
  4. 第二次优化:清理类型合法化引入的冗余
  5. 操作合法化:将不支持的操作替换为支持的等价操作序列
  6. 第三次优化:清理操作合法化引入的冗余
  7. 指令选择:通过模式匹配将目标无关节点转换为目标指令节点
  8. 调度与形成 :线性化 DAG,生成 MachineInstr 序列

此外,GlobalISel 是新一代指令选择框架,使用更统一的 IR(GlobaMIR),设计目标是将更多逻辑从 C++ 硬编码迁移到声明式描述。

4.2 寄存器分配

指令选择后,代码使用无限的虚拟寄存器(SSA 形式)。寄存器分配阶段将其映射到目标平台有限的物理寄存器:

  • 当物理寄存器不够时,插入 溢出代码(spill code) 将值暂存到栈上
  • 处理调用约定约束(如 x86 的 EAX/EDX 用于除法)
  • SSA 形式在分配后被破坏(虚拟寄存器消失)

4.3 MC 层:目标文件级表示

MC 层是代码生成的最后一层,处理标签、节、指令等汇编级概念,不含"常量池"、"跳转表"等高级抽象。它负责:

  • MachineInstr 转换为 MCInst(更简洁的指令表示)
  • 输出汇编文件(.s)或二进制目标文件(.o
  • 支持多种目标文件格式:ELF、Mach-O、COFF、WASM、SPIR-V 等

五、核心子项目详解

LLVM 项目包含十余个子项目,覆盖编译器工具链的每个环节。

5.1 LLVM Core

编译器基础设施的核心,包含:

  • LLVM IR 定义和操作 API
  • 优化器:200+ 个优化 Pass,包括死代码消除、循环展开、向量化、内联、常量传播等
  • 代码生成器:支持 X86、ARM、AArch64、RISC-V、MIPS、PowerPC、AMDGPU、NVPTX、WebAssembly、BPF 等数十种架构

5.2 Clang

"LLVM 原生"的 C/C++/Objective-C 编译器前端,设计目标:

  • 极速编译:比 GCC 快数倍
  • 高质量的错误诊断:精确的行列定位、修复建议、彩色输出
  • 基于库的设计:Clang 的 AST 和表达式解析器可作为库复用,支撑静态分析工具

衍生工具包括:

  • Clang Static Analyzer:符号执行驱动的静态分析器
  • clang-tidy:基于规则的 C/C++ 代码质量检查与自动修复工具
  • clang-format:代码格式化工具

5.3 Flang

现代 Fortran 编译器前端,目标是:

  • 生成高性能代码
  • 支持 Fortran 2023 及所有正式 Fortran 标准(回溯至 Fortran 77)
  • 支持 OpenMP 并行(CPU 和 GPU)
  • 包含常用 Fortran 扩展

5.4 LLDB

基于 LLVM 和 Clang 构建的原生调试器:

  • 复用 Clang AST 和表达式解析器实现 C/C++/Objective-C 表达式求值
  • 利用 LLVM JIT 实现动态代码注入
  • 加载符号比 GDB 更快,内存效率更高
  • 原生支持 macOS/Linux/Windows 等平台

5.5 libc++ / libc++ ABI

C++ 标准库的高性能实现:

  • 完整支持 C++11/14/17/20/23 标准
  • 由 LLVM 团队维护,被 Apple 等公司作为系统默认 C++ 标准库使用

5.6 libc

C 标准库的高性能实现,与 LLVM 深度集成:

  • 针对现代 C 标准(C11/C17/C23)优化
  • 利用 LLVM 编译器优化能力实现高性能

5.7 compiler-rt

编译器运行时库,提供两类功能:

  • 低级运算支持 :当目标平台没有原生指令实现某 IR 操作时,提供软件实现(如 __fixunsdfdi
  • 动态检测工具运行时:AddressSanitizer(内存越界检测)、ThreadSanitizer(数据竞争检测)、MemorySanitizer(未初始化内存检测)、DataFlowSanitizer(数据流跟踪)的运行时库

5.8 MLIR

多级中间表示(Multi-Level IR),是编译器基础设施领域的一项创新:

  • 可扩展的 IR 生态:允许定义自定义的 Dialect(方言),每种 Dialect 有自己的操作、类型和约束
  • 多层抽象:可以在不同抽象层次之间渐进式 lowering------从高层 DSL 到底层机器码,逐步细化
  • 异构计算:原生支持 GPU、TPU、AI 加速器等异构硬件的编译
  • 降低编译器开发成本:领域专用编译器可以复用 MLIR 的基础设施(Pass 管理、模式匹配、验证框架等)

MLIR 已被广泛用于 AI 编译器(如 TensorFlow/XLA、PyTorch/Torch-MLIR)、量子计算编译器、硬件设计等领域。

5.9 LLD

新一代链接器,设计为系统链接器的直接替代品:

  • 比 GNU ld 和 gold 快数倍
  • 支持 ELF、Mach-O、COFF、WASM 等格式
  • 内存占用更低

5.10 BOLT

链接后优化器(Post-Link Optimizer):

  • 基于运行时采样 profile 数据优化代码布局
  • 通过重新排列基本块和函数布局提升指令缓存命中率
  • 对大型应用可获得 2-15% 的性能提升

5.11 Polly

基于多面体模型(Polyhedral Model)的优化框架:

  • 缓存局部性优化
  • 自动并行化
  • 自动向量化

5.12 OpenMP

为 Clang 和 Flang 提供 OpenMP 运行时支持,包括 CPU 和 GPU 的 offloading 能力。

5.13 libclc / klee

  • libclc:OpenCL 标准库实现
  • klee:符号虚拟机,使用定理证明器探索程序所有动态路径,自动发现 bug 并生成测试用例

六、TableGen:声明式目标描述

TableGen 是 LLVM 的代码生成工具,用于描述目标架构的信息:

  • 指令定义:指令的助记符、操作数、编码、调度信息
  • 寄存器定义:寄存器名、别名、寄存器类
  • 调用约定:参数传递规则
  • 指令映射:不同模式间的映射关系

TableGen 将 .td 描述文件转换为 C++ 代码,大幅减少手写代码量。这使得为新架构添加后端支持时,开发者只需编写声明式描述,而非大量 C++ 样板代码。

七、优化器 Pass 系统

LLVM 优化器基于 Pass 框架,每个 Pass 是一个独立的优化模块:

复制代码
LLVM IR ──→ [Pass1] ──→ [Pass2] ──→ [Pass3] ──→ ... ──→ 优化后的 IR

常见的优化 Pass 包括:

  • 标量优化:常量传播、死代码消除、指令合并、标量替换
  • 循环优化:循环展开、循环不变量外提、循环旋转、循环向量化
  • 过程间优化:函数内联、过程间常量传播、死参数消除
  • 向量化:SLP(Superword-Level Parallelism)向量化、循环向量化
  • Profile-Guided Optimization (PGO):基于 profile 数据的优化
  • LTO(Link-Time Optimization):跨模块的全文优化

从 LLVM 15 开始,旧的 Legacy PassManager 已完全迁移到 New PassManager,它采用更现代的设计:

  • Pass 按 Pass Manager 分组管理
  • Pass 之间通过 Analysis Manager 共享分析结果
  • 更好的缓存友好性和更低的 Pass 开销

八、生态与社区

8.1 依赖 LLVM 的语言与项目

LLVM 是众多现代编程语言的编译器后端:

  • Swift:Apple 的编程语言,使用 Clang 和 LLVM
  • Rust :使用 LLVM 作为默认后端(通过 rustc 的 LLVM 后端和 Cranelift 后端)
  • Zig:使用 LLVM 后端
  • Julia:JIT 编译使用 LLVM
  • Crystal:使用 LLVM 后端
  • Haskell:GHC 的 LLVM 后端
  • Ruby:MJIT 和 YJIT 使用 LLVM 相关技术
  • Python:Numba 使用 LLVM 进行 JIT 编译

8.2 商业用户

  • Apple:macOS/iOS 工具链完全基于 LLVM/Clang
  • Google:Android NDK、Chrome OS 使用 Clang/LLVM
  • AMD:GPU 编译器基于 LLVM
  • NVIDIA:CUDA 工具链使用 LLVM
  • 索尼/微软:主机开发工具链基于 LLVM

8.3 社区治理

  • LLVM Foundation:独立的非营利组织,负责社区治理和年度开发者大会
  • LLVM Developers' Meeting:每年举办美国和欧洲两场开发者大会
  • 代码审查:通过 Phabricator/GitHub Pull Requests
  • Discourse 论坛Discord 频道:日常交流
  • 发布节奏:每年 2 个大版本(如 22.x、23.x),每个大版本包含 6-9 个小版本

九、版本与发布

截至 2026 年 7 月,LLVM 的发布情况:

版本系列 首次发布 最新小版本 状态
22.1.x 2026-02 22.1.8 (2026-06) 当前稳定版
23.1.x 预计 2026-08 开发中 release/23.x 分支已创建

LLVM 采用时间驱动的发布策略:

  • 每个大版本约 6 个月周期
  • 每个小版本约 2 周间隔
  • 严格遵循 RC(Release Candidate)流程

十、如何开始使用

10.1 安装

macOS(通过 Homebrew):

bash 复制代码
brew install llvm

Ubuntu/Debian(通过 APT 仓库):

bash 复制代码
# 添加 LLVM 官方仓库
echo "deb http://apt.llvm.org/ $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/llvm.list
sudo apt install llvm

Windows :从 releases.llvm.org 下载预编译二进制包。

10.2 从源码构建

bash 复制代码
git clone https://github.com/llvm/llvm-project.git
cd llvm-project

# 使用 CMake 配置
cmake -S llvm -B build -G Ninja \
  -DCMAKE_BUILD_TYPE=Release \
  -DLLVM_ENABLE_PROJECTS="clang;lld;lldb" \
  -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi" \
  -DLLVM_TARGETS_TO_BUILD="X86;AArch64;RISC-V"

# 编译
ninja -C build

10.3 实战:从源码到 IR 到可执行文件

bash 复制代码
# 1. 将 C 代码编译为 LLVM IR 文本格式
clang -S -emit-llvm hello.c -o hello.ll

# 2. 优化 IR
opt -passes=O2 hello.ll -o hello_opt.bc

# 3. 将 IR 编译为可执行文件
clang hello_opt.bc -o hello

# 4. 查看优化过程中发生了什么
opt -passes=O2 -stats hello.ll -o /dev/null

10.4 编写自定义 Pass

cpp 复制代码
#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;

struct HelloPass : PassInfoMixin<HelloPass> {
  PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {
    errs() << "Hello from function: " << F.getName() << "\n";
    return PreservedAnalyses::all();
  }
};

十一、LLVM 的技术影响

LLVM 对编译器领域和整个软件行业产生了深远影响:

  1. 重新定义了编译器架构:三段式设计成为现代编译器的标准模式,GCC 后期也引入了类似结构(GIMPLE IR + 多后端)

  2. 降低了编译器开发门槛:任何新语言只需实现前端即可获得工业级优化和跨平台能力。Rust、Swift 等语言的成功很大程度上受益于此

  3. 推动了 JIT 编译的普及:LLVM 的 JIT 能力使得运行时优化成为可能,被 Julia、Numba 等动态语言项目广泛采用

  4. 催生了 MLIR 生态:MLIR 正在成为 AI 编译器和异构计算编译的事实标准,连接了从高层 DSL 到底层硬件的完整编译链路

  5. 工业标准级工具链:Apple、Google、Sony、Microsoft 等公司的产品工具链均以 LLVM 为基础,覆盖数十亿设备

十二、结语

LLVM 项目是现代计算机科学领域最成功的开源基础设施项目之一。它不仅是编译器技术的集大成者,更通过模块化设计和可复用组件,深刻改变了编程语言、开发工具和高性能计算的生态格局。

无论你是想为新语言实现编译器、为新型硬件添加后端支持、开发静态分析工具,还是深入理解代码优化原理,LLVM 都是一个值得深入研究的宝库。项目提供了从入门教程到深度文档的完整资源体系,社区也以开放和友好著称。

相关链接

相关推荐
2023自学中1 小时前
C++ 内存追踪器
linux·c++
Hui Baby1 小时前
Spring Security
java·后端·spring
2501_936960362 小时前
GitHub初步了解
github
IT笔记2 小时前
【Rust】Rust Match 模式匹配详解
java·开发语言·rust
EQUINOX12 小时前
【论文阅读】| MoCo精读
论文阅读·人工智能·python·深度学习·机器学习
我才是银古3 小时前
构建 Java GIS 工具库:从碎片化 API 到统一抽象的设计实践
java·gis·geotools·gdal·esri
TPBoreas3 小时前
配置信息防泄露方案:.env 环境隔离详解(dotenv-java)
java·开发语言
用户8356290780513 小时前
使用 Python 自动化 Excel 公式和函数:完整指南
后端·python
wangruofeng3 小时前
11 万 Star 的生成式 AI 入门课,Microsoft 做对了什么
github·aigc·ai编程
敲代码的嘎仔3 小时前
实习日志day6--实习日志day6--title命名规范化&businessType纠正&补充缺失的@Log注解&报警与通信模块补充&产出阶段总结文档
java·开发语言·人工智能·git·python·实习·大二