简体   繁体   English

编译器优化问题

[英]Compiler Optimizations Questions

  1. What are some of the ways a compiler eliminates repeated subexpressions recomputations? 编译器消除重复的子表达式重新计算的一些方法是什么? How do you keep track of the sub-expressions? 你如何跟踪子表达式? And How do you identify the repeated ones? 你如何识别重复的?
  2. Besides the usage of bitwise operators, what are some of the strength reduction techniques common compilers use? 除了使用按位运算符之外,常见编译器还使用了哪些强度降低技术?

For 1, The name of the optimization you're looking for is common subexpression elimination (CSE). 对于1,您正在寻找的优化名称是常见的子表达式消除(CSE)。 Depending on your representation, this can be fairly easy. 根据您的表示,这可能相当容易。 Usually, a compiler will have some intermediate representation of a program where operations are broken down as much as possible and linearized. 通常,编译器将具有程序的一些中间表示,其中操作尽可能地被分解并且线性化。 So for example, the expression c = a * b + a * b might be broken down as: 因此,例如,表达式c = a * b + a * b可能会被细分为:

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

So you could do CSE at a very low level by looking for operations with the same operator and operands. 因此,您可以通过查找具有相同运算符和操作数的操作来以非常低的级别执行CSE。 When you encounter a duplicate (v2 in this case), you replace all instances of it with the original. 遇到重复项(在本例中为v2)时,将其所有实例替换为原始实例。 So we could simplify the code above to be: 所以我们可以简化上面的代码:

v1 = a * b
c = v1 + v1

This generally assumes that you only assign each variable once (single static assignment form), but you can implement something like this without that restriction. 这通常假设您只分配一次变量(单个静态赋值形式),但您可以在没有该限制的情况下实现这样的操作。 This gets more complicated when you try and perform this optimization across branches. 当您尝试跨分支执行此优化时,这会变得更加复杂。 As Zifre mentions, look into Partial Redundancy Elimination. 正如Zifre所提到的那样,请考虑部分冗余消除。

Either way, you get some basic improvement, and all you need to keep track of are basic expressions. 无论哪种方式,您都会得到一些基本的改进,而您需要跟踪的只是基本表达式。 You may want to take this a step further and look for arithmetic identities. 您可能希望更进一步,寻找算术身份。 For instance, a * b is the same as b * a . 例如, a * bb * a相同。 Also, x * (y + z) = x * y + x * z . 此外, x * (y + z) = x * y + x * z This makes your optimization more complicated, and it's not clear that it would give you that much performance improvement. 这使得您的优化变得更加复杂,并且不太清楚它会给您带来如此多的性能提升。 Anecdotally, most of the benefit from a CSE optimization comes from address computations like array accesses, and you won't need complicated identities like the ones above. 有趣的是,CSE优化的大部分好处来自于数组访问等地址计算,您不需要像上面那样复杂的身份。

For 2, what strength reductions are useful really depends on the architecture you compile for. 对于2,有用的强度降低实际上取决于您编译的体系结构。 Usually this just involves transforming multiplications and divisions into shifts, additions, and subtractions. 通常这只涉及将乘法和除法转换为移位,加法和减法。

I would highly recommend two printed references on these subjects: 我强烈推荐这些主题的两个印刷参考:

  1. Advanced Compiler Design & Implementation by Steven S. Muchnick Steven S. Muchnick的高级编译器设计与实现
  2. Building an Optimizing Compiler by Robert Morgan 构建 Robert Morgan 的优化编译器

The Muchnick book is on the formal side but is very readable and has good descriptions of all of the important optimization techniques. Muchnick的书是正式的,但是非常易读,并且对所有重要的优化技术都有很好的描述。 The Morgan book has a much more hands-on feel and would be a great basis for a compiler project focused on optimization techniques. 摩根书籍具有更多动手实践的感觉,并且将成为专注于优化技术的编译器项目的重要基础。 Neither book has much to say about lexical analysis or parsing, knowledge of these subjects is assumed. 这两本书都没有太多关于词汇分析或解析的说法,因此假定这些科目的知识。

  1. I believe many compilers use SSAPRE (Static Single Assignment Partial Redundancy Elimination) to eliminate repeated expressions. 我相信很多编译器都使用SSAPRE(静态单一赋值部分冗余消除)来消除重复的表达式。 This requires the code to be in SSA form , allowing many more optimizations. 这要求代码采用SSA形式 ,允许更多优化。

  2. I'm not really sure about this one, but look at this list of LLVM passes . 我不太确定这个,但看看这个LLVM通行证列表 LLVM is an optimizing IR for compilers that is often faster than even GCC. LLVM是编译器的优化IR,通常比GCC更快。 There is a small explanation of each pass. 每个传球都有一个小的解释。 If you need more info, look at the LLVM source for these passes. 如果您需要更多信息,请查看这些传递的LLVM源。 It is written in C++ but is quite clean and understandable. 它是用C ++编写的,但非常干净且易于理解。

Edit: By the way, if you're developing a compiler, I highly recommend LLVM, it is very easy to use and generates highly optimized code. 编辑:顺便说一句,如果您正在开发编译器,我强烈推荐LLVM,它非常易于使用并生成高度优化的代码。

To add one more book to the list of recommendations, check out "Hacker's Delight" by Henry S. Warren. 要在建议列表中再添一本书,请查看Henry S. Warren撰写的“Hacker's Delight” It's a great compendium of techniques for optimizing common operations, like transforming integer divisions into multiplications. 这是优化常见操作的技术概要,例如将整数除法转换为乘法。

You're looking for partial-redundancy elimination (PRE). 您正在寻找部分冗余消除(PRE)。 Both CSE (from the other answers) and loop-invariant code motion are subsumed by PRE. CSE(来自其他答案)和循环不变的代码运动都包含在PRE中。 (A variation of PRE is Lazy Code Motion, which I believe is optimal). (PRE的变体是Lazy Code Motion,我认为这是最佳的)。

Check out Keith Cooper's lecture notes , which seem to describe the techniques very well. 查看Keith Cooper的讲义 ,这些讲稿似乎很好地描述了这些技巧。

Do NOT use SSAPRE. 不要使用SSAPRE。 AFAIK, this requires a particular form of SSA known as HSSA, which has a few downsides: AFAIK,这需要一种特殊形式的SSA,称为HSSA,它有一些缺点:

  • Its pretty complicated 它非常复杂
  • It requires global value numbering (and so SSAPRE doesn't provide value numbering, as its expected to exist already). 它需要全局值编号(因此SSAPRE不提供值编号,因为它预期已经存在)。
  • It doesn't provide anything if your language doesn't support pointers to stack variables (and if it does, stop writing your own analysis and use LLVM or gcc). 如果您的语言不支持指向堆栈变量的指针(如果它支持,则停止编写您自己的分析并使用LLVM或gcc),它不会提供任何内容。
  • gcc used HSSA for a while, but they have moved away from it. gcc使用HSSA一段时间了,但他们已经离开了它。
  • LLVM experimented with it, but AFAIK they don't use it anymore. LLVM对它进行了实验,但是AFAIK他们不再使用它了。

EDIT: 编辑:

Muchnick's book has a detailed description, its linked in another answer. Muchnick的书有一个详细的描述,它的另一个答案相关联。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM