MSVC为std::optional赋值生成冗余复杂指令的原因咨询
MSVC下std::optional赋值操作性能异常问题
在针对std::optional<double>相关代码做基准测试时,我发现MSVC生成的代码运行速度约为clang、gcc同逻辑代码的50%。经过代码精简复现,确认MSVC为std::optional::operator=生成的代码存在明显异常,而使用std::optional::emplace()接口时不会出现该性能下降问题。
复现案例
赋值实现版本
测试函数代码如下:
void test_assign(std::optional<double> & f){ f = std::optional{42.0}; }
基于MSVC 19.32版本,使用/O2 /std:c++17 /DNDEBUG /arch:AVX选项编译后生成的汇编代码为:
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
可以看到这段代码不仅额外申请了栈空间,还使用了非对齐128位移动操作,指令冗余度很高。
emplace实现版本
对应的emplace写法测试函数:
void test_emplace(std::optional<double> & f){ f.emplace(42.0); }
相同编译选项下生成的汇编代码为:
mov rax, 4631107791820423168 ; 对应常量42.0的二进制表示 mov BYTE PTR [rcx+8], 1 mov QWORD PTR [rcx], rax ret 0
该版本没有额外栈开销,指令简洁,运行效率远高于赋值写法的生成代码。
其他编译器对照
使用clang 14搭配-O3 -std=c++17 -DNDEBUG -mavx选项编译时,两种写法生成的代码完全一致,均为最优指令序列:
movabs rax, 4631107791820423168 mov qword ptr [rdi], rax mov byte ptr [rdi + 8], 1 ret
将std::optional<double>替换为如下自定义结构体,同样可以复现相同问题:
struct MyOptional { double d; bool hasValue; // 复现问题必须的成员 MyOptional(double v) { d = v; } void emplace(double v){ d = v; } };
由此可见问题出在MSVC对携带额外bool标记成员的结构体赋值操作的处理逻辑上。
核心疑问
需要说明的是,此处并非质疑非对齐指令的性能:已有验证表明在该场景下对齐移动指令并不会带来额外性能提升。核心疑问点在于:
- 为什么MSVC在处理赋值场景时,会生成开销显著更高的冗余指令序列?
- 该现象属于MSVC遗漏的优化bug,还是存在我未考虑到的底层机制约束?
内容的提问来源于stack exchange,提问作者Sedenion
相关产品推荐
相关产品推荐

