来自 VS 2008/2010 的 x86 MUL 指令
Visual Studio 或 Visual C++ Express 的现代 (2008/2010) 咒语是否会在编译代码中生成 x86 MUL 指令(无符号乘法)?我似乎无法找到或设计它们出现在编译代码中的示例,即使使用无符号类型也是如此.
Will modern (2008/2010) incantations of Visual Studio or Visual C++ Express produce x86 MUL instructions (unsigned multiply) in the compiled code? I cannot seem to find or contrive an example where they appear in compiled code, even when using unsigned types.
如果 VS 不使用 MUL 编译,有什么理由吗?
If VS does not compile using MUL, is there a rationale why?
推荐答案
imul
(有符号)和 mul
(无符号)都有一个单操作数形式代码>edx:eax = eax * src.即 32x32b => 64b 全乘(或 64x64b => 128b).
imul
(signed) and mul
(unsigned) both have a one-operand form that does edx:eax = eax * src
. i.e. a 32x32b => 64b full multiply (or 64x64b => 128b).
186 添加了一个 imul dest(reg), src(reg/mem),immediate
形式,386增加了一个imul r32, r/m32
形式,两者都只计算结果的下半部分.(根据 NASM 的附录 B,另见 x86 标签维基)
186 added an imul dest(reg), src(reg/mem), immediate
form, and 386 added an imul r32, r/m32
form, both of which which only compute the lower half of the result. (According to NASM's appendix B, see also the x86 tag wiki)
当两个 32 位值相乘时,结果的最低有效 32 位是相同的,无论您认为这些值是有符号还是无符号.换句话说,有符号乘法和无符号乘法之间的区别只有在您查看结果的上"半部分时才会变得明显,即一个操作数 imul
/mul
放入 edx
和两个或三个操作数 imul
无处可放.因此,imul
的多操作数形式可用于有符号和无符号值,并且英特尔也无需添加新的 mul
形式.(他们可以使多操作数 mul
成为 imul
的同义词,但这会使反汇编输出与源不匹配.)
When multiplying two 32-bit values, the least significant 32 bits of the result are the same, whether you consider the values to be signed or unsigned. In other words, the difference between a signed and an unsigned multiply becomes apparent only if you look at the "upper" half of the result, which one-operand imul
/mul
puts in edx
and two or three operand imul
puts nowhere. Thus, the multi-operand forms of imul
can be used on signed and unsigned values, and there was no need for Intel to add new forms of mul
as well. (They could have made multi-operand mul
a synonym for imul
, but that would make disassembly output not match the source.)
在 C 中,算术运算的结果与操作数具有相同的类型(在窄整数类型的整数提升之后).如果将两个 int
相乘,将得到一个 int
,而不是 long long
:上半部分"没有保留.因此,C 编译器只需要 imul
提供的东西,并且由于 imul
比 mul
更易于使用,C 编译器使用 imul
以避免需要 mov
指令将数据输入/输出 eax
.
In C, results of arithmetic operations have the same type as the operands (after integer promotion for narrow integer types). If you multiply two int
together, you get an int
, not a long long
: the "upper half" is not retained. Hence, the C compiler only needs what imul
provides, and since imul
is easier to use than mul
, the C compiler uses imul
to avoid needing mov
instructions to get data into / out of eax
.
作为第二步,由于 C 编译器经常使用 imul
的多操作数形式,因此 Intel 和 AMD 投入精力使其尽可能快.它只写入一个输出寄存器,而不是 e/rdx:e/rax
,因此 CPU 可以比单操作数形式更容易优化它.这使得 imul
更具吸引力.
As a second step, since C compilers use the multiple-operand form of imul
a lot, Intel and AMD invest effort into making it as fast as possible. It only writes one output register, not e/rdx:e/rax
, so it was possible for CPUs to optimize it more easily than the one-operand form. This makes imul
even more attractive.
mul
/imul
的单操作数形式在实现大数算法时很有用.在 C 中,在 32 位模式下,您应该通过将 unsigned long long
值相乘来获得一些 mul
调用.但是,根据编译器和操作系统的不同,那些 mul
操作码可能隐藏在某些专用函数中,因此您不一定会看到它们.在64位模式下,long long
只有64位,不是128位,编译器会简单地使用imul
.
The one-operand form of mul
/imul
is useful when implementing big number arithmetic. In C, in 32-bit mode, you should get some mul
invocations by multiplying unsigned long long
values together. But, depending on the compiler and OS, those mul
opcodes may be hidden in some dedicated function, so you will not necessarily see them. In 64-bit mode, long long
has only 64 bits, not 128, and the compiler will simply use imul
.
相关文章