关于bsr和lzcnt的困惑

hop*_*rpl 8 x86 assembly bmi

我对这两个指令都有点困惑.首先,让我们丢弃的特殊情况下,当扫描的值是0和未定义/ BSR或bitsize/lzcnt结果 - 这种差异是明显的,而不是我的问题的一部分.

我们来看二进制值 0001 1111 1111 1111 1111 1111 1111 1111

根据英特尔的规格,结果为lzcnt3

根据英特尔的规格,结果为bsr28

lzcntcount,bsr从位0返回索引或距离(即lsb).

两个指令如何相同,如何在CPU上没有可用的BMI的情况下lzcnt进行仿真bsr?或者bsr在msb的情况下是0位?英特尔规范中的"代码操作"也不同,一个是左边的计数或索引,另一个来自右边.

也许有人可以提供一些线索这光,我没有CPU无BMI/lzcnt指令测试,如果退回到bsr同样的结果作品(如值为0的特殊情况下扫描从未发生过).

Pau*_*l R 11

LZCNT给出前导零位的数量.BSR给出最重要的1位的位索引.因此,对于非零情况,它们有效地做同样的事情,除了结果的解释不同.因此,您可以BSR从31中减去结果,以获得与之相同的行为LZCNT,即LZCNT == (31 - BSR).

  • 现在我明白了.在没有BMI的CPU上,lzcnt指令不会#ud,而是执行bsr.与lzcnt不同的结果.我在这里误解了这个规范.忽略扫描值为零时的特殊情况,tzcnt和bsf表现相同,但lzcnt和bsr不相同.许多网页都表示两者都是.这显然是不正确的,也是我混淆的原因.谢谢你清理它. (6认同)
  • 顺便说一句(也可以),你也可以把它实现为`LZCNT = BSR ^ 31`,它可以保存一条指令 (6认同)

Bee*_*ope 11

需要明确的是,没有工作的后备lzcntbsr.发生的事情是英特尔使用先前的冗余序列rep bsr来编码新lzcnt指令.使用redudant rep前缀bsr通常被定义为被忽略,但需要注意的是它可能在未来的CPU 1上以不同方式解码.

因此,如果您碰巧lzcnt在不支持它的CPU上执行,它将执行为bsr.当然,这种回退并不是完全有意的,它给出了错误的结果(正如Paul R指出他们看同一位但报告的方式不同):这只是新指令编码方式和无意义的结果rep前缀由先前的CPU处理.因此,世界后备几乎完全不适合lzcntbsr.

这种情况对的情况下,更微妙tzcntbsf.它使用相同的编码技巧:tzcnt具有相同的编码rep bsf,但这里"回退" 主要起作用,因为tzcnt返回与bsf除零之外的所有输入相同的值.对于零输入,tzcnt返回32,但bsf使目标未定义.

你甚至不能真正使用这个后备:如果你从来没有零输入你也可以使用bsf,保存一个字节并兼容几十年的CPU,如果你没有输入,行为就会有所不同.

所以这种行为可能更好地被归类为琐事而不是后备 ......


1通常情况下,这或多或少都是esoterica,但是你可以使用rep前缀,它们没有功能效果来延长指令以帮助对齐后续代码而不插入显式nop指令.鉴于"将来可能会有不同的解码",在编译可能在未来的CPU上运行的代码时,这将是危险的.