- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
以下所有指令都做同样的事情:将 %eax
设置为零。哪种方式是最佳的(需要最少的机器周期)?
xorl %eax, %eax
mov $0, %eax
andl $0, %eax
最佳答案
TL;DR 摘要 : xor same, same
是所有 CPU 的最佳选择 0x2518411921没有其他方法比它有任何优势,它至少比任何其他方法都有一些优势。它是 Intel 和 AMD 官方推荐的,以及编译器的作用。在 64 位模式下,仍然使用 xor r32, r32
,因为 writing a 32-bit reg zeros the upper 32 。 xor r64, r64
是一个字节的浪费,因为它需要一个REX前缀。
更糟糕的是,Silvermont 只将 xor r32,r32
识别为 dep-breaking,而不是 64 位操作数大小。因此 即使仍然需要 REX 前缀,因为您将 r8..r15 归零,请使用 xor r10d,r10d
,而不是 xor r10,r10
0x251819212134。
GP-整数示例:
xor eax, eax ; RAX = 0. Including AL=0 etc.
xor r10d, r10d ; R10 = 0. Still prefer 32-bit operand-size.
xor edx, edx ; RDX = 0
; small code-size alternative: cdq ; zero RDX if EAX is already zero
; SUB-OPTIMAL
xor rax,rax ; waste of a REX prefix, and extra slow on Silvermont
xor r10,r10 ; bad on Silvermont (not dep breaking), same as r10d on other CPUs because a REX prefix is still needed for r10d or r10.
mov eax, 0 ; doesn't touch FLAGS, but not faster and takes more bytes
and eax, 0 ; false dependency. (Microbenchmark experiments might want this)
sub eax, eax ; same as xor on most but not all CPUs; bad on Silvermont for example.
xor cl, cl ; false dep on some CPUs, not a zeroing idiom. Use xor ecx,ecx
mov cl, 0 ; only 2 bytes, and probably better than xor cl,cl *if* you need to leave the rest of ECX/RCX unmodified
pxor xmm, xmm
完成。这通常是 gcc 所做的(甚至在使用 FP 指令之前)。xorps xmm, xmm
是有道理的。它比 pxor
短一个字节,但 xorps
在 Intel Nehalem 上需要执行端口 5,而 pxor
可以在任何端口(0/1/5)上运行。 (Nehalem 的整数和 FP 之间的 2c 旁路延迟延迟通常不相关,因为乱序执行通常可以将其隐藏在新依赖链的开始处)。xorps
和 pxor
的处理方式相同(作为向量整数指令)。vpxor xmm, xmm, xmm
是归零 YMM(AVX1/AVX2) 或 ZMM(AVX512) 或任何 future 向量扩展的不错选择。不过,vpxor ymm, ymm, ymm
不需要任何额外的字节来编码,并且在 Intel 上运行相同,但在 Zen2(2 uop)之前在 AMD 上速度较慢。 AVX512 ZMM 归零需要额外的字节(对于 EVEX 前缀),因此应该首选 XMM 或 YMM 归零。 # Good:
xorps xmm0, xmm0 ; smallest code size (for non-AVX)
pxor xmm0, xmm0 ; costs an extra byte, runs on any port on Nehalem.
xorps xmm15, xmm15 ; Needs a REX prefix but that's unavoidable if you need to use high registers without AVX. Code-size is the only penalty.
# Good with AVX:
vpxor xmm0, xmm0, xmm0 ; zeros X/Y/ZMM0
vpxor xmm15, xmm0, xmm0 ; zeros X/Y/ZMM15, still only 2-byte VEX prefix
#sub-optimal AVX
vpxor xmm15, xmm15, xmm15 ; 3-byte VEX prefix because of high source reg
vpxor ymm0, ymm0, ymm0 ; decodes to 2 uops on AMD before Zen2
# Good with AVX512
vpxor xmm15, xmm0, xmm0 ; zero ZMM15 using an AVX1-encoded instruction (2-byte VEX prefix).
vpxord xmm30, xmm30, xmm30 ; EVEX is unavoidable when zeroing zmm16..31, but still prefer XMM or YMM for fewer uops on probable future AMD. May be worth using only high regs to avoid needing vzeroupper in short functions.
# Good with AVX512 *without* AVX512VL (e.g. KNL / Xeon Phi)
vpxord zmm30, zmm30, zmm30 ; Without AVX512VL you have to use a 512-bit instruction.
# sub-optimal with AVX512 (even without AVX512VL)
vpxord zmm0, zmm0, zmm0 ; EVEX prefix (4 bytes), and a 512-bit uop. Use AVX1 vpxor xmm0, xmm0, xmm0 even on KNL to save code size.
见 Is vxorps-zeroing on AMD Jaguar/Bulldozer/Zen faster with xmm registers than ymm? 和k0..7
掩码寄存器。 SSE/AVX vpcmpeqd
对许多人来说是破坏性的(尽管仍然需要一个 uop 来写 1s),但用于 ZMM regs 的 AVX512 vpternlogd
甚至不是破坏性的。在循环内部考虑从另一个寄存器复制而不是使用 ALU uop 重新创建寄存器,尤其是使用 AVX512。sub same,same
识别为归零习语,如 xor
,但 识别任何归零习语的所有 CPU 都识别 0x25181223181342121243131342121只需使用 xor
这样您就不必担心哪个 CPU 识别哪个归零习语。xor
(作为公认的归零习语,与 xor
不同)有一些明显和一些微妙的优势(总结列表,然后我将扩展这些):mov reg, 0
更小的代码大小。 (所有 CPU) mov reg,0
,因此通过调度程序的完美决策(这在实践中并不总是发生),即使它们都需要,HSW 仍然可以维持每个时钟 4 uop ALU 执行端口。mov r32, imm32
在寄存器重命名阶段处理而无需执行单元(未融合域中的零 uop),但错过了它仍然是一个 uop 的事实融合域。现代英特尔 CPU 每个时钟可以发出和停用 4 个融合域 uops。这就是每个时钟限制 4 个零的来源。寄存器重命名硬件的复杂性增加只是将设计宽度限制为 4 的原因之一。(Bruce 写了一些非常出色的博客文章,比如他关于 FP math and x87 / SSE / rounding issues 的系列文章,我强烈推荐)。xor
在与 mov immediate
相同的 EX0/EX1 整数执行端口上运行。 xor
也可以在 AGU0/1 上运行,但这仅用于寄存器复制,不适用于立即数设置。因此,AFAIK,在 AMD 上,mov reg,reg
比 xor
的唯一优势是更短的编码。它也可能节省物理寄存器资源,但我还没有看到任何测试。mov
将 将寄存器标记为将上半部分归零 ,所以 xor
/xor eax, eax
/0x251818431234 部分 CPU 避免了/0x2518431234134133434334334333433433433434334343343434343434343434334343434343434343434343434343434343434343343343334即使没有 inc al
,当修改高 8 位( inc eax
)然后读取整个寄存器时,IvB 只需要合并 uop,Haswell 甚至将其删除。The processor recognizes the XOR of a register with itself as settingit to zero. A special tag in the register remembers that the high partof the register is zero so that EAX = AL. This tag is remembered evenin a loop:
; Example 7.9. Partial register problem avoided in loop
xor eax, eax
mov ecx, 100
LL:
mov al, [esi]
mov [edi], eax ; No extra uop
inc esi
add edi, 4
dec ecx
jnz LL
(from pg82): The processor remembers that the upper 24 bits of EAX are zero as long asyou don't get an interrupt, misprediction, or other serializing event.
xor
不被认为是归零习惯用法,至少在 PIII 或 PM 等早期 P6 设计中是这样。如果他们在后来的 CPU 上使用晶体管来检测它,我会感到非常惊讶。AH
设置标志 ,这意味着您在测试条件时必须小心。不幸的是,由于 mov reg, 0
仅适用于 8 位目标 ,因此您通常需要注意避免部分寄存器惩罚。xor
,并将谓词编码在 r/m 字段的源寄存器 3 位字段(其他一些单操作数指令将它们用作操作码位的方式)。但是他们没有这样做,无论如何这对 x86-32 没有帮助。setcc
/set flags/setcc r/m
/read full register:...
call some_func
xor ecx,ecx ; zero *before* the test
test eax,eax
setnz cl ; cl = (some_func() != 0)
add ebx, ecx ; no partial-register penalty here
这在所有 CPU 上都具有最佳性能(没有停顿、合并 uops 或错误依赖)。xor
、 setcc
,并且您要么没有备用寄存器,要么希望将 cmp/jle
完全排除在未采用的代码路径之外。sete
/xor
会对较旧的 Intel CPU 产生重大影响,但在较新的 Intel CPU 上仍然会更糟。mov reg, 0
/setcc
可能是英特尔 P6 和 SnB 系列的最佳选择,如果您不能在标志设置指令之前进行异或零。这应该比在异或归零后重复测试要好。 (甚至不要考虑 setcc
/movzx r32, r8
或 sahf
/lahf
)。 IvB 可以消除 pushf
(即通过寄存器重命名处理它,没有执行单元或延迟,如异或归零)。 Haswell的,后来只有消除常规popf
指令,因此movzx r32, r8
需要一个执行单元,具有非零延迟,使得测试/mov
/movzx
比setcc
/测试/movzx
差,但至少还要好,因为测试/xor
/setcc
(和在较旧的 CPU 上要好得多)。mov r,0
/setcc
而不先归零是不好的,因为它们不会单独跟踪子寄存器的 deps。寄存器的旧值会有一个错误的依赖。当 setcc
/test/movzx
不是一个选项时,使用 mov reg, 0
/setcc
进行归零/依赖破坏可能是最好的选择。xor
的输出宽于 8 位,则不需要将任何内容归零。但是,如果您选择的寄存器最近是长依赖链的一部分,请注意对 P6/SnB 以外的 CPU 的错误依赖。 (如果您调用的函数可能会保存/恢复您正在使用的寄存器的一部分,请注意导致部分 reg 停顿或额外的 uop。)setcc
立即为零 不是特殊情况,独立于我所知道的任何 CPU 上的旧值,因此它不会破坏依赖链。它与 setcc
相比没有任何优势,但有许多缺点。and
是一些但不是所有的CPU,而xor
上大家公认的。)sub same,same
确实打破了依赖链上的寄存器的旧值(无论源值如何,零与否,因为这就是 xor same,same
的工作方式)。 mov
仅在 src 和 dest 是同一个寄存器的特殊情况下破坏依赖链,这就是为什么 mov
被排除在特别识别的依赖破坏者列表之外的原因。 (另外,因为它不被认为是归零习语,还有其他好处。)xor
-zeroing 识别为依赖项破坏者,只是为了避免部分寄存器停顿 0x2513411921 的目的的归零习语,所以在某些情况下值得mov
和 xor
都归零以破坏 dep 然后再次归零 + 设置内部标记位,即高位为零,因此 EAX=AX=AL。mov
链的依赖。不幸的是,这证实了 Agner Fog 的结果。xor
归零以避免触及标志,只要您不引入代码大小以外的性能问题。避免破坏标志是不使用 imul
的唯一合理原因,但有时如果您有备用寄存器,您可以在设置标志之前进行异或零。mov
- xor
之前的零比 mov
之后的延迟更好(英特尔除外,当您可以选择不同的寄存器时),但代码大小更糟。
关于performance - 在 x86 程序集 : xor, mov 或 and 中将寄存器设置为零的最佳方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33666617/
XOR 的各个部分如何命名? A xor B = C A和B叫什么 对于分部,它是: A / B = C A = 除数,B = 被除数,C = 商 对于和(和 XOR 与和一样对称)它是 A + B
我在算法方面遇到了问题。 我有一个用于 IO 的字节,可以使用称为 XorAndXor 的方法设置其中的某些位。该算法的工作原理如下: newValue = (((currentValue XOR x
我很惊讶地看到一个 BPMN 图,其中一个异或决策(“XOR-Split”)用相同的网关符号“关闭”。 我真的想知道证明这种方法合理的原因是什么。在我看来,这是多余的。 事实似乎是,XOR-Join
我在查看 XOR 链接列表的实现时多次遇到这段代码,但似乎没有一个人正确解释了这一行(或者也许我错过了一些东西) - struct node* XOR (struct node *a, struct
这应该是一个简单的问题。我是 Coq 的新手。 我想在 Coq 中定义exclusive or in Coq(据我所知,这不是预定义的)。重要的部分是允许多个命题(例如 Xor A B C D)。 我
我试图记住数学是如何计算出来的,以计算循环冗余检查中 XOR 算法的剩余部分,以验证网络消息的剩余位。 我不应该扔掉那本教科书。 这在代码中很容易完成,但是如何手工完成呢? 我知道它看起来有点像标准除
给定一个数字 N 和一个整数数组(所有整数都小于 2^15)。 (A 是数组 100000 的大小) 从数组中找到 N 和整数的最大 XOR 值。 Q是查询次数(50000)和开始,停止是数组中的范围
这更像是一个有趣的问题。我正在研究 SC61860 CPU,它是 8 位 CPU,用于 1987 年的 Sharp PC-1360 掌上电脑(也用于 PC-1401 和 1403)。它的指令集实际上并
我正在尝试在 c 中进行某种异或文件加密,并在 javascript 中进行解密(使用 this 作为基础,现在我遇到了以下问题: 例如我想在 C 中执行 73^122,结果是 57,但在 javas
我的任务是计算数组中字节的异或和: X = char1 XOR char2 XOR char3 ... charN; 我正在尝试将其并行化,改为对 __m128 进行异或运算。这应该提供加速因子 4。
我有一系列错误或 View ( Seq[Xor[Error,View]] ) 我想将其映射到第一个错误(如果有)或 View 序列的异或 ( Xor[Error, Seq[View]] ) 或者可能只
这是我想做的一个例子:假设我有 5 个类,我想表达这样的约束,即我们可以将类“B”或/和“C”的实例链接到“A”,如果是这样,我们就不能拥有其他任何东西,如果我们不这样做没有这些类的任何实例,我们只能
因此我们可以确定异或距离度量是一个真实的度量(它是对称的,满足三角不等式等) 在阅读 Kademlia 及其 k-buckets 之前,我在想每个节点都会简单地找到自己的 id 并存储其最近的 k 个
该函数用于计算一个32位整数的异或 int xor32int(int x, int y) { int res = 0; // Initialize result // Assuming
我是加密新手,我正在尝试解释以下代码。即, 是什么?什么意思? 我有一个 secret_key key 。我也有一个 unique_id。我使用下面的代码创建垫。 pad = hmac.new(sec
我正在尝试将一些 javascript 代码复制到 python 中,由于某种原因,javascript 中的 XOR 运算符 (^) 给我的值与 python 中的 XOR 运算符 (^) 不同。我
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
这个问题在这里已经有了答案: Does Typescript support mutually exclusive types? (7 个答案) 关闭 3 年前。 我怎么说我希望一个接口(inter
我有一些未知的 C++ 代码是在发布版本中编译的,因此对其进行了优化。我正在努力解决的问题是: xor al, al add esp, 8 cmp byte ptr [ebp+
我得到了以下卡诺图,但我仍然无法从每个表中计算 XOR 的表达式。 Table 1 -------
我是一名优秀的程序员,十分优秀!