为何汇编代码中使用MOVUPS指令处理双精度浮点数?
关于向量化汇编中MOVUPS与MOVUPD的疑问
原C++代码
std::vector<double> a(1000000), b(1000000); // fill a with random doubles for (int i = 0; i < b.size(); ++i) { b[i] = a[i]*a[i] + a[i]; } std::cout << b[0] << std::endl; // make sure the compiler doesn't optimize the loop away
g++ -O3优化后的循环汇编代码
movupd xmm1, XMMWORD PTR[rbp + 0 + rax] movapd xmm0, xmm1 mulpd xmm0, xmm1 addpd xmm0, xmm1 movups XMMWORD PTR[r12 + rax], xmm0 add rax, 16 cmp rax, 8000000 jne.L17
疑问
我能理解到movups XMMWORD PTR[r12 + rax], xmm0这行之前的逻辑,该行是将a[i] * a[i] + a[i]的结果以向量化方式写回内存,但为何此处调用的是单精度的MOVUPS指令而非双精度的MOVUPD指令?
解答
其实MOVUPS和MOVUPD的核心差异仅在于CPU对内存操作的语义标记,而非实际处理的数据精度:
- MOVUPD是针对双精度浮点数的非对齐加载/存储指令,MOVUPS是针对单精度浮点数的非对齐加载/存储指令
- 但两者都是操作16字节的内存块(刚好容纳两个
double或四个float),硬件执行时的底层操作完全一致 - GCC这类编译器会在非对齐存储场景下优先选择MOVUPS,原因是它的指令编码长度更短(MOVUPD需要额外的前缀字节),能略微减小代码体积,同时完全不影响执行效率
- 这里存储的是两个
double值,但指令仅负责把XMM寄存器的16字节内容原封不动写入内存,不管数据类型是什么,用MOVUPS完全没问题——CPU不会因为指令后缀而改变数据的存储方式
内容的提问来源于stack exchange,提问作者Urwald
相关产品推荐
相关产品推荐

