2 ms·
Yes, it does. -O0 executes the loop as coded. (0.6s on my machine) -O1 executes the loop faster. (0.152s on my machine) -O2 and beyond just figure out the res
by qiqitori 5y ago
Yes, it does.
-O0 executes the loop as coded. (0.6s on my machine)
-O1 executes the loop faster. (0.152s on my machine)
-O2 and beyond just figure out the result and are equivalent to one strtol + printf.
So what's different between -O0 and -O1?
$ cc -O0 -g -o c_loop c_loop.c
$ objdump -M intel-mnemonic -S c_loop
0000000000001145 <main>:
...
for (s = i = 0; i < NUMBER; ++i) {
116a: c7 45 fc 00 00 00 00 mov DWORD PTR [rbp-0x4],0x0
1171: 8b 45 fc mov eax,DWORD PTR [rbp-0x4]
1174: 89 45 f8 mov DWORD PTR [rbp-0x8],eax
1177: eb 08 jmp 1181 <main+0x3c>
s += 1;
1179: 83 45 f8 01 add DWORD PTR [rbp-0x8],0x1
for (s = i = 0; i < NUMBER; ++i) {
117d: 83 45 fc 01 add DWORD PTR [rbp-0x4],0x1
1181: 8b 45 fc mov eax,DWORD PTR [rbp-0x4]
1184: 3b 45 f4 cmp eax,DWORD PTR [rbp-0xc]
1187: 7c f0 jl 1179 <main+0x34>
}
printf("s: %d",s);
1189: 8b 45 f8 mov eax,DWORD PTR [rbp-0x8]
118c: 89 c6 mov esi,eax
118e: 48 8d 3d 6f 0e 00 00 lea rdi,[rip+0xe6f] # 2004 <_IO_stdin_used+0x4>
1195: b8 00 00 00 00 mov eax,0x0
119a: e8 91 fe ff ff call 1030 <printf@plt>
return 0;
119f: b8 00 00 00 00 mov eax,0x0
}
The take-home here is that it uses the stack (DWORD PTR ...) for almost everything. Just the eax, rdi, esi registers are used. The core loop is four instructions, add, mov, cmp, jl. Caches still make this relatively fast.
$ cc -O1 -g -o c_loop c_loop.c
$ objdump -M intel-mnemonic -S c_loop
0000000000001145 <main>:
...
// NOTE: NUMBER is in eax at this point
for (s = i = 0; i < NUMBER; ++i) {
115c: 85 c0 test eax,eax
115e: 7e 29 jle 1189 <main+0x44>
1160: 89 c6 mov esi,eax
1162: b8 00 00 00 00 mov eax,0x0
s += 1;
1167: 83 c0 01 add eax,0x1
for (s = i = 0; i < NUMBER; ++i) {
116a: 39 f0 cmp eax,esi
116c: 75 f9 jne 1167 <main+0x22>
}
printf("s: %d",s);
116e: 48 8d 3d 8f 0e 00 00 lea rdi,[rip+0xe8f] # 2004 <_IO_stdin_used+0x4>
1175: b8 00 00 00 00 mov eax,0x0
117a: e8 b1 fe ff ff call 1030 <printf@plt>
The take-home here is that registers are being used. The core loop is three instructions now (add, cmp, jne), we don't need the MOV anymore.