【问题标题】:addressing mode efficiency寻址模式效率
【发布时间】:2012-09-26 12:44:22
【问题描述】:

谁能告诉我“立即”寻址模式是否更合适 比通过 [eax] 或任何其他方式寻址更有效。

可以说我的功能很长,有一些读取和 一些写入(比如 5 次读取,5 次写入)到内存中的某个 int 值

     mov some_addr, 12      //immediate adressing
     //other code
     mov eax, aome_addr
     //other code
     mov some_addr, eax    // and so on

     mov eax, some_addr

     mov [eax], 12      // addressing thru [eax]
     //other code
     mov ebx, [eax]
     //other code
     mov [eax], ebx    // and so on

哪个更快?

【问题讨论】:

    标签: optimization assembly x86 cpu addressing-mode


    【解决方案1】:

    可能寄存器间接访问稍微快一些,但它的编码肯定更短,例如(警告 - 气体语法)

    67 89 18                   mov %ebx, (%eax)
    67 8b 18                   mov (%eax), %ebx
    

    对比

    89 1c 25 00 00 00 00       mov %ebx, some_addr
    8b 1c 25 00 00 00 00       mov some_addr, %ebx
    

    所以它在加载指令、使用缓存等时会产生一些影响,因此它可能会更快一些,但是在带有 somelong 函数中读写——我认为这并不重要……

    (十六进制代码中的零应该由链接器填充(只是这么说)。)

    [更新日期="2012-09-30 ~21h30 CEST":

    我进行了一些测试,我真的很想知道它们揭示了什么。这么多,我没有进一步调查:-)

    48 8D 04 25 00 00 00 00    leaq s_var,%rax
    C7 00 CC BA ED FE          movl $0xfeedbacc,(%rax)
    

    在大多数运行中表现优于

    C7 04 25 00 00 00 00 CC    movl $0xfeedbacc,s_var
    BA ED FE
    

    我真的很惊讶,现在我想知道 Maratyszcza 会如何解释这一点。我已经有了一个想法,但我愿意……有什么好玩的……不,看到这些(示例)结果

    movl to s_var
    All 000000000E95F890 244709520
    Avg 00000000000000E9 233
    Min 00000000000000C8 200
    Max 0000000000276B22 2583330
    leaq s_var, movl to (reg)
    All 000000000BF77C80 200768640
    Avg 00000000000000BF 191
    Min 00000000000000AA 170
    Max 00000000001755C0 1529280
    

    可能肯定会支持他的说法,即指令解码器每个周期最多占用 8 个字节,但它没有显示真正解码了多少字节。

    leaq/movl 对中,每条指令(包括操作数)小于 8 个字节,因此很可能每条指令在一个周期内分派,而单个 movl 是分为两个。仍然我确信这不是解码器减慢速度,因为即使使用 11 字节movl,它的工作也是在第三个字节之后完成的——然后它只需要等待地址和立即数中的管道流,两者都不需要解码。

    由于这是 64 位模式代码,我还使用 1 字节较短的 rip-relative 寻址进行了测试——结果(几乎)相同。

    注意:这些测量可能在很大程度上取决于它们所运行的(微)架构。以上数值是在 Atom N450 上运行测试代码给出的(恒定 TSC,boot@1.6GHz,在测试运行期间固定在 1.0GHz),这不太可能代表整个 x86(-64) 平台。

    注意:测量是在运行时进行的,没有进一步分析,例如发生的任务/上下文切换或其他干预中断!

    /更新]

    【讨论】:

    • 其实编码的不同是寄存器访问速度更快的原因。无论寻址模式如何,微操作都是相同的,但是冗长的直接寻址指令很容易使指令解码器停止。
    • 在上面的示例中,CPU 解码器指令的寄存器寻址长度为 3 个字节,立即地址的指令长度为 7 个字节。在 Intel Atom 上,解码器每个周期最多只能解码 8 字节或 2 条指令,在 Intel Nehalem 和 AMD Bulldozer 上 - 最多 16 字节或 4 条指令。请注意,典型指令的长度为 3-5 个字节,因此额外的 4 个字节的立即地址是以未解码指令为代价的。
    • Allrite 我可以接受这个答案,因为“可能 [eax] 更快”没有人确定它:/ - 我也认为它可能是真的,尽管“直接立即”是合乎逻辑的最简单的
    • 由于s_var 是一个全局的,它的地址将在低位32,所以你可以使用mov $s_var, %eax 将它的地址放入一个带有5 字节mov-immediate 而不是执法机构。 (不过,对于 rip-relative 寻址,您需要 LEA。)正如您所指出的,您的结果仅适用于 Atom。具有立即地址的长指令可能需要 SnB 系列 uarch 上的多个 uop-cache 条目,但它仍然是一个 uop,而两步法需要两个 uop。
    【解决方案2】:

    使用寄存器寻址最快。

    请看Register addressing mode vs Direct addressing mode

    【讨论】:

      猜你喜欢
      • 2018-05-31
      • 2012-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多