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

LLVM 开发指南 / 第 3 章:LLVM 整体架构

第 3 章:LLVM 整体架构

“好的架构不是设计出来的,是演化出来的。” — 但 LLVM 的架构确实是精心设计的。


3.1 LLVM 的层次结构

LLVM 采用多层表示的设计思想,从源代码到最终机器码,经过多个层次的逐步降低抽象级别。

3.1.1 四层 IR 模型

┌─────────────────────────────────────────────┐
│  Level 0: AST (抽象语法树)                   │
│  ─────────────────────────────────────────  │
│  · 语言特定 (C/C++/ObjC)                    │
│  · 包含完整的类型信息和源码结构              │
│  · 由 Clang 前端生成                         │
│  · C++ API: clang::ASTContext               │
├─────────────────────────────────────────────┤
│  Level 1: LLVM IR                            │
│  ─────────────────────────────────────────  │
│  · 语言无关的核心中间表示                    │
│  · SSA (静态单赋值) 形式                     │
│  · 类型安全、可验证                          │
│  · .ll (文本) / .bc (二进制)                 │
│  · C++ API: llvm::Module, llvm::Function    │
├─────────────────────────────────────────────┤
│  Level 2: SelectionDAG / MIR                │
│  ─────────────────────────────────────────  │
│  · 面向目标机器的中间表示                    │
│  · SelectionDAG: 指令选择阶段使用            │
│  · MachineIR: 寄存器分配后使用               │
│  · 包含目标特定信息                          │
│  · C++ API: llvm::SelectionDAG, MachineFunction │
├─────────────────────────────────────────────┤
│  Level 3: MCInst (机器指令)                  │
│  ─────────────────────────────────────────  │
│  · 最底层的指令表示                          │
│  · 直接映射到目标指令集                      │
│  · 用于汇编输出和目标文件生成                │
│  · C++ API: llvm::MCInst                    │
└─────────────────────────────────────────────┘

3.1.2 各层之间的转换

源代码          AST           LLVM IR         SelectionDAG    MachineIR       MCInst
  │              │               │                │              │              │
  │  词法/语法   │   IRGen       │   指令选择      │   寄存器     │   MC层       │
  │  语义分析    │   (CodeGen)   │   (ISel)       │   分配       │   汇编输出   │
  │              │               │                │              │              │
  ▼              ▼               ▼                ▼              ▼              ▼
  源码 ──────► Clang AST ────► LLVM IR ────► SelectionDAG ──► MIR ──────► MCInst
                  │               │                │              │              │
                  │               │                │              │              │
             libclang         opt Passes       InstrEmitter  RegAlloc     MCCodeEmitter
             Tooling          新PM/旧PM        Lowering      VirtRegMap   AsmPrinter

3.2 LLVM IR — 核心中的核心

LLVM IR 是整个 LLVM 系统的基石,所有语言前端最终都要生成 LLVM IR,所有后端优化和代码生成都从 LLVM IR 开始。

3.2.1 IR 的三个等价形式

形式文件后缀说明
文本格式 (Textual IR).ll人类可读,便于调试
二进制格式 (Bitcode).bc紧凑高效,用于 LTO
内存格式 (In-memory)程序操作的 C++ 对象
# 文本 → 二进制
llvm-as input.ll -o output.bc

# 二进制 → 文本
llvm-dis input.bc -o output.ll

# C/C++ → 文本 IR
clang -S -emit-llvm source.c -o source.ll

# C/C++ → 二进制 IR
clang -c -emit-llvm source.c -o source.bc

3.2.2 Module — IR 的顶层容器

┌───────────────────────────────────────┐
│  Module                               │
│  ─────────────────────────────────── │
│  · target triple                      │
│  · target datalayout                  │
│  · source_filename                    │
│                                       │
│  ┌─────────────────────────────────┐ │
│  │  GlobalVariable (全局变量)       │ │
│  │  @global_var = global i32 42    │ │
│  └─────────────────────────────────┘ │
│                                       │
│  ┌─────────────────────────────────┐ │
│  │  Function (函数)                │ │
│  │  ┌───────────────────────────┐ │ │
│  │  │  BasicBlock (基本块)      │ │ │
│  │  │  ┌─────────────────────┐ │ │ │
│  │  │  │  Instruction (指令) │ │ │ │
│  │  │  │  %x = add i32 %a, 1│ │ │ │
│  │  │  └─────────────────────┘ │ │ │
│  │  └───────────────────────────┘ │ │
│  └─────────────────────────────────┘ │
│                                       │
│  ┌─────────────────────────────────┐ │
│  │  NamedMetadata (命名元数据)     │ │
│  └─────────────────────────────────┘ │
└───────────────────────────────────────┘

3.3 Pass 框架

