3

对中间代码进行了一些代码优化,因为

  1. 它们增强了编译器对目标处理器的可移植性
  2. 中间代码的程序分析比机器代码更准确
  3. 来自数据流分析的信息不能用于优化
  4. 来自前端的信息不能用于优化

IMO:中间代码是与机器无关的代码。因此,中间代码可用于代码优化,因为可以将给定的源代码转换为目标机器代码。因此,选项 (1) ,但在某处解释选项 (2) 也是正确的。


代码优化的目的是什么,它在编译器的中间阶段有什么好处?

4

1 回答 1

2

编译器优化可移植性并不是对中间代码执行许多优化的原因。然而,这是我们免费获得的一个优势。您所说的其他三点含糊不清。无论如何,我们不必讨论它们。

要回答您的问题,我必须通过典型的Ahead-Of-Time (AOT) 编译器的操作(该问题仅适用于此类编译器)。在编译期间,编译器通常处理源代码的五种表示形式:

  1. 文本表示(这是您编写的代码)。
  2. 解析器生成的具体语法树
  3. 语法分析器生成的抽象语法树。
  4. IR 代码生成器生成的中间表示 (IR)。这将是前端执行的最后一个操作。
  5. 二进制代码生成器生成的二进制表示(由目标 ISA 指定)。

现在让我们看看哪种表示最适合执行优化。使用前三种表示中的任何一种都会导致编译器速度极慢,因为几乎所有优化都需要广泛分析和修改输入表示。我说几乎是因为前端执行的优化很少(通常在 AST 上)。一个常见的例子是常量折叠。在此级别执行此类优化的原因是它们所做的所有修改都是本地的(在表达式内)。因此,它们很便宜。它们还使生成的 IR 代码更清晰,更适合进一步分析. 另一方面,AST 非常适合执行语义分析,以便编译器可以尽快发现任何错误并在发现任何错误时中止进一步处理。

大多数编译器优化接受 IR 代码作为输入并产生(希望优化的)IR 代码作为输出(嗯,一些编译器可能会逐渐降低 IR,直到一种优化发出二进制代码)。中间语言是专门为应用优化而设计的。首先,它有一个顺序表示(类似于二进制代码)可以很容易地修改。其次,IR 保留了 AST 中可用的大部分信息。这包括全局、局部和临时变量定义和类型。这种表现力使编译器能够更有效地优化代码。第三,它是低级的,因此它的指令是原始的,只有一个或几个连续的 IL 指令被映射到几个目标 ISA 指令。这有助于代码生成器快速实现其目的。

对二进制代码执行的优化很少。这些包括第一遍或第二遍指令调度和第二遍寄存器分配。

在所有这些之后,链接器(如果需要)开始其工作,其中可能包括一些其他优化。

请注意,大多数编译器优化也可以在二进制代码上执行(尽管没有那么有效)。这种类型的优化称为动态二进制优化,它们用于动态二进制翻译和检测。

关于便携性,我想说几句。IL 使我们能够为多种源语言使用相同的后端。然而,即使我们确定只支持一种语言,IL 仍然非常重要,正如我刚刚解释的那样。也很少有非常重要的优化依赖于目标 ISA。有许多优化可以将代码从 IR 转换为 IR。这些显然与目标无关。这些优化确实是可移植的,并且可以在不同目标架构的后端之间共享。

于 2015-10-17T22:03:00.343 回答