4

如果我们让人类参与其中,编译器能否做的不仅仅是严格的语义等价优化?

编译器会直接忽略一些潜在的优化,因为它们在语义上可能不等效。

但是,它们也可能没问题,那么为什么不尝试检测并建议它们呢?检测可能涉及两个阶段的过程:编译时分析阶段和运行时分析阶段。

错误、警告和... 建议?

编译器已经对“警告”做了类似的事情,因为它们在每次编译期间都被汇集在一起​​,并且永远坐在列表中,直到您将它们解决给编译器满意为止。为什么没有“建议”或“建议的优化”部分以类似的方式运行,并有可能提高您的应用程序的性能?

如果编译器要分析布尔表达式的复杂性、估计的运行时间、单个操作数是真还是假的可能性等,那么它可以创建一个建议列表,例如表达式操作数的更好顺序,并呈现建议作为程序员的清单。然后,程序员可以单独处理它们,并决定忽略它们,或者让代码编辑器实现建议。

优化布尔表达式操作数顺序

考虑“短路逻辑表达式的优化”。因为操作数的顺序会影响哪个操作数可能被“短路”(即未调用),所以简单布尔表达式(即 A && B && C)中的操作数顺序是(我认为)编译器不会改变的东西如果任何操作数有副作用,则避免引入未知的副作用。

考虑一下:

char c = reader.ReadChar(); //Stream bs; const string NEWLINE;
while (!IsStringPresent( c, bs, NEWLINE ) && c != ',')

由于比较一个字符是(更快/不太复杂),它应该放在表达式的第一位,这样短路逻辑可以避免在遇到逗号时调用 IsStringPresent。同样,在这种情况下,逗号(每行很多)会比换行序列更频繁地出现。

char c = reader.ReadChar(); //Stream bs; const string NEWLINE;
if (c != ',' && !IsStringPresent( c, bs, NEWLINE )) //faster for short-circuit; plus ',' is encountered more often than newline

概括

客观地,可以根据“A 与 B 的错误触发短路的频率”和“计算 A 与 B 的成本,有利于更多昂贵的”。如果编译器可以在编译时、运行时或两者中确定其中任何一个的近似值,那么它可以确定一个特定的表达式可能是次优的,并且它可以为程序员创建一个建议的更改来实现.

今天有没有编译器做这样的事情?如果不是,为什么?

4

3 回答 3

0

我的观点是,仅仅因为程序员认为没问题就允许优化器使函数调用短路,这是导致无法追踪的错误的秘诀。它会在每次编译期间询问吗?我不知道; 听起来像这样的事情会有很多问题。

于 2011-12-01T20:23:44.143 回答
0

我的回答是“可能”,但“这是我们真正想做的吗?”

也许你建议编译器检测到一个可能的同构,它不确定它是否是同构,所以它会询问程序员“这是一个同构吗”,但无论如何“如果是这样,如果我应用它,它会导致更快的代码,你觉得呢?”

然而,我的想法更像是这样的:“嘿,程序员,如果我们能做到这一点,我们会得到更快的代码,但是,语义不同!我们必须加强这个函数的前置条件来做这个优化。 那样行吗?”

加强前置条件可能没问题,哎呀,程序员可能甚至没有写前置条件。如果程序员说“当然,没关系”而程序员错了,那么运气好的话,测试就会发现“前提条件失败”的问题。

于 2011-12-17T10:23:11.503 回答
0

您要问的主要是程序员的任务。在某种程度上,有像静态分析工具或重构工具这样的工具可以扩展来完成你想要的。

编译器的任务是在规则范围内发挥标准(尽可能)。对于某些(积极的)优化,编译器确实提供了特定的标志,可以通过这些标志来启用/禁用它们,例如矢量化、内联、过程间等——这些优化很难手动完成。

重新排序(在您提到的示例中)受到 C、C++ 标准的限制,因为它们可能会改变程序的语义。在操作没有副作用的情况下,可以对它们进行重新排序,并且编译器在指令调度期间执行此类操作(在 clang++ 和 g++ 中的 -O2 处),但我不确定有多少其他编译器这样做。

于 2013-05-02T21:54:49.470 回答