【问题标题】:Why does gcc create redundant assembly code?为什么 gcc 会创建冗余的汇编代码?
【发布时间】:2012-05-26 15:22:08
【问题描述】:

我想研究某些 C/C++ 功能是如何转换为程序集的,我创建了以下文件:

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

char *bar(struct foo *f)
{
    return f->y;
}

然后我用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:

除其他外,线条

        movq    %rax, -24(%rbp)
        movq    -24(%rbp), %rax
        movq    %rax, -16(%rbp)
        movq    -16(%rbp), %rax

似乎毫无意义的多余。 gcc(可能还有其他编译器)有什么理由不能/不优化这个吗?

【问题讨论】:

  • 请使用 -O 开关运行 gcc 以启用标准优化。
  • 您使用的是哪个版本的 gcc?

标签: c optimization gcc assembly compiler-construction


【解决方案1】:

我认为 gcc 应该可以优化掉。

来自gcc manual

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

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

bar:
.LFB0:
        .cfi_startproc
        leaq    4(%rdi), %rax
        ret
        .cfi_endproc

更多详情,请参阅手册中的Options That Control Optimization

【讨论】:

  • 哦,我假设默认情况下会启用标准优化。为什么不呢?
  • @Matt:引用手册,“没有任何优化选项,编译器的目标是降低编译成本,使调试产生预期的结果。”
  • @Matt 因为实施者如此选择。除非你在这里从其中一个人那里得到答案,否则这是一个徒劳的问题。
【解决方案2】:

编译器在没有优化的情况下生成的代码通常是直接的逐条指令翻译,这些指令不是程序的指令,而是可能引入冗余的中间表示的指令。

如果您希望汇编没有此类冗余指令,请使用gcc -O -S

您所期望的优化称为peephole optimization。编译器通常有很多这些,因为与更多的全局优化不同,它们应用起来很便宜并且(通常)不会冒险使代码变得更糟——至少如果在编译结束时应用的话。

this blog post 中,我提供了一个示例,当源代码中的整数类型是 64 位但只有结果的最低 32 位时,GCC 和 Clang 都可以生成更短的 32 位指令问题。

【讨论】:

    猜你喜欢
    • 2012-09-02
    • 1970-01-01
    • 2015-04-26
    • 1970-01-01
    • 1970-01-01
    • 2013-01-22
    • 2020-08-30
    • 2020-06-01
    • 1970-01-01
    相关资源
    最近更新 更多