强制/说服/欺骗 GCC 展开_更长_循环?

2024-04-19

如何说服 GCC 展开迭代次数已知但很大的循环?

我正在编译-O3.

当然,所讨论的实际代码更复杂,但这里有一个具有相同行为的简化示例:

int const constants[] = { 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144 };

int get_sum_1()
{
    int total = 0;
    for (int i = 0; i < CONSTANT_COUNT; ++i)
    {
        total += constants[i];
    }
    return total;
}

...if CONSTANT_COUNT定义为 8(或更少),那么 GCC 将展开循环,传播常量,并将整个函数简化为一个简单的函数return <value>;。另一方面,如果CONSTANT_COUNT是 9 (或更大),则循环不会展开,并且 GCC 会生成一个二进制文件,该二进制文件会循环、读取常量并在运行时添加它们 - 尽管从理论上讲,该函数仍然可以优化为仅返回持续的。 (是的,我看过反编译的二进制文件。)

If I manually展开循环,如下所示:

int get_sum_2()
{
    int total = 0;
    total += constants[0];
    total += constants[1];
    total += constants[2];
    total += constants[3];
    total += constants[4];
    total += constants[5];
    total += constants[6];
    total += constants[7];
    total += constants[8];
    //total += constants[9];
    return total;
}

Or this:

#define ADD_CONSTANT(z, v, c) total += constants[v];

int get_sum_2()
{
    int total = 0;
    BOOST_PP_REPEAT(CONSTANT_COUNT, ADD_CONSTANT, _)
    return total;
}

...然后该函数被优化为返回一个常量。因此,一旦展开,GCC 似乎能够处理较大循环的恒定传播;这个挂断似乎只是让 GCC 考虑首先展开更长的循环。

然而,无论是手动展开还是BOOST_PP_REPEAT是可行的选择,因为有some情况下CONSTANT_COUNT是一个运行时表达式,并且same对于这些情况,代码仍然需要正确工作。 (在这些情况下,性能并不那么重要。)

我正在使用 C (不是 C++),所以模板元编程和constexpr可供我使用。

我试过了-funroll-loops, -funroll-all-loops, -fpeel-loops,并为max-unrolled-insns, max-average-unrolled-insns, max-unroll-times, max-peeled-insns, max-peel-times, max-completely-peeled-insns, and max-completely-peel-times,这些似乎都没有什么区别。

我在 Linux x86_64 上使用 GCC 4.8.2。

有任何想法吗?是否有我缺少的标志或参数...?


我不确定这个解决方法是否适用于您的实际问题,但我发现运行 Parabola GNU/Linux 的 x86_64 上的 GCC 4.9.0 20140604(预发布)展开以下循环,直到并包括CONSTANT_COUNT == 33.

int
get_sum()
{
  int total = 0;
  int i, j, k = 0;
  for (j = 0; j < 2; ++j)
    {
      for (i = 0; i < CONSTANT_COUNT / 2; ++i)
        {
          total += constants[k++];
        }
    }
  if (CONSTANT_COUNT % 2)
    total += constants[k];
  return total;
}

我只通过了-O3旗帜。汇编代码为get_sum真的只是

movl $561, %eax
ret

我没有尝试,但也许该模式可以进一步扩展。

对我来说,这似乎很奇怪,因为——至少在我的肉眼看来——代码现在看起来要复杂得多。不幸的是,这是一种相当侵入性的强制展开方式。编译器标志会好得多。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

强制/说服/欺骗 GCC 展开_更长_循环? 的相关文章

随机推荐