Performance 具有多个加号的程序集跳转或跳转前执行加号(性能)

Performance 具有多个加号的程序集跳转或跳转前执行加号(性能),performance,assembly,x86,micro-optimization,Performance,Assembly,X86,Micro Optimization,在汇编中,如果我有一个地址超过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]

在汇编中,如果我有一个地址超过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相同,但
'addebx,r12d'
被删除并更改为
'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或…)


因此,对于跳转性能而言,在跳转量很大的源代码中,哪种方式更好?

如果您可以不受影响地压缩跳转表,而不是在64位模式下使用qword指针,那么使用32位地址大小是一个不错的选择

否则,您可能需要加载16位或32位偏移量(
movzx
mov
),并将64位代码的RIP相对LEA添加到一些64位基址(这也使其位置独立)

最少的指令并不总是一个解决方案

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

如果您要考虑使用更多的指令,则将指针装入登记号为>JMP-RGE>代码>,而不是使用<代码> JMP[MEM] < /COD>,而不是简化寻址模式。

显示Intel Sandybridge系列上的
jmp mem
仍然只有1个融合域uop,load micro融合到端口6跳转uop中。 因此,单独的
mov
加载实际上会在前端花费更多的UOP


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

方式1应该以
jmp[ebx]结束
否则它将跳转到跳转表的中间。此外,如果您使用的寄存器仅在64位模式下可用,则可能需要进行64位地址计算。不要想得太多。使用第三种方法,它的指令数最少。@1201程序最少指令并不总是一个解决方案!@Ross Ridge r13d i它不是64位模式寄存器!!!!r13d的64位寄存器是r13!!!!r13d是32位寄存器,仅在64位模式下可用!!!!
mov    ebx, [r13d]     ; r13d holds the id of case * 4 so we don't need to '4 * ebx'
jmp    [ebx + .TABLE]