省略帧指针时是否有任何实质性的优化?
如果我通过阅读this页面正确理解,则在我们想要避免保存,设置和恢复帧指针时使用-fomit-frame-pointer
。
这是仅针对每个函数调用完成的吗?如果是这样,是否真的值得为每个函数避免一些指令? 优化不是一件容易的事。 除了调试限制之外,使用此选项的实际意义是什么?
我使用和不使用此选项编译了以下C代码
int main(void)
{
int i;
i = myf(1, 2);
}
int myf(int a, int b)
{
return a + b;
}
,
# gcc -S -fomit-frame-pointer code.c -o withoutfp.s
# gcc -S code.c -o withfp.s
diff -u
两个文件显示以下汇编代码:
--- withfp.s 2009-12-22 00:03:59.000000000 +0000
+++ withoutfp.s 2009-12-22 00:04:17.000000000 +0000
@@ -7,17 +7,14 @@
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
- pushl %ebp
- movl %esp, %ebp
pushl %ecx
- subl $36, %esp
+ subl $24, %esp
movl $2, 4(%esp)
movl $1, (%esp)
call myf
- movl %eax, -8(%ebp)
- addl $36, %esp
+ movl %eax, 20(%esp)
+ addl $24, %esp
popl %ecx
- popl %ebp
leal -4(%ecx), %esp
ret
.size main, .-main
@@ -25,11 +22,8 @@
.globl myf
.type myf, @function
myf:
- pushl %ebp
- movl %esp, %ebp
- movl 12(%ebp), %eax
- addl 8(%ebp), %eax
- popl %ebp
+ movl 8(%esp), %eax
+ addl 4(%esp), %eax
ret
.size myf, .-myf
.ident "GCC: (GNU) 4.2.1 20070719
有人可以了解上面代码的键点 - -fomit-frame-pointer确实有所作为吗?
编辑: objdump
的输出已替换为gcc -S
的
答案 0 :(得分:29)
-fomit-frame-pointer
允许一个额外的寄存器可用于通用目的。我认为这对于32位x86来说真的很重要,因为寄存器有点缺乏。*
人们期望看到EBP不再在每次函数调用时保存和调整,并且可能在普通代码中使用EBP,并且在EBP被用作通用寄存器的情况下更少的堆栈操作。
您的代码太简单了,无法从这种优化中获得任何好处 - 您没有使用足够的寄存器。此外,您还没有打开优化器,这可能是查看其中一些效果所必需的。
* ISA寄存器,而不是微架构寄存器。
答案 1 :(得分:9)
省略它的唯一缺点是调试要困难得多。
主要好处是有一个额外的通用寄存器可以对性能产生重大影响。显然,这个额外的寄存器仅在需要时使用(可能在你非常简单的函数中它不是);在某些功能中,它比其他功能更有区别。
答案 2 :(得分:7)
通过使用-S
参数输出程序集,您通常可以从GCC获得更有意义的汇编代码:
$ gcc code.c -S -o withfp.s
$ gcc code.c -S -o withoutfp.s -fomit-frame-pointer
$ diff -u withfp.s withoutfp.s
GCC不关心地址,因此我们可以比较直接生成的实际指令。对于你的叶子功能,这给出了:
myf:
- pushl %ebp
- movl %esp, %ebp
- movl 12(%ebp), %eax
- addl 8(%ebp), %eax
- popl %ebp
+ movl 8(%esp), %eax
+ addl 4(%esp), %eax
ret
GCC不会生成将帧指针压入堆栈的代码,这会更改传递给堆栈上函数的参数的相对地址。
答案 3 :(得分:5)
描述您的计划,看看是否存在显着差异。
接下来,介绍您的开发过程。调试更容易还是更难?您是否花费更多时间开发或减少开发?
没有分析的优化是浪费时间和金钱。