首页 文章

x86 inc与add指令的相对性能

提问于
浏览
9

快速提问,事先假设

mov eax, 0

哪个更有效率?

inc eax
inc eax

要么

add eax, 2

另外,如果两个 inc 更快,那么编译器(比如GCC)通常(即没有积极的优化标志)会优化 var += 2 吗?

谢谢你的时间!

PS:不要费心回答“不要过早优化”,这仅仅是学术兴趣 .

4 回答

  • 17

    同一寄存器上的两条指令(或更一般地说,两条读 - 修改 - 写指令)总是具有至少两个周期的依赖链 . 这假设一个inc的一个时钟延迟,这是自486以来的情况 . 这意味着如果周围的指令不能与两个inc指令交错以隐藏那些延迟,则代码将执行得更慢 .

    但是没有编译器会发出你提出的指令序列( mov eax,0 将被 xor eax,eax 替换,见What is the purpose of XORing a register with itself?

    mov eax,0
    inc eax
    inc eax
    

    它会被优化

    mov eax,2
    
  • 2

    如果您想知道x86指令的原始性能统计数据,请参阅Dr Agner Fogs listings(准确地说是第4卷) . 关于编译器的部分,那依赖于编译器的代码生成器,而不是你应该依赖的东西 .

    旁注:我觉得有趣/具有讽刺意味的是,在一个关于性能的问题中,你使用了 MOV EAX,0 将寄存器归零而不是 XOR EAX,EAX :P(并且如果 MOV EAX,0 事先完成,最快的变体就是删除inc 's and add'和只是 MOV EAX,2 ) .

  • 12

    出于所有目的,它可能无关紧要 . 但请注意 inc 使用较少的字节 .

    请考虑以下代码:

    int x = 0;
    x += 2;
    

    在不使用任何优化标志的情况下, GCC 将此代码编译为:

    80483ed:       c7 44 24 1c 00 00 00    movl   $0x0,0x1c(%esp)
    80483f4:       00 
    80483f5:       83 44 24 1c 02          addl   $0x2,0x1c(%esp)
    

    使用 -O1-O2 ,它变为:

    c7 44 24 08 02 00 00    movl   $0x2,0x8(%esp)
    

    好笑,不是吗?

  • 2

    从英特尔手册中可以找到here,看起来ADD / SUB指令在一个特定架构上的周期便宜了半个周期 . 但请记住,英特尔为它使用了无序执行模型's (recent) processors. This primarily means, performance bottlenecks show up wherever the processor has to wait for data to come in (eg. it ran out of things to do during the L1/L2/L3/RAM data-fetch). So if you' re profiler告诉你INC可能是问题;从形成数据吞吐量的角度看它,而不是查看原始循环计数 .

    Instruction              Latency1           Throughput         Execution Unit 
                                                                2 
    CPUID                    0F_3H    0F_2H      0F_3H    0F_2H    0F_2H 
    
    ADD/SUB                  1        0.5        0.5      0.5      ALU 
    [...]
    DEC/INC                  1        1          0.5      0.5      ALU
    

相关问题