Pass 框架是 LLVM 优化系统的核心。每一个优化或分析都是一个独立的 Pass。

3.3.1 Pass 的分类

┌─────────────────────────────────────────────────────────┐
│                     LLVM Pass                            │
│                                                         │
│  ┌──────────────────┐    ┌────────────────────┐        │
│  │   分析 Pass       │    │   转换 Pass         │        │
│  │  (Analysis Pass)  │    │ (Transform Pass)   │        │
│  │                   │    │                    │        │
│  │  不修改 IR        │    │  修改 IR            │        │
│  │  计算并缓存信息    │    │  应用优化           │        │
│  │                   │    │                    │        │
│  │  例如:            │    │  例如:              │        │
│  │  · LoopInfo       │    │  · InstCombine     │        │
│  │  · DominatorTree  │    │  · LoopUnroll      │        │
│  │  · AliasAnalysis  │    │  · GVN             │        │
│  │  · ScalarEvolution│    │  · Inliner         │        │
│  └──────────────────┘    └────────────────────┘        │
│                                                         │
│  按作用范围:                                             │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐ │
│  │  Module Pass  │  │Function Pass │  │ Loop Pass    │ │
│  │  整个模块     │  │ 单个函数     │  │ 单个循环     │ │
│  └──────────────┘  └──────────────┘  └──────────────┘ │
└─────────────────────────────────────────────────────────┘

3.3.2 新旧 PassManager

LLVM 有两套 Pass 管理系统:

特性Legacy PassManagerNew PassManager
状态已废弃当前默认(LLVM 14+)
命名空间llvm:: (legacy)llvm::
Pass 注册RegisterPassPassBuilder
Pass 流水线硬编码可编程
错误处理断言Expected<>/Error
推荐使用❌ 不推荐✅ 推荐
# 使用新 PassManager 的 opt
opt -passes='default<O2>' input.ll -o output.bc

# 使用旧 PassManager 的 opt(已废弃)
opt -O2 -enable-new-pm=0 input.ll -o output.bc

# 查看优化流水线
opt -passes='print<module>' -disable-output input.ll

3.4 后端架构

LLVM 后端负责将 LLVM IR 转换为目标机器码。

3.4.1 后端流水线

LLVM IR
   │
   ▼
┌──────────────────────┐
│ 1. IR → DAG          │  SelectionDAGISel
│    (构建 SelectionDAG)│
└──────────┬───────────┘
           │
           ▼
┌──────────────────────┐
│ 2. 指令选择           │  TargetLowering
│    DAG → Machine DAG  │
└──────────┬───────────┘
           │
           ▼
┌──────────────────────┐
│ 3. 指令合并/合法化    │  DAGCombine, Legalize
│    优化 Machine DAG   │
└──────────┬───────────┘
           │
           ▼
┌──────────────────────┐
│ 4. 指令调度           │  ScheduleDAG
│    (前寄存器分配)     │
└──────────┬───────────┘
           │
           ▼
┌──────────────────────┐
│ 5. 寄存器分配         │  RegAllocGreedy
│    虚拟寄存器→物理寄存│
└──────────┬───────────┘
           │
           ▼
┌──────────────────────┐
│ 6. 指令调度           │  PostRAScheduler
│    (后寄存器分配)     │
└──────────┬───────────┘
           │
           ▼
┌──────────────────────┐
│ 7. 指令发射           │  InstrEmitter
│    生成 MachineInstr  │
└──────────┬───────────┘
           │
           ▼
┌──────────────────────┐
│ 8. MC 层              │  MCCodeEmitter
│    MachineInstr →     │
│    MCInst → 机器码    │
└──────────┬───────────┘
           │
           ▼
      目标文件 (.o)

3.4.2 后端模块化

每个目标后端是一个独立的库,只在需要时才链接:

lib/Target/
├── X86/              # x86/x86-64
│   ├── X86.td        # TableGen 描述文件
│   ├── X86InstrInfo.cpp
│   ├── X86RegisterInfo.cpp
│   └── ...
├── AArch64/          # ARM 64-bit
├── ARM/              # ARM 32-bit
├── RISCV/            # RISC-V
├── MIPS/             # MIPS
├── PowerPC/          # PowerPC
├── SystemZ/          # IBM SystemZ
├── WebAssembly/      # WebAssembly
└── ...

3.5 模块化库设计

3.5.1 LLVM 库依赖关系

┌──────────────────────────────────────────────────┐
│                    工具层                         │
│  clang | opt | llc | lld | lldb | llvm-as | ... │
└──────────────────┬───────────────────────────────┘
                   │
