GCC - 两个相同的函数,但生成的代码不同。为什么?

P__*_*J__ 16 c gcc compiler-optimization compiler-bug

代码:

#define OPPOSITE(c) (*((typeof(x) *)&(x)))

int foo(volatile int x)
{
    OPPOSITE(x) = OPPOSITE(x) + OPPOSITE(x);
    return x;
}

int bar(volatile int x)
{
    OPPOSITE(x) = OPPOSITE(x) + OPPOSITE(x);
    return x;
}
Run Code Online (Sandbox Code Playgroud)

结果(-Os):

foo:
        mov     DWORD PTR [rsp-4], edi
        mov     eax, DWORD PTR [rsp-4]
        mov     edx, DWORD PTR [rsp-4]
        add     eax, edx
        mov     DWORD PTR [rsp-4], eax
        mov     eax, DWORD PTR [rsp-4]
        ret
bar:
        mov     DWORD PTR [rsp-4], edi
        mov     eax, DWORD PTR [rsp-4]
        add     eax, eax
        ret
Run Code Online (Sandbox Code Playgroud)

或ARM gcc。( -O3)

foo:
        sub     sp, sp, #8
        str     r0, [sp, #4]
        ldr     r3, [sp, #4]
        ldr     r2, [sp, #4]
        add     r3, r3, r2
        str     r3, [sp, #4]
        ldr     r0, [sp, #4]
        add     sp, sp, #8
        bx      lr
bar:
        sub     sp, sp, #8
        str     r0, [sp, #4]
        ldr     r0, [sp, #4]
        lsl     r0, r0, #1
        add     sp, sp, #8
        bx      lr
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/z/6z5Td9GsP

小智 3

您可以将代码替换为

int foo(volatile int x)
{
        x = x + x;
        return x;
}

int bar(volatile int x)
{
    x = x + x;
    return x;
}
Run Code Online (Sandbox Code Playgroud)

并且有同样的效果。除了 GCC 之外,没有其他 C 编译器会产生这种效果,所以我认为有理由说这是某种编译器错误。

  • 即使您通过使用 tmp 变量来避免无序的易失性访问(在一个语句内)来避免 C11 UB,同样的错误代码生成仍然存在。除非您使用`-fno-ipa-icf` - https://godbolt.org/z/jK5a4j6q8 - 过程间分析:相同的代码折叠((https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options. html#index-fipa-icf)。因此,分析过程显然是 GCC 内部错误的一部分。正如 Lundin 指出的,这是 GCC 5.0 中的回归。 (3认同)