Spa*_*ain 16 c++ compiler-construction x86 assembly visual-studio
Visual Studio或Visual C++ Express的现代(2008/2010)版本是否会在编译代码中生成x86 MUL指令(无符号乘法)?我似乎无法找到或设想它们出现在编译代码中的示例,即使使用无符号类型也是如此.
如果VS不使用MUL进行编译,是否有理由说明原因?
Tho*_*nin 26
imul(signed)和mul(unsigned)都有一个操作数形式edx:eax = eax * src.即32x32b => 64b全乘(或64x64b => 128b).
286添加了一个imul dest(reg), src(reg/mem), immediate表单,386添加了一个imul r32, r/m32表单,这两个表单只计算结果的下半部分.(来自x86标签wiki的链接).
当将两个32位值相乘时,无论您认为值是有符号还是无符号,结果的最低有效32位都是相同的.换句话说,有符号和无符号乘法之间的区别变得很明显只有当你看结果的"上"半部,其中一个操作数imul/ mul放入edx两个三个操作imul使行不通的.因此,多操作数形式imul可以用于有符号和无符号值,并且英特尔也不需要添加新形式mul.(它们可能使多操作数mul成为同义词imul,但这会使反汇编输出与源不匹配.)
在C中,算术运算的结果与操作数具有相同的类型(在窄整数类型的整数提升之后).如果你将两个相乘int,你会得到一个int,而不是long long:"上半部分"不会被保留.因此,C编译器只需要imul提供,并且因为imul它比mulC编译器更容易使用,imul以避免需要mov指令来获取数据eax.
作为第二步,由于C编译器使用imul了大量的多操作数形式,因此英特尔和AMD投入了尽可能快的努力.它只写一个输出寄存器,e/rdx:e/rax因此CPU可以比单操作数形式更容易地优化它.这imul更具吸引力.
在实现大数字运算时,mul/ 的单操作数形式imul很有用.在C中,在32位模式下,您应该mul通过将unsigned long long值相乘来获得一些调用.但是,根据编译器和操作系统,这些mul操作码可能隐藏在某些专用功能中,因此您不一定会看到它们.在64位模式下,long long只有64位,而不是128位,编译器只会使用imul.
x86上有三种不同类型的乘法指令.第一个是MUL reg,它EAX通过reg 执行无符号乘法并将(64位)结果放入EDX:EAX.第二个是IMUL reg,使用带符号的乘法也是如此.第三种类型是IMUL reg1, reg2(将reg1与reg2相乘并将32位结果存储到reg1中)或IMUL reg1, reg2, imm(将reg2与imm相乘并将32位结果存储到reg1中).
由于在C中,两个32位值的乘法产生32位结果,编译器通常使用第三种类型(符号无关紧要,低32位在有符号和无符号32x32乘法之间一致).VC++将生成的"长乘"版本MUL/ IMUL如果你实际使用的全64位的结果,例如在这里:
unsigned long long prod(unsigned int a, unsigned int b)
{
return (unsigned long long) a * b;
}
Run Code Online (Sandbox Code Playgroud)
2操作数(和3操作数)版本IMUL比单操作数版本更快,因为它们不会产生完整的64位结果.宽乘数大而慢; 如果需要,可以更容易地构建一个较小的乘法器并使用Microcode合成长乘法.此外,MUL/IMUL写入两个寄存器,通常通过在内部将其分解为多个指令来解决 - 指令重新排序硬件更容易跟踪每个写入一个寄存器的两个相关指令(大多数x86指令在内部看起来像而不是跟踪一个写两个的指令.