菜单

SSA 优化

相关源文件

本文档涵盖了 Go 编译器中的静态单赋值 (SSA) 优化过程。这些优化在 SSA 中间表示上进行操作,以提高代码效率、消除冗余操作以及执行特定于体系结构的转换。有关通用 SSA 表示及其在编译流程中的作用的信息,请参阅 3.2

SSA 优化概述

Go 编译器在从 Go 源代码构建函数后,会对函数的 SSA 形式应用各种优化过程。这些优化在保持程序语义的同时,转换代码以提高运行时性能。优化过程包括适用于所有目标体系结构的通用优化以及特定于体系结构的转换。

主要优化类别包括:

  1. 值证明 - 建立值之间的关系,以消除冗余的边界检查和不可达代码
  2. 重写规则 - 基于模式的转换,用更优化的代码序列替换低效的代码序列
  3. 死代码消除 - 移除不可达或未使用的代码
  4. 特定转换 - 利用硬件功能的特定于目标的优化

来源

值证明框架

值证明框架跟踪值之间的关系,以实现高级优化,特别是边界检查消除。它维护一个“事实表”,记录属性,例如变量与其已知值范围之间的关系。

事实表

事实表是一种记录和推导值之间关系的复杂数据结构。它跟踪:

  • 界限 - 值的已知上限和下限
  • 顺序 - 值对之间的关系(例如,x < yx == y
  • - 关系适用的上下文(有符号、无符号、指针、布尔值)

来源

值界限

该框架跟踪变量的界限(最小值和最大值),这使得推理值范围成为可能。这对于边界检查消除等优化至关重要。

来源

传播事实

证明框架通过代码传播推导出的事实。例如,如果它知道 x < 10,并且代码根据 x < 5 进行分支,那么它可以在“真”分支中推断出 x < 5,在“假”分支中推断出 5 <= x < 10

这种传播对于边界检查消除至关重要。对于像 a[i] 这样的数组访问,如果框架能够证明 0 <= i < len(a),那么就可以消除边界检查。

来源

重写规则系统

SSA 重写系统应用基于模式的转换来优化代码。该系统由重写规则驱动,这些规则指定要匹配的代码模式及其替换项。

重写过程

重写过程会重复应用规则,直到没有进一步的更改为止。

来源

规则结构

规则定义在特定于平台和通用规则文件中。每个规则指定一个要匹配的模式以及要生成的替换代码。

例如,这条通用规则将乘以零替换为常量零:

(Mul8  (Const8  [0]) _) => (Const8  [0])

SSA 包包含以下规则文件:

  • 通用优化(generic.rules
  • 特定体系结构的优化(例如,RISCV64.rulesPPC64.rulesLOONG64.rules

来源

常见优化

重写系统执行以下几种常见优化:

优化示例优点
常量折叠2 + 35在编译时计算常量
强度缩减x * 2x << 1用更便宜的操作替换昂贵的操作
死代码消除移除未使用的值减小代码大小并提高缓存利用率
代数简化x + 0x移除不必要的运算
边界检查消除移除冗余的数组边界检查提高数组访问性能

来源

特定于架构的优化

除了通用优化之外,Go 编译器还应用特定于体系结构的优化来利用目标处理器的特性。

特定体系结构规则

每个支持的体系结构都有自己的一组重写规则,将通用操作映射到高效的特定于体系结构的指令。例如:

  • RISCV64:将位计数操作映射到专用指令,如 CLZ(计算前导零)
  • PPC64:使用 CNTLZD 等操作进行前导零计数
  • LOONG64:使用 CLZVCTZV 等指令优化位操作

来源

示例:优化位操作

不同的体系结构以各种方式优化位操作

操作RISCV64PPC64LOONG64AMD64
LeadingZeros64CLZCNTLZDCLZVLZCNTQ/BSRQ
TrailingZeros64CTZ-CTZVTZCNTQ
BitLen64---基于前导零
PopCount64-POPCNTDVPCNT64POPCNTQ

来源

分支消除和控制流优化

SSA 包中的一项关键优化是分支消除,它会移除不必要的条件分支并简化控制流。

证明分支条件

证明框架分析分支条件,以确定它们是始终为真、始终为假还是依赖于运行时值。当一个条件被证明是常量时,该分支就可以被简化或消除。

  • 如果条件始终为真:用其“then”路径替换分支
  • 如果条件始终为假:用其“else”路径替换分支

例如,在以下代码中:

x < 10 时,内部条件 x < 20 始终为真,因此可以消除内部 if 语句。

来源

边界检查消除

证明框架的一个重要应用是边界检查消除。Go 通常会为数组和切片访问包含运行时边界检查,但当编译器可以证明它们永远不会失败时,这些检查可以被消除。

编译器可以在以下几种情况下证明边界是安全的:

  1. 对同一个数组使用同一个索引进行多次访问
  2. 在循环变量受约束的循环内的访问
  3. 索引可证明在范围内的访问

来源

SSA 优化流水线

优化在编译过程中的几个阶段进行。

来源

延伸阅读

为了更好地理解这些优化如何与更广泛的编译器集成,请参阅:

  • SSA 表示 3.2
  • 函数内联 3.3.1
  • 后端和代码生成 3.4

来源

  • 本文档中分析的所有文件