跳转至

指令选择

本文简要介绍了指令选择问题中的两种主要方法:

  1. 使用贪心策略的 Maximal Munch 算法,通过选择最大图块覆盖 IR 树节点,快速生成指令。
  2. 基于动态规划的算法,自下而上地计算最优代价,获得更精确的整体最优解。

通过对比这两种方法,可以在编译过程中更好地进行目标代码生成。

(摘要由 OpenAI o1-preview 生成)

基于模式匹配的指令选择

基于树的模式匹配

中间表示树上的一个部分作为一个单元,对应可供选择的某条汇编指令。

将指令选择问题转变为图的覆盖问题(选择代价最小的覆盖)

Optimum Tiling vs Optimal Tiling

Optimum Tiling: 全局最优,整体代价最低。

Optimal Tiling: 局部最优,每个片段最优但整体不一定最优。

指令选择的算法

Maximal Munch 算法

Maximal Munch 算法:找到 Optimal Tiling。这是一个贪心算法,认为选择越大的 Tile 导致的代价越小。

Tile 的「大小」 := Tile 包含的节点数。

在 Maximal Munch 算法中,遇到相同大小的 Tile 将会任意选择其中之一。

从 IR 树的根节点开始,每次选择能够覆盖当前节点的最大图块,这将把原先的 IR 树分割为若干子树。

对每个被分割出的子树,重复相同的算法。

在完成 Tile 的放置后,以相反的顺序生成指令(从叶节点向根节点生成)。

基于动态规划的算法

动态规划:找到 Optimum Tiling。

自下而上地计算每个节点的最小成本。对于每个节点,首先计算其子节点的最小总成本 Tiling。每个节点的成本 := 所选 Tile 的成本 + 产生的子树的成本。

对于节点 \(x\),定义 \(f(x)\) 为以 \(x\) 为根节点的树的 Optimal Tiling 的总成本,\(f(x)\) 以下面的公式计算:

\[ f(x) = \min_{\forall T\text{ covering }x}\left( \text{cots}(T) + \sum_{\forall \text{ child }y\text{ of tile }T}f(y) \right) \]

当整棵 IR 树的根节点的最小代价被找到,根据 IR 树的所有结点的代价状态,可以确定指令的选择(这个过程被称为 instruction emission ),方法为:

Emission(node n):对于 n 选择的 Tile 产生的每一个子树的根节点 li,执行 Emission(li),然后发射节点 n 选择的 Tile 对应的指令。