MSVC 生成不必要的复杂指令

Gug*_*ugi 7 c++ x86-64 compiler-optimization visual-c++ stdoptional

在对涉及 的代码进行基准测试时std::optional<double>,我注意到 MSVC 生成的代码的运行速度大约是 clang 或 gcc 生成的代码的一半。在花了一些时间减少代码后,我注意到 MSVC 显然在为std::optional::operator=. 使用std::optional::emplace()不会表现出速度减慢。

以下功能

void test_assign(std::optional<double> & f){
    f = std::optional{42.0};
}
Run Code Online (Sandbox Code Playgroud)

产生

sub     rsp, 24
vmovsd  xmm0, QWORD PTR __real@4045000000000000
mov     BYTE PTR $T1[rsp+8], 1
vmovups xmm1, XMMWORD PTR $T1[rsp]
vmovsd  xmm1, xmm1, xmm0
vmovups XMMWORD PTR [rcx], xmm1
add     rsp, 24
ret     0
Run Code Online (Sandbox Code Playgroud)

注意未对齐的 mov 操作。相反,函数

void test_emplace(std::optional<double> & f){
    f.emplace(42.0);
}
Run Code Online (Sandbox Code Playgroud)

编译为

mov     rax, 4631107791820423168      ; 4045000000000000H
mov     BYTE PTR [rcx+8], 1
mov     QWORD PTR [rcx], rax
ret     0
Run Code Online (Sandbox Code Playgroud)

这个版本更简单、更快。这些是使用 MSVC 19.32 和/O2 /std:c++17 /DNDEBUG /arch:AVX.

clang 14 与-O3 -std=c++17 -DNDEBUG -mavx产生

movabs  rax, 4631107791820423168
mov     qword ptr [rdi], rax
mov     byte ptr [rdi + 8], 1
ret
Run Code Online (Sandbox Code Playgroud)

在这两种情况下。

替换std::optional<double>

struct MyOptional {
    double d;
    bool hasValue; // Required to reproduce the problem
    
    MyOptional(double v) {
        d = v;
    }

    void emplace(double v){
        d = v;
    }
};
Run Code Online (Sandbox Code Playgroud)

表现出同样的问题。显然 MSVC 在增加bool成员方面遇到了一些麻烦。

请参阅godbolt的实例。

为什么 MSVC 会做出这些不一致的举动?即问题不在于为什么它们不对齐而不是对齐(根据这篇文章,这不会改善事情)。但为什么 MSVC 在赋值情况下会产生相当昂贵的指令集呢?这只是 MSVC 的一个错误(或者错过了优化机会)吗?或者我错过了什么?