一尘不染

< 比 <= 快吗?

javascript

if (a < 901)比 快吗if (a <= 900)

与这个简单的示例不完全一样,但循环复杂代码的性能略有变化。我想这必须与生成的机器代码有关,以防万一。


阅读 176

收藏
2022-02-18

共1个答案

一尘不染

不,在大多数架构上它不会更快。您没有指定,但在 x86 上,所有积分比较通常都将在两条机器指令中实现:

  • 一个testcmp指令,它设置EFLAGS
  • 还有一个Jcc(跳转)指令,具体取决于比较类型(和代码布局):
  • jne- 如果不相等则跳转 –>ZF = 0
  • jz- 如果为零(等于)则跳转–>ZF = 1
  • jg- 大于则跳转 –>ZF = 0 and SF = OF
  • (等等…)

示例(为简洁而编辑)编译为$ gcc -m32 -S -masm=intel test.c

    if (a < b) {
        // Do something 1
    }

编译为:

    mov     eax, DWORD PTR [esp+24]      ; a
    cmp     eax, DWORD PTR [esp+28]      ; b
    jge     .L2                          ; jump if a is >= b
    ; Do something 1
.L2:

    if (a <= b) {
        // Do something 2
    }

编译为:

    mov     eax, DWORD PTR [esp+24]      ; a
    cmp     eax, DWORD PTR [esp+28]      ; b
    jg      .L5                          ; jump if a is > b
    ; Do something 2
.L5:

因此,两者之间的唯一区别是指令jgjge指令。两者将花费相同的时间。


我想解决没有任何迹象表明不同的跳转指令需要相同的时间的评论。这个问题有点难以回答,但我可以给出以下内容:在Intel Instruction Set Reference中,它们都被组合在一个通用指令下Jcc(如果满足条件则跳转)。在优化参考手册的附录 C. 延迟和吞吐量中进行了相同的分组。

延迟— 执行内核完成构成指令的所有 μop 的执行所需的时钟周期数。

吞吐量——在发布端口可以再次自由地接受相同指令之前需要等待的时钟周期数。对于许多指令,一条指令的吞吐量可能远低于其延迟

的值为Jcc

      Latency   Throughput
Jcc     N/A        0.5

附上以下脚注Jcc

  1. 条件跳转指令的选择应基于第 3.4.1 节“分支预测优化”的建议,以提高分支的可预测性。当分支预测成功时,延迟jcc实际上为零。

因此,英特尔文档中的任何内容都不会将一条Jcc指令与其他指令区别对待。

如果考虑用于实现指令的实际电路,可以假设在 中的不同位上会有简单的 AND/OR 门EFLAGS,以确定是否满足条件。因此,一条指令测试两位的时间没有理由比一条只测试一位的指令花费更多或更少的时间(忽略门传播延迟,它远小于时钟周期。)


编辑:浮点

这也适用于 x87 浮点:(与上面的代码几乎相同,但使用double而不是int.)

        fld     QWORD PTR [esp+32]
        fld     QWORD PTR [esp+40]
        fucomip st, st(1)              ; Compare ST(0) and ST(1), and set CF, PF, ZF in EFLAGS
        fstp    st(0)
        seta    al                     ; Set al if above (CF=0 and ZF=0).
        test    al, al
        je      .L2
        ; Do something 1
.L2:

        fld     QWORD PTR [esp+32]
        fld     QWORD PTR [esp+40]
        fucomip st, st(1)              ; (same thing as above)
        fstp    st(0)
        setae   al                     ; Set al if above or equal (CF=0).
        test    al, al
        je      .L5
        ; Do something 2
.L5:
        leave
        ret
2022-02-18