C++ GCC有时不';t内联std::array::operator[]

C++ GCC有时不';t内联std::array::operator[],c++,c++11,gcc,optimization,inline,C++,C++11,Gcc,Optimization,Inline,我有一个复杂的程序,它使用std::array处理小的N值。它使用操作符[]从这些数组中获取值 P>我发现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: c

我有一个复杂的程序,它使用
std::array
处理小的N值。它使用
操作符[]
从这些数组中获取值

<> P>我发现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 
340:
340:48 8d 04 f7 lea(%rdi,%rsi,8),%rax
344:c3 retq
345:90不
346:66 2e 0f 1f 84 00 nopw%cs:0x0(%rax,%rax,1)
34d: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
4c0:e8 7b fe ff ff callq 340
4c5:be 07 00 mov$0x7,%esi
4ca:4c 89 f7移动百分比r14,%rdi
4cd:48 89 44 24 78 mov%rax,0x78(%rsp)
…再复制6份。。。
4d2:e8 69 fe ff ff callq 340
4d7:4889442470MOV%rax,0x70(%rsp)
4dc:31 f6 xor%esi,%esi
4de:4c 89 ef mov%r13,%rdi
这显然很糟糕。问题是小型测试程序不会引发这种行为


所以我的问题是:我如何让GCC告诉我为什么它不内联这些单指令调用,和/或让它内联它们?显然,我无法修改
头文件以添加
\uuuuu属性((内联))

GCC 5和6的优化器中似乎存在一个缺陷,当将
\uu属性((“展开循环”)
-ffast math
或相关选项结合使用时会出现该缺陷

你可以在这里看到它的作用:

如果使用
-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;
}
#包括
typedef std::数组;
void foo(数组和a)uuuuuuu属性(优化(“展开循环”));
void foo(数组和a)
{
对于(尺寸ii=0;ii

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

针对GCC提交一个bug?@Brian:我不确定这是一个bug……我希望GCC中的一些启发会让它认为出于某种原因,这段代码实际上更好。这里的问题是我如何让GCC告诉我它在想什么,和/或改变它。但是如果你提交了一个bug,那么你可以让GCC开发人员向你解释。;-)有各种各样的标志来转储东西,看你是否使用了任何转储标志(正如@T.C所建议的)来查看GCC在想什么以及为什么它没有内联调用?@Nawaz:没有。在我理解这些转储标志之前,我意识到问题只会出现在{GCC 5/6,快速数学,展开循环}的组合中。