技術文章:scf編譯器對C語言的邏輯運算符的優化

2022年10月16日20:12:32 科技 1285

在各種編程語言里,邏輯運算符都是要短路的。

C語言為例:

if (p && p->x > 0) p->x++;

當指針p是NULL的時候,對成員變量p->x的讀寫會導致段錯誤,所以如果&&之前的條件p是NULL就要把後面的p->x跳過去。

這樣才能保證代碼的正常運行。

如果語言本身不支持邏輯運算符的短路,那麼代碼就只能這麼寫了:

if (p) {

if (p->x > 0) p->x++;

}

要多寫一個if條件。

邏輯運算符的結果只有0或1兩種。

在編程里,邏輯運算符既可以作為if / while / for的條件表達式還可以參與普通運算

if (i > 0 && j > 1 && k > 2) return -1; // 條件表達式

n = i > 0 && j > 1 && k > 2; // 普通運算

在對邏輯運算符進行優化時,必須同時考慮這兩種情況

第2種情況下,如果邏輯運算符在計算前2個條件時短路了,必須把計算結果寫入最後一個邏輯運算符對應的臨時變量

最後一個邏輯運算符的計算結果,才是整個表達式的結果,也是對n賦值的結果。

如果只是在if語句里作為條件表達式,邏輯運算的結果不需要寫到臨時變量里,直接根據比較結果跳轉到對應的分支就可以了。

技術文章:scf編譯器對C語言的邏輯運算符的優化 - 天天要聞

賦值運算的語法樹

第2種情況的語法樹如圖,參與賦值運算的是第2個&&對應的臨時變量。

如果在i > 0 或 j > 1時短路的話,它們設置的是第1個&&的值:編譯器在短路跳轉時必須給第2個&&設置運算結果,否則之後的n = ...的結果就不對了。

邏輯運算符生成中間代碼的時候,實際上並不知道它的結果以後會被怎麼使用[捂臉]

從上圖中也可以看出=號在更上面(if也是在更上面),實際上,在處理&&運算符時只能看到它的2個條件表達式,看不到更上層的程序邏輯。

技術文章:scf編譯器對C語言的邏輯運算符的優化 - 天天要聞

if條件的語法樹

如果硬要去看更高層的邏輯,就會破壞模塊封裝性,讓遍歷語法樹生成中間代碼的代碼變得複雜、難看。

scf框架在這裡的處理是:

1,先給所有邏輯運算符的臨時變量設置上結果,把進一步的優化放到以後

技術文章:scf編譯器對C語言的邏輯運算符的優化 - 天天要聞

if的情況

最初的中間代碼是這樣的,可以看到每個cmpteq運算之後都緊跟着setcc

其中cmp是比較大小,結果可以是>、==、<、>=、<=、!=。

teq是比較是不是0,結果只有2種:== 0,!= 0。

技術文章:scf編譯器對C語言的邏輯運算符的優化 - 天天要聞

賦值的情況

在有邏輯運算符的情況下,在cmp之後必然跟着teq去判斷邏輯結果是不是0。

例如上圖中的:

cmp i, 0

setgt v_8_16/&&

jle : teq v_8_16/&&

跳轉的目標代碼是:

teq v_8_16/&&

setnz v_8_25/&&

jz : assign v_8_6/n; v_8_25/&&

數字表示的是行列號,v_8_16/&&表示第8行第16列的&&運算符對應的臨時變量

可以看出,在最初的中間代碼里,邏輯運算符並沒有“真正的短路”:雖然跳過了第2個比較條件,但並沒有跳過邏輯運算。

之所以這樣,就是因為(生成中間代碼時)沒法確定邏輯結果接下來還有沒有用。

既然沒法確定,編譯器就只能先當它有用:代碼里遇到這種情況,是一定會做保守處理的。

所以說,不管是程序員還是數學家,一般都是悲觀主義者[捂臉]

2,跳轉優化時,對這個問題進一步的優化。

如果一個跳轉的目標位置是一個絕對跳轉,就可以把它優化成跳轉到這個絕對跳轉的目標位置。

if a jcc's destination is a jmp, then optimize its destination to the jmp's.

這是對跳轉的基本優化。

實際上,如果跳轉之前對邏輯結果設置了false,而跳轉的目標又是檢測這個結果的話,那麼檢測結果也是false[呲牙]這是跳轉優化的另一條規則。

所以說,在cmp觸發了jle (<=) 的情況下,那麼它倆之間的setgt (>) 就肯定是0

進而導致目標位置的teq也是0

進而導致目標位置的setnz也是0

進而導致目標位置的jz被觸發,

所以,jle的地址就是jz的地址

但在jle之前要把setnz的目標變量也設置一下,使用的設置指令是setgt:與最初觸發跳轉的條件一致。

技術文章:scf編譯器對C語言的邏輯運算符的優化 - 天天要聞

跳轉優化之後的中間代碼

從上圖可以看出,經過跳轉優化之後,測試邏輯結果的teq運算消失了,與teq對應的jz跳轉也消失了:

邏輯運算符被短路到了接下來的賦值運算。

賦值運算只使用最後一個臨時變量v_8_25。

對中間臨時變量v_8_16的設置是多餘的,接下來的問題是怎麼消除它。

