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