首先我們先看以下代碼:
編譯器優(yōu)化優(yōu)化的是什么呢,優(yōu)化的是底層代碼執(zhí)行邏輯条舔,使項(xiàng)目執(zhí)行更加高效毛肋。匯編是最接近底層的代碼怨咪,所以我們從匯編來看編譯器優(yōu)化是如何優(yōu)化的。
在15行打個(gè)斷點(diǎn)润匙,運(yùn)行程序看到的匯編代碼如下:
真機(jī)Debug
模式運(yùn)行下的匯編代碼如上圖诗眨,我們可以看到a
、b
變量的賦值以及加法運(yùn)算過程孕讳。
我們在Build Settings
里面搜索optimization
辽话,可以看到優(yōu)化等級,在Debug
模式下是None
也就是沒有優(yōu)化卫病。release
模式下是Fastest,Smallest
油啤,最小最快,一般情況我們就設(shè)置這個(gè)值即可蟀苛。
我們把Debug
模式下也改成Fastest,Smallest
再運(yùn)行項(xiàng)目益咬,得到的匯編代碼如下:
可以看到,優(yōu)化后代碼比之前少了15行帜平,速度更快幽告。
代碼里面沒有了a
、b
變量的賦值裆甩,直接把結(jié)果0x1e
即30放到了w8
寄存器上冗锁。
在讀OC源碼的時(shí)候,我們會看到大量的fastpath(x)
嗤栓、slowpath(x)
冻河,這些用到了編譯器優(yōu)化。
看下這兩個(gè)宏定義的實(shí)現(xiàn):
#define fastpath(x) (__builtin_expect(bool(x), 1))
#define slowpath(x) (__builtin_expect(bool(x), 0))
__builtin_expect
這個(gè)指令是gcc引入的茉帅,作用是允許程序員將最有可能執(zhí)行的分支告訴編譯器叨叙。這個(gè)指令的寫法為:__builtin_expect(EXP, N)。
意思是:EXP==N的概率很大堪澎。
首先我們需要明確:
if(fastpath(x)) 等價(jià)于 if(x)
if(slowpath(x)) 也等價(jià)于 if(x)
__builtin_expect()
是 GCC (version >= 2.96)提供給程序員使用的擂错,目的是將“分支轉(zhuǎn)移”的信息提供給編譯器,這樣編譯器可以對代碼進(jìn)行優(yōu)化樱蛤,以減少指令跳轉(zhuǎn)帶來的性能下降钮呀。
__builtin_expect((x),1)
表示 x 的值為真的可能性更大;
__builtin_expect((x),0)
表示 x 的值為假的可能性更大昨凡。
也就是說爽醋,使用fastpath(),執(zhí)行 if 后面的語句的機(jī)會更大土匀,使用 slowpath()子房,執(zhí)行 else 后面的語句的機(jī)會更大。通過這種方式,編譯器在編譯過程中证杭,會將可能性更大的代碼緊跟著前面的代碼田度,從而減少指令跳轉(zhuǎn)帶來的性能上的下降。
例如:
int x, y;
if(slowpath(x > 0))
y = 1;
else
y = -1;
上面的代碼中 gcc 編譯的指令會預(yù)先讀取 y = -1 這條指令解愤,這適合 x 的值大于 0 的概率比較小的情況镇饺。如果 x 的值在大部分情況下是大于 0 的,就應(yīng)該用 fastpath(x > 0)送讲,這樣編譯出的指令是預(yù)先讀取 y = 1 這條指令了奸笤。這樣系統(tǒng)在運(yùn)行時(shí)就會減少重新取值了。
所以以后我們再看OC源碼時(shí)候哼鬓,slowpath
可以不太用關(guān)注监右,因?yàn)檫@個(gè)大多是一些容錯(cuò)處理,這樣可以提高我們源碼閱讀效率异希。