【问题标题】:Compiler Optimizations Questions编译器优化问题
【发布时间】:2009-05-06 00:07:44
【问题描述】:
  1. 编译器有哪些方法可以消除重复的子表达式重新计算?你如何跟踪子表达式?以及如何识别重复的?
  2. 除了位运算符的使用之外,常见的编译器还使用了哪些强度降低技术?

【问题讨论】:

  • 你应该把这个问题分成两部分,并修正标题。 (我还没有这个权力)。

标签: optimization compiler-construction compiler-development


【解决方案1】:

对于 1,您正在寻找的优化名称是公共子表达式消除 (CSE)。根据您的代表,这可能相当容易。通常,编译器将有一些程序的中间表示,其中操作被尽可能地分解和线性化。例如,表达式c = a * b + a * b 可以分解为:

v1 = a * b
v2 = a * b
c = v1 + v2

因此,您可以通过查找具有相同运算符和操作数的操作来在非常低的级别执行 CSE。当您遇到重复(在这种情况下为 v2)时,您将其所有实例替换为原始实例。所以我们可以将上面的代码简化为:

v1 = a * b
c = v1 + v1

这通常假设您只为每个变量分配一次(单个静态分配形式),但您可以在没有限制的情况下实现类似的东西。当您尝试跨分支执行此优化时,这会变得更加复杂。正如 Zifre 提到的,研究部分冗余消除。

无论哪种方式,您都会得到一些基本的改进,而您需要跟踪的只是基本的表达方式。您可能想更进一步,寻找算术恒等式。例如,a * bb * a 相同。另外,x * (y + z) = x * y + x * z。这会使您的优化变得更加复杂,并且不清楚它是否会给您带来那么多的性能改进。有趣的是,CSE 优化的大部分好处来自地址计算,如数组访问,您不需要像上面那样复杂的身份。

对于 2,什么强度降低有用实际上取决于您编译的架构。通常这只涉及将乘法和除法转换为移位、加法和减法。

【讨论】:

  • 如果重复的不在同一个表达式中怎么办?例如 x= a * b 和 y = a* b。有没有办法可以检测到重复的 a*b?
  • 这是一个重复。在这种情况下,您将 y 的所有未来使用都替换为 x。
【解决方案2】:

我强烈推荐两本关于这些主题的印刷参考资料:

  1. Advanced Compiler Design & Implementation Steven S. Muchnick
  2. Building an Optimizing Compiler 罗伯特·摩根

Muchnick 的书是正式的,但可读性很强,并且对所有重要的优化技术都有很好的描述。 Morgan 的书具有更多的动手能力,对于专注于优化技术的编译器项目来说,这将是一个很好的基础。这两本书都没有太多关于词法分析或解析的内容,假设您了解这些主题。

【讨论】:

    【解决方案3】:
    1. 相信很多编译器都使用 SSAPRE(静态单一赋值部分冗余消除)来消除重复表达式。这要求代码在SSA form 中,允许进行更多优化。

    2. 我不太确定这个,但是看看this list of LLVM passesLLVM 是针对编译器的优化 IR,它通常比 GCC 还要快。每一关都有一个小的解释。如果您需要更多信息,请查看这些通行证的 LLVM 源代码。它是用 C++ 编写的,但非常简洁易懂。

    编辑:顺便说一句,如果你正在开发编译器,我强烈推荐 LLVM,它非常易于使用并且可以生成高度优化的代码。

    【讨论】:

    • 哇,谢谢。这些链接真的很有帮助。
    • 完全同意 LLVM。我们在我的研究小组中使用它。太棒了。
    • 不推荐 SSAPRE。它需要 HSSA,而您的编译器几乎肯定不会提供。
    【解决方案4】:

    要在推荐列表中再添加一本书,请查看 Henry S. Warren 的 "Hacker's Delight"。这是优化常见运算(例如将整数除法转换为乘法)的技术概要。

    【讨论】:

      【解决方案5】:

      您正在寻找部分冗余消除 (PRE)。 CSE(来自其他答案)和循环不变代码运动都包含在 PRE 中。 (PRE 的一个变体是 Lazy Code Motion,我认为这是最佳的)。

      查看Keith Cooper's lecture notes,它似乎很好地描述了这些技术。

      使用 SSAPRE。 AFAIK,这需要一种特殊形式的 SSA,称为 HSSA,它有一些缺点:

      • 相当复杂
      • 它需要全局值编号(因此 SSAPRE 不提供值编号,因为它预计已经存在)。
      • 如果您的语言不支持指向堆栈变量的指针,则它不会提供任何内容(如果支持,请停止编写您自己的分析并使用 LLVM 或 gcc)。
      • gcc 使用了 HSSA 一段时间,但他们已经远离它。
      • LLVM 对其进行了试验,但 AFAIK 他们不再使用它。

      编辑:

      Muchnick 的书有详细描述,链接在另一个答案中。

      【讨论】:

      • 你知道为什么 GCC 离开了 HSSA,以及为什么 LLVM 决定不使用它吗?当前版本的 GCC (7.0) 用 VDEFVUSE 标记变量,这在我看来类似于 HSSA。你知道它们是否相关吗?
      • 对不起,很久没参与了。我真的不记得这件事了:(
      猜你喜欢
      • 2010-09-30
      • 1970-01-01
      • 2011-11-07
      • 2014-02-21
      • 2011-08-24
      • 2012-02-12
      • 2011-12-29
      相关资源
      最近更新 更多