【发布时间】:2015-05-14 04:28:43
【问题描述】:
我对优化器及其工作方式感兴趣,尤其是在寄存器分配方面。我在编写高级解释器方面有一定的背景,这些解释器不会费心生成高效的机器代码,因此与解析、构造 AST 等相关的编译器构造部分对我来说相当简单。
作为一个学习项目,我一直在尝试一个玩具编译器,它只比机器级稍高一点,主要区别在于它使用变量而不是寄存器。
我非常困惑的是低级优化器部分,特别是关于来自 IR 的寄存器分配以及分支/跳转如何影响它,即使是最基本的启发式算法,但不包括 SSA 和phi 节点。
基本示例:
a = ...
b = ...
c = ...
d = ...
e = ...
f = ...
g = ...
jump_if x == 1, section1
jump_if x == 2, section2
jump_if x == 3, section3
etc
a = a + b - c * 2
jump end
section1:
; all kinds of stuff happens here with some of the above variables
jump end
section2:
; all kinds of stuff happens here with some of the above variables
jump end
section3:
; all kinds of stuff happens here with some of the above variables
jump section1 ; tricky branch!!!
end:
也许我们可以加入循环逻辑和各种其他分支,使这个例子更加复杂。
我不明白的是,如果我们将所有这些分支路径放在一起而不是单独考虑每条路径,那么所有这些分支路径都可能使上述所有变量都“有效”。
对我来说似乎缺少某种基于堆栈的块结构,以便我们可以拥有嵌套块,其中寄存器分配可以考虑最内层块及其外部块引用的变量,并分别执行该寄存器分配启发式在每个块/分支路径上。
在更基于块的高级 IR 中,推断分支路径似乎要容易得多,因为分支将被限制在块内,但是低级 IR 只是稍微抽象在机器级别之上有完全不受约束的分支,你可以在整个地方跳转/分支?
我见过的大多数 IR 示例都是相当低级的机器代码抽象,因此它们似乎经常让我们对如何进行分支(例如:跳转表)变得非常混乱很难推断出这样的块/部分/路径。
人们通常如何处理这个问题?考虑到允许如此灵活的分支/跳转的低级代码,是否有一种算法和干净的组织/代码设计可以分解所有可能的分支路径?
【问题讨论】:
标签: compiler-construction compiler-theory