┌──────────────────▼───────────────────────────────┐
│                  组件层                            │
│                                                  │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐         │
│  │Frontend  │ │Transform │ │ CodeGen  │         │
│  │  Clang   │ │  Utils   │ │          │         │
│  └────┬─────┘ └────┬─────┘ └────┬─────┘         │
│       │            │            │                │
│  ┌────▼────────────▼────────────▼─────┐         │
│  │          Core IR 层                 │         │
│  │  Module → Function → BasicBlock     │         │
│  │    → Instruction → Value → Type     │         │
│  └─────────────────┬──────────────────┘         │
│                    │                             │
│  ┌─────────────────▼──────────────────┐         │
│  │          Support 层                 │         │
│  │  MemoryBuffer, raw_ostream,         │         │
│  │  CommandLine, Timer, Debug          │         │
│  └────────────────────────────────────┘         │
│                                                  │
│  ┌────────────────────────────────────┐         │
│  │          MC 层                      │         │
│  │  MCInst, MCStreamer, MCAsmParser    │         │
│  └────────────────────────────────────┘         │
└──────────────────────────────────────────────────┘

3.5.2 核心库及其功能

库名依赖功能典型用途
LLVMSupport基础工具类命令行、内存管理、调试
LLVMCoreSupportIR 核心Module/Function/Instruction
LLVMAnalysisCore分析 Pass循环分析、别名分析
LLVMTransformUtilsAnalysis转换工具内联、循环变换
LLVMScalarOptsTransformUtils标量优化GVN、InstCombine
LLVMVectorizeTransformUtils向量化SLP、Loop Vectorizer
LLVMipo多个过程间优化LTO、全局优化
LLVMCodeGenCore, MC代码生成指令选择、寄存器分配
LLVMTargetCodeGen目标框架TargetMachine、TargetLowering
LLVMMCSupportMC层MCInst、汇编器
LLVMObjectMC目标文件ELF、MachO、COFF
LLVMBitReaderCoreBitcode 读取.bc 文件解析
LLVMBitWriterCoreBitcode 写入.bc 文件生成
LLVMX86CodeGenCodeGenx86 后端x86 指令生成
LLVMX86AsmParserMCx86 汇编解析x86 汇编输入
LLVMX86DescMCx86 描述x86 指令/寄存器描述

3.5.3 查看库信息

# 查看 LLVM 所有可用组件
llvm-config --components

# 查看某个组件的依赖
llvm-config --libs core analysis

# 查看所有库
llvm-config --libs all

# 查看系统链接标志
llvm-config --system-libs --ldflags

3.6 数据流与控制流

3.6.1 Value-Use 数据流

LLVM IR 使用**SSA(Static Single Assignment)**形式,每个变量只被赋值一次:

; SSA 形式示例
define i32 @example(i32 %x) {
entry:
  %a = add i32 %x, 1        ; %a 只在此处定义
  %b = mul i32 %a, 2        ; %b 只在此处定义
  %c = add i32 %b, %a       ; %c 使用了 %a 和 %b
  ret i32 %c
}
Value-Use 链:
  %a ──uses──► %b (via mul)
  %a ──uses──► %c (via add)
  %b ──uses──► %c (via add)

Use-Def 链:
  %c ──defs──► %a (via add)
  %c ──defs──► %b (via mul)

3.6.2 PHI 节点与控制流合并

当控制流汇合时,使用 PHI 节点选择正确的值:

define i32 @abs(i32 %x) {
entry:
  %cmp = icmp sgt i32 %x, 0
  br i1 %cmp, label %then, label %else

then:
  br label %merge

else:
  %neg = sub i32 0, %x
  br label %merge

merge:
  %result = phi i32 [ %x, %then ], [ %neg, %else ]
  ret i32 %result
}
控制流图 (CFG):

  entry
  ┌──────────┐
  │ cmp = ...│
  │ br cmp   │
  └──┬───┬───┘
     │   │
  then   else
  ┌──┐  ┌────────┐
  │  │  │ neg = -x│
  └┬─┘  └───┬────┘
   │        │
   └───┬────┘
       │
    merge
  ┌─────────────────────┐
  │ result = φ(x, neg)  │
  │ ret result           │
  └─────────────────────┘

3.7 类型系统

3.7.1 LLVM IR 类型层次

Type
├── VoidType          (void)
├── HalfType          (half — 16-bit float)
├── FloatType         (float — 32-bit)
├── DoubleType        (double — 64-bit)
├── X86_FP80Type      (x86_fp80 — 80-bit)
├── FP128Type         (fp128 — 128-bit)
├── IntegerType       (i1, i8, i16, i32, i64, i128, ...)
├── FunctionType      (i32 (i32, i32))
├── StructType        ({i32, float, i8*})
├── ArrayType         ([10 x i32])
├── PointerType       (i32*, ptr)
├── VectorType        (<4 x float>)
└── LabelType         (label — basic block 标签)

3.7.2 地址空间

