如何让gcc使用std::move优化std::bit_cast?

szqfcxe2  于 2022-11-13  发布在  其他
关注(0)|答案(1)|浏览(170)

请考虑以下代码:

#include <cstdint>
#include <bit>
#include <utility>

struct A { uint32_t a[100]; };
struct B { uint16_t b[200]; };

void test(const A&);

void foo() {
    B tmp;
    test(std::bit_cast<A>(std::move(tmp)));
}

void bar() {
    B tmp;
    test(reinterpret_cast<A&>(tmp));
}

对于带有-O3的clang 15,foo和bar是等效的,但是对于带有-O3的GCC 12.2,foo需要进行数据复制(rep movsq)。

foo():
        sub     rsp, 808
        mov     ecx, 50
        lea     rdi, [rsp+400]
        mov     rsi, rsp
        rep movsq
        lea     rdi, [rsp+400]
        call    test(A const&)
        add     rsp, 808
        ret
bar():
        sub     rsp, 408
        mov     rdi, rsp
        call    test(A const&)
        add     rsp, 408
        ret

哪个编译器选项可以让GCC优化像Clang这样的东西?谢谢。Pidoss. -Ofast对这个问题没有帮助。

**[编辑]**根据user 17732522提供的答案,我将代码修改为:

#include <cstdint>
#include <bit>

struct A { uint32_t a[100]; };
struct B { uint16_t b[200]; };

void test(const A&);

void foo(B arg) {
    test(std::bit_cast<A>(arg));
}

void bar(B arg) {
    test(reinterpret_cast<A&>(arg));
}

现在GCC和Clang都使用foo的数据复制。所以,看起来std::bit_cast并不打算涵盖这种情况。

mccptt67

mccptt671#

std::movestd::bit_cast是完全没有意义的,并且根本没有任何效果,因为std::bit_cast具有左值引用参数,并且没有右值引用重载。
在您的测试用例中,除了从foo中读取(未初始化!)数据外,tmp从未在foo中使用过。因此,很明显,编译器没有意识到这个对象根本不需要,而未初始化的A可以直接使用,这是一个错过的优化。这不是您可以在语言级别上解决的问题。这完全取决于编译器优化。
实际上,GCC似乎有意不删除复制指令,因为您正在阅读未初始化的数据。如果您在B中对数组进行零初始化,那么GCC会为两个函数生成相同的输出,而在std::bit_cast版本中不需要额外的复制。
对于这个问题,您确实没有什么可以做的,但是我在测试用例中确实没有看到任何价值。您可以直接声明一个A,并具有相同的效果。

相关问题