2013-10-24 91 views
9

我寫了下面的程序:爲什麼使用JLE而不是JL?

#include <stdio.h> 

int main() 
{ 
    int i = 0; 
    for (; i < 4; i++) 
    { 
     printf("%i",i); 
    } 

    return 0; 
} 

我使用gcc test.c -o test.o編譯它,然後使用objdump -d -Mintel test.o拆開它。彙編代碼我得到了(至少相關部分)如下:

0804840c <main>: 
804840c: 55      push ebp 
804840d: 89 e5     mov ebp,esp 
804840f: 83 e4 f0    and esp,0xfffffff0 
8048412: 83 ec 20    sub esp,0x20 
8048415: c7 44 24 1c 00 00 00 mov DWORD PTR [esp+0x1c],0x0 
804841c: 00 
804841d: eb 19     jmp 8048438 <main+0x2c>   
804841f: 8b 44 24 1c    mov eax,DWORD PTR [esp+0x1c] 
8048423: 89 44 24 04    mov DWORD PTR [esp+0x4],eax 
8048427: c7 04 24 e8 84 04 08 mov DWORD PTR [esp],0x80484e8 
804842e: e8 bd fe ff ff   call 80482f0 <[email protected]> 
8048433: 83 44 24 1c 01   add DWORD PTR [esp+0x1c],0x1 
8048438: 83 7c 24 1c 03   cmp DWORD PTR [esp+0x1c],0x3 
804843d: 7e e0     jle 804841f <main+0x13> 
804843f: b8 00 00 00 00   mov eax,0x0 
8048444: c9      leave 
8048445: c3      ret 

我發現,雖然我比較操作是i < 4,彙編代碼是(在拆解後)i <= 3。爲什麼會發生?爲什麼它會使用JLE而不是JL

+3

這可能是鼓勵後續優化的代碼,如循環展開。哪些沒有發生,避免看未經優化的代碼。 –

+0

這實際上是一個gcc代碼生成選擇(您需要深入代碼的樹形表示),但它會將一個var Petesh

回答

5

向上計數並具有恆定限制的循環非常常見。編譯器有兩個選項來執行循環終止檢查 - JLEJL。儘管這兩種方式看起來完全相同,但請考慮以下幾點。如你在反彙編列表中看到的,常量(在你的情況下爲3)被編碼爲1個字節。如果你的循環計數爲256而不是4,那麼impossibleCMP指令使用如此高效的編碼,編譯器將不得不使用「更大」的編碼。因此,JLE在代碼密度上提供了一個邊際改進(由於高速緩存的原因,這最終對性能有好處)。

0

它會JLE,因爲它將值移動一。

if (x < 4) { 
    // ran when x is 3, 2, 1, 0, -1, ... MIN_INT. 
} 

是邏輯上等同於

if (x <= 3) { 
    // ran when x is 3, 2, 1, 0, -1, ... MIN_INT. 
} 

爲什麼編譯器選擇了一個內部表示了另一種往往是最優化的問題,但實際上它是很難知道的優化是真正的驅動程序。在任何情況下,像這樣的功能等價物都是後向映射不是100%準確的原因。有很多方法可以編寫對相同輸入具有相同效果的條件。

相關問題