13

当我找到选项时,我正在阅读GCC 的优化-funroll-all-loops选项。

它的描述如下:

展开所有循环,即使在进入循环时它们的迭代次数不确定。这通常会使程序运行得更慢。“-funroll-all-loops”暗示与“-funroll-loops”相同的选项

如果在编译时它的迭代次数未知,编译器如何展开循环?编译器不需要这些信息来展开它吗?它会生成哪些相应的 C 代码,如果它通常会使程序运行得更慢,这在什么情况下会有用?

4

4 回答 4

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 的幂允许编译器使用掩码而不是(昂贵的)除法操作。

于 2015-07-01T16:47:44.327 回答
3

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

好吧,他们假设如果您选择此选项,您就知道自己在做什么,如果不这样做,则不应使用此选项。

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

#include <stdio.h>

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

并用godbolt对其进行了测试,它会根据剩余的迭代次数生成一个跳转表(现场查看):

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
于 2015-07-01T16:52:14.213 回答
2

它可以执行以下操作:

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

当然,达夫的设备可以省去编写第二个循环的麻烦。

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

于 2015-07-01T16:43:25.993 回答
0

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

于 2015-07-01T16:41:15.637 回答