我对这两个指令都有点困惑。首先让我们在扫描值为0且未定义/ bsr或bitsize / lzcnt结果时丢弃特殊情况 - 这种差异很明显,不属于我的问题。
我们取二进制值0001 1111 1111 1111 1111 1111 1111 1111
根据英特尔的规范,lzcnt
的结果为3
根据英特尔的规范,bsr
的结果为28
lzcnt
计数,bsr
返回第0位的索引或距离(即lsb)。
两个指令如何相同?如果CPU上没有可用的BMI,如何将lzcnt
模拟为bsr
?或者bsr
msb的位是0?英特尔规范中的“代码操作”也有所不同,一个是左边的计数或索引,另一个来自右边。
也许有人可以对此有所了解,我没有没有BMI/lzcnt
指令的CPU来测试bsr
的回退是否与相同的结果一起工作(因为值0的特殊情况从不扫描发生)。
答案 0 :(得分:9)
LZCNT
给出前导零位的数量。 BSR
给出最重要的1位的位索引。因此,对于非零情况,它们有效地做同样的事情,除了结果的解释不同。因此,您只需从31中减去BSR
结果即可获得与LZCNT
相同的行为,即LZCNT == (31 - BSR)
。
答案 1 :(得分:8)
要明确的是,lzcnt
到bsr
没有工作后备。发生的事情是英特尔使用先前的冗余序列rep bsr
来编码新的lzcnt
指令。对rep
使用减量bsr
前缀通常被定义为被忽略,但需要注意的是,它可能会在未来的CPU 1 上进行不同的解码。
因此,如果您碰巧在不支持它的CPU上执行lzcnt
,它将以bsr
执行。当然,这个后备并不是完全有意的,它给出了错误的结果(正如Paul R指出他们看同一位但报告的方式不同):这只是方式的结果新指令已编码,以前的CPU如何处理无意义的rep
前缀。因此,对于lzcnt
和bsr
来说,世界后备几乎完全不合适。
tzcnt
和bsf
的情况更为微妙。它使用相同的编码技巧:tzcnt
具有与rep bsf
相同的编码,但此处“后备”主要用于,因为tzcnt
返回的值与bsf
相同{1}}表示除零之外的所有输入。对于零输入,tzcnt
返回32,但是bsf使目标未定义。
你甚至不能真正使用这个后备:如果你从来没有零输入你也可以使用bsf
,保存一个字节并兼容几十年的CPU,如果你有零输入行为不同。
因此,行为可能更好地归类为琐事而不是后备 ......
1 通常这或多或少都是esoterica,但你可以使用例如rep
前缀,它们没有功能效果来延长指令以帮助对齐后续代码而不插入显式nop
指示。鉴于“可能在将来以不同方式解码”,在编译可能在未来任何CPU上运行的代码时,这将是危险的。