最小的代码大小循环来计算寄存器中的位(递减另一个寄存器)?



我需要在 8086* 中编写以下 C 代码片段 组装尽可能短(小于 10 字节),但我只能设法用 12 个字节写它。

有什么想法吗?

while (ax) {
bx--;
ax &= ax-1;
}

您尝试的操作称为人口计数,即计算寄存器中的设置位数。

在较新的CPU中实际上只有一个指令。而且由于瞄准原始 8086 在 2018 年真的不是那么有趣。

简单的答案是:

f3 0f b8 c0             popcnt eax,eax
29 c3                   sub    ebx,eax 

6 字节,如果您愿意在ebx中允许正值并且可以假设/确保 ebx 开始时为零,则可以减少到 4。

请注意,没有必要使用 16 位寄存器,已经很多年没有了。

如果您希望代码在原始 8086(不支持popcnt)上运行,则必须保留循环。

以下非常简单的代码需要 12 个字节:

85 c0                   test   ax,ax          ;is AX zero?
74 08                   je     <done>         ;yes, bail out
<loop>:
4b                      dec    bx             ;bx--
89 c1                   mov    cx,ax
49                      dec    cx             ;cx = ax - 1
21 c8                   and    ax,cx          ;ax = ax & (ax-1) 
75 f8                   jne    <loop>         ;repeat until done
<done>:

您可以通过以效率稍低的方式计算位数来将其减少到 9 个字节。在这里,我们简单地测试所有 16 位 ax。

<loop>:
d1 e0                   shl    ax,1       ;MSb to carry flag (CF)
83 db 00                sbb    bx,0       ;bx=bx-CF
85 c0                   test   ax,ax      ;is AX zero?
75 f9                   jnz    <loop>     ;if not then loop until done

诀窍是理解代码的作用,然后以不同的方式重新表述。

相关内容

  • 没有找到相关文章

最新更新