【问题标题】:GCC sometimes doesn't inline std::array::operator[]GCC 有时不会内联 std::array::operator[]
【发布时间】:2017-02-16 02:08:02
【问题描述】:

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

我发现带有 -O2 或 -O3 的 GCC 6.1 不会内联这些调用,导致这些 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 告诉我为什么它不内联这些单指令调用,和/或使其内联?显然不能修改&lt;array&gt;头文件添加__attribute__((inline))。

【问题讨论】:

  • 提交一个针对 GCC 的错误?
  • @Brian:我不确定这是一个错误...我希望 GCC 中的一些启发式方法会使其认为这段代码实际上出于某种原因更好。这里的问题是如何让 GCC 告诉我它在想什么,和/或改变它。
  • 但是如果您提交了一个错误,那么您可以让 GCC 开发人员向您解释它。 ;-)
  • 有各种标志可以转储东西,见gcc.gnu.org/onlinedocs/gcc-6.3.0/gcc/Developer-Options.html

标签: c++ c++11 gcc optimization inline


【解决方案1】:

GCC 5 和 6 的优化器中似乎存在一个错误,当将__attribute__(("unroll-loops")) 与-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 编译,它可以按预期工作。

【讨论】:

  • 您是否使用任何 dump 标志(如@T.C 所建议的那样)来查看 GCC 的想法以及为什么它不内联调用?
  • @Nawaz:不。我意识到问题只发生在 {GCC 5/6, fast-math, unroll-loops} 的组合中,然后我才了解这些转储标志。跨度>
猜你喜欢
  • 2023-04-01
  • 2015-10-19
  • 2016-03-15
  • 2015-01-22
  • 2013-02-18
  • 2015-09-09
相关资源
最近更新 更多