Skip to content
Gains Summary
Main Navigation 首页 / Home
C++ 编程 / C++ Programming
系统与高性能 / Systems & Performance
Web 开发 / Web Development
人工智能 / Artificial Intelligence
工业软件 / Industrial Software
其他内容 / Other Topics
C++ 编程 / C++系统与性能 / SystemsWeb 开发 / Web人工智能 / AI工业软件 / Industrial

外观

Sidebar Navigation

← 人工智能 / Artificial Intelligence

AI 编译器 / AI Compilers

1. AI 编译器全景——为什么模型需要编译器 / The AI Compiler Landscape and Why Models Need Compilers

2. 编译原理速通——面向 ML 工程师的核心概念 / Compiler Fundamentals for Machine Learning Engineers

3. 中间表示基础——理解 IR 层级与 lowering 链路 / Intermediate Representation Levels and Lowering Pipelines

4. 计算图的构建与表示 / Building and Representing Computational Graphs

5. MLIR 架构、方言与渐进式降级 / MLIR Architecture, Dialects, and Progressive Lowering

6. 算子语义、广播、归约与形状推导 / Operator Semantics, Broadcasting, Reduction, and Shape Inference

7. 模型前端格式:ONNX、TFLite、HLO 与 SavedModel / Model Frontend Formats: ONNX, TFLite, HLO, and SavedModel

8. 图优化 Pass——经典优化在 ML 中的应用 / Graph Optimization Passes for Machine Learning

9. 算子融合——编译器最重要的性能优化 / Operator Fusion as a Core Compiler Optimization

10. 内存规划——Buffer 分配与生命周期管理 / Memory Planning, Buffer Allocation, and Lifetime Management

11. Layout 优化——数据排布转换与内存效率 / Layout Optimization for Data Movement and Memory Efficiency

12. 动态 Shape——符号分析与形状处理 / Dynamic Shapes, Symbolic Analysis, and Shape Processing

13. 硬件约束下的操作调度 / Operation Scheduling Under Hardware Constraints

14. 从模板、DSL 到 IR 降级的代码生成架构 / Code Generation Architectures from Templates and DSLs to IR Lowering

15. CPU 后端:SIMD、分块与多线程 / CPU Backends with SIMD, Tiling, and Multithreading

16. CUDA 后端:合并访存与 Tensor Core / CUDA Backends, Memory Coalescing, and Tensor Cores

17. NPU 后端:脉动阵列与端侧 AI 生态 / NPU Backends, Systolic Arrays, and Edge AI Ecosystems

18. Kernel 性能基础:Roofline 与 Occupancy / Kernel Performance Fundamentals with Roofline and Occupancy

19. CUTLASS 与分层 GEMM 模板 / CUTLASS and Hierarchical GEMM Templates

20. TVM Tensor Expression 与计算调度分离 / TVM Tensor Expressions and Compute-Schedule Separation

21. 使用 Triton 编写高性能 GPU Kernel / Triton for High-Performance GPU Kernels in Python

22. 基于成本模型与实测搜索的自动调度 / Automatic Scheduling with Cost Models and Measurement-Based Search

23. XLA 内部机制:HLO、融合与 SPMD / XLA Internals, HLO, Fusion, and SPMD

24. Torch-MLIR:从 PyTorch 算子到 MLIR 方言 / Torch-MLIR from PyTorch Operators to MLIR Dialects

25. torch.compile:Dynamo、AOTAutograd、Inductor 与 Triton / Torch Compile with Dynamo, AOTAutograd, Inductor, and Triton

26. 从 MLIR 经 LLVM 降级到机器码 / Lowering from MLIR Through LLVM to Machine Code

27. 量化——低精度推理的工程实践 / Engineering Low-Precision Inference with Quantization

28. 分布式编译与训练——多设备编排的编译器支持 / Compiler Support for Distributed Training and Multi-Device Orchestration

