- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我编译了以下程序:
#include <stdint.h>
uint64_t usquare(uint32_t x) {
return (uint64_t)x * (uint64_t)x;
}
0: 89 f8 mov eax,edi
2: 48 0f af c0 imul rax,rax
6: c3 ret
imul
是乘法指令
签名 数字。为什么它被
gcc
使用然后?
uint64_t
时 assembly 是类似的:
0: 48 0f af ff imul rdi,rdi
4: 48 89 f8 mov rax,rdi
7: c3 ret
最佳答案
TL:DR:因为当我们不关心上半部分(即输出仅与 2 个输入一样宽)时,这是获得正确结果的更快方法。更灵活的寄存器分配,而不是强制使用 RAX 和 RDX。
如果它不能用于此,英特尔可能会添加 mul
的两个操作数版本。以及。但这不是必需的,正如这个答案所解释的那样。
WARNING This answer is long!
... and it's full of unneeded explanations - but I have always wanted to write something more lengthy about the multiplication.
imul
的两种形式
imul
有两种形式:完整形式和部分形式。
imul ax ;16x16->32, Result is dx:ax
imul rax ;64x64->128, Result is rdx:rax
imul ax, ax ;16x16->16, Lower WORD of the result is ax
imul rax, rax ;64x64->64, Lower QWORD of the result is rax
imul r64, r/m64, imm8/32
,它允许您在一条指令中复制并乘以一个常量。它没有隐式操作数,并且同样不会在任何地方写入高半,所以我们可以处理它等同于
imul r64, r/m64
dst *= src
形式。)
imul
对比
mul
imul
的区别和
mul
在于操作数的转换方式。
mul
指令只是用零填充上部 - 它零扩展。
imul
指令复制高位(左起第一个) - 这称为符号扩展,它具有转换
two's complement 的有趣特性。将 n 位的有符号数转换为具有相同符号和模数的 2 n 位有符号数(即它做正确的事情,留给读者找到零扩展情况的反例)。
How mul extends How imul extends
and operand and operand
+----+ +----+ +----+ +----+
|0...| |1...| |0...| |1...|
+----+ +----+ +----+ +----+
+----+----+ +----+----+ +----+----+ +----+----+
|0000|0...| |0000|1...| |0000|0...| |1111|1...|
+----+----+ +----+----+ +----+----+ +----+----+
imul
的区别和
mul
仅从第 (n+1) 位开始可见。
imul
的部分形式的结果与
mul
相同.
imul
退出?
mul
的单操作数版本和
imul
. x86 的更高版本添加了更灵活的二和三操作数版本
imul
仅适用于您不想要双宽结果的常见用例。
imul r32
在英特尔 CPU 上是 3 个 uops:大概是一个乘法,另一个将 64 位产品分成两半并写入低半部分,另一个对高半部分做同样的事情。
imul r64
是 2 uop;大概 128 位结果来自已经分成 64 位一半的乘法器。
mul
仍然只以非常古老的单操作数形式存在,固定寄存器作为接口(interface)的一部分。
imul
根据有符号乘法设置标志 - 如果部分结果丢弃了任何重要信息(技术条件是:部分结果的符号扩展与完整结果不同),则设置 CF 和 OF,例如在溢出的情况下。
mul
的原因。 ,否则这将是一个非常合适的名称。
#include <stdint.h>
uint64_t foo(uint32_t a)
{
return a*(uint64_t)a;
}
imul
因为一个
unint64_t
适合一个寄存器,因此 64×64→64 乘法可用作
imul <reg64>, <reg64>
foo(unsigned int):
mov eax, edi ;edi = a
imul rax, rax ;64x64->64
ret
imul
的这种乘法。 .
imul <reg32>
或
imul <reg32>, <reg32>, <reg32>
是必要的,但这会产生完整的结果!并且完整的有符号结果通常不等于完整的无符号结果。
mul
:
foo(unsigned int):
mov eax, DWORD PTR [esp+4]
mul eax
ret
You probably means that this is only a way of thinking about it, conceptually. The processor does not necessarily do a full 128-bit multiplication when you use the 64x64 -> 64 form. Indeed, the truncated form takes only 1 uop on recent Intel, but the full form takes 2 uops, so some extra work is being done
Similarly the sign extension may happens "conceptually", but probably not in hardware. They won't have the extra wires and transistors just to do the sign or zero extension, which would add a lot of bulk to an already huge multiplier, but will use some other tricks to do the multiplication "as if" that had happened.
关于assembly - 为什么 imul 用于乘以无符号数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42587607/
我是一名优秀的程序员,十分优秀!