该问题部分是GCC 5.1 Loop unrolling的后续问题。
根据GCC documentation,并在我对上述问题的回答中指出,诸如-funroll-loops
的标志会启用“完整循环剥离(即以少量恒定的迭代次数完全删除循环)”。因此,启用此类标志后,如果编译器确定可以优化给定代码段的执行,则可以选择展开循环。
不过,我在我的一个项目中注意到,即使未启用相关标志,GCC有时也会展开循环。例如,考虑以下简单的代码:
int main(int argc, char **argv)
{
int k = 0;
for( k = 0; k < 5; ++k )
{
volatile int temp = k;
}
}
使用
-O1
编译时,将展开循环,并使用任何现代版本的GCC生成以下汇编代码:main:
movl $0, -4(%rsp)
movl $1, -4(%rsp)
movl $2, -4(%rsp)
movl $3, -4(%rsp)
movl $4, -4(%rsp)
movl $0, %eax
ret
即使使用附加的
-fno-unroll-loops -fno-peel-loops
进行编译以确保禁用了的标志,GCC仍意外地对上述示例执行了循环展开。这种观察使我想到了以下密切相关的问题。为什么即使禁用了与该行为相对应的标志,GCC仍会执行循环展开?展开功能是否也受其他标志控制,即使禁用了
-funroll-loops
,在某些情况下,这些标志也可以使编译器展开循环?有没有一种方法可以完全禁用GCC中的循环展开功能(使用-O0
进行编译的一部分)?有趣的是, Clang 编译器在这里具有预期的行为,并且似乎仅在启用
-funroll-loops
时才执行展开,而在其他情况下则不会。在此先感谢您对此问题的任何其他见解!
最佳答案
从务实的角度考虑它:将这样的标志传递给编译器时,您想要什么?没有C++开发人员会要求GCC展开或不展开循环,只是为了有循环而没有在汇编代码中,这是有目标的。例如,如果您正在开发存储空间有限的嵌入式软件,-fno-unroll-loops
的目标是牺牲一点速度以减小二进制文件的大小。另一方面,-funrool-loops
的目标是告诉编译器您并不关心二进制文件的大小,因此可以毫不犹豫地展开循环。
但这并不意味着编译器会盲目地展开或者不是您所有的循环!
在您的示例中,原因很简单:循环仅包含一条指令-在任何平台上都只有几个字节-编译器知道这是可以忽略的,并且无论如何都将占用与循环所需的汇编代码几乎相同的大小(sub
+ mov
+ x86-64上的jne
)。
这就是为什么带有-O3 -fno-unroll-loops
的gcc 6.2会显示以下代码的原因:
int mul(int k, int j)
{
for (int i = 0; i < 5; ++i)
volatile int k = j;
return k;
}
...到以下汇编代码:
mul(int, int):
mov DWORD PTR [rsp-0x4],esi
mov eax,edi
mov DWORD PTR [rsp-0x4],esi
mov DWORD PTR [rsp-0x4],esi
mov DWORD PTR [rsp-0x4],esi
mov DWORD PTR [rsp-0x4],esi
ret
它不会听您的声音,因为它(几乎取决于体系结构)不会改变二进制文件的大小,但是速度更快。但是,如果您增加循环计数器...
int mul(int k, int j)
{
for (int i = 0; i < 20; ++i)
volatile int k = j;
return k;
}
...遵循您的提示:
mul(int, int):
mov eax,edi
mov edx,0x14
nop WORD PTR [rax+rax*1+0x0]
sub edx,0x1
mov DWORD PTR [rsp-0x4],esi
jne 400520 <mul(int, int)+0x10>
repz ret
如果将循环计数器保留在
5
处,但是将一些代码添加到循环中,则将得到相同的行为。综上所述,可以从务实的开发人员的角度将所有这些优化标志视为对编译器的提示。总是要权衡取舍,并且在构建软件时,您永远不需要全部或完全不需要循环展开。
最后一点,另一个非常相似的示例是
-f(no-)inline-functions
标志。我每天都在争取编译器内联(或不进行内联)我的某些功能(使用inline
关键字和带有GCC的__attribute__ ((noinline))
),当我检查汇编代码时,我发现该smartass有时仍在执行所需的操作,当我想内联某个绝对无法满足其需求的函数时。在大多数时候,这是正确的做法,我很高兴!