在我查看这个问题之后,我在除法时在生成的代码中发现了 MULQ。
完整的代码将一个大的二进制数转换为十亿的块,以便可以轻松地将其转换为字符串。
C++ 代码:
for_each(TempVec.rbegin(), TempVec.rend(), [&](Short & Num){
Remainder <<= 32;
Remainder += Num;
Num = Remainder / 1000000000;
Remainder %= 1000000000;//equivalent to Remainder %= DecimalConvert
});
优化的生成程序集
00007FF7715B18E8 lea r9,[rsi-4]
00007FF7715B18EC mov r13,12E0BE826D694B2Fh
00007FF7715B18F6 nop word ptr [rax+rax]
00007FF7715B1900 shl r8,20h
00007FF7715B1904 mov eax,dword ptr [r9]
00007FF7715B1907 add r8,rax
00007FF7715B190A mov rax,r13
00007FF7715B190D mul rax,r8
00007FF7715B1910 mov rcx,r8
00007FF7715B1913 sub rcx,rdx
00007FF7715B1916 shr rcx,1
00007FF7715B1919 add rcx,rdx
00007FF7715B191C shr rcx,1Dh
00007FF7715B1920 imul rax,rcx,3B9ACA00h
00007FF7715B1927 sub r8,rax
00007FF7715B192A mov dword ptr [r9],ecx
00007FF7715B192D lea r9,[r9-4]
00007FF7715B1931 lea rax,[r9+4]
00007FF7715B1935 cmp rax,r14
00007FF7715B1938 jne NumToString+0D0h (07FF7715B1900h)
注意 MUL 指令 5 行以下。
我知道,这个生成的代码非常不直观,实际上它看起来与编译后的代码完全不同,但 DIV 非常慢,对于 32 位 div 约 25 个周期,根据现代 PC 上的 chart 与 MUL 或 IMUL 相比,约 75 个周期(大约 3 或 4 个周期),因此即使您必须添加各种额外的指令,尝试摆脱 DIV 也是有意义的。
我不完全理解这里的优化,但是如果您想了解使用编译时间和乘法来除常量的理性和数学解释,请参阅paper。
这是编译器利用完整的 64 x 64 位未截断乘法的性能和能力而不向 c++ 编码器显示任何迹象的示例。