计数leading/trailingones/zeros的效率有什么区别吗?

Is there any difference in the efficiency of counting leading/trailing ones/zeros?

我正在设计一个带前缀的可变长度整数。

Rust 有计算前导和尾随 1 和 0 的方法:https://doc.rust-lang.org/std/primitive.u64.html#method.leading_zeros

这些方法在x86_64、arm32和arm64上的效率有什么区别吗?

例如如果计算尾随 1 比尾随零更快,我将使用 xxxx0111 而不是 xxxx1000 作为长度编码字节(在本例中为三个后续字节)。

在所有 3 个 ISA:x86*、ARM、AArch64 上,计算尾随零比尾随零更快。它们都提供像 x86 bsf (find the lowest set bit) or x86 BMI1 tzcnt(尾随零计数)这样的零计数指令。在运行时变量中计算 leading/trailing 个需要否定输入。

ARM / AArch64 提供前导零计数,但尾随零的最佳选择是 rbit / clz 进行位反转(自 ARMv6t2 或 ARMv7 起)。 https://godbolt.org/z/Yr7eac。在此之前,编译器必须用 x & -x 隔离最低设置位,计算它的前导零,然后取 31-clz(x&-x).


(在 x86 上,使用 BMI1 计算前导零最有效。没有它,bsr 可以为您提供最高设置位的位置,因此编译器需要 31-bsr(x) 来实现 clz。On AMD CPU,bsf / bsr 比它们的 tzcnt / lzcnt 对应物慢得多,因此如果可能的话,最好使用 -march=native 或任何 Rust 等价物进行编译。)