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

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 PassManager New PassManager
状态 已废弃 当前默认(LLVM 14+)
命名空间 llvm:: (legacy) llvm::
Pass 注册 RegisterPass PassBuilder
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 基础工具类 命令行、内存管理、调试
LLVMCore Support IR 核心 Module/Function/Instruction
LLVMAnalysis Core 分析 Pass 循环分析、别名分析
LLVMTransformUtils Analysis 转换工具 内联、循环变换
LLVMScalarOpts TransformUtils 标量优化 GVN、InstCombine
LLVMVectorize TransformUtils 向量化 SLP、Loop Vectorizer
LLVMipo 多个 过程间优化 LTO、全局优化
LLVMCodeGen Core, MC 代码生成 指令选择、寄存器分配
LLVMTarget CodeGen 目标框架 TargetMachine、TargetLowering
LLVMMC Support MC层 MCInst、汇编器
LLVMObject MC 目标文件 ELF、MachO、COFF
LLVMBitReader Core Bitcode 读取 .bc 文件解析
LLVMBitWriter Core Bitcode 写入 .bc 文件生成
LLVMX86CodeGen CodeGen x86 后端 x86 指令生成
LLVMX86AsmParser MC x86 汇编解析 x86 汇编输入
LLVMX86Desc MC x86 描述 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 的语法、类型系统和指令集。