2016-12-30 61 views
3

考慮以下循環:編譯器如何優化這一段代碼

unsigned long x = 0; 
for(unsigned long i = 2314543142; i > 0; i--) 
    x+=i; 
std::cout << x << std::endl; 
當我編譯這通常它需要大約6.5秒執行該循環

。但是當我使用-O3優化進行編譯時,循環會在10^-6秒內執行。這怎麼可能?編譯器肯定不知道x的閉式表達式如何...

+2

您是否嘗試過使用匯編語言輸出來查看生成的代碼? –

+0

不幸的是,我不知道任何程序集 – user3726947

+0

你如何計時循環? –

回答

4

如果使用優化進行編譯,您並不需要知道關於程序集的所有信息,以查看編譯器在編譯時確定x的值。

我稍微修改了您的代碼,以便能夠使用在線工具Compiler Explorer,將std::cout << x << std::endl更改爲extern unsigned long foo;foo = x;。沒有必要,但它使輸出更清潔。

與-02編譯:

test(): 
     movabs rax, 2678554979246887653 
     mov  QWORD PTR foo[rip], rax 
     ret 

編譯時-O0:

test(): 
     push rbp 
     mov  rbp, rsp 
     mov  QWORD PTR [rbp-8], 0 
     mov  DWORD PTR [rbp-16], -1980424154 
     mov  DWORD PTR [rbp-12], 0 
     jmp  .L2 
.L3: 
     mov  rax, QWORD PTR [rbp-16] 
     add  QWORD PTR [rbp-8], rax 
     sub  QWORD PTR [rbp-16], 1 
.L2: 
     cmp  QWORD PTR [rbp-16], 0 
     setne al 
     test al, al 
     jne  .L3 
     mov  rax, QWORD PTR [rbp-8] 
     mov  QWORD PTR foo[rip], rax 
     leave 
     ret 

另:未定義行爲由於i >= 0代碼的第一個版本僅僅輸出:

test(): 
.L2: 
     jmp  .L2 

:-)

+0

所以看起來編譯器在編譯時正在計算某些東西。但是我無法在任何地方找到輸出值2678554979246887653 ... – user3726947

+0

@ user3726947對不起,我不小心使用了'extern unsigned foo'而不是'extern unsigned long foo'。更新後的答案顯示正確的輸出值。 – gurka

3

編譯器確定循環後x的值,並在輸出語句中使用該值。

+0

相對於程序的長度,這必須是一個相當慢的編譯。 –

+0

雖然我沒有測量它,但編譯時間幾乎是瞬間的。當然不會超過沒有-O3優化的編譯時間。 – user3726947