assembly 测试$x,%dil与测试$x,%edi

2fjabf4q  于 2022-12-19  发布在  其他
关注(0)|答案(1)|浏览(120)

我想测试一个寄存器中的一个位,即%rdi中倒数第二低的位,我会很天真地写test $2, %edi(或者and $2, %edi--我不知道and ing是否更好--寄存器的其余部分在这里是无关紧要的)。
我检查了clang和gcc生成了什么(对于一个虚拟的void TEST(long X){ if(X&2) abort(); }),虽然它们似乎类似地在testand上分裂,但它们都同意通过%dil而不是%edi寻址寄存器,这让我感到惊讶。
这可能是什么原因呢?

f5emj3cl

f5emj3cl1#

两种方法除了代码长度外具有相同的性能;与例如test $2, %bh不同,阅读低8位部分寄存器从不具有任何损失;阅读高8位寄存器具有extra latency on Haswell and later,但仍能节省代码大小,并且不会损害前端吞吐量。

没有test $sign_extended_imm8, r/m32,因此使用8位操作数大小可以节省代码大小,即使它需要雷克斯前缀来编码DIL。(https://www.felixcloutier.com/x86/test

由于在测试之后不需要x的值,因此实际上可以使用and $imm8, %edi(3字节)以保存代码大小,但and/jnz无法在AMD CPU上进行宏融合,或在Sandybridge之前无法在Intel上进行宏融合,所以编译器更喜欢只写FLAGS。我想没有人s实现了窥视孔优化,即在以后不需要寄存器时使用and而不是test-mtune=sandybridge

0:   f7 c7 02 00 00 00       test   edi,0x2    # imm32 = 2
   6:   40 f6 c7 02             test   dil,0x2    # REX prefix with no bits set
   a:   f6 c7 02                test   bh,0x2     # same byte without REX

   d:   83 e7 02                and    edi,0x2
  10:   40 80 e7 02             and    dil,0x2
  14:   80 e7 02                and    bh,0x2

  17:   0f ba e7 02             bt     edi,0x2    # can't macro-fuse with JCC

相关问题