Assembly 使用CMP reg,0 vs或reg,reg测试寄存器是否为零?
使用以下代码是否存在执行速度差异:Assembly 使用CMP reg,0 vs或reg,reg测试寄存器是否为零?,assembly,optimization,x86,micro-optimization,Assembly,Optimization,X86,Micro Optimization,使用以下代码是否存在执行速度差异: cmp al, 0 je done 以及以下各项: or al, al jz done 我知道JE和JZ指令是相同的,而且使用OR可以将大小提高一个字节。然而,我也关心代码速度。逻辑运算符似乎比SUB或CMP更快,但我只是想确定一下。这可能是大小和速度之间的折衷,也可能是双赢的(当然代码会更加不透明)。这取决于确切的代码顺序、具体的CPU以及其他因素 或al,al,的主要问题是它“修改”EAX,这意味着以某种方式使用EAX的后续指令可能会暂停,直到该指令完
cmp al, 0
je done
以及以下各项:
or al, al
jz done
我知道JE和JZ指令是相同的,而且使用OR可以将大小提高一个字节。然而,我也关心代码速度。逻辑运算符似乎比SUB或CMP更快,但我只是想确定一下。这可能是大小和速度之间的折衷,也可能是双赢的(当然代码会更加不透明)。这取决于确切的代码顺序、具体的CPU以及其他因素
或al,al,
的主要问题是它“修改”EAX
,这意味着以某种方式使用EAX
的后续指令可能会暂停,直到该指令完成。请注意,条件分支(jz
)也取决于指令,但CPU制造商做了大量工作(分支预测和推测执行)来缓解这一问题。还要注意的是,理论上,CPU制造商可以设计一种CPU来识别EAX
在这种特定情况下没有改变,但是有数百种这种特殊情况,识别其中大多数的好处太少了
cmpal,0
的主要问题是它稍大,这可能意味着指令提取速度较慢/缓存压力更大,并且(如果是循环)可能意味着代码不再适合某些CPU的“循环缓冲区”
正如杰斯特在评论中指出的那样<代码>测试al,al避免了这两个问题-它小于cmp al,0
,并且不修改EAX
当然(取决于具体的顺序),
AL
中的值一定来自某个地方,如果它来自适当设置标志的指令,则可能会修改代码,以避免以后使用另一条指令再次设置标志。是,性能会有所不同
比较寄存器与零的最佳选择是。它设置标志的方式与cmp reg,0
设置标志的方式相同,并且至少与任何其他方式一样快1,代码大小更小
(更好的情况是,设置reg
的指令已经适当地设置了ZF
,因此您可以直接进行分支、setcc或cmovcc。例如,通常看起来像dec ecx
/jnz.loop\u top
。大多数x86整数指令“根据结果设置标志”,如果输出为0
,则包括ZF=1)
或reg,reg
无法在任何现有x86 CPU上将值写入单个uop,并为以后读取reg
的任何内容增加延迟,因为它会将值重写到寄存器中cmp
的缺点通常只是代码大小
脚注1:有一个可能的例外,但仅适用于过时的P6系列CPU(从Intel到Nehalem,2011年被Sandybridge系列取代)。请参阅下面关于通过将相同的值重写到寄存器中来避免寄存器读取暂停的内容。其他微体系结构家族没有这样的停顿,而且或比测试
没有任何好处
/和reg,reg
/或reg,reg
的结果是
在所有情况下都与相同(AF除外),因为:
CF=OF=0
因为测试/和总是这样做,而对于cmp
,因为减去零不能溢出或进位
ZF
,SF
,PF
根据结果设置(即reg
):reg®
用于测试,或reg-0
用于cmp
(AF
在test
之后未定义,但根据cmp
的结果设置。我忽略它,因为它非常模糊:读取AF的唯一指令是ASCII调整压缩BCD指令,如和lahf
/pushf
)
当然,您可以检查reg==0
(ZF)以外的条件,例如通过查看SF来测试负符号整数。但有趣的事实是:jl
,即签名小于条件,在cmp
之后,在某些CPU上比js
更有效。由于=0,它们在与零比较后是等效的,因此l
条件(SF!=OF
)等效于SF
每个可以测试/JL的CPU也可以宏融合测试/JS,甚至Core2。但是在CMP byte[mem]之后,0
始终使用JL not JS在符号位上进行分支,因为核心2无法对其进行宏融合。(至少在32位模式下;内核2在64位模式下根本无法进行宏融合)
签署的比较条件还可以让你做一些事情,比如,查看ZF以及SF=的
test
比cmp
短,立即数为0,在所有情况下,除了cmp al、imm8
特殊情况(仍为两个字节)
即使如此,test
出于宏融合的原因(在Core2上使用jle
和类似的工具)还是比较可取的,因为完全没有立即数可能有助于uop缓存密度的提高,因为如果另一条指令需要更多的空间(SnB系列),它会留下一个插槽供另一条指令借用
将test/jcc宏融合到解码器中的单个uop中
Intel和AMD CPU中的解码器可以在内部将带有一些条件分支指令的宏融合到单个比较和分支操作中。这样,在进行宏融合时,每个周期的最大吞吐量为5条指令,而在不进行宏融合时为4条指令。(适用于Core2之后的英特尔CPU。)
最近的英特尔CPU可以宏融合一些指令(如和和添加/子),以及测试和cmp
,但或不是其中之一。AMD CPU只能合并