代码之家  ›  专栏  ›  技术社区  ›  Petr Skocik

测试$x,%dil与测试$x、%ddi

  •  1
  • Petr Skocik  · 技术社区  · 2 年前

    我想测试寄存器中的一位,即中第二低的一位 %rdi 。 天真地我会写 test $2, %edi (或 and $2, %edi --我不知道 and ing会更好——此时寄存器的其余部分无关紧要)。

    我检查了clang和gcc生成的内容(对于一个假人 void TEST(long X){ if(X&2) abort(); } ),尽管他们似乎也有类似的分歧 test ,他们都同意通过 %dil %edi

    这可能是什么原因?

    1 回复  |  直到 2 年前
        1
  •  3
  •   Peter Cordes    2 年前

    除了代码大小之外,这两种方式都具有相同的性能;读取低8位部分寄存器不会有任何损失,不像 test $2, %bh 例如读取高8寄存器具有 extra latency on Haswell and later 但仍然可以节省代码大小,并且不会影响前端吞吐量。

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

    由于 x 在测试后不需要,你实际上可以使用 and $imm8, %edi (3字节)以节省代码大小,但是 and / jnz 无法在AMD CPU或Sandybridge之前的英特尔上进行宏融合,所以编译器更喜欢只写FLAGS。我怀疑没有人实现使用的窥视孔优化 而不是 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