有时GCC无法内联std::array::operator[]。

5

我有一个复杂的程序,其中对于很小的N值使用std :: array <double,N>。 它使用operator []从这些数组中获取值。

我发现GCC 6.1与 -O2 -O3 一起使用时不会内联这些调用,导致这些C ++数组比它们的C等效数组慢。

以下是生成的汇编代码:

340 <std::array<double, 8ul>::operator[](unsigned long) const>:

340:  48 8d 04 f7             lea    (%rdi,%rsi,8),%rax
344:  c3                      retq   
345:  90                      nop
346:  66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
34d:  00 00 00 

对于每个数组大小,都会发出完全相同的代码(因为没有边界检查)。

对这样一个数组的循环如下所示:

4c0:  e8 7b fe ff ff          callq  340 <std::array<double, 8ul>::operator[](unsigned long) const>
4c5:  be 07 00 00 00          mov    $0x7,%esi
4ca:  4c 89 f7                mov    %r14,%rdi
4cd:  48 89 44 24 78          mov    %rax,0x78(%rsp)

...6 more copies of this...

4d2:  e8 69 fe ff ff          callq  340 <std::array<double, 8ul>::operator[](unsigned long) const>
4d7:  48 89 44 24 70          mov    %rax,0x70(%rsp)
4dc:  31 f6                   xor    %esi,%esi
4de:  4c 89 ef                mov    %r13,%rdi

这似乎是明显的不好。问题在于小型测试程序无法引发此行为。

因此,我的问题是:我如何让GCC告诉我为什么它没有内联这些一条指令的调用,并/或使其内联?显然,我不能修改<array>头文件以添加__attribute__((inline))


4
要对GCC提交缺陷报告吗? - Brian Bi
1
@Brian:我不确定这是否是一个错误……我预计GCC中的某些启发式算法会让它认为这段代码实际上更好。问题在于,我该如何让GCC告诉我它在想什么,或者改变它的想法。 - John Zwinck
1
但是如果您提交了一个错误报告,那么您可以让GCC开发人员向您解释它。;-) - Brian Bi
2
有各种标志可以转储东西,请参见https://gcc.gnu.org/onlinedocs/gcc-6.3.0/gcc/Developer-Options.html。 - T.C.
1个回答

2
似乎在GCC 5和6的优化器中存在一个bug,当与-ffast-math或相关选项一起使用时,会出现问题。您可以在此处查看其效果:https://godbolt.org/g/ZBGCDB。如果使用-O3 -ffast-math编译,则此代码会复现错误。
#include <array>

typedef std::array<double, 2> Array;

void foo(Array& a) __attribute__((optimize("unroll-loops")));

void foo(Array& a)
{
  for (size_t ii = 0; ii < a.size(); ++ii)
    a[ii] = 1.0;
}

如果不使用-ffast-math编译,或者使用GCC 4.9、GCC 7或更高版本,或者使用Clang编译,则可以按预期工作。


1
你是否使用了任何 dump 标志(如 @T.C 建议的那样)来查看 GCC 的想法以及为什么它不会内联调用? - Nawaz
@Nawaz:不是的。在我理解这些转储标志之前,我意识到问题只发生在 {GCC 5/6,快速数学,展开循环} 的组合中。 - John Zwinck

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接