; 默认地址空间 (0)
%ptr = alloca i32

; 带显式地址空间
%ptr_global = addrspace(1) global i32 0
%ptr_shared = addrspace(3) global i32 0

; 常用地址空间
; 0: 通用地址空间 (CPU)
; 1: 全局内存 (GPU global memory)
; 2: 共享内存 (GPU shared/local memory)
; 3: 常量内存 (GPU constant memory)

3.8 Target Machine 抽象

每个目标后端需要实现 TargetMachine 接口:

// llvm/lib/Target/X86/X86TargetMachine.h (简化)
class X86TargetMachine : public LLVMTargetMachine {
public:
  // 获取目标特定的指令信息
  const X86InstrInfo *getInstrInfo() const override;

  // 获取目标特定的寄存器信息
  const X86RegisterInfo *getRegisterInfo() const override;

  // 获取目标特定的帧低层信息
  const X86FrameLowering *getFrameLowering() const override;

  // 获取目标特定的指令低层信息
  const X86TargetLowering *getTargetLowering() const override;

  // 创建 MachineFunctionPass(代码生成入口)
  MachineFunctionInfo *createMachineFunctionInfo(...) const;

  // 添加代码生成 Pass 到流水线
  void addPassesToEmitFile(
    PassManagerBase &PM,
    raw_postream &File,
    CodeGenFileType FileType,
    bool DisableVerify
  ) override;
};

3.8.1 Target 描述的三个层次

TableGen 描述 (.td 文件)
       │
       │  tblgen 工具
       ▼
┌──────────────────────────────┐
│ 自动生成的 C++ 头文件         │
│ X86GenInstrInfo.inc          │
│ X86GenRegisterInfo.inc       │
│ X86GenAsmWriter.inc          │
└──────────────┬───────────────┘
               │
               │ 编译
               ▼
┌──────────────────────────────┐
│ 目标后端实现                  │
│ X86InstrInfo.cpp             │
│ X86RegisterInfo.cpp          │
│ X86AsmPrinter.cpp            │
└──────────────────────────────┘

3.9 编译流程全景

3.9.1 clang -O2 背后的完整流程

# 当你执行:
clang -O2 test.c -o test

# 实际经历了以下阶段:
test.c
  │
  ├─ 预处理 (clang -E)
  │    ↓
  │  test.i
  │
  ├─ 词法分析 + 语法分析 (clang Frontend)
  │    ↓
  │  Clang AST
  │
  ├─ 语义分析 + IR 生成 (CodeGen)
  │    ↓
  │  LLVM IR (test.ll)
  │
  ├─ 优化 Pass 流水线 (opt -O2)
  │    ├─ SimplifyCFG
  │    ├─ InstCombine
  │    ├─ SROA
  │    ├─ EarlyCSE
  │    ├─ InlinerPass
  │    ├─ GVN
  │    ├─ LoopVectorize
  │    ├─ SLPVectorize
  │    └─ ... (约 100 个 Pass)
  │    ↓
  │  优化后 LLVM IR
  │
  ├─ 代码生成 (llc -O2)
  │    ├─ SelectionDAG 构建
  │    ├─ 指令选择
  │    ├─ 指令调度 (pre-RA)
  │    ├─ 寄存器分配
  │    ├─ 指令调度 (post-RA)
  │    ├─ Peephole 优化
  │    └─ 汇编发射
  │    ↓
  │  test.s (汇编)
  │
  ├─ 汇编器 (as / MC层)
  │    ↓
  │  test.o (目标文件)
  │
  └─ 链接器 (lld / ld)
       ↓
     test (可执行文件)

3.9.2 优化级别

级别说明Pass 数量编译速度运行速度
-O0无优化~10⚡⚡⚡🐢
-O1基础优化~40⚡⚡🏃
-O2标准优化~100🚀
-O3激进优化~120🐢🚀🚀
-Os体积优化~90🏃
-Oz最小体积~80🚶

3.10 本章小结

概念要点
IR 层次AST → LLVM IR → SelectionDAG/MIR → MCInst
IR 形式.ll (文本)、.bc (二进制)、内存对象
Pass 框架分析 Pass + 转换 Pass,新 PassManager 为默认
后端流水线IR → DAG → 指令选择 → 调度 → 寄存器分配 → MC
库设计每个功能模块是独立的库,可选择性链接
类型系统丰富的类型层次,支持地址空间

扩展阅读

  1. LLVM Programmer’s Manual — 编程指南
  2. LLVM Source Tree — 源码树结构
  3. Writing an LLVM Pass — 新 PassManager 编写指南
  4. LLVM Code Generation — 代码生成器文档

下一章: 第 4 章:LLVM IR 详解 — 深入学习 LLVM IR 的语法、类型系统和指令集。