【问题标题】:Correct way of unrolling loop using gcc使用 gcc 展开循环的正确方法
【发布时间】:2013-09-30 21:31:26
【问题描述】:
#include <stdio.h>
int main() {
        int i;
        for(i=0;i<10000;i++){
            printf("%d",i);
    }
}

我想使用 gcc 对此代码进行循环展开 但即使使用标志。

gcc -O2 -funroll-all-loops --save-temps unroll.c

我得到的汇编代码包含一个 10000 次迭代的循环

_main:
Leh_func_begin1:
        pushq   %rbp
Ltmp0:
movq    %rsp, %rbp
Ltmp1:
pushq   %r14
pushq   %rbx
Ltmp2:
xorl    %ebx, %ebx
leaq    L_.str(%rip), %r14
.align  4, 0x90
LBB1_1:
xorb    %al, %al
movq    %r14, %rdi
movl    %ebx, %esi
callq   _printf
incl    %ebx
cmpl    $10000, %ebx
jne LBB1_1
popq    %rbx
popq    %r14
popq    %rbp
ret
Leh_func_end1:

请告诉我如何在 gcc 中正确实现循环展开

【问题讨论】:

  • 尝试改用-O3
  • 优化器可能发现展开这个循环比让它保持原样慢。
  • 与您的完全相同的标志。
  • 请记住,如果循环展开太多,循环代码将无法放入 L1 缓存,并且缓存未命中比分支更昂贵。展开所有 10k 次迭代可能会比完全不展开要慢(相对而言)。中间某处有一个最佳展开量。
  • 它不会“让代码变得超快”。如果主要开销是循环控制的东西,它会更快。在 printf() 的情况下,它肯定不是:I/O 是瓶颈。编译器没有义务展开每个循环。

标签: c optimization gcc loop-unrolling


【解决方案1】:

循环展开不会给您带来任何好处,因为对printf() 的函数调用本身的开销决定了每次迭代完成的工作。编译器可能会意识到这一点,并且由于它被要求优化代码,它可能会决定展开会增加代码大小而没有明显的运行时性能增益,并决定导致指令缓存未命中的风险太高执行展开。

加速此循环所需的展开类型需要减少对printf() 本身的调用次数。我不知道有任何优化编译器能够做到这一点。

作为展开循环以减少printf() 调用次数的示例,请考虑以下代码:

void print_loop_unrolled (int n) {
    int i = -8;
    if (n % 8) {
        printf("%.*s", n % 8, "01234567");
        i += n % 8;
    }
    while ((i += 8) < n) {
        printf("%d%d%d%d%d%d%d%d",i,i+1,i+2,i+3,i+4,i+5,i+6,i+7);
    }
}

【讨论】:

    【解决方案2】:

    gcc 具有最大循环展开参数。

    您必须使用-O3 -funroll-loops 并使用参数max-unroll-timesmax-unrolled-insnsmax-average-unrolled-insns

    例子:

    -O3 -funroll-loops --param max-unroll-times=200
    

    【讨论】:

    • 我仍然没有得到任何展开.. 我相信它给出了展开次数的上限,但它不能强制编译器展开
    【解决方案3】:

    替换

     printf("%d",i);
    

     volatile int j = i;
    

    看看循环是否展开。

    【讨论】:

      猜你喜欢
      • 2016-10-24
      • 1970-01-01
      • 2019-09-18
      • 2017-01-21
      • 1970-01-01
      • 2015-09-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多