- 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的最佳选择。没有其他方法比它有任何优势,并且它比任何其他方法都至少具有某些优势。英特尔和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位操作数大小。因此,即使由于将r8..r15清零而仍需要REX前缀时,也应使用xor r10d,r10d
,而不是xor r10,r10
。
GP整数示例:
xor eax, eax ; RAX = 0. Including AL=0 etc.
xor r10d, r10d ; R10 = 0
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 everywhere else 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 al, al ; false dep on some CPUs, not a zeroing idiom. Use xor eax,eax
mov al, 0 ; only 2 bytes, and probably better than xor al,al *if* you need to leave the rest of EAX/RAX 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)或任何未来向量扩展置零的不错选择。但是,
vpxor ymm, ymm, ymm
不需要花费任何额外的字节来编码,并且在Intel上运行相同,但是在Zen2之前(2微秒)在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.
k0..7
掩码寄存器。 SSE / AVX
vpcmpeqd
在许多方面都是断断续续的(尽管仍然需要uop来写1),但是ZMM regs的AVX512
vpternlogd
甚至还没有断断续续。在循环内部,请考虑从另一个寄存器复制,而不是使用ALU uop(特别是使用AVX512)重新创建一个。
sub same,same
一样将
xor
识别为清零习惯,但是所有识别任何清零习惯的CPU都可以识别
xor
。只需使用
xor
,就不必担心哪个CPU可以识别哪个清零习惯。
xor
(与
mov reg, 0
不同,它是一种公认的归零惯用法)具有一些明显和微妙的优点(摘要列表,然后我将对其进行扩展):
mov reg,0
的代码大小。 (所有CPU)
mov r32, imm32
),因此,通过调度程序的完美决策(实际上并不总是这样),即使HSW即使它们始终保持每个时钟4 oups都需要ALU执行端口。
xor
是在寄存器重命名阶段处理的,不需要执行单元(未融合域中的零uops),但错过了它仍然存在的事实融合域中的一个uop。现代的Intel CPU可以每个时钟发出和退出4个融合域uops。这就是每个时钟限制4个零的来源。寄存器重命名硬件的复杂性增加只是将设计的宽度限制为4的原因之一。(Bruce写了一些非常出色的博客文章,例如他强烈推荐的
FP math and x87 / SSE / rounding issues系列文章)。
mov immediate
在与
xor
相同的EX0 / EX1整数执行端口上运行。
mov reg,reg
也可以在AGU0 / 1上运行,但这仅用于寄存器复制,而不能用于立即数设置。所以AFAIK,在AMD上,
xor
优于
mov
的唯一优势是较短的编码。它也可能节省物理寄存器资源,但是我还没有看到任何测试。
xor
会将寄存器标记为上半部分为零,因此
xor eax, eax
/
inc al
/
inc eax
避免了IvB之前的CPU常见的部分寄存器损失。即使没有
xor
,仅当高8位(
AH
)被修改然后读取整个寄存器时,IvB才需要合并uop,Haswell甚至将其删除。
; 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
mov reg, 0
不被视为归零习惯。如果他们花晶体管在以后的CPU上检测它,我会感到非常惊讶。
xor
设置标志,这意味着在测试条件时必须小心。不幸的是,由于
setcc
仅适用于8位目标地址,因此您通常需要注意避免部分注册处罚。
setcc r/m
,并且谓词编码在r / m字段的源寄存器3位字段中,那就太好了。 (其他一些单操作数指令将它们用作操作码位的方式)。但是他们没有这样做,这对x86-32毫无帮助。
xor
/设置标志/
setcc
/读取完整寄存器:
...
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
cmp/jle
,
sete
,或者您没有备用寄存器,或者您想将
xor
完全排除在未使用的代码路径之外。
mov reg, 0
/
setcc
在较旧的Intel CPU上将有很大的损失,而在较新的Intel上仍然会更糟。
setcc
/
movzx r32, r8
可能是Intel P6&SnB系列的最佳选择。这应该比在异或归零后重复测试更好。 (甚至不考虑
sahf
/
lahf
或
pushf
/
popf
)。 IvB可以消除
movzx r32, r8
(即通过寄存器重命名来处理它,而无需执行单元或等待时间,例如异或归零)。 Haswell及其以后仅消除常规的
mov
指令,因此
movzx
采用执行单元并且具有非零延迟,这使得test /
setcc
/
movzx
比
xor
/ test /
setcc
差,但仍然至少与test /
mov r,0
/
setcc
一样好(在较旧的CPU上更好)。
setcc
/
movzx
是不好的,因为它们不会分别跟踪子寄存器的dep。寄存器的旧值将有错误的查询。如果不选择
mov reg, 0
/ test /
setcc
,则使用
xor
/
setcc
进行调零/打破依赖关系可能是最佳选择。
setcc
的输出宽于8位,则不需要将任何内容归零。但是,如果选择的寄存器最近是长依赖性链的一部分,请当心对除P6 / SnB以外的CPU的虚假依赖性。 (并且要小心,如果您调用的函数可能会保存/恢复您正在使用的寄存器的一部分,则会导致部分注册表停止或额外的uop。)
and
在我所知道的任何CPU上都没有特殊情况,因为它与旧值无关,因此不会破坏依赖链。与
xor
相比,它没有优点,但有很多缺点。
sub same,same
在某些但不是所有CPU上,而
xor same,same
在所有CPU上都可以识别。)
mov
确实打破了对寄存器的旧值(与源值无关,是否为零,因为
mov
是这样工作的)。
xor
仅在src和dest是同一寄存器的特殊情况下才断开依赖关系链,这就是为什么
mov
不在特殊识别的依赖破坏者列表中的原因。 (此外,因为它不被视为归零习惯,还有其他好处。)
xor
-zeroing视为依赖破坏者,只是为了避免部分寄存器停顿而将其作为归零习惯,因此在某些情况下值得使用依次
mov
和
xor
置零以中断dep,然后再次置零+将内部标记位设置为高位为零,所以EAX = AX = AL。 (请参阅Agner Fog的Example 6.17。在他的microarch pdf文件中。他说这也适用于P2,P3甚至是(早期?)PM。
A comment on the linked blog post说只有PPro对此进行了监督,但是我已经在Katmai上进行了测试。 PIII和@Fanael在奔腾M上进行了测试,我们都发现它并没有打破对延迟绑定的
imul
链的依赖性。不幸的是,这证实了Agner Fog的结果。)
mov
设置为零以避免触及这些标志。但是,避免使用破坏性标志是不使用
xor
的唯一明智的原因。
关于performance - 在x86汇编中将寄存器设置为零的最佳方法是什么:xor,mov或and?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46481490/
这个问题在这里已经有了答案: How to initialize var? (11 个答案) 关闭 8 年前。 我想给一个变量赋初值 null,并在下一个 if-else block 中赋值,但是编
我正在使用 TypeScript 3.8 编写 JS 和 TS 混合的代码。我写了以下行: export * as Easing from './easing'; 应该是 fair game在 Typ
我需要将 R 代码中的“/”更改为“\”。我有这样的事情: tmp <- paste(getwd(),"tmp.xls",sep="/") 所以我的 tmp是 c:/Study/tmp.xls 我希望
我有个问题。例如我有这个: id truth count 1 1 1 2 1 2 3 0 0 4 1 1 5 1 2 6 1
我正在尝试使用“IN”和“=”来查找一些 bean。我目前正在使用此代码: $ids = array(1,2,3,4); $user = 1; $things = R::find( 'thing'
是否可以在 Xcode 中部署到其他人的手机上?我没有 iPhone,但我想测试我在 friend 手机上制作的应用程序。在我支付 99 美元之前,我想确保这不会造成麻烦。 谢谢。 最佳答案 不会有任
我试图得到一个非常大的数字(超过 unsigned long long int )。所以我把它作为一个字符串,然后一个数字一个数字地转换成整数并使用它。 #include #include int
我在 Rust 中有 C 语言库的绑定(bind),但它们并不完整。 在 C 代码中,我定义了一个简化的宏,如下所示: #define MY_MACROS1(PTR) (((my_struct1
我正在努力解决这个问题。 http://jsfiddle.net/yhcqfy44/ 动画应该自动相对于 滚动到顶部每次出现滚动条时的高度。 我已经写了这个,但没有运气: var hheight =
我正在处理一个将数字作为字符串返回的 JSON API。例如 "12" ,但是,该字段值也可以是非数字的,例如:"-" . 我已将 JSON 数据解析为映射,我想将此字段提取为 elixir 中的整数
我正在尝试编写一个类,将.wav文件转换为.aiff文件作为项目的一部分。 我遇到了几个库Alvas.Audio(http://alvas.net/alvas.audio,overview.aspx)
我想在 Lucene 中将像“New York”这样的“复合词”索引为单个术语,而不是像“new”、“york”那样。这样,如果有人搜索“new place”,则包含“new york”的文档将不会匹
我希望这个解释能让我更好地了解使用宏的优点。 最佳答案 在函数中,所有参数在调用之前都会被评估。 这意味着 or 作为函数不能是惰性的,而宏可以将 or 重写为 if 语句,该语句仅在以下情况下计算分
我有一些看起来像这样的 XML foo ]]> (注意 > 登录 "> foo")和 XSLT 样式表 当我运行xsltproc stylesheet.xs
当我尝试将 Any 转换为 List 时,如下面的示例所示,我得到“Unchecked cast: Any!”到列表'警告。有没有解决此类问题的方法? val x: List = objectOfTy
我正在使用 Python 开发一个简单的爬虫。目的是创建一个 sitemap.xml。(你可以在这里找到真正的 alpha 版本:http://code.google.com/p/sitemappy/
我想知道在 VBScript 中是否可以在多行中中断 If 语句。喜欢: If (UCase(Trim(objSheet.Cells(i, a).Value)) = "YES") Or _ (UCas
for (String item : someList) { System.out.println(item); } 使用“do while”是否等效? 谢谢。 最佳答案 如果列表为空,f
这个问题已经有答案了: 已关闭10 年前。 Possible Duplicate: Split string with delimiters in C 在 C 中将“,”分隔的列表拆分为数组的最佳方法
我有一个如下所示的字符数组: [0, 10, 20, 30, 670] 如何将此字符串转换为整数数组? 这是我的数组 int i=0; size_t dim = 1; char* array = (c
我是一名优秀的程序员,十分优秀!