为什么gcc会创建冗余汇编代码?

Mat*_*att 5 c compiler-construction optimization assembly gcc

我想研究一下如何将某些C/C++特性转换为汇编,并创建了以下文件:

struct foo {
    int x;
    char y[0];
};

char *bar(struct foo *f)
{
    return f->y;
}
Run Code Online (Sandbox Code Playgroud)

然后我编译了这个gcc -S(并且也试过g++ -S)但是当我查看汇编代码时,我很失望地发现bar函数中的一个微不足道的冗余,我认为gcc应该能够优化掉:

_bar:
Leh_func_begin1:
        pushq   %rbp
Ltmp0:
        movq    %rsp, %rbp
Ltmp1:
        movq    %rdi, -8(%rbp)
        movq    -8(%rbp), %rax
        movabsq $4, %rcx
        addq    %rcx, %rax
        movq    %rax, -24(%rbp)
        movq    -24(%rbp), %rax
        movq    %rax, -16(%rbp)
        movq    -16(%rbp), %rax
        popq    %rbp
        ret
Leh_func_end1:
Run Code Online (Sandbox Code Playgroud)

除其他外,线条

        movq    %rax, -24(%rbp)
        movq    -24(%rbp), %rax
        movq    %rax, -16(%rbp)
        movq    -16(%rbp), %rax
Run Code Online (Sandbox Code Playgroud)

似乎毫无意义多余.是否有任何理由gcc(可能还有其他编译器)不能/不优化它?

NPE*_*NPE 11

我以为gcc应该能够优化掉.

gcc手册:

如果没有任何优化选项,编译器的目标是降低编译成本并使调试产生预期结果.

换句话说,除非你提出要求,否则它不会优化.当我使用-O3标志启用优化时,gcc 4.4.6会生成更高效的代码:

bar:
.LFB0:
        .cfi_startproc
        leaq    4(%rdi), %rax
        ret
        .cfi_endproc
Run Code Online (Sandbox Code Playgroud)

有关更多详细信息,请参阅手册中的"控制优化选项".

  • @Matt:引用手册"没有任何优化选项,编译器的目标是降低编译成本并使调试产生预期结果." (7认同)

Pas*_*uoq 8

编译器在没有优化的情况下生成的代码通常是直接逐指令转换,并且指令不是程序的指令,而是可能已经引入冗余的中间表示的指令.

如果您希望装配时没有这些冗余指令,请使用 gcc -O -S

您期望的那种优化称为窥孔优化.编译器通常有很多这样的,因为与更全局的优化不同,它们应用起来很便宜,并且(通常)不会冒险使代码变得更糟 - 如果应用于编译结束,至少.

这篇博文中,我提供了一个例子,当源代码中的整数类型为64位但只有结果最低的32位时,GCC和Clang都可以生成更短的32位指令.