在x86-64中设置和清除零标记(ZF)的最有效方法是什么?
首选不需要已知值的寄存器或根本不需要任何空闲寄存器的方法,但是如果在这些或其他假设成立的情况下可以使用更好的方法,那也值得一提。
答案 0 :(得分:3)
假设您不需要保留其他标志的值,
cmp eax, eax
答案 1 :(得分:3)
这很难。已知的两个不相等的规则之间的cmp
。或cmp reg,imm
具有某些reg无法拥有的任何值。 test r32,imm8
不存在(宽度仅与reg相同),因此体积更大。但如果有一个已知的位总是具有低8的上方设置,这意味着该REG值本身是有保证非零所以可以test reg,reg
。
通常,test reg,reg
适用于任何已知的非0寄存器值,例如一个指针强>
或者cmp reg,1
与任何已知的零寄存器。
我看不到一种在没有错误依赖某些输入reg的情况下在一条指令中创建ZF = 0的方法。如果您不介意破坏寄存器,打破虚假的依赖关系,xor eax,eax
/ neg eax
将在2微秒内解决问题。
or eax, -1
不需要任何寄存器值的先决条件。(错误的依赖关系,但不是真正的依赖关系,因此即使它可能为零,您也可以选择任何寄存器。 )它不一定是-1
,它并没有给您带来任何好处,因此,如果您可以使它变得有用,那就更好了。
<强> or eax,-1
FLAG结果:ZF = 0 PF = 1 SF = 1 CF = 0 = 0(AF =未定义)强>
如果您需要循环执行此操作,则可以明显地为循环设置 ,如果您可以将寄存器专用于非零值以用于test
xor-zeroing(就像使用任何免费寄存器的xor eax,eax
一样)绝对是SnB系列的最有效方法(与2字节nop
相同的费用 ,如果您的免费注册表是r8d..r15且需要REX前缀,则为3个字节):1个前端uop,零个后端uop,并且FLAGS结果在发出的同一周期内即可获得。 (相关的唯一的情况下,前端被停滞,或取决于在其上的微指令发出周期和有没有在RS任何旧的uop。)
<强>标志结果:ZF = 1 PF = 1 SF = 0 CF = 0 = 0(AF =未定义)强>
当然,零或零在所有其他uarch上也非常便宜:没有输入依赖性,并且不需要任何预先存在的寄存器值。 (因此对P6系列寄存器读取档没有帮助)。因此,在最糟糕的情况下,它将与您在其他uarch上可能需要执行的任何其他操作(确实需要执行单元)捆绑在一起。
(在早期的P6家族中,在Pentium M之前,xor
归零不会打破依赖关系;它只会触发特殊的al = eax状态,从而避免了部分寄存器的使用。但是这些CPU都不是x86-64,都是32位。)
这是很常见的,以想为某一个归零寄存器反正,例如作为sub
复制和否定的0 - x
目的地,因此可以通过在需要的地方放置异或零来创建有用的FLAG条件,从而充分利用它。
正如@prl所建议的,cmp same,same
与任何寄存器一起工作都不会干扰值。我怀疑这不是不是特殊情况,因为这种依赖打破了某些CPU上sub same,same
的方式,因此选择一个“冷”寄存器。还是2或3个字节,1个uop。它可以与JCC进行微熔丝连接,但这很愚蠢(除非JCC还是其他条件下的分支目标?)
标记结果:与“异或归零”相同。
缺点:
只是为了好玩,其他作为便宜的替代物包括test al, 0
。 AL为2个字节,任何其他8位寄存器为3或4个字节。 (REX)+操作码+ modrm + imm8。原始寄存器值并不重要,因为imm8
的零个保证reg & 0 = 0
。
如果您碰巧在寄存器中有1
或-1
可以销毁,则32位模式inc
或dec
会将ZF设置为仅1个字节。但在X86-64这是至少2个字节。没有想到在64位模式中的1字节的指令这实际上有效和集FLAGS。
sbb same,same
可以设置ZF = CF(CF留下未修饰),和REG设置为0(CF = 0)或-1(CF = 1)。推土机系列,这对GP寄存器,只有CF不存在相关性,但在其他uarches这不是特殊的套管,并没有对REG假DEP。
要设置ZF = integer_reg,显然是普通的test reg,reg
is your best bet。 (优于and reg,reg
或or reg,reg
,除非你有意重写寄存器,以避免P6寄存器读取档位。)
test
或cmp
的预先存在的寄存器值,则无法实现)。pushf
/ pop rax
是不可怕,但是写标志与popf
是非常缓慢(例如1 / 20C吞吐量SKL)。之所以使用微码,是因为诸如IF之类的标志也存在于EFLAGS中,并且没有纯条件代码版本或用户空间专用的快速路径。 (或者20c 是快速路径。)lahf
(FLAGS-> AH)/ sahf
(AH-> FLAGS)可以是有用的,但作者未命中。 CF具有clc
/ stc
/ cmc
的指令。 (clc
是一样有效XOR调零上SNB-家族。)