设置和清除x86的零标志

时间:2019-02-03 02:04:37

标签: performance assembly x86 x86-64 micro-optimization

在x86-64中设置和清除零标记(ZF)的最有效方法是什么?

首选不需要已知值的寄存器或根本不需要任何空闲寄存器的方法,但是如果在这些或其他假设成立的情况下可以使用更好的方法,那也值得一提。

2 个答案:

答案 0 :(得分:3)

假设您不需要保留其他标志的值,

cmp eax, eax

答案 1 :(得分:3)

ZF = 0

这很难。已知的两个不相等的规则之间的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


ZF = 1

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还是其他条件下的分支目标?)

标记结果:与“异或归零”相同。

缺点:

  • (可能)错误的依赖关系
  • 在P6系列有助于寄存器读的摊位,所以挑一个寒冷注册你已经在附近的指令读取。
  • 需要SnB系列的后端执行单元

只是为了好玩,其他作为便宜的替代物包括test al, 0。 AL为2个字节,任何其他8位寄存器为3或4个字节。 (REX)+操作码+ modrm + imm8。原始寄存器值并不重要,因为imm8的零个保证reg & 0 = 0


如果您碰巧在寄存器中有1-1可以销毁,则32位模式incdec会将ZF设置为仅1个字节。但在X86-64这是至少2个字节。没有想到在64位模式中的1字节的指令这实际上有效和集FLAGS。


ZF = CF

sbb same,same可以设置ZF = CF(CF留下未修饰),和REG设置为0(CF = 0)或-1(CF = 1)。推土机系列,这对GP寄存器,只有CF不存在相关性,但在其他uarches这不是特殊的套管,并没有对REG假DEP。


ZF = bool(整数寄存器)

要设置ZF = integer_reg,显然是普通的test reg,reg is your best bet。 (优于and reg,regor reg,reg,除非你有意重写寄存器,以避免P6寄存器读取档位。)


其它标志条件:

CF具有clc / stc / cmc的指令。 (clc是一样有效XOR调零上SNB-家族。)