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

Isa*_*hen 4 x86 assembly

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

mov byte [edi],0
mov byte [edi+1],1
mov byte [edi+2],2
mov byte [edi+3],3
...
Run Code Online (Sandbox Code Playgroud)

还是这样?

mov byte [edi],0
inc edi
mov byte [edi],1
inc edi
mov byte [edi],2
inc edi
mov byte [edi],3
inc edi
...
Run Code Online (Sandbox Code Playgroud)

有些人可能会在小端看到以下内容:

mov dword [edi],0x3210
Run Code Online (Sandbox Code Playgroud)

或者以下是big-endian:

mov dword [edi],0x0123
Run Code Online (Sandbox Code Playgroud)

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

mov byte [edi+5],0xFF
mov byte [edi+5],0xFF
mov byte [edi+5],0xFF
mov byte [edi+5],0xFF
Run Code Online (Sandbox Code Playgroud)

比这更快?

add edi,5
mov byte [edi],0xFF
mov byte [edi],0xFF
mov byte [edi],0xFF
mov byte [edi],0xFF
Run Code Online (Sandbox Code Playgroud)

Pet*_*des 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
...
Run Code Online (Sandbox Code Playgroud)

会更快.在任何当前的微体系结构AFAIK上使用位移都没有额外的成本,除了额外的一个或四个字节的指令大小. 在Intel SnB系列CPU上,双寄存器寻址模式可能较慢,但固定位移很好.

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


而BTW,一个4字节的存储,0x03020100几乎比四个独立的单字节存储快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将具有相同的代码大小,但仍然在最近的英特尔和AMD微体系结构上解码为两倍的uop.如果代码在商店吞吐量或其他方面仍然存在瓶颈,这可能不是问题,但是没有办法让它变得更好.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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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