如果在编译时它的迭代次数未知,GCC如何展开循环呢?

时间:2015-07-01 16:37:22

标签: c gcc optimization loop-unrolling

当我找到-funroll-all-loops选项时,我正在阅读optimization options for GCC

其描述如下:

  

展开所有循环,即使它们的迭代次数不确定时也是如此   输入循环。这通常会使程序运行得更慢。   ' -funroll,全循环'暗示与' -funroll-loops'

相同的选项

如果编译时迭代次数未知,编译器如何展开循环?编译器是否需要此信息才能展开它?它产生了什么相应的C代码,如果它通常使程序运行得更慢,在什么情况下这可能是有用的?

4 个答案:

答案 0 :(得分:3)

以下是一些显示如何操作的C代码:

int iterations = 100;
int unrollValue = 8;

while (iterations%unrollvalue)
{
   // insert loop code here
   iterations--;
}

while (iterations)
{
   // insert unrollValue copies of loop code here
   iterations-= unrollValue;
}

编译器将用相对跳转替换第一个循环,但是在C中表示不容易。注意,以2的幂展开允许编译器使用掩码而不是(昂贵的)除法操作

答案 1 :(得分:3)

  

如果通常会使程序运行得更慢,那么在什么情况下这可能会有用呢?

他们假设你选择这个选项就知道你在做什么,如果你不这样做,你就不应该使用这个选项。

gcc将要做什么,我使用了这个示例程序:

#include <stdio.h>

void f(int j )
{
  for( int k = 0; k < j; ++k )
  {
    printf( "%d\n", k ) ;
  }
}

并使用godbolt对其进行测试,并根据剩余的迭代次数生成跳转表( see it live ):

cmpl    $1, %ebp
movl    $1, %ebx
je  .L1
testl   %r12d, %r12d
je  .L27
cmpl    $1, %r12d
je  .L28
cmpl    $2, %r12d
je  .L29
cmpl    $3, %r12d
je  .L30
cmpl    $4, %r12d
je  .L31
cmpl    $5, %r12d
je  .L32
cmpl    $6, %r12d
je  .L33

答案 2 :(得分:2)

它可以做类似的事情:

while(n >= 8){
  foo(); foo(); foo(); foo(); foo(); foo(); foo(); foo(); 
  n -= 8;
}
while(n > 0){
  foo();
  n--;
}

当然,Duff的设备可以省去写第二个循环。

为什么这样?这取决于用户。 如果foo()花费的时间超过几个周期,,如果原始循环占用整个挂钟时间的5%,,如果{{1}通常很小,这可能不值得麻烦。

答案 3 :(得分:0)

你不能假设编译器的中间表示存在对应的C代码这样的东西。但在这种情况下,我希望最接近的等价物类似于Duff's Device,这是一个可以在计算位置输入的序列(通常在循环中)。