C ++循环展开编译时常量小值

时间:2013-03-29 14:02:10

标签: c++ optimization

我有这两个功能:

template<int N>
void fun()
{
    for(int i = 0; i < N; ++i)
    {
        std::cout<<i<<" ";
    }
}

void gun(int N)
{
    for(int i = 0; i < N; ++i)
    {
        std::cout<<i<<" ";
    }
}

我可以假设在第一个版本中,编译器会为每个小N优化循环(小的意思是N = {1,2,3,4})?

5 个答案:

答案 0 :(得分:3)

  

我可以假设在第一个版本中,编译器将为每个小N

优化循环

这是典型的优化,虽然“假设”是一个强有力的词。如果优化是命令式,您最终会对任何潜在的优化感到失望。

如果编译器能够内联函数,则第二版可能会遇到相同的优化。

答案 1 :(得分:2)

您永远不会保证优化会做什么,但是如果有合适的优化级别,您通常可以依靠它做出比手动优化时更好的选择。

如果您真的想知道生成了什么代码,可以随时查看生成的程序集。

答案 2 :(得分:1)

这取决于您的优化级别和标志。 -O0 -g(没有优化,启用调试),-O3(针对速度进行积极优化)和-Os(优化空间)之间存在很大差异。

这些天循环展开不一定是胜利,即使在优化速度时也是如此。太多的代码会导致指令高速缓存未命中,这将大大超过内联简单循环的速度。并且像这样的循环中的条件分支的成本几乎可以忽略不计,因为分支预测将正确地预测除最后一次迭代之外的所有迭代。

答案 3 :(得分:1)

如果编译器可以内联其中一个函数,那么如果它认为这是正确的事情,它也会展开循环。当&amp;编译器如何决定展开循环是否有好处是一个非常复杂的问题,并且在很大程度上取决于其他因素,例如可用寄存器的数量,循环内部发生的事情(我怀疑上面给出的例子,例如,考虑到cout ...可能消耗数千倍的时间 - 编译器是否可以解决这个问题是另一回事,但是它不是在减少循环中涉及的5个左右的指令时获得了很多时间。完全不知道编译器是否对函数是否小而有所了解。

另一方面,如果代码看起来像这样:

int arr[N];  // Global array. 

template<int N>
int fun()
{
    int sum = 0;
    for(int i = 0; i < N; ++i)
    {
        sum += arr[i];
    }
}

然后我希望编译器将循环展开为:​​

    int *tmp = arr;
    sum += *tmp++;
    sum += *tmp++;
    sum += *tmp++;
    sum += *tmp++;
    sum += *tmp++;

假设N = 5.

这适用于任何对编译器“可见”的函数以及在编译时已知N的函数。因此,假设gun不在不同的源文件中,那么我希望它内联并展开与fun完全相同(作为模板函数,它在此处可见编译单位)

答案 4 :(得分:0)

如果您想要更明确一些,可以使用Duff's Device使用switch case fallthrough来展开循环。但是,我无法谈论它在实践中的运作情况。但是,我想,如果您可以提示编译器将其展开,那就更快了。

编译器也非常聪明,虽然它们并非绝对可靠,但它们的优化选择通常比我们自己的直觉更好。

相关问题