具有多个加号的跳转或在跳转之前执行加号(性能)

问题描述 投票:0回答:1

在汇编中,如果我有一个JUMP表,其地址超过2000个标签:

.TABLE:
     DD .case0
     DD .case1
     DD .case2
     DD .case3
     DD .case4
     ...
     ...
     ...
     DD .case2000

哪种方法更适合跳转:

方式1:

mov    r12d, .TABLE    ; r12d or any other registers
mov    ebx, [r13d]     ; r13d holds the id of case * 4 so we don't need to '4 * ebx'
add    ebx, r12d       ; ebx = address for Jumping
jmp    ebx

方式2 :(与方式1相同,但'add ebx, r12d'被删除并更改为'jmp [ebx+r12d]'

mov    r12d, .TABLE    ; r12d or any other registers
mov    ebx, [r13d]     ; r13d holds the id of case * 4 so we don't need to '4 * ebx'
jmp    [ebx+r12d]

方式3:

mov    ebx, [r13d]     ; r13d holds the id of case * 4 so we don't need to '4 * ebx'
jmp    [ebx + .TABLE]

在“方法1”中,由于额外的功能,我们遇到了源代码大小问题,但是我认为它比其他方法具有更好的性能,因为我将进行约2000次跳转(不规则跳转(可能是case0到case1000或...)

因此,对于跳跃性能,在具有大量JUMP的源代码中哪种方法更好?

performance assembly x86 micro-optimization
1个回答
1
投票

如果您不使用32位地址大小来压缩跳转表,而对于64位模式使用qword指针,则是一个很好的选择。

否则,您将希望加载16位或32位偏移(movzxmov),并从相对RIP的LEA中为64位代码添加到一些64位基址。 (这也使其与位置无关)。

最少的说明并不总是解决方案!

但是在这种情况下,最少的指令也是最少的指令。 [disp32 + reg]寻址模式非常有效。

如果要考虑使用更多指令,则将指针加载到jmp reg的寄存器中,而不是使用jmp [mem],而不是进一步简化寻址模式。

https://agner.org/optimize/显示Intel Sandybridge家族上的jmp mem仍然只有1个融合域uop,负载微融合到端口6跳uop中。因此,单独的mov负载实际上将在前端花费more uops。

(索引寻址模式可能会取消分层; jmp [.TABLE + ebx*4]在问题发布/重命名阶段将花费2块,但在解码器和uop缓存中仍然只有1块。但是由于某种原因,您似乎在内存中存储了字节偏移,因此您不需要缩放索引。)

© www.soinside.com 2019 - 2024. All rights reserved.