3

我一直在对这个主题进行一些研究,但没有找到好的具体答案。假设您的代码中有这些表达式:

B = 2
…
B = B + 5
…
B = J + B
…

(这些都是非常简单的例子,我知道它们不现实)

B在这些行中有许多不同的值。在第一行它是2,后来它变成了7,然后更多的是它7 + J。编译器需要跟踪这些不同的值B,因此一种方法是重命名它们。例如,当B被重新定义为B = B+5时,可以更改为B1 = B+5。最后的重新定义看起来像B2 = J+B1.

这个想法背后的动机涉及我正在构建的优化程序。它涉及用它们相关的表达式替换变量。然而,如果一个变量被重新定义,那么字符“B”可以同时表示多个事物。我用来跟踪事物的方法就是我上面描述的,重新定义变量名。

这就是编译器的工作方式吗?有这个名字吗?

在重新定义变量的情况下,我试图尽可能多地了解编译器重新定义变量的过程。

如果有帮助,我相信这将在编译的预处理阶段完成,并且我相信这与宏扩展类似。

编辑:我为这个问题添加了更多背景信息。

4

2 回答 2

3

您所描述的内容已正式化为静态单一分配 (SSA) 表格。它比“在赋值时重命名变量”更具侵入性,因为您还必须知道在面对控制流时要读取的“当前”变量,例如,如果您重写以下代码:

if (a) x = 0;
else x = 1;
print(x);

对此,您必须插入一个所谓的 phi 节点以在以下位置选择正确的值print

if (a) x0 = 0;
else x1 = 1;
print(<which x?>)

通常,IR 具有内置的 SSA,因此代码在转换为 IR 时(或此后不久)转换为 SSA。宏扩展在此之前很久就发生了,通常在令牌流或 AST 上,具体取决于宏的强大程度。

但是请注意,这绝不是强制性的。它对某些优化很有用,但不是必需的(有些优化根本没有好处)。您可以使用可变变量执行相同的优化(并且许多具有 SSA 的编译器 IR 至少将堆保留为非 SSA),它只是不太方便并且可能更昂贵。例如,在传播常量时,您必须确保在常量和您要替换的用途之间没有任何其他分配,但您可以在没有 SSA 的情况下很容易地检查这一点。

于 2013-07-31T21:24:27.843 回答
3

您的预感是正确的,许多现代编译器使用流分析来重命名变量,以便每个变量都是唯一的。生成的形式称为“单一静态分配”或简称 SSA。

输入:

B = 2
B = B + 5
B = J + B

输出:

B1 = 2
B2 = B1 + 5
B3 = J + B2

还有其他部分用于处理分支和循环,例如:

输入:

if X < 5
    B = Y + Z
else
    B = 2
B = B + 1

输出:

if X < 5:
    B1 = Y + Z
else
    B2 = 2
B3 = phi(B1, B2)
B4 = B3 + 1

“phi”函数选择其输入中的任何一个是实时的。

这不是在预处理期间完成的,它是在代码编译到一些 IR 之后完成的,通常由基本块组成。它与宏扩展不同。

于 2013-07-31T21:18:21.477 回答