我正在观察为下面的函数here创建的程序集。
int square(int num) {
return num;
}
字符串
这是为上面的函数生成的程序集:
square:
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], edi
mov eax, DWORD PTR [rbp-4]
pop rbp
ret
型
我的问题是,我能把它重写成这样,并假设它工作正常吗?
square:
push rbp
mov rbp, rsp
mov eax, edi
pop rbp
ret
型
首先将edi
移动到[rbp-4]
,然后将[rbp-4]
移动到eax
的必要性是什么?由于源和目的地都是寄存器,我认为我们可以在单个移动指令中移动数据。
已编辑
我的问题是关于未优化版本的代码,我知道如果我用-O1
编译它,它会发出更短更简洁的代码。但我的问题是关于额外的mov
指令的语义。
3条答案
按热度按时间w8ntj3qf1#
在没有优化的情况下,编译器会按照语言的字面说明生成要做的步骤。在C中,函数的参数本质上是局部变量,就像你在函数内部声明了它们一样。所以下面的C代码:
字符串
在C标准的语义中,很像:
型
如果没有优化,编译器就遵循这个模型。当例程启动时,编译器建立一个堆栈框架,并将参数(寄存器中)存储到参数(堆栈上)中。
然后
return num;
从堆栈加载参数。优化打开后,编译器将删除堆栈的不必要使用。
fd3cxomn2#
相信你的编译器的优化器。
如果你使用
-O1
编译,你会得到以下结果:字符串
4ngedf3f3#
我们拥有的最好的编译器技术是生成愚蠢的,简单的,准确的代码,然后使用模式识别,一遍又一遍地重复,以优化它。
这种方法抓住了许多优化的机会,这些机会是隐藏在一个“聪明”的编译器面前的,编译器可以生成更好的非优化代码,但是几十年的研究表明,模式识别才是投资的方向。
此外,最初未优化的简单精确代码对调试是友好的,如果您开始对最初生成的代码应用太多智能,这实际上是非常复杂的。
因此,优先事项是:生成在执行和调试中准确的代码,然后,当被请求时,使用各种模式匹配来识别和执行优化转换。