系列简介
编译器是软件开发的基础设施——你写的每一行代码,都要经过编译器的翻译才能变成机器能执行的指令。然而,大多数开发者对编译器的理解停留在 gcc main.c 或 cargo build 的层面:输入源码,输出可执行文件,中间发生了什么?黑盒。
本系列就是要打开这个黑盒。从编译器的前端(词法分析、语法分析、语义分析)出发,经过中间表示(IR、SSA)和优化(常量折叠、循环优化、寄存器分配),到达后端(指令选择、代码生成、链接),然后深入三大工业级编译器基础设施(LLVM、V8、Go/Rust 编译器),最后探索前沿方向(WASM、AI 驱动优化)和综合实战。
每一章都配有可运行的 Python/C/LLVM IR 代码实验,让你不仅知道”是什么”,更理解”为什么”。
系列定位
- 不是:编译原理教科书(不会用大量数学推导折磨你)
- 不是:LLVM 源码解读(不会逐行分析 C++ 代码)
- 是:从原理到实践的编译器深入指南——理解每个阶段的设计动机、核心算法和工程权衡
- 是:连接前端与后端、连接理论与实践的桥梁
场景驱动阅读路线
不想按部就班地从第 1 章读到第 19 章?没问题。以下 5 条路线从你日常遇到的真实问题出发,按”你需要什么→编译器怎么实现”的顺序串联章节。每条路线可独立阅读,前置依赖已在路线内标注。
路线总览
路线A:我想写一个编程语言
场景:你有一个新语言的 idea,想从零开始实现——词法分析器怎么写?语法分析用 LL 还是 LR?类型检查怎么做?如何生成可执行代码?
| 顺序 | 章节 | 为什么读这章 |
|---|---|---|
| 1 | Ch1 编译器全景 | 建立编译器整体架构认知——前端、优化、后端三段式 |
| 2 | Ch2 词法分析 | 从字符流到 Token 流——手工编写 vs 工具生成 |
| 3 | Ch3 语法分析 | 从 Token 流到 AST——递归下降 vs LR 分析 |
| 4 | Ch4 语义分析 | 类型检查与作用域解析——让 AST 具备语义 |
| 5 | Ch5 中间表示 | IR 设计与 SSA 构造——连接前端与后端的桥梁 |
| 6 | Ch19 综合实战 | 端到端构建一个迷你编程语言——综合运用前 5 章知识 |
路线逻辑:按照编译器的流水线顺序,从源码输入到代码输出,逐步构建你的语言实现能力。
路线B:我的程序为什么慢——编译优化视角
场景:你的 C/C++/Rust 程序运行缓慢,
-O2和-O3有什么区别?循环为什么没有被向量化?寄存器溢出是怎么回事?如何读懂 LLVM 优化 Pass 的输出?
| 顺序 | 章节 | 为什么读这章 |
|---|---|---|
| 1 | Ch1 编译器全景 | 理解编译优化在编译流水线中的位置 |
| 2 | Ch5 中间表示 | SSA 是所有优化的基础——理解 def-use 链 |
| 3 | Ch6 优化基础 | 常量传播、死代码消除、公共子表达式消除 |
| 4 | Ch7 循环优化 | 循环展开、向量化、不变量外提——性能提升的关键 |
| 5 | Ch8 寄存器分配 | 图着色 vs 线性扫描——理解溢出的代价 |
| 6 | Ch11 LLVM架构 | Pass 框架与优化流水线——如何自定义优化 |
路线逻辑:从理解 IR 和 SSA 开始,逐步深入各类优化技术,最后掌握 LLVM 的优化框架。
路线C:深入工业级编译器
场景:你想理解 V8 如何让 JavaScript 飞起来、Go 编译器为什么编译这么快、LLVM 的 Pass 框架如何工作、JIT 编译的懒编译策略是什么。
| 顺序 | 章节 | 为什么读这章 |
|---|---|---|
| 1 | Ch1 编译器全景 | AOT vs JIT 的设计权衡 |
| 2 | Ch5 中间表示 | LLVM IR 是工业级 IR 的标杆 |
| 3 | Ch11 LLVM架构 | 核心:Pass 框架、IR 层次、后端代码生成 |
| 4 | Ch12 JIT编译 | 运行时代码生成——ORC API、懒编译、内联缓存 |
| 5 | Ch14 V8引擎 | Ignition + TurboFan 双层架构——JIT 的工程实践 |
| 6 | Ch15 Go编译器 | 编译速度优先的设计哲学——逃逸分析与 GC 协作 |
路线逻辑:先掌握 LLVM 这一基础设施,再理解 JIT 编译原理,然后深入 V8 和 Go 两个工业级实现。
路线D:内存安全与运行时
场景:你想理解 Rust 的借用检查器如何在编译期保证内存安全、Go 的 GC 如何与编译器协作、垃圾回收的三色标记算法如何工作。
| 顺序 | 章节 | 为什么读这章 |
|---|---|---|
| 1 | Ch1 编译器全景 | 编译期检查 vs 运行时检查的设计空间 |
| 2 | Ch4 语义分析 | 类型系统是内存安全的基础——静态类型 vs 动态类型 |
| 3 | Ch13 垃圾回收 | 核心:引用计数、标记-清除、分代 GC、三色标记 |
| 4 | Ch16 Rust编译器 | 借用检查器 + 生命周期 + MIR——编译期内存安全 |
| 5 | Ch15 Go编译器 | 逃逸分析决定堆/栈分配——编译器与 GC 的接口 |
路线逻辑:从类型系统出发,理解内存安全的理论基础,然后对比 GC(运行时安全)和 Rust(编译期安全)两种路径。
路线E:从源码到可执行文件的完整旅程
场景:一个
.c文件如何变成可执行的 ELF?链接器做了什么?WASM 是如何编译的?AI 能否自动优化编译?
| 顺序 | 章节 | 为什么读这章 |
|---|---|---|
| 1 | Ch1 编译器全景 | 编译流水线全貌——从源码到机器码 |
| 2 | Ch2 词法分析 | 源码的第一步转换——字符流到 Token 流 |
| 3 | Ch9 指令选择与调度 | IR 如何映射到目标机器指令 |
| 4 | Ch10 代码生成与链接 | 核心:ELF 格式、重定位、符号解析、动态链接 |
| 5 | Ch17 WASM编译 | 编译到 Web——WASM 字节码、Cranelift、WASI |
| 6 | Ch18 AI与编译优化 | MLGO、AutoTVM——AI 驱动的编译优化前沿 |
路线逻辑:沿着编译流水线走完全程,从源码入口到可执行文件输出,再扩展到 WASM 和 AI 优化。
路线交叉参考
同一章节在不同路线中的关注点不同:
| 章节 | 路线A 关注点 | 路线B 关注点 | 路线C 关注点 | 路线D 关注点 | 路线E 关注点 |
|---|---|---|---|---|---|
| Ch1 | 前端-优化-后端三段式 | 优化在流水线中的位置 | AOT vs JIT | 编译期 vs 运行时检查 | 编译流水线全貌 |
| Ch2 | 手写词法分析器 | — | — | — | 源码第一步转换 |
| Ch4 | 类型检查实现 | — | — | 类型系统与安全 | — |
| Ch5 | IR 设计 | SSA 与优化基础 | LLVM IR | — | — |
| Ch6 | — | 常量传播/死代码消除 | — | — | — |
| Ch7 | — | 循环展开/向量化 | — | — | — |
| Ch8 | — | 图着色/溢出 | — | — | — |
| Ch9 | — | — | — | — | 指令映射 |
| Ch10 | — | — | — | — | ELF/链接/重定位 |
| Ch11 | — | Pass 框架 | 核心章节 | — | — |
| Ch12 | — | — | JIT 原理 | — | — |
| Ch13 | — | — | — | 核心章节 | — |
| Ch14 | — | — | TurboFan+Ignition | — | — |
| Ch15 | — | — | Go 编译速度 | 逃逸分析+GC | — |
| Ch16 | — | — | — | 借用检查器 | — |
| Ch17 | — | — | — | — | WASM 编译 |
| Ch18 | — | — | — | — | AI 优化前沿 |
| Ch19 | 核心章节 | — | — | — | — |
知识导图
以下导图展示 19 章知识之间的网络关系。与线性目录不同,这里强调跨阶段的连接——一个类型检查器同时牵动语义分析和内存安全;一个 SSA 构造同时服务于优化和寄存器分配。
概念关系图
章节网络关系图
知识关联参考表
| 用户可见概念 | 对应章节 | 编译器机制 | 对应章节 | 共享基础 | 对应章节 |
|---|---|---|---|---|---|
gcc -O2 编译优化 | Ch6 | 常量传播 + 死代码消除 | Ch6 | SSA def-use 链 | Ch5 |
| 循环自动向量化 | Ch7 | SIMD 指令生成 | Ch7 | 依赖分析与别名分析 | Ch6 |
| Rust 所有权检查 | Ch16 | 借用检查器 + 生命周期 | Ch16 | 类型系统与语义分析 | Ch4 |
| Go 编译速度极快 | Ch15 | 简化前端 + 无泛型优化 | Ch15 | 递归下降解析 | Ch3 |
| V8 JIT 热点优化 | Ch14 | Ignition + TurboFan | Ch14 | 内联缓存 + 类型反馈 | Ch12 |
| Java/C# GC 暂停 | Ch13 | 分代 GC + 写屏障 | Ch13 | 三色标记不变式 | Ch13 |
| WASM 跨平台运行 | Ch17 | 字节码验证 + Cranelift | Ch17 | 指令选择 + 代码生成 | Ch9, Ch10 |
链接错误 undefined reference | Ch10 | 符号解析 + 重定位 | Ch10 | ELF 格式与段 | Ch10 |
clang -emit-llvm 输出 IR | Ch11 | LLVM IR 生成 | Ch11 | SSA 构造 | Ch5 |
| MLGO 自动优化策略 | Ch18 | 强化学习 + 编译特征 | Ch18 | 优化 Pass 框架 | Ch11 |
系列大纲
以下是按章节编号排列的完整目录。建议结合上方的场景驱动阅读路线和知识导图选择适合你的阅读顺序。
| 章节 | 标题 | 核心内容 |
|---|---|---|
| 0 | 系列导读 | 系列定位、场景路线、知识导图、环境搭建 |
| 1 | 编译器全景 | 编译器 vs 解释器 vs JIT、三段式架构、编译流水线 |
| 2 | 词法分析 | 正则表达式 → NFA → DFA、手工词法分析器、Token 设计 |
| 3 | 语法分析 | LL/LR/递归下降、AST 设计、算符优先、错误恢复 |
| 4 | 语义分析 | 类型检查、符号表、作用域、类型推导 |
| 5 | 中间表示 | IR 层次、SSA 构造、基本块、控制流图、LLVM IR |
| 6 | 优化基础 | 常量折叠/传播、死代码消除、公共子表达式、值编号 |
| 7 | 循环优化 | 循环展开、向量化、不变量外提、强度消减 |
| 8 | 寄存器分配 | 图着色、线性扫描、溢出处理、合并 |
| 9 | 指令选择与调度 | DAG 覆盖、TableGen、指令调度、流水线 |
| 10 | 代码生成与链接 | ELF 格式、重定位、符号解析、动态链接 |
| 11 | LLVM 架构深入 | Pass 框架、IR 层次、后端 Pipeline、调试信息 |
| 12 | JIT 编译 | ORC API、懒编译、内联缓存、Speculation |
| 13 | 垃圾回收 | 引用计数、标记-清除、分代 GC、三色标记、写屏障 |
| 14 | V8 引擎深入 | Ignition、TurboFan、内联缓存、隐藏类 |
| 15 | Go 编译器深入 | 编译流程、逃逸分析、Go GC、调度器与编译器协作 |
| 16 | Rust 编译器与借用检查器 | 借用检查器、MIR、生命周期、HIR → MIR → LLVM IR |
| 17 | WebAssembly 编译 | WASM 字节码、Cranelift、WASI、浏览器编译流水线 |
| 18 | AI 驱动的编译优化 | MLGO、AutoTVM、TVM、编译特征、强化学习 |
| 19 | 综合实战 | 端到端构建一个迷你编程语言 |
开发环境搭建
Python 环境(前端实验)
本系列前端的词法分析、语法分析、语义分析实验使用 Python 3.10+ 实现:
# 确认 Python 版本python3 --version # 需要 3.10+
# 安装依赖pip3 install lark-parser graphviz
# 可选:安装 ANTLR4 Python 运行时pip3 install antlr4-python3-runtimeLLVM 环境(后端实验)
# Ubuntu/Debiansudo apt install llvm llvm-dev clang lld
# macOSbrew install llvm
# 确认版本(需要 LLVM 15+)llvm-config --versionclang --version
# 查看 LLVM IR 输出clang -emit-llvm -S -o - hello.cC/C++ 编译工具链
# 安装 GCC 和构建工具sudo apt install build-essential gcc g++ make cmake
# 安装 binutils(包含 objdump、readelf、nm 等工具)sudo apt install binutils
# 查看 ELF 文件readelf -h a.outobjdump -d a.outnm a.outRust 与 Go 环境
# 安装 Rustcurl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# 查看 Rust 中间表示rustc --emit=mir hello.rsrustc --emit=llvm-ir hello.rs
# 安装 Gowget https://go.dev/dl/go1.22.0.linux-amd64.tar.gzsudo tar -C /usr/local -xzf go1.22.0.linux-amd64.tar.gz
# 查看 Go 编译器 SSA 输出GOSSAFUNC=main go build -o hello hello.goWASM 环境
# 安装 Emscripten(WASM 编译工具链)git clone https://github.com/emscripten-core/emsdk.gitcd emsdk && ./emsdk install latest && ./emsdk activate latest
# 安装 WABT(WASM 二进制工具)sudo apt install wabt
# 编译到 WASMemcc hello.c -o hello.jswasm2wat hello.wasm # 反汇编 WASM本系列的实践方法论
本系列遵循 理解原理 → 动手实现 → 工具验证 的学习方法:
- 理解原理:通过图解和伪代码理解算法的核心思想
- 动手实现:用 Python/C 手写核心算法的简化版本
- 工具验证:使用 LLVM/GCC/Rust/Go 等工具验证理解是否正确
每章的「动手实践」部分都遵循这一方法论,让你不仅知道”是什么”,更理解”为什么”。
开发环境搭建
以下环境搭建步骤基于 Ubuntu 22.04 LTS。其他发行版的包名和路径可能不同,请参考各项目官方文档。编译器开发涉及大量 C/C++/Python 工具链,建议在虚拟机或 Docker 容器中操作。
编译器开发工具架构
Python 编译器开发环境
# 安装 Python 3.11+(推荐使用 pyenv)curl https://pyenv.run | bashpyenv install 3.11.5pyenv global 3.11.5
# 安装编译器开发常用库pip install lark-parser # 解析器组合子pip install llvmlite # Python LLVM 绑定pip install rpython # PyPy 的翻译工具链LLVM 开发环境
# 安装 LLVM 15(包含 clang、llc、opt 等工具)sudo apt install llvm-15 llvm-15-dev clang-15 libpolly-15-dev
# 验证安装llvm-as-15 --versionopt-15 --version
# 编译 LLVM Pass 示例git clone https://github.com/llvm/llvm-project.gitcd llvm-project && mkdir build && cd buildcmake -G Ninja -DLLVM_ENABLE_PROJECTS=clang -DCMAKE_BUILD_TYPE=Release ../llvmninja -j$(nproc)LLVM 从源码编译需要约 30GB 磁盘空间和 16GB+ 内存。如果资源有限,可以使用预编译的二进制包(apt install llvm-15-dev),或使用 Docker 镜像 silkeh/clang。
推荐参考资料
经典教材
| 书籍 | 作者 | 特点 |
|---|---|---|
| 《Crafting Interpreters》 | Robert Nystrom | 手写两个完整解释器,实践性极强,适合入门 |
| 《Engineering a Compiler》 | Keith D. Cooper 等 | 工程视角,算法清晰,适合深入 |
| 《编译原理》(龙书) | Alfred V. Aho 等 | 理论权威,数学推导详尽,适合查阅 |
| 《LLVM Cookbook》 | Mayur Pandey 等 | LLVM 实践指南,Pass 开发详解 |
| 《GC Handbook》 | Richard Jones 等 | 垃圾回收的百科全书 |
| 《Programming Language Pragmatics》 | Michael L. Scott | 语言设计视角,广度与深度兼备 |
在线资源
- LLVM 官方文档 — LLVM 基础设施的权威参考
- Crafting Interpreters 在线版 — 免费在线阅读
- Compiler Explorer (Godbolt) — 在线查看编译器输出
- LLVM Language Reference — LLVM IR 完整规范
- V8 引擎博客 — V8 团队的最新技术文章
实用工具
- Compiler Explorer (Godbolt):在线对比不同编译器的输出,无需本地安装
- LLVM opt:运行单个优化 Pass,观察 IR 变化
- clang -emit-llvm:生成 LLVM IR,理解前端到中端的转换
- readelf / objdump:分析 ELF 文件结构,理解链接过程
- wasm2wat:WASM 二进制反汇编为 WAT 文本格式
准备好开始了吗?从 编译器全景 开始你的编译器深入之旅吧!
参考
支持与分享
如果这篇文章对你有帮助,欢迎支持作者或分享给更多人
部分信息可能已经过时






