计算臂组件中的位数

时间:2016-03-13 23:48:42

标签: assembly arm bit-manipulation bits

我找到了以下代码,用于在最小数量的指令中计算Arm组件中4字节整数的位:

  ;R0 - value
  ;R1 = number of ones
  ;Uses R0-R1
  ;81 cycles worst case, 4 cycles best case, exit when r1=0

mov    r1,r0,lsr #31
loop   movs     r0,r0,lsl #2    
       adc  r1,r1,r0,lsr #31    
       bne  loop
       mov  pc,r14

您能解释一下这里的算法是什么吗?虽然我知道所有指令都做了什么,但我无法理解。

1 个答案:

答案 0 :(得分:2)

       mov    r1,r0,lsr #31        @ start with r1 = the high bit of r0 (right shift by 31 bits)
loop   movs     r0,r0,lsl #2       @ left shift r0 by 2, and set flags on the result
       adc  r1,r1,r0,lsr #31
       bne  loop                   @ loop if r0 is non-zero (testing flags set by movs)

add-with-carry是一个巧妙的技巧:r0 >> 31是高位,进位标志是由movs r0,r0,lsl #2移出的位(我假设ARM以这种方式工作x86,否则算法没有意义。)

因此每次迭代会向popcnt总计增加2位:高位,最后一位向外移位。

这是不是 popcnt的最快方式。

上一个问题:Fastest way to count number of 1s in a register, ARM assembly解决了这个问题,一个答案使用vcnt.8 d0, d0,然后是四个8位计数的水平和。其中没有一个答案提到这个两位一次循环。

即使没有LUT(例如8位LUT来查找每个字节的计数)或专用的popcnt指令,也存在bithacks,like this one from Sean Anderson's collection

v = v - ((v >> 1) & 0x55555555);                    // reuse input as temporary
v = (v & 0x33333333) + ((v >> 2) & 0x33333333);     // temp
c = ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; // count

恒定时间没有分支,但确实需要几个32位常量(每个需要两条指令才能进入ARM上的regs)

相关问题