C代码
#include <stdio.h>
int main() {
int i = 0;
while(i<10) {
printf("Hello\n");
i++;
}
i = 0;
while(i<10) {
printf("i: %d\n", i);
i++;
}
}
当我使用
-Os
或-O2
编译代码时,第一个循环的工作方式略有不同。它减少而不是增加,并且以两种不同的方式。我想知道为什么它像代码中那样递减而不是递增,以及-Os
和-O2
之间的微小差异。-Os编译的/> -O2编译
0x400486 <main+6> mov edi,0x40068c
0x40048b <main+11> call 0x400450 <puts@plt>
0x400490 <main+16> dec ebx
0x400492 <main+18> jne 0x400486 <main+6>
#1 楼
通过递减,编译器可以利用jne
(如果不等于零/零,则跳转)进行比较(至零)并跳转到一条指令中。如果递增,则必须执行cmp/test
(带有10),然后执行条件跳转(如jnz/jne
)。我相信这是优化的一部分。-Os
标志进行了优化以减小代码大小。使用-Os
生成的代码使用dec ebx
而不是sub ebx, 0x1
,因为dec ebx
是2字节指令,而sub ebx, 0x1
是3字节指令(请注意下一条指令开始的地址)。这就说明了微小的差异。#2 楼
因为我无法发表评论,所以我将尝试修复pnak4j的答案中的一些错误。 。在以下情况下,dec ebx
根据(DEC
)的结果相应地设置ZF
标志:零或非零。然后,如果不为零,则ebx-1
会执行跳转(JNE
/ JNE
相同)。 JNZ
不是条件跳转,因此在JMP
/ CMP
之后没有太大意义。 评论
jmp是指有条件的跳转。比较后无条件跳转没有多大意义。已被编辑。谢谢。
– pank4j
2014年3月11日在7:20
dec ebx是0xff 0xcb
– PlasmaHH
2014年3月11日13:07
评论
这确实解释了一个方向的差异,但没有解释另一方向的差异。看来sub一定比sub有优势,否则O2不会选择它。
– PlasmaHH
2014年3月11日13:03
通过一些研究,我认为我找到了O2使用sub而不是dec的原因。英特尔®64和IA-32架构优化参考手册在附录C的表C-19中,添加/订阅的延迟较低。
– pyCtrl_
2014年3月13日在12:37