29. 生产调试——真实问题的编译器视角排查 / Production Debugging from the Compiler Perspective

30. 未来方向——AI 编译器的新挑战与机遇 / Future Challenges and Opportunities for AI Compilers

本页目录

📅 创建时间:2026-06-03 🏷️ 标签:#MLIR #LLVM #Lowering #Codegen #GlobalISel #SelectionDAG #TargetTransformInfo #x86 #ARM 📚 前置知识:[[/04-ai/01-llm-engineering/07-llm-evolution]](LLM 发展脉络) 📚 相关知识:[[04-mlir-architecture]](MLIR 架构) [[14-backend-cpu]](CPU 后端)


从 MLIR 经 LLVM 降级到机器码 / Lowering from MLIR Through LLVM to Machine Code ​

┌─────────────────────────────────────────────────────────────────────────────┐
│  场景:从 MLIR 到 x86 汇编的疑惑                                              │
├─────────────────────────────────────────────────────────────────────────────┤
│  你在研究 IREE 如何把一个 MLIR 程序编译成 x86 汇编:                          │
│                                                                             │
│  Linalg matmul → Linalg to Affine → Affine to SCF → SCF to LLVM → x86      │
│                                                                             │
│  你想知道:                                                                  │
│  - MLIR 的 dialect conversion 到底做了什么?                                  │
│  - 为什么一个 Affine loop nest 能最终变成 x86 的 AVX-512 指令?               │
│  - GlobalISel 和 SelectionDAG 是什么,哪个更好?                              │
└─────────────────────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12

第1节 MLIR 到 LLVM IR 转换 ​

1.1 Dialect Conversion 机制 ​

MLIR 的核心特性之一是多层次 Dialect,Conversion Pass 负责把高层 Dialect 降到低层 Dialect:

mlir
// Dialect Conversion 示例
// 从 Linalg 到 LLVM 的完整转换路径

// ===== Stage 1: Linalg Dialect (高层) =====
#map = affine_map<(d0, d1, d2) -> (d0, d2)>
#map1 = affine_map<(d0, d1, d2) -> (d2, d1)>
#map2 = affine_map<(d0, d1, d2) -> (d0, d1)>

func.func @matmul(%A: tensor<128x256xf32>, 
                  %B: tensor<256x512xf32>, 
                  %C: tensor<128x512xf32>) 
    -> tensor<128x512xf32> {
  
  // Linalg matmul:抽象的矩阵乘法描述
  %D = linalg.matmul 
    ins(%A, %B: tensor<128x256xf32>, tensor<256x512xf32>)
    outs(%C: tensor<128x512xf32>)
    -> tensor<128x512xf32>
  
  return %D : tensor<128x512xf32>
}

