Performance x86 inc与add指令的相对性能
快速提问,事先假设Performance x86 inc与add指令的相对性能,performance,assembly,optimization,x86,increment,Performance,Assembly,Optimization,X86,Increment,快速提问,事先假设 mov eax, 0 哪个更有效 inc eax inc eax 或 此外,如果两个incs速度更快,编译器(比如GCC)是否通常(即不带积极优化标志)对其进行var+=2优化 PS:不要费心回答“不要过早优化”,这仅仅是学术兴趣。就所有目的而言,这可能并不重要。但要考虑到inc使用的字节更少 考虑以下代码: int x = 0; x += 2; 不使用任何优化标志,GCC将此代码编译为: 80483ed: c7 44 24 1c 00 00 00 m
mov eax, 0
哪个更有效
inc eax
inc eax
或
此外,如果两个inc
s速度更快,编译器(比如GCC)是否通常(即不带积极优化标志)对其进行var+=2
优化
PS:不要费心回答“不要过早优化”,这仅仅是学术兴趣。就所有目的而言,这可能并不重要。但要考虑到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)
有趣的是,不是吗?如果您想知道x86指令的原始性能统计,请参阅(确切地说是第4卷)。至于关于编译器的部分,这取决于编译器的代码生成器,而不是你应该依赖太多的东西
另一方面:我觉得有趣/讽刺的是,在一个关于性能的问题中,你使用
MOV-EAX,0
将寄存器归零,而不是XOR-EAX,EAX
:p(如果MOV-EAX,0
是事先做的,最快的变化就是删除inc和add,而只是MOV-EAX,2
).同一寄存器上的两条inc
指令(或者更一般地说,两条读-修改-写指令)始终具有至少两个周期的依赖链。这是假设inc的延迟为一个时钟,这是自486以来的情况。这意味着,如果周围的指令不能与两条inc指令交错以隐藏这些延迟,代码将执行得较慢
但无论如何,没有编译器会发出您建议的指令序列(mov-eax,0
将被xor-eax,eax
,请参阅)
它将被优化为
mov eax,2
从《英特尔手册》中,您可以发现,在一种特定的体系结构上,ADD/SUB指令的成本似乎要低半个周期。但请记住,英特尔(最近)的处理器采用无序执行模式。这主要意味着,性能瓶颈在处理器必须等待数据进入的任何地方都会出现(例如,在L1/L2/L3/RAM数据获取过程中,处理器没有事情可做)。所以,如果你是探查器告诉你,公司可能是问题所在;从数据吞吐量的角度看它,而不是看原始周期计数
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
答案可能是处理器特定的,在大多数情况下,很可能没有可测量的差异。如果你真的有兴趣知道一个特定CPU的答案,那么就对它进行基准测试。IIRC 0f_2h的可能复制品是P4 Prescott,愿他安息。这些半时钟延迟是由内部双时钟管道造成的。这对英特尔来说是一个非常糟糕的主意;不过,大多数编译器都喜欢inc-eax而不是
mov-eax,1
。可能是因为它是3字节而不是5。@LưuVĩnhPhúcmov eax,1
是5字节:b8 01 00
。由于8字节的文字和QWORD前缀:48 b8 01 00 00
,64位为10字节。相对而言,xor-rax,rax;inc-eax只有5个字节:48 31 c0 ff c0
@多项式:所有现代主流编译器都将使用mov-eax,1
,除非您特别告诉他们优化大小而不是速度(-clang或ICC-Os-m32
或MSVC-O1
将在32位模式下使用xor
/inc
。gcc-Os-m32
仍使用mov)。在优化速度时,为后端节省2字节的代码大小并不值得额外的uop(或为前端额外的解码指令).clang-Oz
要在不考虑速度的情况下优化大小,将在64位模式下使用push 1
/pop rax
。所有这些编译器都使用mov
和正常选项。@phuclv:您可能应该清理您以前的注释;早期的注释中有几个错误(也是在Polynomy的第2条注释中,64位字节计数膨胀)。选项包括mov-eax,1
(5字节)通过隐式零扩展设置RAX=1,或push 1
/
(3字节),或xor-eax,eax
/inc-eax
(4字节)。但编译器只使用mov
,除非优化大小超过速度。指出,从另一个已知值的寄存器中选择3字节leaeax、[rdx+1]
可能很有用
mov eax,2
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