为啥 gcc 会产生这个奇怪的程序集 vs clang?

Posted

技术标签:

【中文标题】为啥 gcc 会产生这个奇怪的程序集 vs clang?【英文标题】:Why does gcc produce this weird assembly vs clang?为什么 gcc 会产生这个奇怪的程序集 vs clang? 【发布时间】:2020-02-16 02:05:46 【问题描述】:

我试图弄清楚 gcc 和 clang 之间的区别以及它们如何处理std::vector。有更多知识的人能解释一下为什么 gcc 和 clang 会产生如此不同的输出吗?

gcc 9.2:https://godbolt.org/z/AFN46d 铿锵声9.0:https://godbolt.org/z/kEkpWE

程序:

#include <vector>

int foo(int a) 
    auto vec = std::vector<int>;
    vec.push_back(1);
    vec.push_back(2);
    return vec[1] * a;

int main () 
    return foo(5) + foo(4);

clang 生成非常易于理解的程序集。然而,gcc 会产生这种奇怪的东西:

void std::vector<int, std::allocator<int> >::_M_realloc_insert<int>(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, int&&):
        movabs  rcx, 2305843009213693951
        push    r15
        push    r14
        push    r13
        push    r12
        push    rbp
        push    rbx
        sub     rsp, 24
        mov     r12, QWORD PTR [rdi+8]
        mov     r8, QWORD PTR [rdi]
        mov     rax, r12
        sub     rax, r8
        sar     rax, 2
        cmp     rax, rcx
        je      .L16
        mov     r15, rdx
        mov     rdx, rsi
        mov     rbp, rdi
        mov     r13, rsi
        sub     rdx, r8
        test    rax, rax
        je      .L11
        movabs  r14, 9223372036854775804
        lea     rsi, [rax+rax]
        cmp     rax, rsi
        jbe     .L17

这些神奇的数字是从哪里来的?

【问题讨论】:

我想知道为什么他们都没有优化到return 2 * a; foo(int) 的代码由foo(int): 行引入,您引用了向量证明成员函数的程序集 @M.M 我想这是因为::operator new 可能会在另一个翻译单元中被替换。 @L.F.即使存在全局替换,它也被允许优化,因为 C++14,see here 【参考方案1】:

GCC 尽量保证安全并发出一些额外的检查。您看到的第一个常量仅仅是

__gnu_cxx::__numeric_traits<ptrdiff_t>::__max / sizeof(int)

并且构成 x86-64 上整数向量的最大可能大小。

第二个常数似乎只是

__gnu_cxx::__numeric_traits<ptrdiff_t>::__max

四舍五入以被sizeof(int)整除。

一般来说,这些东西来自 libstdc++ 中的各种max_size() 方法。 clang 有可能证明一些检查是不必要的。

【讨论】:

以上是关于为啥 gcc 会产生这个奇怪的程序集 vs clang?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 GCC 会为几乎相同的 C 代码生成如此完全不同的程序集?

为啥这个结构文字在 VS2013 中通过地址而不是 gcc/clang 时会损坏?

为啥这个 C++ 包装类没有被内联?

使用指定初始化程序时的不同 gcc 程序集

为啥减去这两次(在 1927 年)会产生奇怪的结果?

gcc的奇怪/错误的程序集输出?