// ===== Stage 2: After Linalg to Affine (优化后) =====
// matmul 被展开为 Affine loop nest
func.func @matmul_affine(%A: memref<128x256xf32>, 
                         %B: memref<256x512xf32>,
                         %C: memref<128x512xf32>) {
  affine.for %i = 0 to 128 {
    affine.for %j = 0 to 512 {
      %c0 = arith.constant 0.0 : f32
      affine.store %c0, %C[%i, %j] : memref<128x512xf32>
      affine.for %k = 0 to 256 {
        %a_val = affine.load %A[%i, %k] : memref<128x256xf32>
        %b_val = affine.load %B[%k, %j] : memref<256x512xf32>
        %c_val = affine.load %C[%i, %j] : memref<128x512xf32>
        %new_c = arith.addf %c_val, %a_val : f32
        affine.store %new_c, %C[%i, %j] : memref<128x512xf32>
      }
    }
  }
  return
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

1.2 Builtin 到 LLVM Dialect 转换 ​

mlir
// Type 转换规则
// tensor<...> → memref<...> → LLVM pointer

// Before: Tensor Type
%tensor = "test.tensor"() : () -> tensor<128x256xf32>

// After: Memref Type  
%memref = "test.to_memref"(%tensor) : (tensor<128x256xf32>) -> memref<128x256xf32>

// After: LLVM Pointer Type
%ptr = "test.to_llvm_ptr"(%memref) : (memref<128x256xf32>) -> !llvm.ptr<f32>

// ===== Complete Type Conversion =====
"""
tensor<128x256xf32>
        │
        ▼ (bufferization)
memref<128x256xf32, strided<[256, 1], offset: 0>>
        │
        ▼ (memref to LLVM)
!llvm.struct<(ptr<f32>, ptr<f32>, i64, array<2xi64>, array<2xi64>)>
        │
        ▼ (LLVM lowering)
!llvm.ptr<f32> (with metadata)
"""
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

1.3 Function Calling Convention ​

mlir
// MLIR 函数到 LLVM 函数
// 函数签名转换

// MLIR 函数(高层)
func.func @compute(%arg0: tensor<128xf32>, %arg1: tensor<128xf32>) 
    -> tensor<128xf32> {
  %result = "arith.addf"(%arg0, %arg1) : (tensor<128xf32>, tensor<128xf32>) 
    -> tensor<128xf32>
  return %result : tensor<128xf32>
}

// Lower 到 LLVM Dialect
llvm.func @compute(
  %arg0: !llvm.ptr<f32>,   // 替换 tensor
  %arg1: !llvm.ptr<f32>,
  %arg2: !llvm.ptr<f32>     // output ptr (return via out-param)
) {
  // 使用 LLVM intrinsics
  %0 = llvm.load %arg0 : !llvm.ptr<f32>
  %1 = llvm.load %arg1 : !llvm.ptr<f32>
  %2 = llvm.fadd %0, %1 : f32
  llvm.store %2, %arg2 : !llvm.ptr<f32>
  llvm.return
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

第2节 LLVM Pass 流水线 ​

2.1 LLVM 优化 Pass 概览 ​

┌─────────────────────────────────────────────────────────────────────────────┐
│                        LLVM Optimization Pipeline                            │
└─────────────────────────────────────────────────────────────────────────────┘

    ┌──────────────────────────────────────────────────────────────────────┐
    │  LLVM IR Input (from MLIR)                                           │
    └──────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
    ┌──────────────────────────────────────────────────────────────────────┐
    │  Analysis Passes (不修改 IR,只提供信息)                              │
    │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐               │
    │  │ Dominator    │  │ PostDominator│  │ LoopInfo      │               │
    │  │ Tree         │  │ Tree         │  │               │               │
    │  └──────────────┘  └──────────────┘  └──────────────┘               │
    │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐               │
    │  │ ScalarEvoul  │  │ Alias        │  │ Target       │               │
    │  │              │  │ Analysis     │  │ TransformInfo│               │
    │  └──────────────┘  └──────────────┘  └──────────────┘               │
    └──────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
    ┌──────────────────────────────────────────────────────────────────────┐
    │  Transform Passes                                                     │
    │  ┌────────────────────────────────────────────────────────────────┐  │
    │  │ IPO (Interprocedural Optimization)                             │  │
    │  │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐             │  │
    │  │ │ArgPromo │ │DeadFunc │ │Inline   │ │MergeFunc│             │  │
    │  │ └─────────┘ └─────────┘ └─────────┘ └─────────┘             │  │
    │  └──────────────────────────────────────────────────────────────┘  │
    │  ┌────────────────────────────────────────────────────────────────┐  │
    │  │ Scalar Passes                                                  │  │
    │  │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐             │  │
    │  │ │SROA     │ │InstComb │ │ GVN     │ │LICM     │             │  │
    │  │ └─────────┘ └─────────┘ └─────────┘ └─────────┘             │  │
    │  └──────────────────────────────────────────────────────────────┘  │
    │  ┌────────────────────────────────────────────────────────────────┐  │
    │  │ Vectorization Passes                                           │  │
    │  │ ┌───────────────────┐ ┌───────────────────┐                   │  │
    │  │ │ SLP Vectorizer    │ │ Loop Vectorizer   │                   │  │
    │  │ │ (horizontal)      │ │ (vertical)        │                   │  │
    │  │ └───────────────────┘ └───────────────────┘                   │  │
    │  └──────────────────────────────────────────────────────────────┘  │
    └──────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
    ┌──────────────────────────────────────────────────────────────────────┐
    │  CodeGen Passes                                                      │
    │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐              │
    │  │ RegAlloc    │  │ Instruction  │  │ Peephole     │              │
    │  │ (寄存器分配) │  │ Select       │  │ Optimizer    │              │
    │  └──────────────┘  └──────────────┘  └──────────────┘              │
    └──────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
    ┌──────────────────────────────────────────────────────────────────────┐
    │  Assembly/MC Layer                                                   │
    │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐              │
    │  │  x86_64      │  │  AArch64     │  │  RISC-V      │              │
    │  │  Assembly    │  │  Assembly    │  │  Assembly    │              │
    │  └──────────────┘  └──────────────┘  └──────────────┘              │
    └──────────────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

2.2 关键 Pass 详解 ​

llvm
; 1. SROA (Scalar Replacement of Aggregates)
; 把 aggregate (struct/array) 拆分到独立变量

; Before SROA
%agg = alloca { i32, float }
%val = load %agg
%sum = add i32 %val.0, 42

; After SROA
%val.0 = alloca i32
%val.1 = alloca float
%loaded.0 = load i32* %val.0
%sum = add i32 %loaded.0, 42

; 2. InstCombine (Instruction Combining)
; 代数化简

; Before
%a = add i32 %x, 0      ; x + 0 → x
%b = mul i32 %a, 1      ; * 1 → 保持
%c = and i32 %b, -1     ; & -1 → 保持

; After InstCombine
%c = and i32 %x, -1     ; 合并为单一操作

; 3. GVN (Global Value Numbering)
; 消除冗余计算

; Before
%a = load i32* %ptr
%b = load i32* %ptr     ; 相同的 load
%c = add i32 %a, %b

; After GVN
%a = load i32* %ptr
%c = add i32 %a, %a     ; 使用已有值

; 4. LICM (Loop Invariant Code Motion)
; 循环不变式外提

; Before
for (i = 0; i < n; i++) {
    x = compute();    ; 循环不变
    y = arr[i] + x;
}

; After LICM
x = compute();         ; 提到循环外
for (i = 0; i < n; i++) {
    y = arr[i] + x;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

2.3 Vectorization Passes ​

llvm
; SLP Vectorizer (Scalar to Vector)
; 合并独立的标量操作到向量操作

; Before (处理4个独立的加法)
%a0 = fadd float %x0, %y0
%a1 = fadd float %x1, %y1
%a2 = fadd float %x2, %y2
%a3 = fadd float %x3, %y3

; After SLP Vectorization (一条向量指令)
%vec.x = vector.shuffle <4 x float> %x0, %x1, %x2, %x3
%vec.y = vector.shuffle <4 x float> %y0, %y1, %y2, %y3
%vec.a = fadd <4 x float> %vec.x, %vec.y

; Loop Vectorizer (向量化循环)
; 把标量循环转为向量循环

; Before
for (i = 0; i < 1024; i++)
    y[i] = x[i] + z[i];

; After Loop Vectorization (AVX-512, 16元素并行)
; <16 x float> 表示16个float的向量
for (i = 0; i < 1024; i += 16)
    %vx = vector.load <16 x float> &x[i]
    %vy = vector.load <16 x float> &y[i]
    %vz = vector.load <16 x float> &z[i]
    %vr = fadd <16 x float> %vx, %vy
    vector.store %vr, &y[i]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

第3节 LLVM Codegen 架构 ​

3.1 指令选择概述 ​

LLVM 的核心任务之一是把 LLVM IR 指令转换为目标机器指令,这称为指令选择:

llvm
; LLVM IR (抽象)
%result = fadd float %a, %b
%result2 = fmul float %result, %c

; 可能的 x86_64 目标代码
vmovss (%rdi), %xmm0      ; load %a
vaddss (%rsi), %xmm0, %xmm0  ; add %b
vmulss (%rdx), %xmm0, %xmm0  ; multiply %c
1
2
3
4
5
6
7
8

3.2 SelectionDAG vs GlobalISel ​

特性SelectionDAGGlobalISel
设计时间2000年代初期2015年后
架构DAG(有向无环图)单一函数 IR
选择方式两步:ISel + RegAlloc一步:Combined
处理范围BB 内函数级
寄存器分配单独 pass集成
支持目标所有目标x86, AArch64, RISC-V
性能成熟稳定新,但潜力更大
复杂度复杂(多 pass)简洁(一体化)

3.3 SelectionDAG 详解 ​

llvm
// SelectionDAG 的工作流程

; 1. DAG 构建阶段
; LLVM IR → SelectionDAG

%add = fadd float %a, %b    ; DAG 节点: FDIV
%mul = fmul float %add, %c  ; DAG 节点: FMUL

DAG 拓扑:
        ┌─────┐
        │ 0   │ (Entry)
        └──┬──┘
           │
        ┌──┴──┐
        │FDIV │
        └──┬──┘
           │
        ┌──┴──┐
        │FMUL │
        └──┬──┘
           │
        ┌──┴──┐
        │ 0   │ (Finish)
        └─────┘

; 2. 指令选择阶段
; DAG 节点 → 目标机器指令

; x86_64 目标:
FDIV → vaddss (使用 FADD 或根据精度选择)
FMUL → vmulss

; ARM 目标:
FDIV → vadd.f32 (NEON)
FMUL → vmul.f32 (NEON)

; 3. 调度阶段
; 确定指令执行顺序

; 发射顺序:
vmovss (%rdi), %xmm0    ; 1. load a
vmovss (%rsi), %xmm1    ; 2. load b
vaddss %xmm1, %xmm0      ; 3. add
vmovss (%rdx), %xmm1    ; 4. load c  
vmulss %xmm1, %xmm0      ; 5. multiply
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

3.4 GlobalISel 详解 ​

llvm
// GlobalISel 的优势:一体化处理

; 1. 函数级 IR
; 直接在 MachineFunction 上操作,不经过 DAG

MachineFunction:
%bb.0:
  %a:f32 = LGLOBAL_LOAD_F32 %p0
  %b:f32 = LGLOBAL_LOAD_F32 %p1
  %c:f32 = LGLOBAL_LOAD_F32 %p2
  
  %add:f32 = G_FADD %a, %b      ; 统一的指令
  %mul:f32 = G_FMUL %add, %c    ; 无需转换为 DAG
  
  SGLOBAL_STORE_F32 %mul, %p3
  RET

; 2. Combined 指令选择和寄存器分配
; 使用寄存器分配器同时做选择

; Register Allocator 工作:
; - 计算 SSA 值的生命周期
; - 分配物理寄存器
; - 插入 copy 和 spill 指令

; 3. 发射 x86_64 代码
; 最终输出:
vmovss 16(%rsp), %xmm0   ; load a
vaddss 24(%rsp), %xmm0   ; add b
vmulss 32(%rsp), %xmm0   ; multiply c
vmovss %xmm0, 40(%rsp)   ; store result
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

第4节 TargetTransformInfo ​

4.1 TTI 的作用 ​

TargetTransformInfo (TTI) 是 LLVM 用来描述目标硬件特性的接口,让优化 pass 能根据具体硬件特性做决策:

cpp
// TTI 抽象的硬件特性

class TargetTransformInfo {
    // 1. 向量化和 SIMD 能力
    int getMaxVF(unsigned EF, Type *Ty);     // 最大向量宽度
    bool hasNeon(Type *Ty);                   // NEON 可用 (ARM)
    bool hasAVX512(Type *Ty);                  // AVX-512 可用 (x86)
    
    // 2. 内存层次
    unsigned getCacheLineSize();               // 缓存行大小
    L1CacheCost getCacheSize(Level);           // 各层缓存大小
    
    // 3. 指令延迟和吞吐量
    unsigned getLatency(unsigned Opcode);      // 指令延迟
    unsigned getIssueWidth();                  // 发射宽度
    
    // 4. 并行化能力
    bool supportsOutOfOrderExecution();        // 乱序执行
    unsigned getNumberOfRegisters();          // 寄存器数量
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

4.2 TTI 在优化中的应用 ​

llvm
; TTI 帮助 Vectorizer 做出正确决策

; 输入: 处理 10000 个 float 的加法

; 询问 TTI: hasAVX512() = true (目标机器支持)
; 询问 TTI: getMaxVF(f32) = 16 (AVX-512 = 512bit / 32bit = 16)

; 决策: 使用 <16 x float> 向量

; 生成的 x86_64 (AVX-512) 代码:
vmovups (%rdi), %zmm0      ; load 16 floats
vaddps (%rsi), %zmm0, %zmm0 ; add 16 floats
vmovups %zmm0, (%rdx)      ; store 16 floats

; 循环 10000 / 16 = 625 次迭代完成

; 如果 TTI 报告 hasAVX512 = false,则选择 SSE/AVX2:
; vmovups + vaddps (128/256bit,每次处理 4/8 个 float)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

第5节 具体 Lowering 链路演示 ​

5.1 完整 Lowering 路径 ​

┌─────────────────────────────────────────────────────────────────────────────┐
│              MLIR → x86_64 ASM 完整 Lowering 路径                            │
└─────────────────────────────────────────────────────────────────────────────┘

Stage 1: Linalg Dialect (抽象的算子描述)
─────────────────────────────────────────
linalg.matmul ins(A, B) outs(C)
        │
        ▼ (linalg-to-affine pass)
Stage 2: Affine Dialect (索引表达式)
─────────────────────────────────────────
affine.for i = 0 to M
  affine.for j = 0 to N
    affine.for k = 0 to K
      %c[i,j] += %a[i,k] * %b[k,j]
        │
        ▼ (affine-to-scf pass)
Stage 3: SCF Dialect (结构化控制流)
─────────────────────────────────────────
scf.for i = 0 to M
  scf.for j = 0 to N
    scf.for k = 0 to K
        │
        ▼ (scf-to-cf pass + affine-loop-collapsed pass)
Stage 4: CF/Arith Dialect (基础控制流和算术)
─────────────────────────────────────────
br label %i_loop
i_loop:
  %i_phi = phi [0, %entry], [%i_next, %i_loop]
  ...
        │
        ▼ (memref-to-llvm pass)
Stage 5: LLVM Dialect (类型转换为 LLVM)
─────────────────────────────────────────
llvm.func @matmul(
  %A: !llvm.ptr<f32>,
  %B: !llvm.ptr<f32>,
  %C: !llvm.ptr<f32>,
  %M: i64, %N: i64, %K: i64
)
        │
        ▼ (builtin-to-llvm pass)
Stage 6: LLVM IR (标准 LLVM 中间表示)
─────────────────────────────────────────
define void @matmul(float* %A, float* %B, float* %C,
                    i64 %M, i64 %N, i64 %K) {
entry:
  br label %i_loop
i_loop:
  %i = phi i64 [0, %entry], [%i_next, %i_loop]
  ...
        │
        ▼ (LLVM optimization pipeline)
Stage 7: Optimized LLVM IR
─────────────────────────────────────────
; 已做 loop tiling, vectorization, 注册压力减少等优化
        │
        ▼ (llc/x86_64 codegen)
Stage 8: x86_64 Assembly
─────────────────────────────────────────
matmul:
    vmovups (%rdi), %xmm0
    vaddps %xmm1, %xmm0, %xmm0
    ...
    ret
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

5.2 Affine Loop 变换到 Vectorized ASM ​

mlir
// 完整转换示例

// ===== Input: Linalg matmul =====
func.func @matmul(%A: tensor<128x256xf32>,
                  %B: tensor<256x512xf32>,
                  %C: tensor<128x512xf32>) -> tensor<128x512xf32> {
  %D = linalg.matmul ins(%A, %B: tensor<128x256xf32>, tensor<256x512xf32>)
                     outs(%C: tensor<128x512xf32>) -> tensor<128x512xf32>
  return %D : tensor<128x512xf32>
}

// ===== After LinalgToAffine + Tile =====
// 循环分块 (tile 32x32)
func.func @matmul_tiled(...) {
  scf.for %i = 0 to 128 step 32:
    scf.for %j = 0 to 512 step 32:
      scf.for %k = 0 to 256 step 32:
        // 处理 32x32x32 tile
        linalg.matmul ins(%A[%i:%i+32, %k:%k+32], ...)
                     outs(%C[%i:%i+32, %j:%j+32])
}

// ===== After AffineToSCF + Vectorization =====
// <8 x float> = AVX2 (256bit) 向量
scf.for %i = 0 to 128 step 8:       // 向量化 factor = 8
  scf.for %j = 0 to 512 step 4:    // 4 accumulator
    %acc = vector.broadcast ...    // broadcast
    scf.for %k = 0 to 256:
      %va = vector.load %A[%i, %k]
      %vb = vector.load %B[%k, %j:%j+4]
      %acc = vector.fma %va, %vb, %acc  // fused multiply-add
    vector.store %acc, %C[%i, %j]
}

// ===== Generated x86_64 ASM (伪代码) =====
// 实际生成代码(AVX2):
matmul_kernel:
    ; Setup
    mov %rdi, %rax              ; A pointer
    mov %rsi, %rbx              ; B pointer  
    mov %rdx, %rcx              ; C pointer
    
.loop_i:
    vbroadcastss (%rax), %ymm0  ; broadcast A[i,k] to 8 elements
    xor %rbp, %rbp              ; j = 0
    
.loop_j:
    vmovups (%rbx,%rbp,4), %ymm1 ; load B[k,j:j+8]
    vfmadd231ps %ymm1, %ymm0, %ymm2 ; %ymm2 += %ymm0 * %ymm1
    add $8, %rbp                ; j += 8
    cmp $512, %rbp              ; j < N
    jl .loop_j
    
    vmovups %ymm2, (%rcx,%rbp,4) ; store result
    add $8, %rax                ; i += 8
    ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

第6节 Target Machine 与指令编码 ​

6.1 Target Machine 抽象 ​

cpp
// LLVM TargetMachine 抽象

class TargetMachine {
    // 1. 目标描述
    const Triple &getTargetTriple();  // "x86_64-unknown-linux-gnu"
    
    // 2. 后端选择
    const TargetPassConfig *createPassConfig();
    
    // 3. 指令编码
    const MCAsmInfo *getMCAsmInfo();  // 汇编格式信息
    const MCInstrInfo *getInstrInfo(); // 指令编码
    const MCRegisterInfo *getRegInfo(); // 寄存器编码
};

// 常用 TargetMachine
TargetMachine *TM = 
    createX86TargetMachine(Triple("x86_64-unknown-linux-gnu"),
                          CPU::Generic,
                          Features::AVX2);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

6.2 x86_64 指令编码基础 ​

x86_64 指令编码结构:

┌─────────────────────────────────────────────────────────────────────────────┐
│  指令编码格式                                                               │
├─────────────────────────────────────────────────────────────────────────────┤
│  Prefix | Opcode | ModR/M | SIB | Displacement | Immediate                │
│  1-4B   | 1-3B   | 0-1B   | 0-1B | 0,1,2,4B     | 0,1,2,4,8B              │
└─────────────────────────────────────────────────────────────────────────────┘

AVX-512 vmulps 指令示例:
  vmulps %ymm1, %ymm2, %ymm3
  
  编码: [EVEX] [Opcode] [ModRM]
  62 F1 72 08 D1
  
  62: EVEX 前缀 (指定向量长度、掩码等)
  F1: Opcode (vmulps = 59)
  72: ModR/M (指定操作数: %ymm2, %ymm3)
  08: 额外扩展
  D1: ModR/M (指定 %ymm1)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

6.3 MC Layer:从 IR 到目标文件 ​

llvm
; MC Layer 的任务

; 1. LLVM IR → MCInst
; 每个 LLVM IR 指令映射到一个或多个 MCInst

; 2. MCInst → 字节序列
; 编码指令为机器码

; 3. 输出目标文件
; ELF (Linux), MachO (macOS), COFF (Windows)

; 示例:生成 ELF .o 文件
; LLVM IR
define void @foo() {
  ret void
}

; 汇编
    .text
    .globl foo
    .type foo, @function
foo:
    ret
    .size foo, .-foo

; 编译命令
; llc -filetype=obj -o foo.o foo.ll
; 或
; clang -c foo.s -o foo.o

; ELF 输出 (objdump -d foo.o)
foo.o:     file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <foo>:
   0:   c3                      retq
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

升华 ​

┌─────────────────────────────────────────────────────────────────────────────┐
│                    MLIR-LLVM 集成核心原则                                    │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  1. 层次化 Lowering 是关键                                                  │
│     Linalg → Affine → SCF → LLVM → 机器码,每层解决不同抽象层次的问题       │
│                                                                             │
│  2. Conversion Pattern 是桥梁                                               │
│     DialectConversion framework 提供声明式转换规则,简化多层次 lowering     │
│                                                                             │
│  3. TTI 抽象硬件差异                                                        │
│     TargetTransformInfo 让优化 pass 能够根据具体硬件特性做出最优决策        │
│                                                                             │
│  4. GlobalISel 是未来                                                        │
│     一体化指令选择更简洁高效,但 SelectionDAG 仍然可靠                       │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

"AI 可查 vs 必须理解"清单 ​

必须理解(不理解就等于不会):

  • 🔴 MLIR Dialect Conversion 机制:通过 PatternRewrite 系统进行层次化 lowering
  • 🔴 LLVM Pass 分类:Analysis(分析)、Transform(变换)、CodeGen(代码生成)
  • 🔴 Vectorization 的两种类型:SLP(水平合并)、Loop(垂直向量化)
  • 🔴 SelectionDAG vs GlobalISel:传统 DAG 两步选择 vs 新的一体化选择
  • 🔴 Lowering 路径:Linalg → Affine → SCF → LLVM → ASM 的转换顺序

AI 可查(知道去哪查就行):

  • ✅ 特定 x86_64 指令编码:Intel SDM 指令集参考
  • ✅ 具体 LLVM Pass 的实现细节:LLVM 源码 lib/Target/X86/
  • ✅ TTI 各接口的精确语义:LLVM 文档 TargetTransformInfo.rst
  • ✅ GlobalISel 的具体设计:LLVM 论文和源码
  • ✅ MC Layer 的汇编解析:LLVM 源码 lib/MC/

学习状态:🟡 开始学习

最后更新于:

Pager
上一篇25. torch.compile:Dynamo、AOTAutograd、Inductor 与 Triton / Torch Compile with Dynamo, AOTAutograd, Inductor, and Triton
下一篇27. 量化——低精度推理的工程实践 / Engineering Low-Precision Inference with Quantization

持续记录,持续成长

Copyright © Tidenflow