Compiler Engineering Roadmap
From Source Code to IR, Optimization, Runtime, and Hardware
Part 1: Compiler Worldview and Engineering Mental Model
Chapter 1: Compiler Transformation Model
- 1.1 Source Text, Program Meaning, and Executable Behavior(区分源码文本、程序语义和最终运行行为,分析编译器转换的是程序含义)
- 1.2 Translation vs Transformation(分析编译器是不断重写、降低、优化和约束程序表示的工程系统)
- 1.3 Frontend, Middle-End, Backend, and Runtime Boundaries(建立前端、中端、后端、运行时之间的职责边界)
- 1.4 Correctness as Semantic Preservation(分析每次编译转换都必须保持程序语义,并说明优化合法性来自可证明的等价关系)
- 1.5 Engineering Insight: A Compiler Turns Human Intent into Machine Constraints(编译器的核心是把人类可读的意图逐步压缩成机器、ABI、运行时和硬件能够执行的约束)
Chapter 2: Source Code as a Structured System
- 2.1 Text Is Only the Surface Form of a Program(说明源码文本只是程序的表层表达,程序结构需要经过词法、语法和语义阶段才能形成)
- 2.2 Formatting, Comments, and Human-Oriented Structure(分析缩进、注释、换行和命名主要服务人类阅读,需要区分于编译器最终执行模型)
- 2.3 Undefined Behavior, Implementation Choices, and Semantic Gaps(分析源码写出来的形式与语言标准、编译器实现、目标平台之间可能存在语义间隙)
- 2.4 Optimized Code Can Diverge from Source Shape(说明优化后代码、汇编、调试栈和变量状态如何偏离源码表面结构)
- 2.5 Engineering Insight: The Program You Debug Is Already a Compiler Product(程序员调试到的二进制、栈帧、符号和运行行为,已经是编译器加工后的结果)
Chapter 3: Compilation as a Sequence of Representations
- 3.1 Tokens, AST, IR, Machine IR, and Binary Forms(从 token、AST、IR、Machine IR 到 object file,分析多种中间表示承载的语义信息和执行约束)
- 3.2 Each Representation Keeps Some Information and Drops Some Information(每一层表示都会保留某些语义,同时丢弃某些源码细节)
- 3.3 Lowering as Moving Toward Execution(lowering 是把高层语言语义逐步改写成更接近目标机器的约束)
- 3.4 Analysis and Transformation Across Representations(分析 pass 和转换 pass 如何在不同表示层上获取事实、改写程序)
- 3.5 Engineering Insight: Compiler Understanding Lives in Its Representations(编译器“分析”程序的地方,是它构造并维护的一系列表示)
Chapter 4: Interpreter, Compiler, Transpiler, and JIT
- 4.1 Interpreter as Direct Execution of Program Representation(解释器直接执行 AST、bytecode 或其他中间表示,可能提前生成机器码)
- 4.2 Ahead-of-Time Compiler as Pre-Execution Translation(AOT 编译器在程序运行前完成大部分转换,生成目标平台可执行产物)
- 4.3 Transpiler as Source-to-Source Compilation(transpiler 把一种源语言转换成另一种源语言,仍然需要保持语义映射)
- 4.4 JIT as Runtime Compilation with Feedback(JIT 在运行时根据真实类型、热点路径和动态反馈生成或优化代码)
- 4.5 Engineering Insight: Execution Strategy Changes Where Compilation Cost Is Paid(解释、AOT、transpile、JIT 的区别,同时编译成本、优化机会和运行时风险被放在了不同阶段)
Chapter 5: Compiler Correctness, Performance, and Developer Experience
- 5.1 Correctness as the Compiler First Contract(说明语义保持为何是编译器优化、诊断和开发体验的前提)
- 5.2 Performance: Generated Code, Compile Time, and Runtime Tradeoffs(编译器性能既包括生成代码的运行效率,也包括编译耗时、内存占用和增量构建体验)
- 5.3 Diagnostics: Errors as Part of the Compiler Interface(错误信息、warning、source range、fix-it hint 是编译器面向程序员的重要接口)
- 5.4 Debuggability: Preserving Enough Source-Level Evidence(优化、inline、寄存器分配会破坏源码形态,因此 debug info 必须尽量保留可观察关系)
- 5.5 Engineering Insight: A Good Compiler Serves Both the Machine and the Programmer(优秀编译器同时服务机器执行效率和程序员的错误分析、调试、维护需求)
Part 2: Source Text, Tokens, and Lexical Analysis
Chapter 6: Source Text as Raw Characters
- 6.1 Source Files, Bytes, Encodings, and Unicode Text(分析源码文件首先是字节流,编译器必须先按编码把它解释成字符序列)
- 6.2 Characters as Raw Input Before Syntax(说明字符在词法阶段之前只是原始输入,语法意义来自后续 token 化)
- 6.3 Source Location: Line, Column, Offset, and File Identity(分析编译器为什么必须记录文件名、行号、列号、字节偏移,用于错误诊断和调试信息)
- 6.4 Normalization, Newlines, and Platform Differences(处理不同平台换行、BOM、Unicode 形式、文件结尾等输入差异)
- 6.5 Engineering Insight: Compilation Begins by Turning Bytes into Trustworthy Text(编译的第一步是把不可靠的字节输入转换成可定位、可诊断、可扫描的文本)
Chapter 7: Tokens as the First Structured Representation
- 7.1 Lexemes vs Tokens(区分源码中的具体字符片段 lexeme 和编译器内部使用的 token 类型)
- 7.2 Token Kind, Token Value, and Token Location(分析 token 通常包含类别、字面值或附加数据、源码位置三类信息)
- 7.3 Token Streams as Parser Input(说明 parser 如何把 lexer 产出的 token stream 当作带边界、类别和值的结构化输入)
- 7.4 Longest Match and Token Boundary Decisions(分析词法器如何决定
==需要区分两个=,123abc是否非法,标识符在哪里结束) - 7.5 Engineering Insight: Tokens Are the First Moment Source Code Becomes Data(token 是源码第一次从人类文本变成编译器可处理数据结构的时刻)
Chapter 8: Lexical Rules, Keywords, Identifiers, and Literals
- 8.1 Keywords vs Identifiers(分析
if、while、return这类关键字如何和普通标识符区分) - 8.2 Identifier Rules and Language Character Sets(分析标识符允许哪些字符、是否支持 Unicode、是否区分大小写)
- 8.3 Numeric, String, Character, and Boolean Literals(分析字面量如何从文本形式转化为内部值、类型候选和源码范围)
- 8.4 Operators, Delimiters, and Punctuation Tokens(处理
+、->、::、,、;、括号、花括号等操作符和分隔符) - 8.5 Engineering Insight: Lexical Rules Define the Smallest Meaningful Units of a Language(词法规则定义语言最小的可识别单位,也决定后续 parser 能否稳定工作)
Chapter 9: Whitespace, Comments, Newlines, and Layout-Sensitive Syntax
- 9.1 Whitespace as Separator, Noise, or Syntax(空格和制表符在某些语言中只是分隔符,在 Python、YAML 等语言中可能参与结构)
- 9.2 Comments as Ignored Text with Diagnostic Consequences(注释通常不进入语法结构,但仍影响源码位置、文档提取和错误定位)
- 9.3 Newlines, Semicolon Insertion, and Statement Boundaries(换行可能只是空白,也可能参与语句结束、自动分号插入或缩进结构)
- 9.4 INDENT, DEDENT, and Layout Tokens(分析 Python 这类缩进敏感语言如何把缩进变化转成 token)
- 9.5 Engineering Insight: What the Lexer Ignores Still Shapes the Language Experience(说明被忽略的空白和注释仍会塑造错误信息、源码映射和语言可读性)
Chapter 10: Lexer Errors, Diagnostics, and Source Locations
- 10.1 Invalid Characters and Unknown Token Sequences(识别无法归类的字符或字符组合,并给出可定位错误)
- 10.2 Unterminated Strings, Escapes, and Literal Errors(处理字符串未闭合、非法转义、数字格式错误等常见词法错误)
- 10.3 Recovering After Lexical Errors(词法阶段如何在出错后继续扫描,以便一次报告更多问题)
- 10.4 Diagnostic Messages with Source Ranges(用 token location、source range、行列信息生成可读错误提示)
- 10.5 Engineering Insight: A Lexer Is Also the First Diagnostic System(lexer 同时切 token,它也是编译器最早面对错误输入、建立源码证据和用户反馈的系统)
Part 3: Grammar, Parsing, and Abstract Syntax Trees
Chapter 11: Grammar as the Shape of Valid Programs
- 11.1 Grammar as the Formal Shape of a Language(分析 grammar 如何定义 token 可以按照什么结构组合成合法程序)
- 11.2 Terminals, Nonterminals, Productions, and Start Symbols(区分终结符、非终结符、产生式和起始符号在语法定义中的作用)
- 11.3 Expressions, Statements, Declarations, and Program Units(分析语言通常如何把程序结构拆成表达式、语句、声明、模块或顶层单元)
- 11.4 Grammar vs Language Semantics(语法说明结构是否合法,名字存在性、类型正确性和程序意义需要由后续语义分析建立)
- 11.5 Engineering Insight: Grammar Defines What Can Be Structured(grammar 负责让 token stream 变成结构,但程序意义还需要后续语义分析建立)
Chapter 12: Parsing Token Streams into Structure
- 12.1 Parser as the Consumer of Token Streams(分析 parser 如何读取 lexer 生成的 token stream,并根据 token 边界建立语法结构)
- 12.2 Recursive Descent, Pratt Parsing, PEG, LR, and Parser Generators(区分常见 parser 技术路线,以及手写 parser 和 parser generator 的工程取舍)
- 12.3 Predicting, Matching, and Consuming Tokens(分析 parser 如何根据当前 token、lookahead 和语法规则决定下一步匹配路径)
- 12.4 Parse Failure, Backtracking, and Ordered Choice(分析语法匹配失败后 parser 如何恢复、回退或选择其他分支;CPython 现在使用 PEG parser,PEG 的选择顺序本身会影响匹配语义)
- 12.5 Engineering Insight: Parsing Is Controlled Commitment Under Uncertainty(parser 的核心是在有限上下文中不断做结构判断和路径承诺)
Chapter 13: Parse Trees vs Abstract Syntax Trees
- 13.1 Parse Tree as a Full Grammar Derivation(分析 parse tree 通常保留完整语法推导细节,包括许多只是为了匹配 grammar 而存在的节点)
- 13.2 AST as the Program Structure the Compiler Actually Wants(分析 AST 会删去多余语法细节,保留后续语义分析、优化或代码生成需要的结构)
- 13.3 Syntax Sugar and AST Normalization(分析括号、分隔符、语法糖和表面写法如何在 AST 中被归一化或改写)
- 13.4 AST Node Kinds, Children, Source Ranges, and Metadata(分析 AST 节点通常包含类型、子节点、源码范围和部分辅助元数据)
- 13.5 Engineering Insight: AST Is Where Source Syntax Becomes Compiler-Usable Structure(AST 是源码结构进入编译器内部世界的关键边界,它既保留语言形状,又去掉不必要表面细节)
Chapter 14: Operator Precedence, Associativity, and Ambiguity
- 14.1 Expression Grammar Ambiguity(分析
a + b * c、a - b - c中优先级和结合性规则对 AST 结构的影响) - 14.2 Precedence as Binding Strength(优先级决定哪个操作符更早绑定操作数,例如乘法通常比加法更紧)
- 14.3 Associativity as Direction of Grouping(结合性决定同优先级操作符如何分组,例如左结合的减法会解析为
(a - b) - c) - 14.4 Pratt Parsing and Operator-Precedence Parsing(分析 expression parser 如何用 binding power 或 precedence table 处理复杂表达式)
- 14.5 Engineering Insight: Expression Parsing Is Where Human Math Notation Meets Compiler Determinism(表达式语法看似自然,但编译器必须把它确定地还原成唯一结构)
Chapter 15: Parser Error Recovery and Developer Feedback
- 15.1 Syntax Errors as Structural Breakpoints(语法错误意味着 parser 无法继续建立预期结构,好的编译器仍需要恢复到后续可分析区域)
- 15.2 Panic Mode, Synchronization Tokens, and Local Recovery(分析 parser 如何通过分号、换行、右括号、关键字等同步点跳过错误区域继续解析)
- 15.3 Reporting Expected Tokens and Actual Tokens(错误提示通常需要说明 parser 期待什么 token、实际遇到什么 token,以及源码位置在哪里)
- 15.4 Controlling Cascading Errors(一次语法错误可能引发大量伪错误,parser 需要控制恢复策略,使错误信息保持可读并服务定位)
- 15.5 Engineering Insight: A Parser Is Also a User Interface for Broken Programs(parser 不只服务合法程序,也必须面对大量半成品代码,并给程序员可分析、可修复的反馈)
Part 4: Semantic Analysis, Symbol Tables, and Scopes
Chapter 16: Names, Bindings, and Program Meaning
- 16.1 Names as References(分析变量名、函数名、类型名、模块名只是对某个声明或对象的引用,本身需要区分值)
- 16.2 Binding as Connecting a Name to a Declaration(semantic analysis 的核心任务之一,是把源码中的名字使用点绑定到对应声明点)
- 16.3 Name Resolution Before Type Checking(很多类型检查、调用检查和访问控制,必须先知道某个名字到底指向谁)
- 16.4 Shadowing, Overriding, and Ambiguous Names(分析局部变量遮蔽外层变量、成员覆盖、重名导入和歧义名字如何影响程序意义)
- 16.5 Engineering Insight: A Program Becomes Meaningful When Its Names Become Relationships(程序语义是在名字与声明建立关系之后才开始形成)
Chapter 17: Symbol Tables and Scope Chains
- 17.1 Symbol Table as the Compiler’s Name Database(分析 symbol table 如何记录名字、声明位置、类别、作用域、属性和后续分析所需信息)
- 17.2 Lexical Scope and Nested Scope Chains(分析块、函数、类、模块如何形成嵌套作用域,名字查找如何沿作用域链进行)
- 17.3 Local, Global, Free, Cell, and Captured Variables(分析局部变量、全局变量、自由变量、闭包捕获变量在不同语言中的表示方式)
- 17.4 Scope Construction from AST Traversal(编译器如何遍历 AST 建立作用域树、插入声明、记录引用和处理嵌套函数)
- 17.5 Engineering Insight: Symbol Tables Are Where Source Structure Becomes Semantic Memory(symbol table 是编译器记住“哪个名字在哪个范围内代表什么”的地方)
Chapter 18: Declarations, Definitions, and Resolution
- 18.1 Declaration vs Definition(区分声明告诉编译器某个实体存在,定义提供实体完整内容或存储/实现)
- 18.2 Forward Declarations and Multi-Pass Resolution(分析为什么有些语言允许先使用后定义,需要多遍扫描或延迟解析)
- 18.3 Function, Variable, Type, and Member Resolution(不同类别名字的解析规则不同,函数、变量、类型、成员访问通常有各自查找路径)
- 18.4 Overload Resolution and Candidate Selection(在支持重载的语言中,名字解析之后还要根据参数、类型和可见性选择具体候选)
- 18.5 Engineering Insight: Resolution Turns Syntax into a Specific Program(解析阶段让一段合法语法变成具体语义:每个名字、调用和访问都指向明确目标)
Chapter 19: Modules, Imports, and Visibility Rules
- 19.1 Modules as Compilation and Visibility Boundaries(模块同时承担文件组织、名字导出、导入、隔离和编译单元边界职责)
- 19.2 Import Resolution and Dependency Graphs(编译器或解释器如何根据 import 构建依赖关系,并决定哪些符号进入当前作用域)
- 19.3 Public, Private, Internal, and Exported Symbols(不同语言如何通过 visibility 规则控制 API 边界和实现细节)
- 19.4 Cyclic Imports and Partial Initialization(循环依赖如何导致名字尚未绑定、模块半初始化、编译顺序或运行时加载问题)
- 19.5 Engineering Insight: Module Systems Turn Name Resolution into Architecture(模块系统是在语言层面组织大型程序边界和依赖结构)
Chapter 20: Semantic Errors Beyond Syntax
- 20.1 Undefined Names and Unbound Variables(语法正确的程序会因为名字缺失、尚未绑定或作用域不可见进入语义错误路径)
- 20.2 Duplicate Declarations and Conflicting Definitions(同一作用域内重复定义、重复导出或不兼容声明如何破坏语义一致性)
- 20.3 Invalid Control Flow Contexts(
break、continue、return、yield、await等语句必须出现在合法语义上下文中) - 20.4 Access Rules, Visibility Violations, and Capability Checks(成员访问、模块私有符号、unsafe 区域、权限边界等语义规则如何产生错误)
- 20.5 Engineering Insight: Semantic Analysis Rejects Programs That Look Correct but Mean Nothing Legal(semantic analysis 负责拒绝那些语法上成立、但语言规则和程序意义上无法成立的代码)
Part 5: Type Systems, Type Checking, and Type Inference
Chapter 21: Types as Compile-Time Program Facts
- 21.1 Types as Constraints on Values and Operations(分析类型是约束某个值能参与哪些操作、能传递到哪些位置、能被如何解释)
- 21.2 Type Information as Compiler Knowledge(编译器通过类型知道表达式结果、函数参数、返回值、字段访问和运算是否合法)
- 21.3 Type Safety and Illegal Program States(类型系统的目标之一是提前排除某些非法状态,例如把字符串当函数调用、对整数取字段、错误参数传递)
- 21.4 Types as Optimization Evidence(当编译器知道值的类型,就可以省掉部分运行时检查、选择更具体指令、优化内存布局或调用路径)
- 21.5 Engineering Insight: Types Are Program Facts the Compiler Can Trust(类型的核心是编译器可依赖的程序事实,越可靠的类型事实,越能支撑错误检查和优化)
Chapter 22: Static Typing, Dynamic Typing, and Gradual Typing
- 22.1 Static Typing as Compile-Time Verification(静态类型在运行前检查类型约束,提前拒绝一部分不满足类型规则的程序)
- 22.2 Dynamic Typing as Runtime Type Validation(动态类型把类型信息绑定到运行时对象,在操作发生时检查对象是否支持对应行为)
- 22.3 Strong, Weak, Explicit, and Implicit Typing Are Different Axes(区分强弱类型、显式/隐式类型、静态/动态类型这些容易混淆的维度)
- 22.4 Gradual Typing and Optional Type Information(分析 TypeScript、Python type hints、C#
dynamic等机制如何让静态信息和动态行为共存) - 22.5 Engineering Insight: Typing Strategy Decides When Type Errors Become Visible(类型策略改变的是错误在编译期、运行期还是边界转换处暴露)
Chapter 23: Type Checking Expressions, Statements, and Functions
- 23.1 Expression Types and Operator Rules(分析二元运算、函数调用、字段访问、数组索引、类型转换如何根据规则计算表达式类型)
- 23.2 Statement-Level Type Constraints(分析
return、if、while、break、continue等语句如何施加上下文约束) - 23.3 Function Signatures, Parameters, and Return Types(函数签名如何成为调用者和被调用者之间的类型契约)
- 23.4 Subtyping, Conversion, Coercion, and Casting(区分子类型、多态替换、隐式转换、强制转换和可能丢失信息的转换)
- 23.5 Engineering Insight: Type Checking Connects Local Expressions to Global Contracts(类型检查是在函数、模块、接口之间传播和验证契约)
Chapter 24: Generics, Templates, and Parametric Polymorphism
- 24.1 Generic Code Reuse Model(分析泛型让同一段逻辑适用于多种类型,同时减少重复编写结构相同的代码)
- 24.2 Parametric Polymorphism as Type-Level Abstraction(泛型参数让函数、容器、算法可以在类型层面抽象,而不提前绑定具体类型)
- 24.3 Monomorphization vs Type Erasure(比较 C++/Rust 这类按具体类型生成实例,和 Java/TypeScript 等擦除或运行时表示方式的差异)
- 24.4 C++ Templates as Compile-Time Code Generation(分析 C++ template 同时泛型类型检查,也是编译期实例化、特化和元编程机制)
- 24.5 Engineering Insight: Generics Move Reuse from Values to Types(泛型改变的是复用层级:代码不只复用运行时值,也复用类型结构和类型约束)
Chapter 25: Type Inference and Constraint Solving
- 25.1 Type Inference as Recovering Missing Type Information(类型推导让程序员不必显式写出所有类型,编译器从表达式、调用和上下文中恢复类型事实)
- 25.2 Local Inference, Global Inference, and Contextual Typing(区分只在局部表达式中推导、跨函数/模块推导,以及根据赋值目标或参数位置推导)
- 25.3 Constraints, Unification, and Type Variables(编译器通过类型变量和约束方程表达未知类型,再通过统一或求解得到具体类型)
- 25.4 Inference Failures and Ambiguous Types(推导失败可能来自信息不足、约束冲突、重载候选不唯一或泛型参数无法确定)
- 25.5 Engineering Insight: Type Inference Is the Compiler Solving for the Types the Programmer Did(类型推导是在语言规则允许范围内求解缺失的类型信息)
Part 6: Intermediate Representation and Program Lowering
Chapter 26: Intermediate Representation as Compiler Working Language
- 26.1 AST Is Too Close to Source Syntax(说明 AST 保留了大量语言表面结构,适合语义分析和诊断定位,却难以直接服务跨语言优化和目标代码生成)
- 26.2 Machine Code Is Too Close to Hardware(直接从 AST 生成机器码会让优化、移植、多目标后端和语义保持变得困难)
- 26.3 IR as the Compiler’s Working Language(IR 是编译器中端工作的语言,用来表达控制流、数据流、类型、内存和操作语义)
- 26.4 Frontend-Backend Decoupling(不同语言前端可以生成同一种 IR,不同后端可以从同一种 IR 生成不同目标代码)
- 26.5 Engineering Insight: IR Is Where Compilation Becomes Engineering(IR 的出现把编译从“语言翻译”变成了可分析、可优化、可复用的工程管线)
Chapter 27: High-Level IR vs Low-Level IR
- 27.1 High-Level IR Preserves Language Intent(高层 IR 保留闭包、对象、张量、循环、异常、泛型等高层语义,适合做语义相关优化)
- 27.2 Low-Level IR Exposes Execution Constraints(低层 IR 更接近机器,显式表达地址、内存访问、分支、调用和目标平台约束)
- 27.3 Mid-Level IR as the Optimization Sweet Spot(中层 IR 在语言无关性和机器独立性之间取得平衡,是许多通用优化的主要发生地)
- 27.4 Multiple IRs in One Compiler Pipeline(大型编译器通常是根据阶段逐步从高层表示降低到低层表示)
- 27.5 Engineering Insight: The Right IR Level Depends on What You Want to Prove or Transform(IR 没有绝对高低优劣,关键是当前阶段需要保留哪些信息、暴露哪些约束)
Chapter 28: Lowering as Controlled Loss of Abstraction
- 28.1 Lowering Turns Rich Semantics into Simpler Operations(lowering 把高层语言结构转换成更基础、更统一、更接近执行模型的操作)
- 28.2 What Gets Preserved and What Gets Lost(每次 lowering 都会保留必要语义,同时丢弃某些源码级结构、类型细节或抽象边界)
- 28.3 Progressive Lowering Through Multiple Stages(复杂系统会通过多阶段 lowering,把高级结构逐步变成低级 IR、machine IR 或目标字节码)
- 28.4 Lowering vs Optimization(lowering 主要改变表示层级,optimization 主要在语义保持前提下改善性能、大小或可执行性)
- 28.5 Engineering Insight: Lowering Is How a Compiler Pays for Abstraction(高级语言给程序员提供抽象,lowering 则负责把这些抽象逐步转换成机器能承担的形式)
Chapter 29: IR Verification and Structural Invariants
- 29.1 IR Must Have Rules Stronger Than Text(IR 是必须满足控制流、类型、操作数、作用域和 ownership 等结构约束)
- 29.2 Verifier as the Compiler’s Internal Contract Checker(IR verifier 用来检查每次生成或转换后的 IR 是否仍满足基础不变量)
- 29.3 Dominance, Type Consistency, and Well-Formed Blocks(常见 IR 约束包括定义支配使用、类型一致、基本块终止指令合法、分支目标有效)
- 29.4 Invalid IR as a Compiler Bug(用户写错代码通常是源程序错误,但编译器生成非法 IR 往往意味着编译器自身 bug)
- 29.5 Engineering Insight: IR Verification Keeps Compiler Passes Honest(IR 验证约束每个 pass 保持内部结构合法,是大型编译器管线可靠性的基础)
Chapter 30: Designing IR for Analysis and Transformation
- 30.1 Operation Granularity and Expressive Power(IR 操作太高层会不利于机器生成,太低层会丢失优化所需语义,粒度决定分析能力)
- 30.2 Explicit Control Flow and Explicit Data Flow(优秀 IR 通常让控制流和数据依赖足够显式,方便分析、重写和验证)
- 30.3 Type System, Memory Model, and Side-Effect Semantics(IR 需要表达类型、内存访问、别名、副作用和调用约束,否则优化无法安全进行)
- 30.4 Textual IR, Binary IR, and In-Memory IR(IR 可能有可读文本形式、紧凑二进制形式和编译器内部对象形式,各自服务调试、存储和执行效率)
- 30.5 Engineering Insight: IR Design Decides What the Compiler Can Understand(编译器能分析和优化什么,首先取决于 IR 是否把那些事实表达出来)
Part 7: Control Flow Graphs, Basic Blocks, and Program Structure
Chapter 31: Basic Blocks as Straight-Line Code Regions
- 31.1 Basic Block as a Single-Entry Straight-Line Region(分析 basic block 是没有内部控制流分叉的一段连续指令区域,通常只有一个入口)
- 31.2 Terminator Instructions and Block Boundaries(分析 branch、return、switch、invoke 等 terminator 如何结束一个 block,并决定后继 block)
- 31.3 Labels, Predecessors, and Successors(每个 block 可以有标签,并通过前驱和后继关系连接到其他 block)
- 31.4 Entry Block and Function-Level Structure(分析函数入口 block 的特殊地位:它是函数执行的起点,通常不允许有其他 block 跳入)
- 31.5 Engineering Insight: Basic Blocks Turn Code into Units the Compiler Can Move, Analyze, and Connect(basic block 把程序切成可分析单元,让编译器能独立处理局部指令并通过边连接全局结构)
Chapter 32: Control Flow Graphs and Branch Structure
- 32.1 CFG as a Directed Graph of Basic Blocks(分析 CFG 如何用节点表示 basic block,用边表示可能的控制转移)
- 32.2 Conditional Branches, Unconditional Branches, and Returns(分析条件分支、无条件跳转、函数返回如何形成不同控制流形状)
- 32.3 If-Else, Loops, Switch, and Short-Circuit Logic in CFG Form(分析高层控制结构如何 lowering 成 block、branch 和 merge point)
- 32.4 Exceptional Control Flow and Non-Local Edges(异常、panic、longjmp、invoke 等机制如何让控制流图出现非普通顺序边)
- 32.5 Engineering Insight: Once Code Becomes CFG, Program Order Becomes Graph Reachability(进入 CFG 后,程序顺序由可达路径、分支条件和 block 连接关系决定)
Chapter 33: Dominators, Loops, and Reachability
- 33.1 Reachability as the First Control-Flow Fact(分析某个 block 是否可能执行,是死代码删除、错误检查和优化的基础)
- 33.2 Dominance and Must-Pass-Through Relationships(如果所有到达 B 的路径都必须经过 A,则 A 支配 B;dominance 是 SSA、优化和循环分析的基础)
- 33.3 Immediate Dominators and Dominator Trees(分析 dominator tree 如何把支配关系组织成可遍历结构,服务许多编译器分析)
- 33.4 Natural Loops, Headers, Latches, and Backedges(分析循环如何在 CFG 中表现为 header、body、latch、backedge,以及为什么回边是识别循环的关键)
- 33.5 Engineering Insight: Compiler Loop Understanding Starts from Graph Shape(编译器分析循环是看 CFG 中的支配关系和回边结构)
Chapter 34: Structured Control Flow vs Unstructured Jumps
- 34.1 Structured Constructs as Human-Friendly Control Flow(
if、while、for、match等结构化语法让程序员用嵌套结构表达分支和循环) - 34.2 Lowering Structured Constructs to Branches and Blocks(分析结构化控制流最终会被 lowering 成基本块和 terminator)
- 34.3
goto,break,continue, and Early Return(非线性跳转如何改变 CFG 形状,并产生额外 merge、exit 或 cleanup 路径) - 34.4 Irreducible Control Flow and Optimization Difficulty(某些非结构化跳转会产生 irreducible CFG,使循环识别和优化更复杂)
- 34.5 Engineering Insight: Structured Syntax Is for Humans; CFG Is for Compilers(源码控制结构服务可读性,CFG 则服务分析、优化和后端生成)
Chapter 35: Control Flow Evidence in Real Compiler Pipelines
- 35.1 Viewing CFG in LLVM IR(通过 LLVM IR 中的 basic block label、branch、return、phi 等观察控制流结构)
- 35.2 CFG Visualization and Compiler Debug Dumps(使用 compiler dump、graph view、opt 工具或 pass 输出观察 CFG 变化)
- 35.3 How Control Flow Changes After Optimization(优化可能删除不可达块、合并 block、简化分支、提取循环结构或改变布局)
- 35.4 Control Flow and Debugging Optimized Code(优化后的控制流可能与源码结构不同,导致断点、单步执行和调用栈观察出现跳跃)
- 35.5 Engineering Insight: To Understand Optimized Programs, Learn to Read Their Control Flow Graphs(分析优化后的程序行为时,建立从 CFG 和 block 关系读取真实执行路径的能力)
Part 8: Data Flow Analysis, Def-Use Chains, and Program Facts
Chapter 36: Program Facts and Fixed-Point Thinking
- 36.1 Program Facts as Compiler Knowledge(分析编译器在分析过程中计算的事实,例如变量是否初始化、表达式是否可用、值是否仍然存活)
- 36.2 Facts Flow Along CFG Edges(程序事实是沿 control flow graph 的边在 basic block 之间传播)
- 36.3 Transfer Functions and State Updates(每条语句或指令都会根据当前事实生成新事实,例如定义变量、杀死旧值、产生新可用表达式)
- 36.4 Fixed Point as Analysis Convergence(数据流分析通常反复传播事实,直到继续迭代也不会产生新变化)
- 36.5 Engineering Insight: Data Flow Analysis Turns Execution Paths into Static Knowledge(data flow analysis 的核心是把所有可能执行路径上的状态变化,压缩成编译器可使用的静态事实)
Chapter 37: Reaching Definitions and Live Variables
- 37.1 Reaching Definitions as “Which Write Can Reach Here?”(分析 reaching definitions 用来判断某个程序点可能看到哪些先前赋值)
- 37.2 Kill and Gen Sets in Definition Tracking(一条赋值会生成新的定义,同时杀死同一变量的旧定义)
- 37.3 Live Variables as “Will This Value Be Used Later?”(分析 liveness analysis 判断某个变量当前值在未来路径上是否还可能被读取)
- 37.4 Backward Analysis for Liveness(活跃变量分析通常从使用点向前传播,因为它关心未来是否会读当前值)
- 37.5 Engineering Insight: Reaching Definitions Looks Backward in Meaning, Liveness Looks Forward in Need(reaching definitions 关心当前值来自哪里,liveness 关心当前值是否还有未来用途)
Chapter 38: Use-Def Chains and Value Tracking
- 38.1 Definitions, Uses, and Value Identity(区分一个值在哪里被定义、在哪里被使用,以及这些使用点是否指向同一个值来源)
- 38.2 Def-Use Chains as Value Flow Edges(def-use chain 把定义点和使用点连接起来,形成值在程序中的传播关系)
- 38.3 Use-Def Chains and Querying Value Origins(use-def chain 从使用点反查可能来源,帮助编译器定位某个操作数由哪些定义产生)
- 38.4 Value Tracking Across Blocks and Branches(跨 basic block、分支合流、循环回边时,值追踪需要结合 CFG 和数据流事实)
- 38.5 Engineering Insight: Optimization Begins When the Compiler Knows Where Values Come From and Where They Go(只有知道值的来源和用途,编译器才能安全删除、替换、合并或移动代码)
Chapter 39: Forward vs Backward Data Flow Analysis
- 39.1 Forward Analysis from Causes to Effects(forward analysis 从程序入口或定义点向后传播,适合 reaching definitions、available expressions 等问题)
- 39.2 Backward Analysis from Needs to Requirements(backward analysis 从程序出口或使用点向前传播,适合 liveness、needed expressions 等问题)
- 39.3 May Analysis vs Must Analysis(may analysis 计算“可能成立”的事实,must analysis 计算“所有路径都必须成立”的事实)
- 39.4 Meet Operators and Path Merging(当多条路径汇合时,编译器需要用 union、intersection 等 meet operator 合并事实)
- 39.5 Engineering Insight: Direction and Merge Rules Define What Kind of Truth the Compiler Can Prove(数据流分析的方向和合并规则,决定了编译器得到的是可能性、必然性,还是保守近似)
Chapter 40: Data Flow as the Basis of Optimization
- 40.1 Dead Code Elimination from Liveness(当某个计算结果的后续使用计数为零且副作用集合为空时,可以成为死代码删除候选)
- 40.2 Constant Propagation from Value Facts(当编译器能证明某个值在某些路径上恒定,就可以传播常量并简化表达式)
- 40.3 Common Subexpression Elimination from Availability Facts(如果表达式结果已经计算过且操作数未改变,就可能复用旧结果)
- 40.4 Safety Through Conservative Approximation(当编译器无法证明优化安全时,必须保守放弃,等待足够证据支持改写)
- 40.5 Engineering Insight: Most Optimizations Are Data Flow Questions Disguised as Code Rewrites(许多优化表面是改写代码,核心上是在回答值、定义、使用、可达性和副作用相关的数据流问题)
Part 9: SSA Form and Modern IR Design
Chapter 41: Static Single Assignment and Value Identity
- 41.1 The Problem of Reassigned Variables(分析源码里同一个变量可以被多次赋值,但编译器优化更希望每个值有明确唯一来源)
- 41.2 SSA as “One Definition per Name”(SSA 形式要求每个 SSA value 只被定义一次,让 value identity 和 definition site 直接绑定)
- 41.3 Variables vs Values(区分源码变量和 IR value:源码变量是可变槽位,SSA value 更像一次计算结果)
- 41.4 SSA Optimization Benefits(SSA 让 use-def chain、常量传播、死代码删除、公共子表达式消除等优化更直接)
- 41.5 Engineering Insight: SSA Makes Value Flow Explicit Enough for Optimizers to Trust(SSA 让编译器清楚知道每个使用点的值从哪里来,从而安全分析和转换)
Chapter 42: Phi Nodes, Block Arguments, and Value Merging
- 42.1 The Join-Point Problem in Branching Control Flow(当不同分支给同一源码变量赋不同值后,在合流点需要决定后续使用哪个值)
- 42.2 PHI Nodes as Path-Dependent Value Selection(LLVM IR 中的
phiinstruction 根据控制流来自哪个 predecessor block 选择对应输入值) - 42.3 Block Arguments as an Alternative SSA Representation(MLIR 使用 block arguments 表达合流值,由前驱 terminator 把值传给后继 block)
- 42.4 Parallel Copy Semantics and Edge Values(分析 phi/block argument 表示的是控制流边上的值传递,区别于普通顺序赋值语句)
- 42.5 Engineering Insight: Value Merging Is Where SSA Meets Control Flow(SSA 的难点是多条控制路径合并时如何表达“当前值”)
Chapter 43: SSA Construction and Destruction
- 43.1 Renaming Variables into SSA Versions(把源码变量或非 SSA 临时值重命名成多个只定义一次的 SSA version)
- 43.2 Where PHI Nodes Are Needed(在控制流合流点,编译器需要根据 dominance frontier 等信息插入 phi 或等价 block argument)
- 43.3 Mem2Reg and Promoting Stack Slots to Registers(分析 LLVM 中常见的 memory-to-register promotion 如何把
alloca/load/store模式转成 SSA values) - 43.4 Leaving SSA for Machine Code(后端最终需要把 SSA value 映射到寄存器、栈槽和 move 指令,因此 SSA 也需要被销毁或 lower)
- 43.5 Engineering Insight: SSA Is a Compiler Convenience(SSA 服务分析和优化,但真实机器仍然执行寄存器、内存和控制转移)
Chapter 44: SSA-Based Optimizations
- 44.1 Constant Propagation on Explicit Value Graphs(SSA 让常量值沿 def-use chain 传播更直接,减少对变量历史赋值的追踪成本)
- 44.2 Dead Code Elimination Through Unused SSA Values(如果一个 SSA value 没有使用者且没有副作用,对应计算通常可以删除)
- 44.3 Sparse Conditional Constant Propagation(结合 SSA 和 CFG 可达性,在只访问相关 def-use 边的情况下传播常量和不可达信息)
- 44.4 Global Value Numbering and Redundant Computation(SSA 让等价计算、重复表达式和可替换 value 更容易识别)
- 44.5 Engineering Insight: SSA Turns Many Optimizations into Graph Rewrites(在 SSA 中,许多优化转化为 value graph 和 control-flow graph 上的安全替换)
Chapter 45: SSA as the Language of Modern Optimizers
- 45.1 SSA as the Common Shape of Optimizing IRs(现代优化型编译器常以 SSA 或 SSA-like 表示作为中端优化基础)
- 45.2 SSA Values, Types, and Operations(一个现代 IR 通常围绕 operation 产生 SSA value、value 被其他 operation 使用来组织程序)
- 45.3 Memory Is the Exception That Makes SSA Hard(寄存器值容易 SSA 化,但内存、指针、别名和副作用让 SSA 分析变得复杂)
- 45.4 SSA Across LLVM, MLIR, Swift SIL, and Other IRs(不同工程系统会用 phi、block arguments、ownership SSA 等形式表达类似的唯一值定义思想)
- 45.5 Engineering Insight: Modern Optimizers Think in Values(优化器操作的是 SSA values、依赖边和控制流,区别于程序员源码里看到的可变变量名)
Part 10: Optimization Passes and Transformation Pipelines
Chapter 46: Semantics Preserving Transformation Criteria
- 46.1 Optimization as Program Rewriting Under a Contract(分析优化是在保持可观察语义不变的前提下替换程序表示)
- 46.2 Observable Behavior and the Boundary of Correctness(编译器必须尊重 I/O、副作用、volatile、异常、未定义行为、内存模型等可观察边界)
- 46.3 Precondition, Proof, and Conservative Refusal(每个优化都依赖前提;如果编译器无法证明前提成立,就必须保守放弃优化)
- 46.4 Local Transformations vs Whole-Program Transformations(区分局部基本块内优化、函数级优化、模块级优化和链接时/全程序优化)
- 46.5 Engineering Insight: Optimization Is Legal Only When Meaning Is Preserved(优化的核心是“在不改变程序意义的情况下更快、更小或更简单”)
Chapter 47: Analysis Passes vs Transform Passes
- 47.1 Analysis Passes as Fact Producers(analysis pass 计算 CFG、dominance、alias、liveness、loop info、call graph 等事实,供后续优化使用)
- 47.2 Transform Passes as Program Rewriters(transform pass 基于分析结果改写 IR,例如删除死代码、内联函数、简化控制流或传播常量)
- 47.3 Analysis Preservation and Invalidation(当 transform pass 修改 IR 后,某些旧 analysis 结果可能失效,pass manager 必须知道哪些事实还能复用)
- 47.4 Pass Granularity: Function, Loop, Module, and CGSCC(不同 pass 作用在不同粒度上:函数、循环、模块、调用图强连通分量等)
- 47.5 Engineering Insight: Optimizers Alternate Between Learning Facts and Spending Facts(优化器先通过 analysis 获得事实,再通过 transform 消耗这些事实改写程序;改写后又必须重新评估事实是否仍然有效)
Chapter 48: Constant Folding, DCE, CSE, and Inlining
- 48.1 Constant Folding and Compile-Time Evaluation(把编译期已知表达式直接计算成常量,例如
1 + 2 * 3变成7) - 48.2 Dead Code Elimination and Unused Results(如果某段计算结果不会被使用,且没有副作用,就可以从 IR 中删除)
- 48.3 Common Subexpression Elimination and Redundant Work(当两个表达式在同一语义条件下计算相同结果,编译器可以复用已有值)
- 48.4 Inlining and Call Boundary Removal(把被调用函数体展开到调用点,减少调用开销并暴露更多跨函数优化机会)
- 48.5 Engineering Insight: Simple Optimizations Become Powerful When Passes Feed Each Other(常量折叠、DCE、CSE、inline 单独看很简单,但在 pass pipeline 中互相创造机会后会产生巨大效果)
Chapter 49: Pass Ordering and Optimization Pipelines
- 49.1 Pass Order and Optimization Opportunity(某个 pass 的结果可能为后续 pass 创造机会,顺序不同会导致优化效果和编译时间明显不同)
- 49.2 Cleanup Passes After Transformations(inline、loop transform、lowering 等改写后通常需要 simplifycfg、instcombine、DCE 等清理 pass 恢复简洁 IR)
- 49.3 Optimization Levels:
O0,O1,O2,O3,Os, andOz(不同优化等级代表不同的编译时间、代码大小、运行性能和调试体验权衡) - 49.4 Pipeline Tuning for Language Semantics and Target Behavior(语言前端和目标后端可能需要插入特定 pass,以利用语言语义或硬件特性)
- 49.5 Engineering Insight: An Optimization Pipeline Is a Strategy(pass pipeline 是在编译时间、代码质量、调试性和目标平台之间做工程策略选择)
Chapter 50: Miscompilation as the Dark Side of Optimization
- 50.1 Miscompilation vs Program Bug(miscompilation 指编译器生成了与源程序语义不一致的结果,区别于用户程序本身写错)
- 50.2 Wrong Assumptions About Undefined Behavior and Side Effects(过度利用 UB、错误建模副作用、别名、内存顺序或异常路径,都可能导致错误优化)
- 50.3 Optimization Bugs and Pass Interaction(单个 pass 看似正确,但多个 pass 交互后可能破坏不变量、错误保留 analysis 或产生非法 IR)
- 50.4 Reducing, Reproducing, and Diagnosing Miscompilations(通过最小化源码、保存 IR、关闭部分 pass、使用差分测试定位错误优化来源)
- 50.5 Engineering Insight: The More Powerful the Optimizer, the More Dangerous Its Wrong Proofs Become(优化器越强,依赖的证明也越复杂;一旦证明错误,它生成的错误代码可能非常隐蔽)
Part 11: Memory, Alias Analysis, and Side Effects
Chapter 51: Memory as the Hard Part of Program Analysis
- 51.1 Registers and SSA Values Are Easier Than Memory(SSA value 有明确 def-use 关系,但内存中的值可能通过多个地址、指针、引用和调用间接访问)
- 51.2 Loads, Stores, and Hidden State(
load和store表面只是读写,但背后可能涉及堆、栈、全局变量、对象字段、数组元素和外部可见状态) - 51.3 Memory Dependencies Across Control Flow(一次读取可能依赖前面哪次写入,取决于控制流路径、别名关系和函数调用副作用)
- 51.4 MemorySSA and Explicit Memory Access Modeling(分析 MemorySSA 如何把内存访问建模成可分析的 use/def/phi 关系,用于推理 memory operation 的交互)
- 51.5 Engineering Insight: Memory Breaks the Illusion That Values Are Easy to Track(普通 SSA value 的来源清晰,但内存让“哪个值被读到”变成路径、地址和副作用共同决定的问题)
Chapter 52: Pointers, References, and Aliasing
- 52.1 Aliasing as “Different Names, Same Memory”(分析 aliasing 指多个指针、引用或表达式可能访问同一块内存)
- 52.2 Must-Alias, May-Alias, and No-Alias(区分一定指向同一对象、可能指向同一对象和一定不重叠这三种分析结果)
- 52.3 Pointer Arithmetic, Object Fields, and Array Indexing(指针运算、字段访问、数组下标会让内存位置推理更困难)
- 52.4 Alias Analysis as a Conservative Proof System(alias analysis 是在无法证明不别名时必须保守认为可能别名)
- 52.5 Engineering Insight: Memory Reordering Requires Proven Independence(说明两个内存访问的独立性证据如何支撑交换、合并或删除操作)
Chapter 53: Escape Analysis and Object Lifetime
- 53.1 Escape as Leaving the Compiler’s Local Control(当对象地址被返回、存入全局、传给未知函数或跨线程共享时,它就可能逃逸当前分析范围)
- 53.2 Stack Allocation vs Heap Allocation Opportunities(如果编译器能证明对象不逃逸,就可能把堆分配优化成栈分配或直接消除)
- 53.3 Scalar Replacement and Object Decomposition(对象未逃逸时,编译器可以把字段拆成独立 SSA values,减少真实内存访问)
- 53.4 Lifetime Markers, Allocation Sites, and Deallocation Safety(对象生命周期信息能帮助优化内存分配、析构、GC root、use-after-free 检查或栈槽复用)
- 53.5 Engineering Insight: Escape Analysis Decides Object Materialization(如果对象没有逃出局部语义边界,它可能只是编译器 IR 中的一组值,不必成为真实内存对象)
Chapter 54: Side Effects, Volatile, and Observable Behavior
- 54.1 Pure Computation vs Side-Effecting Operations(纯计算只产生结果值,副作用操作会改变内存、I/O、全局状态、同步状态或外部世界)
- 54.2 Function Calls as Unknown Effect Boundaries(未知函数调用可能读写内存、抛异常、阻塞、执行 I/O 或触发运行时行为,因此会限制优化)
- 54.3
volatileas Observable Access(volatile通常要求访问保持可观察性,同时需要区分于完整同步或原子内存序) - 54.4 I/O, Atomics, Exceptions, and Language Memory Models(I/O、原子操作、异常和语言内存模型都会定义哪些行为必须被保留为可观察语义)
- 54.5 Engineering Insight: Optimization Stops Where Observable Behavior Begins(编译器可以改写内部计算,同时必须保持语言或平台定义为可观察的行为边界)
Chapter 55: Optimization Under Memory Uncertainty
- 55.1 Conservative Optimization in the Presence of May-Alias(当两个访问可能别名时,编译器通常需要保留它们之间的依赖和可观察顺序)
- 55.2 Load Elimination and Store Forwarding Conditions(只有证明中间没有可能修改同一内存位置的操作,才能用先前写入或读取结果替代新的 load)
- 55.3 Code Motion Across Memory Operations(把 load/store 移出循环、提前或延后执行,需要证明不会跨过影响同一内存或可观察行为的操作)
- 55.4 Memory Barriers, Atomics, and Reordering Limits(内存屏障和原子操作限制编译器和硬件重排,是并发语义的一部分)
- 55.5 Engineering Insight: When Memory Facts Are Weak, Good Compilers Become Cautious(内存事实越不确定,优化器越要保守;编译器需要根据证据边界决定哪些变换可以执行)
Part 12: Loop Optimization, Vectorization, and Parallelism
Chapter 56: Loop Dominance in Performance Engineering
- 56.1 Loops Multiply Small Costs(循环会把一次微小的计算、一次内存访问、一次分支预测失败放大成成千上万次成本)
- 56.2 Hot Loops and Runtime Profiles(程序运行时间常集中在少数热点循环中,profile-guided optimization 往往首先关注这些循环)
- 56.3 Loop Structure in CFG and LoopInfo(编译器通过 CFG、header、latch、backedge、preheader 等结构识别和描述循环)
- 56.4 Canonical Loop Forms for Optimization(很多 loop pass 需要循环先被规范化,例如拥有 preheader、single latch、明确退出边等)
- 56.5 Engineering Insight: Optimizing a Loop Means Optimizing Repetition Itself(循环优化的核心是优化被重复执行的结构、依赖和内存访问模式)
Chapter 57: Loop Invariant Code Motion and Strength Reduction
- 57.1 Loop-Invariant Computations(分析循环中某些表达式每次迭代结果不变,因此可以移出循环体)
- 57.2 Hoisting to Preheaders and Sinking to Exits(LICM 通常把循环不变量提升到 preheader,或在安全时下沉到 exit block;LLVM 的 LICM pass 文档也明确描述了这两种方向。)
- 57.3 Safety Conditions: Side Effects, Aliasing, and Exceptions(只有在不会改变可观察行为、不会跨越有害副作用、不会破坏内存依赖时,代码才能移动)
- 57.4 Strength Reduction as Replacing Expensive Operations(把循环中的乘法、除法、复杂地址计算替换为递增、移位或更便宜的等价操作)
- 57.5 Engineering Insight: Loop Optimization Often Moves Work Out of Time-Critical Repetition(许多循环优化的核心,是把不必重复做的工作从重复路径中移走)
Chapter 58: Loop Unrolling, Fusion, Fission, and Tiling
- 58.1 Loop Unrolling and Branch Overhead Reduction(循环展开通过一次处理多次迭代,减少分支、索引更新和循环控制开销)
- 58.2 Unrolling vs Code Size Growth(展开会增加代码体积,可能改善 instruction-level parallelism,也可能伤害 instruction cache 和编译产物大小)
- 58.3 Loop Fusion and Locality Improvement(把遍历同一范围的多个循环合并,可能减少遍历次数并改善 cache locality)
- 58.4 Loop Fission and Parallelization Opportunities(把一个复杂循环拆成多个简单循环,可能隔离依赖、改善 vectorization 或提升局部性)
- 58.5 Loop Tiling as Cache-Aware Reordering(tiling/blocking 通过分块访问数据,让工作集更适合 cache 层级,常见于矩阵和张量计算)
Chapter 59: Auto-Vectorization and SIMD Code Generation
- 59.1 SIMD as Multiple Data Elements per Instruction(分析 SIMD 通过一条指令处理多个数据元素,适合规则、独立、连续的数据操作)
- 59.2 Loop Vectorization vs SLP Vectorization(LLVM 文档说明 LLVM 有 Loop Vectorizer 和 SLP Vectorizer:前者让循环一次处理多个连续迭代,后者把代码中多个标量操作合并成向量操作。)
- 59.3 Vectorization Legality and Dependence Checks(编译器必须证明不同迭代之间没有破坏语义的数据依赖,才能安全向量化)
- 59.4 Cost Model, Vector Width, and Target Instructions(向量化是否值得取决于目标硬件、向量宽度、内存对齐、shuffle 成本和 fallback 路径)
- 59.5 Engineering Insight: Vectorization Is Parallelism Extracted from Regularity(自动向量化的关键是从规则循环中证明并提取数据并行性)
Chapter 60: Parallelism, Dependence Analysis, and Safety
- 60.1 Loop-Carried Dependencies(一次迭代依赖前一次迭代产生的值时,循环需要保留依赖顺序,再判断并行、重排或向量化空间)
- 60.2 Dependence Distance and Memory Access Patterns(编译器需要分析数组下标、指针访问和内存别名,判断不同迭代是否访问同一数据)
- 60.3 Reductions as Structured Dependencies(sum、min、max 等 reduction 有跨迭代依赖,但在满足结合性和精度约束时可以被特殊并行化)
- 60.4 Speculative Parallelization and Runtime Checks(当静态证明不足时,编译器可能生成运行时检查,在条件满足时走优化路径,否则回退到安全路径)
- 60.5 Engineering Insight: Compilers Parallelize Only What They Can Prove Independent or Safely Restructure(编译器不会因为循环“看起来能并行”就并行,它必须证明独立性,或把依赖改写成安全结构)
Part 13: Backend Fundamentals and Instruction Selection
Chapter 61: From IR Operations to Target Instructions
- 61.1 Target-Independent IR vs Target-Specific Instructions(分析 LLVM IR、MLIR 等中间表示通常隐藏了具体 CPU 指令细节,而后端必须把它们映射到目标机器)
- 61.2 Operation Semantics Before Instruction Encoding(后端首先关心 IR 操作的语义,例如加法、比较、分支、load/store,再进入二进制编码选择)
- 61.3 Target Description: Registers, Instructions, Types, and Constraints(目标架构需要向后端描述寄存器、指令模式、合法类型、寻址模式、调用约定和限制)
- 61.4 Lowering Generic Operations into Target Operations(通用 IR 操作可能被 lower 成一个目标指令、多个指令、运行时 helper 调用或特殊伪指令)
- 61.5 Engineering Insight: Backend Work Begins When Abstract Operations Must Obey Real Hardware(后端的核心是让抽象程序操作服从真实硬件的指令、寄存器和 ABI 约束)
Chapter 62: Instruction Selection and Pattern Matching
- 62.1 Instruction Selection as Choosing Hardware Realizations(分析 instruction selection 如何为 IR 中的操作选择等价的目标指令序列)
- 62.2 Tree Patterns, DAGs, and SelectionDAG Thinking(许多后端会把表达式和依赖关系组织成 tree 或 DAG,再通过模式匹配选择目标指令)
- 62.3 Complex Instructions and Addressing Modes(复杂指令可能同时完成计算和内存访问,instruction selector 需要识别可合并模式)
- 62.4 GlobalISel and More Generic Selection Infrastructure(现代 LLVM 也提供 GlobalISel 这类全局指令选择框架,用于更统一地处理目标选择和 legalization 流程)
- 62.5 Engineering Insight: Instruction Selection Is Semantics Matching Under Hardware Constraints(指令选择是在语义等价和硬件能力之间寻找最合适实现)
Chapter 63: Legalization and Target Constraints
- 63.1 Target-Legal IR Operations(某个目标 CPU 可能不支持特定位宽、向量类型、浮点操作、原子操作或寻址模式)
- 63.2 Type Legalization and Operation Legalization(后端需要把非法类型拆分、扩展、收缩或转成多个合法操作,把非法操作替换成可执行序列)
- 63.3 Expand, Promote, Split, and Libcall Lowering(常见 legalization 策略包括展开成多条指令、提升到更大类型、拆分向量或调用运行时库函数)
- 63.4 Target Feature Flags and Conditional Legality(同一架构不同扩展集可能支持不同指令,例如 SIMD、crypto、float、atomic 扩展会改变 legal set)
- 63.5 Engineering Insight: Legalization Is Where Portable IR Meets Non-Portable Hardware Reality(legalization 的核心是承认目标机器不分析所有 IR 表达,并把它们改写成该机器能执行的形式)
Chapter 64: Machine IR and Target-Specific Lowering
- 64.1 Machine IR as the Backend’s Working Representation(分析后端通常会使用更接近机器的 IR,表达虚拟寄存器、机器指令、目标操作数和调度信息)
- 64.2 Virtual Registers Before Physical Register Allocation(在寄存器分配前,后端可以使用无限数量的虚拟寄存器表达值流动)
- 64.3 Pseudo Instructions and Late Expansion(伪指令用于在后端中间阶段保留抽象操作,等到寄存器分配、指令调度或目标信息足够后再展开)
- 64.4 Instruction Scheduling and Pipeline Awareness(后端可能根据目标流水线、延迟、吞吐、依赖关系和资源冲突重新排列指令)
- 64.5 Engineering Insight: Machine IR Is Where the Compiler Starts Thinking Like the CPU(Machine IR 让编译器从“程序语义”转向“目标机器执行成本、寄存器和指令约束”)
Chapter 65: Backend Correctness and Target Semantics
- 65.1 Semantic Equivalence Across Lowering Steps(后端每次 lowering、legalization、selection、scheduling 都必须保持源 IR 的可观察语义)
- 65.2 Undefined Behavior, Poison, Flags, and Target-Specific Semantics(IR 层的 UB、poison、overflow flags、fast-math flags 到后端时必须被正确解释,否则可能生成错误代码)
- 65.3 Calling Conventions, ABI, and Boundary Correctness(函数参数、返回值、栈布局、寄存器保存规则必须符合 ABI,否则链接和运行时边界会出错)
- 65.4 Testing Backends with IR, Assembly, and Execution Tests(后端测试通常需要同时验证 IR lowering、汇编输出、目标约束和真实执行结果)
- 65.5 Engineering Insight: A Backend Bug Is a Broken Contract Between IR Semantics and Hardware Semantics(后端错误往往是 IR 语义、目标语义和 ABI 契约之间的映射破裂)
Part 14: Register Allocation, Stack Frames, and Calling Conventions
Chapter 66: Registers as Scarce Execution Resources
- 66.1 Virtual Registers vs Physical Registers(分析后端中可以先使用大量虚拟寄存器表达值流动,但真实 CPU 只有有限数量的物理寄存器)
- 66.2 Register Classes and Target Constraints(不同寄存器可能服务整数、浮点、向量、地址、特殊状态,目标架构会定义不同 register class)
- 66.3 Register Pressure and Code Quality(当同时活跃的值过多,寄存器压力升高,编译器就更可能把值 spill 到栈上)
- 66.4 Caller-Saved, Callee-Saved, and Reserved Registers(调用约定会规定哪些寄存器由调用者保存,哪些由被调用者保存,哪些寄存器保留给栈指针、帧指针或平台用途)
- 66.5 Engineering Insight: Registers Are the Backend’s Most Valuable Temporary Storage(寄存器分配的核心是在有限高速资源中安排程序所有临时值的生存位置)
Chapter 67: Liveness, Interference, and Register Allocation
- 67.1 Liveness as “Which Values Still Matter?”(寄存器分配首先依赖活跃性分析,判断某个值在程序点之后是否仍会被使用)
- 67.2 Interference as “Which Values Cannot Share a Register?”(两个值的 live ranges 重叠时,它们需要分配到不同物理寄存器)
- 67.3 Interference Graphs and Coloring Thinking(经典寄存器分配可建模为图着色问题:冲突的值需要使用不同颜色,也就是不同寄存器)
- 67.4 Linear Scan vs Graph Coloring Strategies(比较线性扫描和图着色寄存器分配在编译速度、代码质量和实现复杂度上的取舍)
- 67.5 Engineering Insight: Register Allocation Is Scheduling Value Lifetimes onto Hardware Slots(寄存器分配是把值的生命周期安排到有限硬件槽位中)
Chapter 68: Spilling, Reloading, and Stack Slot Management
- 68.1 Spill as Moving Values from Registers to Stack(当寄存器不够时,编译器把部分值保存到栈槽中,腾出物理寄存器)
- 68.2 Reload as Bringing Spilled Values Back(当被 spill 的值再次需要参与计算时,编译器必须从栈中 reload 回寄存器)
- 68.3 Spill Cost and Hot Path Damage(如果热循环中频繁 spill/reload,会显著增加内存访问、指令数和延迟)
- 68.4 Stack Slot Reuse and Lifetime-Based Packing(不同时间段不重叠的 spill slot 可以复用同一栈空间,以减少栈帧大小)
- 68.5 Engineering Insight: Spilling Is Where Register Scarcity Becomes Memory Traffic(spill/reload 是寄存器不足的外在表现,会把本来应该在 CPU 内部完成的值流动转化为真实内存访问)
Chapter 69: Stack Frames, Prologues, and Epilogues
- 69.1 Stack Frame as the Function’s Runtime Workspace(分析栈帧如何保存局部变量、spill slot、返回地址、保存寄存器、对齐填充和调用相关数据)
- 69.2 Prologue as Function Entry Setup(函数 prologue 通常负责调整栈指针、保存 callee-saved 寄存器、建立 frame pointer 或分配栈空间)
- 69.3 Epilogue as Function Exit Restoration(函数 epilogue 通常负责恢复保存的寄存器、释放栈帧、恢复栈指针并返回调用者)
- 69.4 Frame Pointer Omission, Red Zones, and Stack Alignment(不同平台和优化设置会决定是否保留 frame pointer、是否使用 red zone、如何满足 ABI 对齐要求)
- 69.5 Engineering Insight: A Stack Frame Is the Runtime Shadow of a Function Call(函数调用在源码里只是调用表达式,在运行时却会留下栈帧、保存寄存器和返回路径这些具体执行痕迹)
Chapter 70: Calling Conventions as Binary-Level Contracts
- 70.1 Calling Convention as Agreement Between Caller and Callee(调用约定规定参数放在哪里、返回值放在哪里、谁负责清理栈、哪些寄存器必须保留)
- 70.2 Parameter Passing in Registers and on the Stack(小整数、指针、浮点、结构体、可变参数等可能根据 ABI 被分配到寄存器或栈中)
- 70.3 Return Values, Hidden Pointers, and Aggregate Returns(复杂返回值可能通过寄存器、内存地址或隐藏参数返回,需要按 ABI 选择寄存器或内存路径)
- 70.4 Cross-Language Calls and ABI Stability(C、C++、Rust、Swift、Python extension、系统库之间能互相调用,依赖的是稳定 ABI 和一致调用约定)
- 70.5 Engineering Insight: Function Calls Work Because Both Sides Obey the Same Invisible Protocol(调用约定是二进制层面的隐藏协议;只要调用者和被调用者分析不一致,程序就会在最底层崩坏)
Part 15: Object Files, Relocation, Linking, and Debug Information
Chapter 71: Object Files as Partially Built Programs
- 71.1 Object Files as Compiler Output Before Final Linking(分析 object file 是编译器为 linker 准备的半成品)
- 71.2 Code, Data, Symbols, and Metadata in One Container(object file 同时保存机器指令、常量数据、全局变量、符号表、重定位项和调试信息)
- 71.3 Relocatable Objects vs Executables vs Shared Libraries(区分可重定位目标文件、最终可执行文件和动态共享库在结构与用途上的差异)
- 71.4 Section-Based Linking View and Segment-Based Loading View(分析 section 主要服务链接器组织代码和数据,segment 主要服务 loader 把程序映射进内存)
- 71.5 Engineering Insight: Object Files Are Programs Waiting for Their Final Addresses(object file 已经包含机器级内容,但许多地址、符号和依赖还要等链接阶段才能最终确定)
Chapter 72: Symbols, Sections, and Relocation Records
- 72.1 Symbols as Names for Code and Data Locations(分析函数、全局变量、静态对象、外部引用如何以 symbol 形式出现在 object file 中)
- 72.2 Sections as Organized Regions of Object Content(
.text、.data、.bss、.rodata、.debug_*等 section 如何按用途组织二进制内容) - 72.3 Relocation Records as Deferred Address Fixups(编译器无法确定的地址会生成 relocation record,等待 linker 根据最终布局修正)
- 72.4 Local, Global, Weak, Undefined, and Common Symbols(不同 symbol binding 和 symbol state 如何影响链接解析、覆盖规则和库选择)
- 72.5 Engineering Insight: Relocation Is How Separate Compilation Becomes One Address Space(重定位把多个独立编译单元中的符号引用,修正成最终程序里的真实地址关系)
Chapter 73: Static Linking, Dynamic Linking, and Loaders
- 73.1 Static Linking as Combining Code Before Execution(静态链接把 object files 和静态库中的代码直接合并进最终可执行文件)
- 73.2 Dynamic Linking as Deferred Library Binding(动态链接让可执行文件在加载或运行时解析共享库符号,减少重复代码并支持库升级)
- 73.3 Loader Responsibilities at Program Startup(loader 负责把可执行文件和共享库映射到进程地址空间,处理动态重定位、入口点和运行时初始化)
- 73.4 PLT, GOT, Lazy Binding, and Position-Independent Code(分析动态链接中函数跳转、全局偏移表、延迟绑定和位置无关代码如何协作)
- 73.5 Engineering Insight: Linking Decides Which Code the Program Actually Becomes(源码和 object file 只是候选材料,最终程序由链接阶段解析出的符号、库和地址布局共同决定)
Chapter 74: ELF, Mach-O, COFF, and Platform Formats
- 74.1 Object File Formats as Platform Toolchain Contracts(ELF、Mach-O、COFF/PE 等格式定义编译器、汇编器、链接器、loader、debugger 之间如何交换二进制信息)
- 74.2 ELF as the Dominant Unix/Linux Binary Format(分析 ELF 如何用 header、section、program header、symbol 和 relocation 组织二进制)
- 74.3 Mach-O on Apple Platforms(分析 Mach-O 如何服务 macOS/iOS 的动态库、framework、dyld 和 Apple 平台加载模型)
- 74.4 COFF and PE in Windows Toolchains(分析 COFF object 和 PE executable 如何支撑 Windows 编译、链接和动态加载)
- 74.5 Engineering Insight: Binary Formats Are the ABI Written to Disk(二进制格式把平台 ABI、链接规则、加载规则和调试信息编码成工具链可交换的文件结构)
Chapter 75: Debug Information and Source-Level Observability
- 75.1 Debug Info as a Map Back from Binary to Source(调试信息帮助 debugger 把机器地址、寄存器、栈帧和变量位置映射回源码行、函数、类型和变量)
- 75.2 DWARF, Line Tables, Types, and Variable Locations(分析 DWARF 等格式如何描述源码位置、类型结构、作用域、变量位置和内联关系)
- 75.3 Optimization and Debug Information Drift(优化会移动、删除、合并、内联代码,debug info 必须尽量维护源码级可观察关系)
- 75.4 Inspecting Object Files with
llvm-objdump,llvm-readobj, and Debuggers(通过 object dumping 和 debugger 工具观察 sections、symbols、relocations、debug records 和反汇编) - 75.5 Engineering Insight: Debug Info Is the Compiler’s Apology for Destroying the Source Shape(优化和代码生成会重塑程序,调试信息则尽量保存程序员分析运行状态所需的源码证据)
Part 16: Runtime Systems, ABI, Exceptions, and Garbage Collection
Chapter 76: What the Compiler Leaves to the Runtime
- 76.1 Compile-Time Decisions vs Runtime Responsibilities(区分编译器能提前决定的代码结构,和必须在程序运行时处理的对象、类型、异常、内存与调度问题)
- 76.2 Runtime Helpers as Compiler-Generated Calls(分析编译器会把复杂语言语义 lower 成对 runtime helper 的调用,例如分配对象、检查类型、抛异常、写屏障)
- 76.3 Language Semantics That Require Runtime State(动态类型、闭包、反射、协程、GC、异常、模块加载等能力通常需要运行时状态支撑)
- 76.4 Runtime Metadata and Execution Support(类型描述、vtable、interface table、exception table、GC map、debug info 等元数据如何服务运行时行为)
- 76.5 Engineering Insight: A Compiler Generates Code for a World the Runtime Maintains(编译器生成的是可执行路径,但很多语言语义要依赖运行时持续维护对象、栈、类型和内存状态)
Chapter 77: ABI, Runtime Helpers, and Language Support Libraries
- 77.1 ABI as the Binary Contract Between Components(ABI 规定函数调用、参数传递、返回值、栈布局、寄存器保存、符号命名和对象布局等二进制规则)
- 77.2 Runtime Libraries as Language Semantics in Binary Form(标准库、语言运行时、启动代码、异常库、数学库和内存分配器共同承接编译器留给运行时的一部分语义)
- 77.3 Compiler-Inserted Calls and Hidden Dependencies(编译器可能自动插入对
memcpy、malloc、type check、bounds check、panic、throw、GC barrier 等 helper 的调用) - 77.4 Cross-Language and Cross-Compiler Interoperability(不同语言、不同编译器和不同版本能否互相调用,取决于 ABI、对象布局和运行时协议是否一致)
- 77.5 Engineering Insight: ABI Is Where Separate Programs Agree to Behave Like One System(ABI 的核心是让独立编译、独立链接、甚至不同语言生成的二进制在运行时仍能互相分析)
Chapter 78: Exception Handling and Stack Unwinding
- 78.1 Exceptions as Non-Local Control Flow(异常是从出错位置跨越多个栈帧跳到匹配 handler 的非局部控制流)
- 78.2 Zero-Cost Exception Handling and the Normal Path(zero-cost EH 的目标是让未抛异常的正常路径尽量不付出额外检查成本,把代价转移到异常路径和元数据上)
- 78.3 Stack Unwinding, Landing Pads, and Personality Functions(分析异常传播时如何通过 unwind 信息恢复栈帧、运行 cleanup,并由 personality routine 判断 handler 是否匹配)
- 78.4 Cleanup, Destructors, and Resource Safety(C++ RAII、defer、finally 等机制要求异常路径仍然正确执行资源释放逻辑)
- 78.5 Engineering Insight: Exception Handling Is Control Flow Reconstructed from Metadata(异常处理困难的是运行时如何根据编译器生成的元数据安全穿越栈帧并恢复语言语义)
Chapter 79: Garbage Collection and Memory Safety Support
- 79.1 GC as Runtime Ownership of Object Lifetime(GC 让对象释放从程序员显式控制转移到运行时 collector,但编译器必须帮助运行时识别对象引用)
- 79.2 Roots, Stack Maps, and Precise Reference Tracking(GC 需要知道栈、寄存器、全局变量和对象字段中哪些位置保存了可追踪引用)
- 79.3 Safepoints and Moving Collectors(分析 safepoint 如何支持线程暂停、指针更新和 moving collector 语义)
- 79.4 Write Barriers, Read Barriers, and Generational GC(编译器可能插入 barrier,帮助 collector 维护跨代引用、并发标记或移动对象一致性)
- 79.5 Engineering Insight: GC Needs Compiler-Provided Pointer Maps(说明 GC 为什么依赖编译器提供精确引用位置和安全点)
Chapter 80: Runtime Systems as Execution Partners
- 80.1 Runtime as the Other Half of Language Implementation(编译器负责生成代码和元数据,runtime 负责执行时对象模型、内存、异常、线程、模块和反射)
- 80.2 Static Languages Still Have Runtime Assumptions(即使是 C/C++/Rust 这类偏静态语言,也依赖启动代码、ABI、libc、libgcc/libunwind、panic/exception 支持和 allocator)
- 80.3 Dynamic Languages Depend on Runtime Even More Deeply(Python、JavaScript、Ruby 等语言的对象模型、类型分派、GC、解释器/JIT、模块加载都高度依赖 runtime)
- 80.4 Runtime Boundaries as Optimization Barriers and Opportunities(runtime call 可能阻止优化,也可能通过 intrinsic、deopt metadata、inline cache、profile feedback 反过来帮助优化)
- 80.5 Engineering Insight: Compilation Ends Only When Generated Code Meets Its Runtime World(的程序执行是生成代码、运行时系统、ABI、库和操作系统共同协作的行为)
Part 17: Interpreters, Bytecode VMs, and JIT Compilation
Chapter 81: AST Interpreters and Direct Execution
- 81.1 AST Interpreter as Direct Tree Execution(分析 AST interpreter 直接遍历语法树节点,根据节点类型执行表达式、语句、函数和控制流)
- 81.2 Evaluation Rules Instead of Code Generation(解释器把语言语义实现为一组运行时求值规则,并在需要时再接入 bytecode、threaded dispatch 或 JIT 路径)
- 81.3 Environment, Scope, and Runtime Bindings(AST 执行时需要维护变量环境、作用域链、闭包捕获和运行时对象引用)
- 81.4 Simplicity, Debuggability, and Performance Limits(AST interpreter 易于实现和调试,但频繁树遍历、动态分派和对象操作会带来性能成本)
- 81.5 Engineering Insight: An Interpreter Directly Executes Program Meaning(解释器可以直接执行程序表示中的语义)
Chapter 82: Bytecode as a Compact Execution Format
- 82.1 Bytecode Between AST and Machine Code(bytecode 比 AST 更线性、更紧凑、更适合执行循环,同时比机器码更可移植)
- 82.2 Instruction Streams, Operands, and Constant Pools(bytecode 通常由 opcode、操作数、常量池、名字表和跳转偏移共同表达程序行为)
- 82.3 Stack-Based vs Register-Based Bytecode(栈式 bytecode 通过隐式 operand stack 传递值,寄存器式 bytecode 通过虚拟寄存器显式保存中间结果)
- 82.4 Bytecode Verification and Runtime Safety(某些 VM 会在执行前检查 bytecode 的类型、栈平衡、控制流和访问权限)
- 82.5 Engineering Insight: Bytecode Is a Portable Machine for the Language Runtime(bytecode 的核心是一台由语言运行时定义的虚拟机器指令集)
Chapter 83: Virtual Machines and Evaluation Loops
- 83.1 VM as the Runtime That Executes Bytecode(虚拟机负责读取 bytecode、维护栈帧、操作数栈、局部变量、对象和异常状态)
- 83.2 Dispatch Loops: switch, Threaded Code, and Direct Dispatch(VM 主循环通过 opcode dispatch 选择每条 bytecode 指令的执行逻辑)
- 83.3 Frames, Operand Stacks, and Call Handling(函数调用会创建 VM frame,保存局部变量、返回地址、异常处理状态和执行栈)
- 83.4 Runtime Objects, Type Checks, and Dynamic Semantics(动态语言 VM 需要在执行时处理对象模型、类型分派、属性查找、方法调用和运行时错误)
- 83.5 Engineering Insight: A VM Is a CPU Designed Around a Language(虚拟机是围绕语言语义设计的一套执行机器)
Chapter 84: JIT Compilation and Runtime Specialization
- 84.1 JIT as Compilation During Execution(JIT 在程序运行时把 bytecode、IR 或热点路径编译成机器码)
- 84.2 Hot Paths, Profiling, and Tiered Compilation(运行时通过计数器、采样和类型反馈发现热点函数或循环,再决定是否升级到更优化层级)
- 84.3 Runtime Type Feedback and Speculative Optimization(JIT 可以根据真实运行类型做激进假设,例如某个调用点长期只看到一种对象类型)
- 84.4 Code Cache, Guards, and Patchable Machine Code(JIT 需要管理生成代码的缓存、入口跳转、guard 检查和运行时 patch)
- 84.5 Engineering Insight: JIT Pays Compilation Cost Only Where Runtime Evidence Says It Matters(JIT 的核心是把编译成本集中花在真实热点路径上)
Chapter 85: Deoptimization, Inline Caches, and Dynamic Feedback
- 85.1 Inline Caches as Remembered Dynamic Dispatch Results(inline cache 记录某个调用点或属性访问点过去看到的类型和目标,用于加速后续动态分派)
- 85.2 Monomorphic, Polymorphic, and Megamorphic Sites(根据调用点看到的类型数量,JIT 可以采用单态、多态或退化为通用慢路径策略)
- 85.3 Deoptimization as Returning from Optimized Assumptions(当 speculative optimization 的假设失效时,运行时必须从优化机器码安全退回解释器或低层代码)
- 85.4 Reconstructing Interpreter State from Optimized Code(deopt 需要根据 metadata 恢复虚拟栈帧、局部变量、对象状态和 bytecode 位置)
- 85.5 Engineering Insight: Dynamic Optimization Requires a Way Back When Reality Changes(动态优化的强大来自假设真实运行模式,但它必须能在假设失效时安全撤回)
Part 18: LLVM Infrastructure and Pass Engineering
Chapter 86: LLVM as a Modular Compiler Infrastructure
- 86.1 LLVM Is Infrastructure(分析 LLVM 同时一套包含 IR、优化、代码生成、工具链组件和运行时支持的基础设施)
- 86.2 Frontend, Optimizer, Backend, and Tooling Boundaries(Clang、LLVM IR、optimizer、target backend、lld、llvm-objdump 等组件如何形成可组合工具链)
- 86.3 Language-Independent IR as the Integration Point(不同语言前端可以生成 LLVM IR,优化器和后端围绕统一 IR 工作)
- 86.4 Static Compilation, JIT, LTO, and Cross-Compilation Use Cases(LLVM 可用于静态编译、JIT、链接时优化、交叉编译和语言实验)
- 86.5 Engineering Insight: LLVM Turns Compiler Construction into Infrastructure Reuse(LLVM 把 IR、优化、后端和工具链能力变成可复用工程基础)
Chapter 87: LLVM IR, Modules, Functions, and Basic Blocks
- 87.1 Module as the Top-Level LLVM IR Container(分析 LLVM module 如何保存函数、全局变量、metadata、target triple 和 data layout)
- 87.2 Functions, Basic Blocks, and Instructions(LLVM IR 中函数由 basic blocks 组成,basic block 由 instructions 组成,并以 terminator 结束)
- 87.3 SSA Values, Types, and Use-Def Relationships(LLVM IR 是 SSA-based representation,每个 instruction 也可以产生 typed value 并被其他 instruction 使用)
- 87.4 Textual IR, Bitcode, and In-Memory IR(LLVM IR 有可读文本形式、bitcode 序列化形式和 C++ API 操作的内存对象形式)
- 87.5 Engineering Insight: LLVM IR Is Both a Language and a Compiler Data Structure(LLVM IR 既能被打印成文本供人阅读,也能作为内存中的对象图被 pass 分析和改写)
Chapter 88: The LLVM Pass Manager and Analysis Preservation
- 88.1 Passes as Units of Analysis and Transformation(LLVM pass 是分析或改写 IR 的基本工程单元)
- 88.2 Analysis Passes Produce Facts, Transform Passes Rewrite IR(analysis pass 计算 dominance、loop info、alias info 等事实,transform pass 使用这些事实改写程序)
- 88.3 New Pass Manager, PassBuilder, and Default Pipelines(分析
PassBuilder如何按优化等级构建默认 pass pipeline) - 88.4 Analysis Preservation and Invalidation(当 transform 修改 IR 后,必须声明哪些 analysis 结果仍然有效,哪些需要失效重算)
- 88.5 Engineering Insight: A Pass Manager Is the Compiler’s Optimization Orchestrator(Pass Manager 的作用是组织 pass 粒度、缓存分析结果、处理失效和构建优化策略)
Chapter 89: Building and Testing LLVM Passes
- 89.1 Choosing Pass Granularity: Module, Function, Loop, or CGSCC(根据分析范围和改写目标选择 module pass、function pass、loop pass 或 call graph SCC pass)
- 89.2 Reading and Modifying IR with LLVM C++ APIs(分析 pass 如何遍历 module、function、basic block、instruction,并通过 IRBuilder 或 API 插入、删除、替换指令)
- 89.3 Registering Passes and Running Them with
opt(使用opt加载和运行 pass,观察 IR 进入和离开 pass 后的变化) - 89.4 Writing FileCheck-Based Regression Tests(通过
.ll输入、RUN:行和 FileCheck 断言验证 pass 输出,防止后续改动破坏行为) - 89.5 Engineering Insight: A Compiler Pass Is Production Code That Must Be Tested Like a Transformation(pass 需要区分实验脚本,它会改写程序语义表示,必须用 IR 测试和回归用例证明其正确性)
Chapter 90: Reading Optimized LLVM IR
- 90.1 Comparing IR Before and After Optimization(通过
clang -S -emit-llvm、opt、不同-O等级对比 IR 变化) - 90.2 Recognizing Common Optimization Patterns(识别 constant folding、DCE、instcombine、simplifycfg、mem2reg、inline 和 loop optimization)
- 90.3 Understanding Lost Source Shape in Optimized IR(优化后源码变量、临时表达式、函数边界和控制结构可能消失、合并或重排)
- 90.4 Debug Metadata and Optimized IR Observability(debug metadata 试图把优化后的 IR 和源码位置、变量、inline stack 重新关联)
- 90.5 Engineering Insight: Optimized IR Shows What the Compiler Proved(优化后的 IR 是编译器在证明语义后得到的更适合执行和后端生成的程序形态)
Part 19: MLIR, Dialects, and Multi-Level Compiler Infrastructure
Chapter 91: Multi-Level IR and Progressive Lowering
- 91.1 The Limits of a Single Universal IR(分析单一 IR 很难同时适合高层领域语义、通用优化、硬件映射和低层代码生成)
- 91.2 High-Level Semantics Need High-Level Representations(张量、矩阵、循环嵌套、图计算、shader stage、数据库算子等语义如果过早降低,会丢失优化机会)
- 91.3 Low-Level Constraints Need Low-Level Representations(寄存器、内存布局、向量指令、设备地址空间、ABI 等约束需要更接近机器的表示)
- 91.4 Progressive Lowering Across Abstraction Levels(程序可以先在高层 dialect 中优化,再逐步 lowering 到更低层 dialect,最后进入 LLVM IR 或目标后端)
- 91.5 Engineering Insight: Multi-Level IR Preserves the Right Semantics Until the Right Time(多层 IR 的核心是在每个阶段保留最适合分析和变换的语义)
Chapter 92: Dialects as Domain-Specific Compiler Languages
- 92.1 Dialect as an Extensible Namespace of IR Concepts(分析 dialect 是 MLIR 扩展生态的基本机制,用于定义新的 operations、attributes 和 types)
- 92.2 Domain Semantics Encoded as Operations and Types(不同领域可以通过 dialect 表达自己的算子、类型、内存、shape、控制流或硬件语义)
- 92.3 Standard Dialects vs Custom Dialects(分析内置 dialect 提供通用基础,自定义 dialect 则让语言、框架或硬件后端表达自己的抽象)
- 92.4 Dialect Boundaries and Composition(多个 dialect 可以在同一个 module/function 中共存,让程序在 lowering 过程中同时包含不同抽象层)
- 92.5 Engineering Insight: Dialects Let Compiler Infrastructure Speak Many Domain Languages(dialect 让统一编译器基础设施承载多个领域语言,保留领域语义进入合适降级阶段)
Chapter 93: Operations, Regions, Attributes, and Types
- 93.1 Operation as the Central Unit of MLIR(分析 operation 如何组织 operands、results、attributes、regions 和 successors)
- 93.2 Regions and Blocks as Nested Program Structure(regions 允许 operation 内部包含 block 和嵌套 operation,从而表达函数体、循环体、控制流或领域结构)
- 93.3 Attributes as Compile-Time Metadata(attributes 表达编译期已知的常量、配置、布局、符号、策略或领域元数据)
- 93.4 Types as Constraints on Values and Operations(types 约束 SSA values、operation operands/results,并帮助 verifier、rewriter 和 lowering 保持结构正确)
- 93.5 Engineering Insight: MLIR Generalizes IR Around Operations with Extensible Semantics(MLIR 的关键是把 IR 统一建模为可扩展 operation 系统,同时允许不同 dialect 定义自己的语义)
Chapter 94: Dialect Conversion and Progressive Lowering
- 94.1 Conversion Targets and Legal Operations(分析 dialect conversion 会定义哪些 operation 在当前阶段合法,哪些需要被转换)
- 94.2 Rewrite Patterns as Lowering Rules(通过 pattern-based rewriting,把高层 operation 转换成一个或多个低层 operation)
- 94.3 Type Conversion and Value Remapping(当 lowering 改变类型系统时,TypeConverter 负责把高层类型转换成目标 dialect 支持的类型)
- 94.4 Partial Lowering and Mixed-Dialect IR(MLIR 支持不同 dialect 在同一 IR 中共存,因此 lowering 可以分阶段、局部、渐进地完成)
- 94.5 Engineering Insight: Dialect Conversion Turns Abstraction Loss into a Controlled Compiler Process(dialect conversion 的核心是把“丢失高层抽象”变成可验证、可测试、可组合的工程流程)
Chapter 95: MLIR in Heterogeneous and Domain-Specific Compilation
- 95.1 Heterogeneous Hardware Needs Multiple Abstraction Layers(CPU、GPU、NPU、TPU、DSP、FPGA 等目标需要不同层级的并行、内存和指令抽象)
- 95.2 Tensor, Linear Algebra, Affine, GPU, and LLVM Dialects(分析不同 dialect 如何分别服务张量计算、线性代数、仿射循环、GPU 映射和 LLVM IR 输出)
- 95.3 From Domain IR to LLVM IR or Hardware-Specific Dialects(程序可以从高层 domain dialect 逐步 lowering 到 LLVM dialect、GPU dialect 或硬件特定 dialect)
- 95.4 Optimization Before Lowering vs After Lowering(高层优化利用领域语义,低层优化利用机器约束;过早 lowering 会丢失前者,过晚 lowering 会阻碍后者)
- 95.5 Engineering Insight: MLIR Is a Compiler Construction Strategy for a World with Too Many Targets(MLIR 的意义在于,当语言、框架和硬件目标越来越多时,用多层 IR 和 dialect 组合降低编译器工程成本)
Part 20: CPython Compilation Pipeline and Bytecode VM
Chapter 96: From Python Source to Tokens
- 96.1 Python Source as Encoded Text(分析
.py文件首先是字节和编码,CPython 必须先把源码解码成可分析的文本) - 96.2 Tokenization in the Python Frontend(Python 源码会先被 tokenizer 切成 token stream,parser 的输入边界已经从字符提升到 token)
- 96.3 INDENT, DEDENT, NEWLINE, and Python Layout Semantics(Python 的缩进结构会被词法阶段转成
INDENT、DEDENT、NEWLINE等 token) - 96.4 Names, Literals, Operators, and Keywords as Tokens(变量名、数字、字符串、操作符和关键字在 token 层被分类,并携带源码位置)
- 96.5 Engineering Insight: Python’s Whitespace Sensitivity Starts Before Parsing(Python 的缩进语义是在 tokenization 阶段就被结构化)
Chapter 97: Parsing Python into AST
- 97.1 Parser as the Consumer of Python Token Streams(CPython parser 消费 tokenizer 产出的 token stream,并根据 Python grammar 建立语法结构)
- 97.2 Concrete Syntax vs Abstract Syntax(区分完整语法推导结构和 AST:AST 会保留程序语义结构,去掉许多纯语法细节)
- 97.3 Python AST Nodes and Program Structure(
Module、FunctionDef、ClassDef、If、For、Call、Name等 AST 节点如何表示 Python 程序) - 97.4 Syntax Errors and Parser Diagnostics(parser 在结构不合法时生成 syntax error,并尽量定位错误 token、源码范围和上下文)
- 97.5 Engineering Insight: Python AST Is the First Compiler-Usable Shape of Python Code(Python AST 是 CPython 后续符号表、作用域分析和字节码生成使用的程序结构)
Chapter 98: Symbol Table, Scopes, and Code Objects
- 98.1 Symbol Table Construction from AST(CPython compiler 会从 AST 构造 symbol table,用来计算每个 identifier 的作用域)
- 98.2 Local, Global, Nonlocal, Free, and Cell Variables(分析局部变量、全局变量、
nonlocal、自由变量、闭包 cell 变量在 Python 作用域中的区别) - 98.3 Function, Class, Module, and Comprehension Scopes(Python 的函数、类、模块、推导式都会形成不同作用域规则)
- 98.4 Code Objects as Compiled Execution Units(
code object保存 bytecode、常量、名字、变量表、freevars、cellvars 和执行所需元数据) - 98.5 Engineering Insight: Python Names Are Resolved Before the VM Executes Them(Python 虽然是动态语言,但名字的作用域分类并是在编译阶段已经计算出来)
Chapter 99: AST to CFG to Bytecode
- 99.1 AST Walking and Pseudo-Instruction Generation(CPython compiler 会遍历 AST,把不同节点转换成更接近 bytecode 的 pseudo instructions)
- 99.2 CFG as the Intermediate Structure Before Final Bytecode(CPython 使用 CFG 表示控制流,让跳转目标、异常路径和 block 关系更容易处理)
- 99.3 Basic Blocks, Jumps, and Control Flow Assembly(
if、for、while、try、match等结构会被转换成 basic blocks 和跳转关系) - 99.4 Bytecode Emission and Offset Resolution(最终 bytecode 生成时,需要确定指令顺序、jump offset、异常表和 line table 信息)
- 99.5 Engineering Insight: CPython Bytecode as Assembled from Compiler Structure(CPython bytecode 是 AST、symbol table、CFG、pseudo instructions 多阶段加工后的产物)
Chapter 100: Evaluation Loop and Runtime Objects
- 100.1 Bytecode as Input to the CPython VM(CPython VM 执行的是 code object 中的 bytecode,code object 是执行入口)
- 100.2 Frames, Value Stack, and Instruction Dispatch(执行函数时会创建 frame,维护局部变量、value stack、instruction pointer 和异常状态)
- 100.3 Runtime Objects and Dynamic Type Operations(Python 的整数、字符串、函数、类、模块、列表、字典等都是运行时对象,bytecode 操作会调度对象协议)
- 100.4 Disassembling Python Bytecode with
dis(用dis观察 CPython bytecode,并连接 compiler 输出和 interpreter 输入) - 100.5 Engineering Insight: CPython Is a Compiler plus a Virtual Machine(CPython 的核心是先编译成 code object 和 bytecode,再由 VM 在运行时执行对象语义)
Part 21: WebAssembly and Portable Runtime Targets
Chapter 101: WebAssembly as a Portable Compilation Target
- 101.1 Wasm as a Low-Level Code Format(分析 WebAssembly 是编译器可以生成的低层目标格式)
- 101.2 Portable Compilation Target Across Languages(C、C++、Rust、AssemblyScript、TinyGo 等语言可以把代码编译到 Wasm,用统一运行时执行)
- 101.3 Browser, Server, Edge, Embedded, and Plugin Use Cases(Wasm 不只在浏览器运行,也可用于服务器、边缘计算、插件系统、沙箱扩展和嵌入式场景)
- 101.4 Wasm Text Format vs Binary Format(分析
.wat文本格式便于阅读调试,.wasm二进制格式便于传输、加载和执行) - 101.5 Engineering Insight: WebAssembly Is a Compiler Target Designed for Portable Sandboxed Execution(Wasm 的核心是为多语言程序提供可移植、可验证、可沙箱执行的目标机器)
Chapter 102: Stack Machine, Linear Memory, Tables, and Modules
- 102.1 Stack-Based Execution Model(分析 Wasm 指令通过 operand stack 传递中间值,抽象掉物理寄存器模型)
- 102.2 Linear Memory as an Explicit Byte Address Space(Wasm linear memory 是模块可访问的连续字节数组,用于模拟 C/C++/Rust 等语言的堆、栈和数据区)
- 102.3 Tables, Function References, and Indirect Calls(table 用于保存函数引用等间接调用目标,支撑动态分发、函数指针和宿主交互)
- 102.4 Modules, Imports, Exports, and Instantiation(Wasm module 定义函数、内存、表、全局变量、imports、exports,实例化后才能和宿主环境交互)
- 102.5 Engineering Insight: Wasm Defines a Small Virtual Machine Contract Instead of a Real CPU(Wasm 定义一套更小、更安全、更容易验证的抽象执行机器,并和 x86 或 ARM 这类物理 ISA 保持边界)
Chapter 103: Validation, Security, and Sandboxing
- 103.1 Validation Before Execution(Wasm runtime 在执行前验证 module,确保类型、控制流、栈状态和指令结构满足规范)
- 103.2 Type Safety and Structured Control Flow(Wasm 用静态验证和结构化控制流限制非法跳转、栈错配和未定义执行状态)
- 103.3 Memory Isolation and Bounds Checking(Wasm 模块只能访问自己的 linear memory,越界访问必须被阻止)
- 103.4 Host Capabilities Instead of Ambient Authority(Wasm 模块默认只通过 import、WASI 等接口获得文件、网络、系统调用或宿主资源能力)
- 103.5 Engineering Insight: Wasm Security Comes from Validation plus Explicit Host Boundaries(Wasm 的安全性是靠加载前验证、受限内存模型和明确的宿主接口边界)
Chapter 104: WASI and Host Environment Interfaces
- 104.1 WASI and System Interfaces Outside the Browser(在浏览器外运行 Wasm 时,程序仍需要文件、时钟、随机数、环境变量、网络等系统能力)
- 104.2 WASI as a Standards-Track API Family(WASI 是面向编译到 Wasm 的软件的一组标准化 API 规范,目标是在浏览器、云、嵌入式等环境提供安全标准接口)
- 104.3 Capability-Oriented Resource Access(WASI 倾向于通过显式授权能力访问资源,通过显式能力限制系统权限)
- 104.4 Preview Versions, Component Model, and Interface Evolution(WASI 从 Preview 1 发展到基于 Component Model 的新接口体系,接口仍在演进)
- 104.5 Engineering Insight: WASI Is the Operating-System Boundary for Portable Wasm Programs(Wasm 定义可执行代码格式,WASI 则试图定义 Wasm 程序如何安全、可移植地接触宿主系统)
Chapter 105: JIT, AOT, and Runtime Embedding
- 105.1 Interpreting, JIT Compiling, or AOT Compiling Wasm(Wasm runtime 可以解释执行、运行时 JIT 编译,也可以提前 AOT 编译成宿主机器码)
- 105.2 Runtime Embedding in Browsers and Host Applications(浏览器、服务器、数据库、插件系统和应用程序可以把 Wasm runtime 嵌入为受控执行环境)
- 105.3 Startup Time, Compilation Cost, and Code Cache(JIT/AOT/interpreter 的选择会影响启动速度、峰值性能、内存占用和代码缓存策略)
- 105.4 Host Calls, Imports, and Boundary Crossing Cost(Wasm 调用宿主函数或宿主调用 Wasm 函数会产生边界成本,频繁跨边界可能影响性能)
- 105.5 Engineering Insight: Wasm Runtime Design Is About Where to Pay Compilation and Boundary Costs(Wasm 执行性能不只由指令格式决定,还取决于 runtime 如何选择解释、JIT、AOT、缓存和宿主边界策略)
Part 22: Shader Compilers, SPIR-V, and GPU Code Generation
Chapter 106: Shader Source as a Specialized Program
- 106.1 Shader Code as Stage-Specific GPU Programs(分析 vertex、fragment、compute、geometry、mesh 等 shader stage 是运行在图形/计算管线特定阶段的并行程序)
- 106.2 Inputs, Outputs, Builtins, and Pipeline Contracts(shader 的输入输出、内建变量、插值规则、资源绑定和执行频率都由图形 API 与 pipeline state 共同约束)
- 106.3 Shader Semantics vs General-Purpose Language Semantics(shader 语言强调向量、矩阵、纹理、采样、坐标空间、并行实例和 GPU 资源访问,区别于通用系统编程的自由内存和系统调用模型)
- 106.4 Compilation Boundaries Between Application, API, Driver, and GPU(应用提交 shader 源码或 IR,API 验证格式,driver 进一步编译成目标 GPU 可执行代码)
- 106.5 Engineering Insight: A Shader Is a Program Written Inside a Rendering Contract(shader 的意义需要结合 pipeline stage、资源布局、GPU 并行模型和图形 API 状态分析)
Chapter 107: GLSL, HLSL, WGSL, and Frontend Differences
- 107.1 GLSL as the OpenGL/Vulkan-Oriented Shading Language(分析 GLSL 的语法、类型、stage 修饰符、layout qualifier 和 OpenGL/Vulkan 生态关系)
- 107.2 HLSL as the Direct3D-Oriented Shading Language(分析 HLSL 的语义标注、resource model、shader model 和 Direct3D 工具链关系)
- 107.3 WGSL as the WebGPU Shading Language(WGSL 是 WebGPU 的着色语言,强调强验证、显式资源绑定和浏览器安全执行边界;W3C 规范定义了 WGSL 与 WebGPU 的语言关系和验证要求)
- 107.4 Frontend Translation and Cross-Compilation(不同 shader 语言可以被翻译到 SPIR-V、DXIL、MSL 或其他中间/目标格式,同时保留语言语义、资源模型和限制差异)
- 107.5 Engineering Insight: Shader Frontends Translate Language Style into Pipeline-Compatible Semantics(shader 前端同时语法转换器,它必须把语言特性映射到图形 API、资源绑定和 GPU 执行约束)
Chapter 108: SPIR-V and GPU-Oriented Intermediate Representation
- 108.1 SPIR-V as Binary IR for Graphics and Compute(分析 SPIR-V 是面向 shader stage 和 compute kernel 的二进制中间表示,需要区分最终 GPU 机器码)
- 108.2 Modules, Capabilities, Execution Models, and Entry Points(SPIR-V module 通过 capability、execution model、entry point、storage class 等结构表达目标环境和程序入口)
- 108.3 SSA, Basic Blocks, and Control Flow in SPIR-V(SPIR-V 使用接近 SSA 的 value 表示和 basic block/control-flow 结构,便于验证、优化和后续驱动编译)
- 108.4 Validation, Portability, and Driver Consumption(SPIR-V 需要满足规范和目标环境限制,driver 再把它 lower 到具体 GPU ISA 或内部 IR)
- 108.5 Engineering Insight: SPIR-V Is Portable Enough for APIs, but Still Abstract Enough for Drivers(SPIR-V 作为 API 与驱动之间的标准中间层,仍需要厂商后端完成最终生成)
Chapter 109: Driver Compilers and GPU Machine Code
- 109.1 SPIR-V as Structured GPU IR(SPIR-V 仍需由 GPU driver 编译到具体硬件后端,因为不同 GPU 的 ISA、寄存器、调度、内存层级和 wavefront/warp 模型不同)
- 109.2 Vendor IR, Optimization, and Hardware Lowering(driver 可能把 SPIR-V/DXIL/MSL 转成厂商内部 IR,再进行目标相关优化和指令选择)
- 109.3 Resource Binding, Descriptor Layouts, and Hardware State(连接 descriptor、binding、push constants、buffer、texture 和 sampler 布局)
- 109.4 Register Pressure, Occupancy, and GPU Scheduling Constraints(GPU shader 编译要考虑寄存器数量、线程组大小、occupancy、shared memory 和内存访问模式)
- 109.5 Engineering Insight: GPU Code Generation Is Where Shader Semantics Meet Hardware Throughput Geometry(GPU 后端同时在并行粒度、寄存器压力、资源访问和吞吐模型之间做映射)
Chapter 110: Graphics Pipeline State and Shader Optimization
- 110.1 Shader Optimization Depends on Pipeline Context(分析 blend、depth/stencil、rasterization、vertex layout 和 render target 对优化的影响)
- 110.2 Constant Folding, Dead Code Elimination, and Specialization(常量、宏、specialization constants、未使用 varying/resource 都可能让 driver 或离线工具删减 shader 路径)
- 110.3 Texture, Derivatives, Divergence, and Control Flow Costs(纹理采样、屏幕空间导数、分支发散和内存访问模式会显著影响 shader 性能)
- 110.4 Offline Compilation, Runtime Compilation, and Pipeline Cache(游戏/引擎会在离线编译、运行时编译、pipeline cache 和 shader variant 管理之间权衡卡顿与灵活性)
- 110.5 Engineering Insight: Shader Performance Is Compiled from Code, State, and Hardware Together(shader 性能是 shader 代码、pipeline state、资源布局、driver 编译器和 GPU 架构共同形成的结果)
Part 23: AI Graph Compilers, Tensor IR, and Operator Fusion
Chapter 111: Neural Networks as Computation Graphs
- 111.1 Model Execution as a Graph of Tensor Operations(分析神经网络模型可以被表示成 operator 节点和 tensor 边组成的计算图)
- 111.2 Eager Execution vs Graph Compilation(区分逐条执行框架操作的 eager 模式,和先捕获/构建计算图再整体优化的 graph compilation)
- 111.3 Operators, Tensors, Parameters, and Constants(分析卷积、矩阵乘、归一化、激活、reshape、transpose 等 operator 如何通过 tensor 数据流连接)
- 111.4 Graph Boundaries, Dynamic Shapes, and Runtime Inputs(分析 batch size、序列长度、动态 shape、控制流和 runtime input 如何影响图编译)
- 111.5 Engineering Insight: An AI Model Becomes Optimizable When It Becomes a Graph(模型一旦从 Python 调用序列变成计算图,编译器就能跨 operator 观察数据流、消除冗余并规划执行)
Chapter 112: Tensor Shapes, Layouts, and Type-Like Information
- 112.1 Tensor Shape as Compile-Time and Runtime Structure(shape 描述 tensor 的维度、rank、静态/动态大小,是 AI 编译器推理内存和算子合法性的基础)
- 112.2 DType, Quantization, and Numeric Semantics(float32、float16、bfloat16、int8、quantized type 等 dtype 会影响精度、性能、硬件指令和内存带宽)
- 112.3 Layouts: NCHW, NHWC, Tiling, and Packed Formats(tensor layout 决定数据在内存中的排列方式,会直接影响 cache、向量化、GPU coalescing 和 accelerator kernel)
- 112.4 Shape Inference, Broadcasting, and Constraint Propagation(编译器通过 shape inference 和约束传播判断 operator 输入输出是否匹配,以及哪些维度可静态确定)
- 112.5 Engineering Insight: Tensor Metadata Is the Type System of AI Compilers(shape、dtype、layout、quantization 参数共同扮演类似类型系统的角色,决定计算是否合法以及如何高效 lowering)
Chapter 113: Graph Optimization and Operator Fusion
- 113.1 Constant Folding, Dead Node Elimination, and Algebraic Simplification(图层优化会删除无用节点、折叠常量计算、简化代数结构并减少 runtime work)
- 113.2 Operator Fusion as Removing Intermediate Materialization(operator fusion 把多个相邻算子合并成一个 kernel,减少中间 tensor 写回全局内存)
- 113.3 Fusion Patterns: Elementwise, Reduction, Producer-Consumer, and Epilogue Fusion(比较 elementwise、reduction、producer-consumer 和 epilogue fusion 模式)
- 113.4 Legality, Profitability, and Backend Constraints(融合必须满足语义正确、shape/layout 兼容、内存访问安全,并且要符合目标硬件和 kernel 生成能力)
- 113.5 Engineering Insight: Fusion Is Data Movement Optimization Disguised as Operator Optimization(算子融合表面是在合并计算,核心通常是减少中间 tensor 分配、内存读写和 kernel launch 成本)
Chapter 114: Lowering Tensor IR to Kernels
- 114.1 From Graph IR to Tensor IR(高层计算图通常需要 lowering 到更接近循环、索引、内存访问和并行维度的 tensor IR)
- 114.2 Structured Tensor Operations and Loop Nests(tensor IR 会把矩阵乘、卷积、broadcast、reduction 等表达成结构化循环和索引映射)
- 114.3 Bufferization and Memory Planning(从不可变 tensor 语义 lowering 到可写 buffer 时,需要决定内存分配、复用、别名和生命周期)
- 114.4 Scheduling: Tiling, Vectorization, Unrolling, and Thread Binding(追踪 tiling、vectorization、unrolling 和 thread binding 如何映射硬件)
- 114.5 Engineering Insight: Tensor Lowering Turns Mathematical Operators into Memory-Aware Loop Programs(AI 编译器最终要把高层数学算子变成具体循环、buffer、线程、向量指令和硬件 kernel)
Chapter 115: Runtime Scheduling, Memory Planning, and Hardware Backends
- 115.1 Runtime as the Executor of Compiled Graphs(编译后的模型仍需要 runtime 负责输入绑定、kernel launch、stream/queue 管理、内存分配和结果回收)
- 115.2 Memory Planning, Buffer Reuse, and Peak Memory Reduction(runtime/compiler 会根据 tensor 生命周期复用 buffer,降低峰值显存/内存占用)
- 115.3 Backend Targets: CPU, GPU, TPU, NPU, and Custom Accelerators(不同后端有不同指令、内存层级、并行模型、kernel 库和编译约束)
- 115.4 Compilation Cache, Dynamic Shapes, and Runtime Guards(动态 shape 或输入变化可能触发重新编译、specialization、guard 检查和缓存复用策略)
- 115.5 Engineering Insight: AI Compiler Performance Is Co-Designed by Graph, Kernel, Runtime, and Hardware(AI 编译性能是图优化、kernel 生成、内存规划、runtime 调度和硬件后端共同决定)
Part 24: Database Query Optimizers as Compiler Systems
Chapter 116: SQL as a Declarative Source Language
- 116.1 SQL Describes Results(分析 SQL 声明“想要什么结果”,执行步骤交给优化器生成)
- 116.2 Declarative Semantics and Optimization Freedom(因为 SQL 只规定结果语义,优化器可以自由选择扫描、连接、排序、聚合和访问路径)
- 116.3 Tables, Relations, Predicates, and Expressions(SQL 查询会被拆解成关系、谓词、投影、表达式、分组和排序等语义结构)
- 116.4 Query Text vs Query Meaning(不同写法的 SQL 可能表达同一查询语义,优化器关心的是逻辑等价关系,文本形状只是进入逻辑计划的表面形式)
- 116.5 Engineering Insight: SQL Is Source Code for a Dataflow Compiler(SQL 的核心是数据处理意图的源码,数据库优化器负责把它编译成可执行的数据流计划)
Chapter 117: Parsing, Binding, and Logical Query Plans
- 117.1 Parsing SQL into a Query Tree(SQL 文本先被 parser 转成结构化查询树,类似普通编译器从 token/grammar 得到 AST)
- 117.2 Binding Names to Tables, Columns, Functions, and Types(binder/analyzer 把表名、列名、函数、类型和作用域绑定到数据库 catalog 中的真实对象)
- 117.3 Query Rewriting and View Expansion(视图、规则、子查询、等价谓词可能在优化前被重写成更适合分析的逻辑形式)
- 117.4 Logical Operators: Scan, Filter, Join, Aggregate, Sort, and Project(逻辑计划用关系代数风格算子表达查询语义,而不急于决定具体算法)
- 117.5 Engineering Insight: Binding Turns SQL Text into Database-Specific Meaning(SQL 只有绑定到 catalog、schema、类型和权限后,才成为某个数据库实例里的具体查询)
Chapter 118: Cost-Based Optimization and Plan Search
- 118.1 Many Plans Can Produce the Same Result(同一逻辑查询可能通过顺序扫描、索引扫描、不同 join order、不同 join algorithm 得到相同结果)
- 118.2 Statistics, Cardinality Estimation, and Selectivity(优化器依赖表统计、列分布、选择率和行数估算判断中间结果规模)
- 118.3 Cost Models for CPU, I/O, Memory, and Network(cost model 试图估算扫描、连接、排序、聚合、物化和数据移动的相对成本)
- 118.4 Search Space, Join Ordering, Dynamic Programming, and Heuristics(连接顺序搜索空间会快速爆炸,因此优化器需要动态规划、启发式或遗传算法等策略)
- 118.5 Engineering Insight: Query Optimization Is Search Under Imperfect Knowledge(数据库优化器是在统计信息不完美的情况下搜索预计成本最低的执行方式)
Chapter 119: Physical Operators and Execution Plans
- 119.1 Physical Plan as the Executable Form of a Query(物理计划决定具体使用哪些 scan、join、sort、aggregate、materialize 等执行算子)
- 119.2 Sequential Scan, Index Scan, Bitmap Scan, and Access Paths(不同访问路径在 I/O、随机访问、缓存命中和过滤条件上的成本不同)
- 119.3 Nested Loop, Hash Join, Merge Join, and Join Strategy(不同 join 算法对输入大小、有序性、内存、索引和数据分布有不同适用条件)
- 119.4 Pull-Based Execution and Plan Nodes(分析 PostgreSQL executor 如何按 demand-pull 机制从 plan node 拉取下一行)
- 119.5 Engineering Insight: An Execution Plan Is a Program Made of Data Operators(执行计划就是由物理算子组成的程序,只不过它处理的是 tuple 流、buffer、索引和中间结果)
Chapter 120: Query Compilation, JIT, and Vectorized Execution
- 120.1 Interpreted Plan Execution vs Compiled Query Execution(传统 executor 解释执行 plan node,而 query compilation 可以把部分表达式或算子路径编译成更直接的机器码)
- 120.2 Expression JIT and Hot Query Fragments(JIT 常先优化表达式计算、tuple deforming、过滤谓词等热点片段,而可能把整个数据库 executor 都编译掉)
- 120.3 Vectorized Execution and Batch Processing(向量化执行一次处理一批 rows/columns,降低解释器分发开销并改善 CPU cache 和 SIMD 利用)
- 120.4 Runtime Adaptivity and Feedback(实际执行行数可能和估算不同,现代系统可能通过 runtime feedback、自适应执行或重新优化修正计划)
- 120.5 Engineering Insight: Database Execution Performance Depends on Both Plan Quality and Operator Machinery(SQL 性能同时取决于优化器计划质量,以及 executor、JIT、向量化、内存布局和缓存行为如何执行这个计划)
Part 25: Compiler Diagnostics, Error Recovery, and Developer Experience
Chapter 121: Diagnostics as a Compiler User Interface
- 121.1 Diagnostics Are How the Compiler Talks to Programmers(分析 error、warning、note、remark 同时编译器面向开发者的主要交互界面)
- 121.2 Error, Warning, Note, Remark, and Help Messages(区分错误、警告、补充说明、优化备注和帮助信息在严重性与用途上的差异)
- 121.3 Diagnostic Quality as Engineering Productivity(好的诊断能缩短定位时间,差的诊断会把编译器内部复杂性转嫁给用户)
- 121.4 Diagnostics in Batch Builds, IDEs, and CI Systems(命令行构建、IDE 实时提示、CI 日志和代码审查工具对诊断信息有不同展示需求)
- 121.5 Engineering Insight: A Compiler That Cannot Explain Failure Becomes Part of the Failure(编译器错误解释不清时,程序员会同时调试代码和调试编译器反馈)
Chapter 122: Source Ranges, Notes, Hints, and Fix-Its
- 122.1 Source Locations and Ranges as Diagnostic Evidence(诊断信息必须指向具体文件、行、列和源码范围,帮助用户把问题落到真实代码位置)
- 122.2 Carets, Highlights, and Related Source Spans(caret 和 range highlight 能指出主要错误位置以及参与该错误的相关表达式、声明或调用)
- 122.3 Notes as Context for the Main Diagnostic(note 可以补充模板实例化栈、重载候选、宏展开、previous declaration、类型推导过程等上下文)
- 122.4 Fix-It Hints as Safe Local Transformations(fix-it hint 提供具体修改建议,例如插入关键字、删除多余语法、替换错误 token;Clang 的 fix-it 可以表示插入、删除和替换源码范围)
- 122.5 Engineering Insight: Good Diagnostics Preserve the Reasoning Path from Error to Fix(优秀诊断是把编译器发现错误的推理路径浓缩成可行动信息)
Chapter 123: Syntax Error Recovery
- 123.1 Syntax Errors Break Structure, but Editing Must Continue(语法错误会破坏 parser 构建结构的过程,但编译器/IDE 仍需要在错误之后继续分析整个文件)
- 123.2 Synchronization Tokens and Panic Recovery(parser 可以通过分号、右括号、换行、关键字、缩进边界等同步点跳过错误区域继续分析)
- 123.3 Placeholder Nodes and Partial ASTs(为了支持 IDE 和后续分析,parser 可能构造错误节点、缺失节点或 partial AST 表示不完整程序)
- 123.4 Controlling Cascading Syntax Errors(一次缺失括号或分号可能引发大量伪错误,恢复策略必须尽量减少误导性后续报错)
- 123.5 Engineering Insight: Error Recovery Supports Incomplete Programs(说明错误恢复如何让编译器处理编辑中的半成品程序并保留后续分析能力)
Chapter 124: Semantic Error Reporting
- 124.1 Undefined Names, Type Errors, and Invalid Operations(语义错误包括名字未定义、类型不匹配、非法调用、无效成员访问、不可见符号等)
- 124.2 Reporting Candidate Sets and Resolution Failures(重载失败、模板推导失败、trait bound 不满足等错误需要展示候选、约束和失败原因)
- 124.3 Macro, Template, Generic, and Instantiation Contexts(宏展开、模板实例化、泛型约束会让错误来源跨越多层上下文,诊断必须展示相关路径)
- 124.4 Balancing Precision and Noise(诊断需要足够具体,同时控制内部实现细节、过长候选列表和无关上下文的暴露范围)
- 124.5 Engineering Insight: Semantic Diagnostics Translate Compiler Reasoning into Human Reasoning(语义报错的难点,是把类型系统、名字解析和约束求解的内部失败,翻译成程序员能分析和修复的问题)
Chapter 125: Designing Diagnostics for Human Understanding
- 125.1 Message Wording and Mental Model Alignment(错误文字应使用用户分析的语言模型,减少编译器内部术语泄漏)
- 125.2 Locality: Point to the Cause(好的诊断尽量指向原因,减少只报告后续崩坏位置)
- 125.3 Actionability: Tell the User What Can Be Changed(诊断最好能暗示下一步,例如改类型、补 import、加括号、改签名、调整 lifetime 或检查候选)
- 125.4 IDE Integration, Machine-Readable Diagnostics, and Tooling(现代编译器还需要输出机器可读格式,供 LSP、IDE、formatter、linter 和自动修复工具消费)
- 125.5 Engineering Insight: Developer Experience Is a Compiler Feature(诊断、恢复、fix-it、IDE 集成和错误解释都是编译器产品质量的一部分,需要区分附属文档)
Part 26: Compiler Testing, Fuzzing, Verification, and Miscompilation Debugging
Chapter 126: Golden Tests, Unit Tests, and Integration Tests
- 126.1 Unit Tests for Compiler Data Structures and Algorithms(测试 lexer、parser、AST、IR builder、type checker、analysis pass 等局部组件是否按预期工作)
- 126.2 Golden Tests for Stable Textual Outputs(用固定输入和期望输出验证 token stream、AST dump、IR dump、diagnostic message、assembly 输出是否稳定)
- 126.3 Regression Tests as Bug Memory(每个修复过的 compiler bug 都应该变成 regression test,防止未来 pass、frontend 或 backend 改动重新引入问题)
- 126.4 End-to-End Tests from Source to Execution(从源码输入一路编译、链接、运行并检查输出,用来验证整条 pipeline 是否保持语义)
- 126.5 Engineering Insight: Compiler Tests Preserve Trust Across Transformations(编译器测试的核心是证明一连串表示转换后程序意义仍然可信)
Chapter 127: IR Tests and Pass-Level Verification
- 127.1 IR-Level Test Value(很多优化和 lowering bug 不需要完整源码触发,直接用 IR 构造最小输入更稳定、更精确)
- 127.2 FileCheck and Pattern-Based Output Validation(用 FileCheck 这类模式检查工具验证 IR、assembly、diagnostic 输出中是否包含或不包含关键结构)
- 127.3 Testing One Pass in Isolation(通过
opt或类似工具只运行目标 pass,隔离 pass 行为并排除 frontend/backend 噪声) - 127.4 Verifiers as Internal Consistency Tests(IR verifier、dominator verifier、machine verifier 等工具检查 pass 是否破坏结构不变量)
- 127.5 Engineering Insight: Pass Tests Should Prove the Transformation(pass-level 测试要证明具体变换是否发生、是否保持结构合法,同时检查目标变换证据)
Chapter 128: Fuzzing Parsers, Optimizers, and Code Generators
- 128.1 Fuzzing as Automated Exploration of Strange Inputs(fuzzing 用大量随机或变异输入探索人类不会手写的语法组合、IR 结构和目标约束)
- 128.2 Parser and Frontend Fuzzing(对 lexer/parser/type checker 输入异常源码,寻找 crash、hang、错误诊断、非法 AST 或安全问题)
- 128.3 IR and Optimizer Fuzzing(生成合法或接近合法的 IR,触发 optimizer pass 组合中的 crash、非法 IR 或错误改写)
- 128.4 Backend and Codegen Fuzzing(用随机 IR、目标特性和优化等级测试 instruction selection、register allocation 和 emission)
- 128.5 Engineering Insight: Fuzzing Finds Compiler States No Human Test Author Would Imagine(fuzzing 系统性探索边界状态、奇怪组合和 pass 交互,扩展到人工用例覆盖不到的状态)
Chapter 129: Differential Testing and Miscompilation Detection
- 129.1 Differential Testing as Comparing Independent Compilers(同一程序交给多个编译器、多个优化等级或多个后端执行,如果输出不一致,就可能暴露 bug)
- 129.2 Csmith and Random Valid Program Generation(分析 Csmith 如何生成规避 undefined behavior 的随机 C 程序并比较编译器输出)
- 129.3 Metamorphic and Equivalence-Based Testing(通过语义等价变换、输入扰动、优化等级变化或源程序改写,检查编译器是否保持等价结果)
- 129.4 Crash vs Wrong-Code vs Performance Regression(区分编译器崩溃、生成错误代码、编译时间爆炸、运行性能退化和诊断变化等不同失败类型)
- 129.5 Engineering Insight: Miscompilation Is Detected by Disagreement Between Promised Meaning and Observed Behavior(miscompilation 的核心是编译器承诺保持语义,但最终行为和原程序意义不一致)
Chapter 130: Reducing and Debugging Compiler Bugs
- 130.1 Testcase Reduction as Making Bugs Understandable(大型工程触发的 bug 往往太复杂,必须缩减到最小源码、IR 或 pass pipeline 才能分析)
- 130.2 Reducing Source, IR, and Pass Pipelines Separately(有时要缩减源码,有时要直接缩减 IR,有时要缩小触发 bug 的 pass 序列或目标特性组合)
- 130.3
bugpoint,creduce, and Automated Reduction Tools(使用bugpoint、creduce等工具把 crash、miscompilation 和 codegen bug 缩成小用例) - 130.4 Bisecting Passes, Commits, and Optimization Levels(通过关闭 pass、改变优化等级、git bisect、保存中间 IR,定位错误从哪个提交或哪个 transformation 开始出现)
- 130.5 Engineering Insight: A Compiler Bug as a Structured System(修复编译器 bug,同时改掉当前失败,还要把它最小化、可复现化,并加入 regression test)
Part 27: Building a Small Compiler from Scratch
Chapter 131: Designing a Tiny Language
- 131.1 Defining the Learning Goal Before the Language(先明确这个 tiny language 是为了学习编译器 pipeline,把语言范围控制在编译器 pipeline 学习目标内)
- 131.2 Minimal Syntax: Variables, Expressions, Functions, and Control Flow(设计最小语法集合,例如变量声明、算术表达式、函数调用、
if、while、return) - 131.3 Type Model: Dynamic, Static, or Minimal Static Types(决定语言是否使用动态类型、简单静态类型,或只支持 number/bool/string 等最小类型系统)
- 131.4 Runtime Model: Interpreter, Bytecode VM, LLVM IR, or Wasm(从一开始明确执行目标:直接解释 AST、编译到 bytecode、生成 LLVM IR,还是输出 WebAssembly)
- 131.5 Engineering Insight: A Tiny Language Should Be Small Enough to Finish and Rich Enough to Expose the Pipeline(教学语言应刚好覆盖编译器各阶段的核心问题)
Chapter 132: Implementing Lexer, Parser, and AST
- 132.1 Token Definitions and Source Location Tracking(定义 token kind、lexeme、literal value、line/column/range,为后续 parser 和 diagnostics 提供基础)
- 132.2 Recursive Descent or Pratt Parser for Expressions(用 recursive descent 处理语句和声明,用 Pratt 或 precedence parser 处理表达式优先级)
- 132.3 AST Node Design and Source Ranges(设计 expression、statement、declaration、function、block 等 AST 节点,并保留源码位置)
- 132.4 Parser Errors and Partial Recovery(实现基本语法错误恢复,让 parser 能在出错后继续处理后续代码)
- 132.5 Engineering Insight: The First Milestone as a Trustworthy Program Structure(小编译器第一阶段的成果是稳定地把源码变成可信 AST)
Chapter 133: Building Semantic Analysis and IR
- 133.1 Symbol Tables, Scope Stacks, and Name Resolution(实现作用域栈、符号表、变量/函数声明绑定,检查未定义名字和重复声明)
- 133.2 Type Checking and Semantic Constraints(根据语言设计检查表达式类型、函数调用参数、返回值、控制流上下文和非法操作)
- 133.3 Lowering AST into a Simple IR(把 AST 转换成更适合分析和执行的 IR,例如三地址码、basic blocks、SSA-like values 或 bytecode-friendly IR)
- 133.4 CFG Construction for Branches and Loops(为
if、while、短路逻辑、return构造 basic blocks 和 control-flow edges) - 133.5 Engineering Insight: Semantic Analysis Decides What the Program Means Before IR Decides How It Runs(名字、类型和语义约束先把程序意义固定下来,IR 才能安全表示执行路径)
Chapter 134: Adding Optimizations and Bytecode Execution
- 134.1 Constant Folding and Simple Algebraic Simplification(实现最小优化:编译期计算常量表达式、简化明显冗余运算)
- 134.2 Dead Code Elimination and Unreachable Block Removal(基于 CFG 和 use information 删除不可达 block、未使用且无副作用的计算)
- 134.3 Bytecode Instruction Set and Chunk Format(设计 opcode、constant pool、local slots、jump offsets、function objects 和调试行号表)
- 134.4 VM Frames, Operand Stack, and Dispatch Loop(实现 bytecode VM 的调用帧、操作数栈、局部变量、instruction pointer 和 opcode dispatch)
- 134.5 Engineering Insight: Bytecode Execution Makes the Compiler’s Internal Decisions Observable(bytecode VM 让 AST、IR、优化和运行时执行第一次在一个完整系统里连起来)
Chapter 135: Generating LLVM IR or WebAssembly
- 135.1 Mapping Tiny Language Values to LLVM IR or Wasm Types(把语言里的 number、bool、string、function、local variable 映射到目标 IR 支持的类型和表示)
- 135.2 Generating Functions, Basic Blocks, Branches, and Calls(把函数定义、表达式、条件分支、循环和调用 lowering 到 LLVM IR basic blocks 或 Wasm structured control flow)
- 135.3 Runtime Helpers, Strings, Memory, and I/O Boundaries(处理 print、string、heap allocation、host calls、libc/WASI import 或自定义 runtime helper)
- 135.4 Compiling, Linking, Running, and Inspecting Output(用 LLVM tools、
opt、llc、clang、wasm-ld、Wasm runtime 或 disassembler 检查输出产物) - 135.5 Engineering Insight: External Backends Turn a Toy Compiler into a Real Toolchain Participant(生成 LLVM IR 或 Wasm 后,小语言开始接入真实优化器、链接器、运行时和平台生态)