英特尔C++编译器了解执行的优化

Bo *_*sen 5 c++ compiler-construction optimization intel

我有一个代码段,它很简单:

for( int i = 0; i < n; ++i)
{
  if( data[i] > c && data[i] < r )
  {
    --data[i];
  }
}
Run Code Online (Sandbox Code Playgroud)

它是大型功能和项目的一部分.这实际上是对不同循环的重写,这被证明是耗时的(长循环),但我对两件事感到惊讶:

当data [i]临时存储时,如下所示:

for( int i = 0; i < n; ++i)
{
  const int tmp = data[i];
  if( tmp > c && tmp < r )
  {
    --data[i];
  }
}
Run Code Online (Sandbox Code Playgroud)

它变得更慢.我并不认为这应该更快,但我不明白为什么它应该这么慢,编译器应该能够弄清楚是否应该使用tmp.

但更重要的是,当我将代码段移动到一个单独的函数时,它变得慢了四倍.我想了解发生了什么,所以我查看了opt报告,在这两种情况下,循环都是矢量化的,似乎做了同样的优化.

所以我的问题是什么可以在一个不被称为百万次的函数上产生这样的差异,但它本身是耗时的?在opt报告中要查找什么?

我可以通过保持内联来避免它,但是为什么要烦我.

更新:

我应该强调,我的主要关注点是要理解,为什么它变得更慢,当移动到一个单独的功能.使用tmp变量给出的代码示例只是我在此过程中遇到的一个奇怪示例.

Pup*_*ppy 4

您可能缺乏寄存器,编译器必须加载和存储。我非常确定本机 x86 汇编指令可以使用内存地址进行操作,即编译器可以保持这些寄存器空闲。但通过将其本地化,您可以改变行为。别名和编译器可能无法证明更快的版本具有相同的语义,特别是如果这里存在某种形式的多线程,允许它更改代码。

该函数在新段中速度较慢,可能是因为函数调用不仅会破坏管道,还会导致指令缓存性能较差(参数推送/弹出等有额外的代码)。

教训:让编译器来做优化,它比你聪明。我并不是说这是一种侮辱,它也比我聪明。但实际上,尤其是英特尔编译器,这些人知道他们在针对自己的平台时在做什么。

编辑:更重要的是,您需要认识到编译器的目标是优化未优化的代码。它们的目的不是识别半优化的代码。具体来说,编译器将为每个优化设置一组触发器,如果​​您碰巧以不触发它们的方式编写代码,则即使代码在语义上相同,也可以避免执行优化。

而且您还需要考虑实施成本。并非每个适合内联的函数都可以内联 - 只是因为内联该逻辑对于编译器来说太复杂而无法处理。我知道 VC++ 很少会内联循环,即使内联会带来好处。您可能会在英特尔编译器中看到这一点 - 编译器编写者只是认为不值得花时间来实现。

我在处理 VC++ 中的循环时遇到了这种情况 - 编译器会以稍微不同的格式为两个循环生成不同的程序集,即使它们都实现了相同的结果。当然,他们的标准库使用了理想的格式。您可以std::for_each通过使用和 函数对象观察到加速。