Assembly 为什么在这个代码段中16位寄存器与BSR指令一起使用?

Assembly 为什么在这个代码段中16位寄存器与BSR指令一起使用?,assembly,x86,bit-manipulation,Assembly,X86,Bit Manipulation,在中有一个函数find_maskwidth(),它基本上检测表示itemCountdictinct值所需的位数: unsigned int find_maskwidth( unsigned int itemCount ) { unsigned int maskWidth, count = itemCount; __asm { mov eax, count mov ecx, 0 mov maskWidth, ecx d

在中有一个函数
find_maskwidth()
,它基本上检测表示
itemCount
dictinct值所需的位数:

unsigned int find_maskwidth( unsigned int itemCount )
{
    unsigned int maskWidth, count = itemCount;
    __asm {
        mov eax, count
        mov ecx, 0
        mov maskWidth, ecx
        dec eax
        bsr cx, ax
        jz next
        inc cx
        mov maskWidth, ecx
    next:
    }
    return maskWidth; 
} 

问题是为什么他们使用
ax
cx
寄存器而不是
eax
ecx

我只能猜测他们只希望处理不超过16位的字段。由于它被用来确定可用于报告数据包中的内核或逻辑处理器数量等信息的位数,因此可能需要一段时间才能溢出到65535以上

我只是希望有人不要为了更广泛的目的而使用这个例程


仅供参考-如果您想在不使用x86汇编的情况下执行类似操作(尽管我猜出于本文的目的,不可移植几乎是既定的),您已经介绍过了。

我只能猜测,他们希望只处理不超过16位的字段。由于它被用来确定可用于报告数据包中的内核或逻辑处理器数量等信息的位数,因此可能需要一段时间才能溢出到65535以上

我只是希望有人不要为了更广泛的目的而使用这个例程


仅供参考-如果您想在不使用x86汇编的情况下完成类似的操作(尽管我想出于本文的目的,不可移植几乎是既定的),您已经介绍过了。

我想原始数据只有16位宽。由于cx得到的是一个位数,所以无论如何,它不可能大于一个非常小的位数


值得注意的是,16位和32位ia32指令的操作码在一个级别上除了前缀字节外是相同的,因此根据您所处的模式,发出全32或全16位指令更有效。我想这就是你问这个问题的原因…

我猜原始数据只有16位宽。由于cx得到的是一个位数,所以无论如何,它不可能大于一个非常小的位数


值得注意的是,16位和32位ia32指令的操作码在一个级别上除了前缀字节外是相同的,因此根据您所处的模式,发出全32或全16位指令更有效。我想这就是你问这个问题的原因…

鉴于这段代码的编写非常糟糕(例如,绝对不需要maskWidth和count变量——除了让代码变得混乱之外),我想你可以放心,这只是另一件“坏事”在这段代码中。

鉴于这段代码编写得非常糟糕(例如,绝对不需要maskWidth和count变量——除了使代码混乱之外),我想您可以放心,这只是这段代码中的另一件“坏事”。

例程基本上确定二进制(以2为基数)itemCount的对数

如果itemCount>2^16,它将提供完全错误的值。它并没有饱和或其他什么,它只是完全错了。输入参数是“unsigned int”,这使得它更加错误。因此,它将在超过65536个核上停止工作


我的猜测是,英特尔公司有人挖掘了一些非常古老的代码,可以追溯到16位时代,但没有真正理解它,并使用了它,因为65536将永远足够了,正如640k内存将永远足够,或者两位数的年份数字将足够,直到时间结束。

例程基本上确定itemCount的二进制(以2为底)对数

如果itemCount>2^16,它将提供完全错误的值。它并没有饱和或其他什么,它只是完全错了。输入参数是“unsigned int”,这使得它更加错误。因此,它将在超过65536个核上停止工作


我的猜测是,英特尔公司有人挖掘了一些非常古老的代码,可以追溯到16位时代,但没有真正理解它,并使用了它,因为65536将永远足够了,确切地说,640k内存将永远足够,或者两位数的年份数字将足够,直到时间结束。

我会说,这是因为这段代码的作者可能真的不知道他在做什么:-)。这些指令的16位版本更长,而不是更快。事实上,它们可能会导致使用ECX的下一条指令(即MOV)出现部分寄存器暂停

还要注意,跳转可以安全地提前一条指令移动(在DEC之后),因为DEC在其输出为零时已经设置了ZF。这可以稍微简化代码

这就是我编写代码片段的方式:

  mov eax, [count]
  xor ecx, ecx
  dec eax
  jz next
  bsr ecx, eax
  inc ecx
next:
  mov [maskWidth], ecx
此外,这里进行汇编的动机似乎是使用BSR指令,它在C语言或库中没有任何等价的指令。为此,可以使用编译器特定的内在函数来避免使用汇编。虽然这些本质上是不可移植的,但内联程序集也不是

在GCC中,等效函数如下所示:

unsigned int find_maskwidth(unsigned int itemCount)
{
   if(itemCount <= 1)
      return 0;
   else
      return 32 - __builtin_clz(itemCount - 1);
}
unsigned int find\u maskwidth(unsigned int itemCount)
{

如果(itemCount我会说这是因为这段代码的作者可能并不真正知道他在做什么:-)。这些指令的16位版本更长,而且不会更快。事实上,它们可能会导致下一条使用ECX的指令(即MOV)上的部分寄存器暂停

还要注意,跳转可以安全地提前一条指令(在DEC之后),因为DEC已经在其输出为零时设置了ZF。这可以稍微简化代码

这就是我编写代码片段的方式:

  mov eax, [count]
  xor ecx, ecx
  dec eax
  jz next
  bsr ecx, eax
  inc ecx
next:
  mov [maskWidth], ecx
此外,这里跳转到汇编的动机似乎是使用BSR指令,它在C语言或库中没有任何等价的指令