我有一些C ++代码正在使用MSVC编译器v14.24编译为以下程序集:
00007FF798252D4C vmulsd xmm1,xmm1,xmm7
00007FF798252D50 vcvttsd2si rcx,xmm1
00007FF798252D55 vmulsd xmm1,xmm7,mmword ptr [rbx+28h]
00007FF798252D5A mov ecx,ecx
00007FF798252D5C imul rdx,rcx,0BB8h
00007FF798252D63 vcvttsd2si rcx,xmm1
00007FF798252D68 mov ecx,ecx
00007FF798252D6A add rdx,rcx
00007FF798252D6D add rdx,rdx
00007FF798252D70 cmp byte ptr [r14+rdx*8+8],0
00007FF798252D76 je applyActionMovements+15Dh (07FF798252D8Dh)
如您所见,编译器添加了两个
mov ecx,ecx
对我来说没有任何意义的指令,因为它们将数据从同一寄存器移入和移入同一寄存器。
我缺少什么吗?
这里是一个小型的Godbolt复制器:https://godbolt.org/z/UFo2qe
int arr[4000][3000];
inline int foo(double a, double b) {
return arr[static_cast<unsigned int>(a * 100)][static_cast<unsigned int>(b * 100)];
}
int bar(double a, double b) {
if (foo(a, b)) {
return 0;
}
return 1;
}
这是将ECX零扩展到RCX的低效率方法。更有效的方法是将mov
放入另一个寄存器so mov-elimination could work。
重复项:
但是您的特定测试用例需要零扩展是出于一个不太明显的原因:
x86仅在FP和signed整数之间进行转换(直到AVX512)。通过执行FP-> unsigned int
,然后将低32位用作int64_t
,可以在x86-64上有效地实现FP-> unsigned int
。
此序列正在执行的操作:
vcvttsd2si rcx,xmm1 ; double -> int64_t, unsigned int result in ECX
mov ecx,ecx ; zero-extend to promote unsigned to ptrdiff_t for indexing
add rdx,rcx ; 64-bit integer math on the zero-extended result