在编译器的中间阶段进行代码优化的目的是什么?

时间:2015-10-17 07:58:29

标签: optimization compiler-construction compiler-optimization intermediate-code

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

  1. 它们增强了编译器对目标处理器的可移植性
  2. 程序分析在中间代码上比在机器代码上更准确
  3. 来自数据流分析的信息不能用于优化
  4. 来自前端的信息不能用于优化
  5. IMO:中间代码是与机器无关的代码。因此,中间代码可用于代码优化,因为给定的源代码可以转换为目标机器代码。因此,选项(1),但某处解释选项(2)也是如此。

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

1 个答案:

答案 0 :(得分:1)

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

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

  1. 文字表示(这是您编写的代码)。
  2. 解析器生成的concrete syntax tree
  3. 语法分析器生成的abstract syntax tree
  4. IR代码生成器生成的中间表示(IR)。这将是前端执行的最后一次操作。
  5. 由二进制代码生成器生成的二进制表示(由目标ISA指定)。
  6. 现在让我们看看哪种表示最适合执行优化。使用前三个表示中的任何一个将导致编译器极其缓慢,因为几乎任何优化都需要广泛地分析和修改输入表示。我说几乎是因为前端执行的优化很少(通常在AST上)。一个常见的例子是恒定折叠。在此级别执行此类优化的原因是它们所做的所有修改都是本地的(在表达式中)。因此,他们很便宜。此外,它们使生成的IR代码更清晰,更适合further analysis。另一方面,AST非常适合执行语义分析,因此编译器可以尽快发现任何错误,并在发现任何错误时中止进一步处理。

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

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

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

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

    我想谈谈可移植性。 IL使我们能够为多种源语言使用相同的后端。然而,即使我们确信只支持一种语言,IL仍然非常重要,正如我刚刚解释的那样。此外,极少数非常重要的优化依赖于目标ISA。有许多优化可以将代码从IR转换为IR。这些显然是与目标无关的。这些优化确实是可移植的,可以在不同目标体系结构的后端之间共享。