这个问题部分是关于GCC 5.1 循环展开的后续问题。
根据GCC文档和我对上述问题的回答,像
尽管如此,我注意到在我的项目中,即使没有启用相关标志,GCC有时也会展开循环。例如,请考虑以下简单的代码片段:
这个观察结果引出以下密切相关的问题。为什么GCC会执行循环展开,即使相应于该行为的标志已被禁用?循环展开是否也受其他标志的控制,这些标志可以使编译器在某些情况下展开循环,即使
有趣的是,Clang编译器在这里具有期望的行为,似乎只在启用
提前感谢,任何关于此事的额外见解将不胜感激!
根据GCC文档和我对上述问题的回答,像
-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
时才执行展开,而不是在其他情况下。提前感谢,任何关于此事的额外见解将不胜感激!