如果邏輯運算只是作為if的條件的話,那麼最後一個邏輯結果也是不需要的

3,基於活躍變量分析的優化,

算術運算會使用最後一個邏輯結果的臨時變量,if條件不使用任何邏輯結果的臨時變量,這在臨時變量的活躍度上可以體現出來。

不活躍的臨時變量DAG上去掉就行了。

技術文章:scf編譯器對C語言的邏輯運算符的優化 - 天天要聞

最終的優化結果

對n的賦值運算只使用臨時變量v_8_25,可以看出它是前面基本塊的出口活躍變量,被保留了下來。

如果是if條件,因為所有的臨時變量都不活躍,在DAG優化之後就只剩下比較和跳轉了[呲牙]

如下圖:

技術文章:scf編譯器對C語言的邏輯運算符的優化 - 天天要聞

if最終的圖

上圖是if條件的最終的圖,下圖是跳轉優化之後、DAG優化之前的圖。

可以看到,所有的setgt都被去掉了。

技術文章:scf編譯器對C語言的邏輯運算符的優化 - 天天要聞

if之前的圖

科技分類資訊推薦

浙江首家縣域級虛擬電廠資源接入省級平台 - 天天要聞

浙江首家縣域級虛擬電廠資源接入省級平台

潮新聞客戶端 通訊員 範金凱5月30日,國網杭州市蕭山區供電公司所屬浙江中新電力工程建設有限公司打造的蕭山雙碳大腦虛擬電廠成功接入浙江省電力負荷管理中心省級平台,並獲得新型主體資質,成為全省首家接入該平台的縣域級虛擬電廠。
美團閃購不考數學 - 天天要聞

美團閃購不考數學

1每年618,電商平台都能人頭打成狗頭,今年登場的嘉賓更是重量級。美團閃購瘋了,都開始參加618了,代言人樊振東拿着球拍一拍一拍把價格打下來了嘿。電商們這麼多年都打累了吧?花里胡哨的活兒已經整完了吧?已經開始打默契拳踢友誼賽了是吧?
小米米家洗衣機 Pro 藍氧洗烘 10kg 開售,國補價 1727 元起 - 天天要聞

小米米家洗衣機 Pro 藍氧洗烘 10kg 開售,國補價 1727 元起

IT之家 5 月 31 日消息,小米米家洗衣機 Pro 藍氧洗烘 10kg 現已在京東平台開售,售價 2399 元,疊加 9 折優惠券、8 折國補,到手價 1727 元起。據介紹,這款產品支持藍氧護衣洗,可有效去除 6 大類、35 種常見污漬;達到超高洗凈比 1.27,遠超國家標準 1.03;支持 30 種洗烘護程序,針對羊毛衫、羽絨服、真絲、衝鋒衣、運..
華碩推出 NUC 15 Pro 迷你主機:Ultra 5-225H,5799 元 - 天天要聞

華碩推出 NUC 15 Pro 迷你主機:Ultra 5-225H,5799 元

IT之家 5 月 31 日消息,華碩現已在京東上架 NUC 15 Pro 迷你主機,該機搭載英特爾酷睿 Ultra 5-225H + 16GB RAM + 512GB SSD,定價為 5799 元,國補後 4239.2 元。這款迷你主機整體造型簡約,採用啞光工藝,尺寸為 117x112x54mm,體積為 0.7L,搭載 14 核心 14 線程英特爾酷睿 Ul
外賣騎手們的“流量”副業 - 天天要聞

外賣騎手們的“流量”副業

奶茶鋪女店員手中的五六杯飲品接連砸向外賣騎手花田,那一瞬間,狼狽至極的他不會知道,800萬短視頻流量也即將砸向他。這場激烈又尋常的外賣糾紛,若不是因為花田送餐時胸前佩戴的運動相機的記錄,或許會被永遠淹沒在上海4月這個工作日午高峰時分。花田將相機里的事發視頻剪輯發布在自己的短視頻賬號里。之後的幾天里,這個...
上汽賈健旭:余總說我們不太像國企,尚界鋪天蓋地華為頂天立地 - 天天要聞

上汽賈健旭:余總說我們不太像國企,尚界鋪天蓋地華為頂天立地

IT之家 5 月 31 日消息,在今日的未來汽車先行者大會上,上海汽車集團股份有限公司總裁賈健旭說,公司現在要 ALL IN 華為。“余總(IT之家註:華為常務董事、終端 BG 董事長余承東)調侃我們不太像國企,我很汗顏…… 我們要拿出私企人的性格、做國企人的企業。…… 尚界鋪天蓋地,華為頂天立地!”賈健旭強調,上汽要堅持...
小米 REDMI 顯示器 G27 開售:200Hz 刷新率,669 元 - 天天要聞

小米 REDMI 顯示器 G27 開售:200Hz 刷新率,669 元

IT之家 5 月 31 日消息,小米 REDMI 顯示器 G27 現已在京東等平台開售,支持 1080P 分辨率、200Hz 刷新率,售價 669 元。據介紹,這款新品配備一塊 27 英寸 1920x1080 分辨率 200Hz Fast IPS 面板,顯示器峰值亮度 400 尼特,靜態對比度 1000:1,GtG 響應速度 1ms,顯示器支持 8-Bit