来自 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 提供的东西,并且由于 imulmul 更易于使用,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.

相关文章