assembly 为什么编译器在未优化的调试版本中不简单地将数据从edi移动到eax?

slhcrj9b  于 10个月前  发布在  其他
关注(0)|答案(3)|浏览(155)

我正在观察为下面的函数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指令的语义。

w8ntj3qf

w8ntj3qf1#

在没有优化的情况下,编译器会按照语言的字面说明生成要做的步骤。在C中,函数的参数本质上是局部变量,就像你在函数内部声明了它们一样。所以下面的C代码:

int square(int num)
{
    …
}

字符串
在C标准的语义中,很像:

int square(?)
{
    int num = value that the caller passed as the first argument;
    …
}


如果没有优化,编译器就遵循这个模型。当例程启动时,编译器建立一个堆栈框架,并将参数(寄存器中)存储到参数(堆栈上)中。
然后return num;从堆栈加载参数。
优化打开后,编译器将删除堆栈的不必要使用。

fd3cxomn

fd3cxomn2#

相信你的编译器的优化器。
如果你使用-O1编译,你会得到以下结果:

square:
        mov     eax, edi
        ret

字符串

4ngedf3f

4ngedf3f3#

我们拥有的最好的编译器技术是生成愚蠢的,简单的,准确的代码,然后使用模式识别,一遍又一遍地重复,以优化它。
这种方法抓住了许多优化的机会,这些机会是隐藏在一个“聪明”的编译器面前的,编译器可以生成更好的非优化代码,但是几十年的研究表明,模式识别才是投资的方向。
此外,最初未优化的简单精确代码对调试是友好的,如果您开始对最初生成的代码应用太多智能,这实际上是非常复杂的。
因此,优先事项是:生成在执行和调试中准确的代码,然后,当被请求时,使用各种模式匹配来识别和执行优化转换。

相关问题