【问题标题】:Assembly Jump with Multiple plus or do plus before jump (performance)使用 Multiple plus 或 do plus 组合跳转(表演)
【发布时间】:2019-11-26 18:12:06
【问题描述】:

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

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

哪种方式更适合寻址跳转:

方式一:

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 的源代码中,哪种方式更好?

【问题讨论】:

  • 方式 1 应该以jmp [ebx] 结尾,否则它会跳到跳转表的中间。此外,如果您使用仅在 64 位模式下可用的寄存器,您可能应该进行 64 位地址计算。
  • 别想太多。采用第三种方式,指令最少。
  • @1201ProgramAlarm 最少的指令并不总是一个解决方案!
  • @Ross Ridge r13d 不是 64 位模式寄存器!!!! r13d 的 64 位寄存器是 r13 !!!!
  • R13D 是一个 32 位寄存器,仅在 64 位模式下可用。 !!!!

标签: performance assembly x86 micro-optimization


【解决方案1】:

使用 32 位地址大小是一个不错的选择,如果您可以摆脱它来压缩跳转表而不是使用 64 位模式的 qword 指针。

否则,您需要加载 16 位或 32 位偏移量(movzxmov)并从 RIP 相关 LEA 中添加一些 64 位基地址以用于 64 位代码。 (这也使它与位置无关)。

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

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

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

https://agner.org/optimize/ 显示英特尔 Sandybridge 家族上的jmp mem 仍然只有 1 个融合域 uop,负载微融合到端口 6 跳转 uop。 因此,单独的 mov 负载实际上会在前端花费 更多 微指令。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-12
    • 2015-01-31
    • 2015-10-26
    • 1970-01-01
    相关资源
    最近更新 更多