增加指针比执行" mov [指针+ 1],eax"?更快

时间:2016-01-14 03:47:05

标签: assembly x86

假设我们想在EDI中存储一个字符串。以这种方式存储它会更快吗?

mov byte [edi],0
mov byte [edi+1],1
mov byte [edi+2],2
mov byte [edi+3],3
...

还是这样?

mov byte [edi],0
inc edi
mov byte [edi],1
inc edi
mov byte [edi],2
inc edi
mov byte [edi],3
inc edi
...

有些人可能会在little-endian中提出以下建议:

mov dword [edi],0x3210

或者big-endian中的以下内容:

mov dword [edi],0x0123

但这不是我的问题。我的问题是,增加指针然后执行mov需要更多指令是否更快,或者更快地在每个mov指令中指定添加到EDI指向的偏移地址的数量?如果后者为真,那么在将多少个具有相同数字的mov指令添加到偏移地址之后,是否值得将该数量添加到指针?换句话说,就是这个

mov byte [edi+5],0xFF
mov byte [edi+5],0xFF
mov byte [edi+5],0xFF
mov byte [edi+5],0xFF

比这更快?

add edi,5
mov byte [edi],0xFF
mov byte [edi],0xFF
mov byte [edi],0xFF
mov byte [edi],0xFF

1 个答案:

答案 0 :(得分:9)

有关如何优化asm的文档,请参阅http://agner.org/optimize/以及 wiki中的其他链接。

这样:

mov byte [edi],0
mov byte [edi+1],1
mov byte [edi+2],2
mov byte [edi+3],3
...

会更快。在任何当前的微体系结构AFAIK上使用位移都没有额外的成本,除了额外的一个或四个字节的指令大小。 Two-register addressing modes can be slower on Intel SnB-family CPUs,但固定的位移很好。

像gcc和clang这样的真正的编译器在展开循环时总是使用第一种方法(有效地址中的位移)。

而BTW,0x03020100的4字节存储将比四个单独的单字节存储快4倍。大多数现代CPU都有128b数据路径,因此任何高达128b的单个存储都需要与8b存储相同的执行资源。 AVX 256b商店仍然比英特尔SnB / IvB上的两个128b商店便宜,而英特尔Haswell和后来的商店可以在一次操作中实现256b商店。但是,mov-immediate到内存仅适用于8,16和32位操作数。 mov r64,imm64在64位模式下可用,但没有128或256个mov-immediate指令。

在32位模式下,inc reg的单字节编码可用,inc edi / mov byte [edi],1将具有相同的代码大小,但仍会解码为最近的两倍uop英特尔和AMD微体系结构。如果代码在商店吞吐量或其他方面仍然存在瓶颈,那么这个可能不会出现问题,但是没有办法让它变得更好。 CPU非常复杂,通过计算uops进行简单分析并不总是与实际结果相符,但我认为每个商店之间inc运行更快的可能性极小。你能说的最好的是它可能运行得慢得多。它可能会使用更多的功率/热量,并且对于超线程不太友好。

在64位模式下,inc rdx需要3个字节进行编码:1个REX指定64位操作数大小(而不是默认的32位),1个操作码字节指定int r/m32,1个mod / rm字节指定rdx作为操作数。

因此在64位模式下,存在代码大小的缺点。在这两种情况下,inc解决方案将在高价值的uop-cache(在Intel SnB系列CPU上)使用两倍的条目,该缓存包含融合域uops。

第二部分:

mov byte [edi+5],0xFF
mov byte [edi+5],0xFF
mov byte [edi+5],0xFF
mov byte [edi+5],0xFF

VS

add edi,5            ; 3 bytes to encode.  (2 if it was eax)
mov byte [edi],0xFF  ; saving one byte in each instruction
mov byte [edi],0xFF
mov byte [edi],0xFF
mov byte [edi],0xFF

除非代码大小非常重要(不太可能),或者许多更多商店,否则请使用第一个表单。第二种形式长一个字节,但融合域uop少一个。它将在拥有它们的CPU上使用uop-cache中较少的空间。在较旧的CPU(没有uop缓存)上,指令解码更成为瓶颈,因此可能存在一些情况,其中指令更好地排列成4组是瓶颈。但是,如果你在商店港口遇到瓶颈,情况就不是这样了。