第二章:详解静态单赋值形式
我们在前面章节已经讨论了 SSA 形式在编译器技术中的重要性,以及 SSA 形式在现代编译器技术中的应用。
那么,我们希望在接下来的章节中,更详细的介绍 SSA 的概念,以及在现代编程语言特性中的应用。
术语介绍:
本文开始,将会出现很多编译技术中的术语,我们希望在这里做一个简单的介绍,以便于大家理解。
- AST:抽象语法树(Abstract Syntax Tree),是源代码的树形结构表示,每个节点代表一个语法结构。
- SSA IR:静态单赋值形式中间表示(Static Single Assignment Form Intermediate Representation),是编译器中一种中间表示形式,每个变量只能被赋值一次。
- IR:中间表示(Intermediate Representation),是编译器中一种中间表示形式,通常是SSA IR。
- 左值:可以出现在赋值符号左边的东西,通常是变量,指针,数组,结构体等。
- 右值:可以出现在赋值符号右边的值,通常是常量,变量,指针,数组,结构体等。
- Phi 函数或
φ
符号:在 SSA 形式中,Phi 函数用于处理多路 分支情况下的变量赋值,根据控制流图的不同路径,选择不同的赋值,在后续文章中的φ
符号均表示 Phi 函数。 - 基本块:在编译器中,基本块是代码的连续执行序列,没有分支和跳转,通常是循环或条件语句的内部。
- CFG: 控制流图:在编译器中,控制流图是代码执行流程的图形化表示,每个节点代表一个基本块,边代表控制流关系。
- 闭包:在编译器中,闭包是指一个函数与其相关的环境(包括自由变量)一起被捕获和存储的组合。
- OOP:面向对象编程(Object-Oriented Programming),是一种编程范式,通过类和对象来组织代码,实现代码的复用和抽象。
SSA 的基本概念
SSA(Static Single Assignment)是一种中间表示形式,其核心特征是:
- 每个变量只能被赋值一次
- 每次使用变量时都能明确知道它的定义来源
- 使用版本号来区分同一个变量的不同定义
我们接下来将会根据下图来讨论 SSA 的几个核心问题与他们在实际生产中的概念扩展
核心特征一:每个变量只能被赋值一次
SSA 的核心特征是“每个变量只能被赋值一次”,这个特征在现代编译器技术中非常重要,作为对 比,我们可以观察下面这个案例:
# 原始代码
x = 1
x = x + 1
x = x * 2
# SSA 形式
x1 = 1
x2 = x1 + 1
x3 = x2 * 2
在 SSA 形式中,每个变量只能被赋值一次,因此我们可以看到,原始代码中的 x
变量在 SSA 形式中被 拆分成了多个版本,每个版本都用不同的变量名来表示。
“覆盖” 与 “传递” 概念解析
覆盖释义
在原始代码中,我们使用 =
符号表示赋值,覆盖掉了名字为 x
的变量。在这个操作中,x
这个词法符号表示的变量是一个可以重复赋值的容器。虽然在运行时,x
变量在任何时候都只有一个值,但是在原代码的编译期(无脚手架),我们无法知道 x
变量在运行时会被赋值几次,每次赋值的值是什么。
我们每一次对 x
的操作,都会“覆盖”掉 x
变量之前存储的值。
传递释义
我们在 SSA 的形式中,可以认为 x1
和 x2
是两个不同的变量,x3
是另一个变量。x
被分割成了三个变量,每隔变量也都可以准确的找到他的数据流依赖关系。