13

我对这两个指令有点困惑。首先,让我们丢弃扫描值为 0 且 undefined/bsr 或 bitsize/lzcnt 结果的特殊情况 - 这种差异很明显,不是我的问题的一部分。

让我们取二进制值0001 1111 1111 1111 1111 1111 1111 1111

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

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

lzcnt计数,bsr返回从位 0(即 lsb)的索引或距离。

如果 CPU 上没有可用的 BMI,这两条指令如何相同以及如何lzcnt模拟?或者在 msbbsr的情况下是位 0 ?bsr英特尔规范中的两个“代码操作”也不同,一个从左侧计数或索引,另一个从右侧计数。

也许有人可以对此有所了解,我没有 CPU 没有BMI/lzcnt指令来测试回退到是否bsr具有相同的结果(因为扫描值 0 的特殊情况永远不会发生)。

4

2 回答 2

16

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

于 2014-09-05T10:28:11.713 回答
12

需要明确的是,从to没有工作回退。发生的事情是英特尔使用之前的冗余序列来编码新指令。使用冗余前缀 for通常被定义为被忽略,但需要注意的是,它在未来的 CPU 1上可能会以不同的方式解码。lzcntbsrrep bsrlzcntrepbsr

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

对于 和 的情况,情况更加tzcnt微妙bsf。它使用相同的编码技巧:tzcnt与 具有相同的编码rep bsf,但这里的“后备”主要工作,因为tzcnt返回与bsf除零以外的所有输入相同的值。对于零输入tzcnt返回 32,但 bsf 未定义目标。

但是,您甚至不能真正使用这种回退:如果您从来没有零输入,您最好只使用bsf,节省一个字节并与几十年的 CPU 兼容,如果您确实有零输入,则行为会有所不同。

因此,这种行为可能更好地归类为琐事而不是后备......


1通常这或多或少是深奥的,但是您可以例如使用rep前缀是它们没有功能性影响的地方来延长指令以帮助对齐后续代码而无需插入显式nop指令。鉴于“将来可能会以不同的方式解码”,这在编译可能在任何未来 CPU 上运行的代码时会很危险。

于 2017-04-17T00:47:45.083 回答