【问题标题】:How can GCC unroll a loop if its number of iterations is unknown at compile time?如果在编译时迭代次数未知,GCC 如何展开循环?
【发布时间】:2015-07-01 16:37:22
【问题描述】:

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

它的描述如下:

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

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

【问题讨论】:

  • @Olaf 这不是一个具体的问题吗? OP 明确询问 gcc(特定的 C 编译器)如何知道如果循环的边界未知,如何展开循环。
  • @Olaf 如果我想知道特定编译器选项的作用,那它太宽泛了?
  • @paulsm4 我不这么认为。如果编译器已经知道边界,那么决定归结为实际展开多少。这个问题不是问那个。
  • 您可能会发现在my answerSwitch case weird scoping 中有关达夫设备的讨论很有帮助。 (其他海报也提到了达夫的设备。)

标签: c gcc optimization loop-unrolling


【解决方案1】:

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

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

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

【讨论】:

  • 当然,有了printf,收益基本上为零;-)
【解决方案2】:

这里有一些 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 的幂允许编译器使用掩码而不是(昂贵的)除法运算。

【讨论】:

    【解决方案3】:

    它可以做这样的事情:

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

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

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 2022-10-15
        • 1970-01-01
        • 1970-01-01
        • 2020-02-17
        • 1970-01-01
        • 2016-02-20
        • 2021-10-04
        • 1970-01-01
        • 2011-12-03
        相关资源
        最近更新 更多