指令选择器调查
Posted wuhui_gdnt
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了指令选择器调查相关的知识,希望对你有一定的参考价值。
3.5. 动态规划优化模式选择
在1985年Aho与Ganapathi【6】展示了一个称为CGL的语言,它提供了一个Glanville-Graham风格的记法来描述模式。描述送到一个预处理器,产生一个可以被包括在编译器后端的指令选择器。指令选择器以Aho-Corasick算法为基础进行模式匹配,包含了Aho与Johnson之前使用的动态规划(DP)技术的一个简化版。指令选择器在输入树上执行三个遍:两个自底向上遍——第一个用于标记模式匹配的节点,第二个用于计算最优选择;以及一个流出代码的自顶向下遍。每个遍执行显示出O(n)的时间复杂性,因此在线性时间内产生最优指令选择。
DP算法的概要(不包括模式匹配部分)在图3.11中给出。每个节点维护一个标记及两个向量——costs与matches。在产生式“l ← tree”中非终结符l用作索引,costs[l]给出归纳到l的代价最低的规则,matches[l]给出该规则的索引。在这个上下文里规则与模式持有相同的含义,它们将互换地使用。对于一个给定的节点n,算法遍历n的匹配集中所有的模式。如果相比当前最好的选择,这个模式严格地以一个更低的代价归纳到一个非终结符l,那么更新向量以反映这更好的选择。应用一个模式p的代价就是模式自身的代价加上匹配p的v个节点的模式的代价。因而使用一个辅助函数cost(t, n)来方便这个代价的计算。因为某些规则可能是链式法则——即一个替代符号被重写为另一个——规则被遍历的次序必须是这样:如果某些节点被修改了,之前检查过的规则不需要重新检查。例如,如果在匹配集中产生式“s ← r”与“t ← s”存在两个规则,那么首先应该检查“s ← r”,因为它可能降低“t ← s”所依赖的代价。这个做法被Aho等【7】改进并扩展为一个称为twig的著名的树操作框架(一个早期的参考手册在【224】可以得到)。图3.12中给出了几个以twig表示的加法规则。
这个动态规划设计比起线性化语法解析,有几个好处:
· 归纳冲突被DP算法自动处理,因此消除了之前规则次序对代码质量的影响。
· 不再需要显式地打破规则集中的环,在基于Glanville-Graham的指令选择器中,这会造成无限循环。
· 机器描述更简洁,因为仅在代价上不同的规则可以更容易地重构为单条规则,只带有不同的代价及动作。
结果,这导致了一个更简单、更小的机器描述。例如,Aho等报告VAX机器的整个twig描述仅使用了115个规则。
Twig的几个改进随后由Yates与Schwartz【242】及Emmelmann等【75】做出。Yates与Schwartz把twig的Hoffmann-O’Donnell的模式匹配算法的自顶向下版本,替换为匹配更快并扩展属性支持以允许更强大谓词的自底向上的版本。Emmelmann等实现了一个称为BEG的后端生成器,它包括了伴随IR树构建并行运行的一个DP算法改进版本。另外,BEG把辅助函数代码内联进算法。类似的改进也由Fraser等【98】在实现IBURG时做出,它更简单(950对比3,000行C代码),比twig快25倍。随后Gough与Ledermann【114,115】对IBURG进行少量改进,实现了MBURG,而且IBURG已经被以各种编程语言重新实现(即用于Java的JBURG【222】,及用于C++的OCamlBURG【225】)。
Tjiang【223】[1]把twig与IBURG的思想整合进了OLIVE(这个名字是twig的副产品)。Tjiang也做出了几个额外的改进,比如允许规则使用任意的代价函数。而不是固定的数值。通过返回无限的代价,依赖于当前的上下文,规则可以被动态停止使用,这允许更通用的指令选择。
3.6. 预计算代价
在之前展示的动态规划的做法里,模式匹配算法完全是表驱动的,而用于模式最优选择的代价计算在代码生成时执行。正如我们将看到的,这些运算也可以预先计算并整合进表中。我们将这称为线下代价分析。
直觉是,与使用标记解析输入树以找出所有匹配模式的方式相同,也可以创建状态来解析输入树以找出最优的选择。一个状态不仅代表一棵特定子树的匹配集,还代表最优地把该子树归纳到任意给定非终结符的模式集。这里理解的关键是,这不意味着根节点处的状态携带了这棵树的信息。事实上,这样的尝试要求数量无限的状态。相反,一个状态仅表示在根节点处应该应用哪个规则,使得子树的后续规则选择将共同为整棵树产生一个最优的模式选择。随着继续我们的讨论,这会更加清晰。
从现在开始,假定我们有一组表StateTablei,对于一个特定的操作符i,它给出了下一个状态;以及一张表RuleTable,它给出用于一个给定状态和目标的规则。那么模式匹配与最优模式选择完全可以表驱动,因此避免了在运行时依靠动态规划计算代价。对这样一个指令选择器,图3.13给出了伪代码。
根据文献,Henry【128】[2]首先在他的博士论文里讨论了这个想法,但实际尝试它的先驱是Hatcher与Christopher【124】。这个做法看起来相当不为人知,因为它很少被引用,但从收集到的信息——这是Hoffmann与O’Donnell的自底向上算法的一个扩展——算法工作如下。一开始,强制通过一张额外查找表,增强模式匹配器来处理交换性。在模式匹配遍之后,根据哪些标记被分配给了节点,执行一个选择模式的自顶向下遍。这通过查询另一组表matchsettab——使用当前节点的标记及一个非终结符作为索引——来完成。因此这类似于DP做法里,在代价被计算出来后,如何进行模式的选择。
那么问题是如何计算表matchsettab。首先,因为预处理器构建包含图,它也收集了把模式p转换到另一个被p包含的模式q的代价。这通过递归地使用其他模式改写p直到它等于q。这个代价就是所有被使用模式的代价总和。我们把这个代价以函数reducecost(p q)来表示。现在,计划是选择以最低代价将根节点是给定标记的一棵子树归纳到一个特定的非终结符的规则。Hatcher与Christopher通过首先构建该标记最大的表示树R——这通过重叠匹配集中的所有模式来实现——然后选择使得reducecost(R x) = reducecost(R z.rhs) +z.cost的规则z来着手这个问题 。这将要么选择最大的模式,或者如果存在,一个较小、导致较低代价的模式。不过,如果存在无关的模式,就不能总是保证最优,要求手工调整语法。