您現在的位置是:首頁 > 遊戲
iOS編譯簡析
宏替換佔用執行時間嗎
前言
一般的編譯器都是由三部分構成。從原始碼到機器碼基本上都要經過這三部分。
編譯器前端(FrontEnd): 詞法分析,語法分析,語義分析,將原始碼抽象為語法樹 AST,繼而生成中間程式碼 IR。
最佳化器(Optimizer): 對得到的中間程式碼 IR 進行最佳化。
編譯器後端(BackEnd): 將得到的中間程式碼轉化為各平臺的機器碼,如 x86,ARM 等。
從 GCC 到 LLVM 以及大部分編譯器都是這種結構。
LLVM 歷史
早期 iOS 選用的是當時一家獨大的 GCC 編譯器作為 OC 語言的前端,但是隨著時間的推移,Apple 為 OC 增加了很多特性,想要 GCC 給與實現,但是 GCC 卻並沒有支援,並且 GCC 本身程式碼耦合度較高,模組獨立性比較差,並且《GCC執行環境豁免條款》限制了LLVM-GCC。這種背景下,Apple 就想找到一個高效、模組化的且開源的替換品,LLVM 進入了蘋果的視線。
LLVM 最早來源於伊利諾伊大學厄巴納-香檳分校維克拉姆·艾夫(Vikram Adve)與克里斯·拉特納(Chris Lattner)的研究,本來目的是寫一個底層的虛擬機器,這也是 LLVM 名字的由來(Low Level Virtual Machine)。LLVM 是以 BSD 授權來發展的開源軟體。在進入到蘋果視線後,蘋果公司並邀請 Chris Lattner 及其團隊加入蘋果,併為 LLVM 提供贊助支援。
Chris Lattner 是一個名副其實的大神,LLVM 之父,Swift 之父,Clang 主要貢獻者。2005-2017 年供職蘋果,前開發部高階總監,架構師;2017。1-2017。6,擔任特斯拉軟體副總裁,負責自動駕駛。2017。8-2020。1,加入 Google Brain 團隊,加入後編寫了 Swift 版的 TensorFlow。目前加入晶片創業公司 SiFive 負責其平臺工程。
iOS 在 Xcode 5 版本前使用的是 GCC ,在 Xcode 5 中將 GCC 徹底拋棄,替換為了 LLVM ,這期間也是慢慢過渡過來的,由開始使用 GCC 編譯->GCC 與 LLVM 共存->LLVM 編譯器。
LLVM
LLVM 廣義上是指整個 LLVM 架構,也就是整個編譯器三部分,但是狹義上講,是指 LLVM 後端。
如果所示,不同的前端後端使用統一的中間程式碼 LLVM Intermediate Representation (LLVM IR),如果需要支援一種新的程式語言,那麼只需要實現一個新的前端,如果需要支援一種新的硬體裝置,那麼只需要實現一個新的後端,最佳化階段是一個通用的階段,它針對的是統一的 LLVM IR,不論是支援新的程式語言,還是支援新的硬體裝置,都不需要對最佳化階段做修改。
主要子專案:
LLVM 核心庫
編譯器前端 Clang
LLDB
libc ++和 libc++
lld
Clang
Clang 是 LLVM 專案的一個子專案,是 C 系列(C、C++、OC)的編譯器前端。相對於 GCC,Clang 具有以下優點
編譯速度快:在某些平臺上,Clang 的編譯速度顯著的快過 GCC(Debug 模式下編譯 OC 速度比 GGC 快 3 倍)
佔用記憶體小:Clang 生成的 AST 所佔用的記憶體是 GCC 的五分之一左右
模組化設計:Clang 採用基於庫的模組化設計,易於 IDE 整合及其他用途的重用
診斷資訊可讀性強:在編譯過程中,Clang 建立並保留了大量詳細的元資料 (metadata),有利於除錯和錯誤報告
設計清晰簡單,容易理解,易於擴充套件增強
主要流程
預處理(Pre-process):include 擴充套件、標記化處理、去除註釋、條件編譯、宏刪除、宏替換。對
C
輸出
。i
, 對
C++
輸出
。ii
, 對 OC 輸出
。mi
, 對
Objective-C++
輸出
。mii
;
詞法分析 (Lexical Analysis):將程式碼切成一個個 token,比如大小括號,等於號還有字串等。是計算機科學中將字元序列轉換為標記序列的過程;
語法分析(Semantic Analysis):驗證語法是否正確,然後將所有節點組成抽象語法樹 AST 。由 Clang 中 Parser 和 Sema 配合完成;
靜態分析(Static Analysis):使用它來表示用於分析原始碼以便自動發現錯誤;
中間程式碼生成(Code Generation):開始 IR 中間程式碼的生成了,CodeGen 會負責將語法樹自頂向下遍歷逐步翻譯成 LLVM IR。
SwiftC
SwiftC 是 Swift 語言的編譯器前端。
主要流程
Parse: 詞法分析元件,生成 AST;
Sema(Semantic Analysis):對 AST 進行型別檢查,轉換為格式正確且型別檢查完備的 AST;
Clang Importer: 負責匯入 Clang 模組,並將匯出的 C 或 Objective-C API 對映到相應的 Swift API 中。最終匯入的 AST 可以被語義分析引用。
SIL Gen:由 AST 生成 Raw SIL(原生 SIL,程式碼量很大,不會進行型別檢查);
SIL 保證轉換:SIL 保證轉換階段負責執行額外且影響程式正確性的資料流診斷,轉換後的最終結果是規範的 SIL;
SIL 最佳化:該階段負責對程式執行額外的高階且專用於 Swift 的最佳化,包括(例如)自動引用計數最佳化、去虛擬化、以及通用的專業化;
Swift 編譯過程引入 SIL 有幾個優點:
完成的變數程式的語義(Fully represents program semantics );
既能進行程式碼的生成,又能進行程式碼分析(Designed for both code generation and analysis );
處在編譯管線的主通道(Sits on the hot path of the compiler pipeline );
架起橋樑連線原始碼與 LLVM,減少原始碼與 LLVM 之間的抽象鴻溝(Bridges the abstraction gap between source and LLVM)
IR
LLVM IR 有三種表示形式。
text:便於閱讀的文字格式,類似於組合語言,拓展名
。ll
;
bitcode:二進位制格式,拓展名
。bc
memory:記憶體格式
LLVM 後端
主要流程
最佳化(Optimize):LLVM 會去做些最佳化工作;在 Xcode 的編譯設定裡也可以設定最佳化級別-01,-03,-0s;最佳化級引數位於引數位於
Build Settings
->
Apple Clang - Code Generation
->
Optimization Level
。是利用 LLVM 的 Pass 去處理的,我們可以自己去自定義 Pass。
生成目標檔案(Assemble):生成 Target 相關 Object(Mach-o);
連結(Link):生成 Executable 可執行檔案。
相關命令
clang
// 假設原始檔案為LLVMOC。m// 預編譯命令clang -E LLVMOC。m -o LLVMOC。mi// 生成AST語法樹clang -Xclang -ast-dump -fsyntax-only LLVMOC。m// 生成IR中間程式碼clang -S -emit-llvm LLVMOC。m -o LLVMOC。ll// 生成IR中間程式碼並最佳化,clang -O3 -S -emit-llvm LLVMOC。m -o LLVMOC。ll// 如果開啟bitcode,生成。bc檔案,這也是中間碼的一種形式clang -emit-llvm -c LLVMOC。m -o LLVMOC。bc// 產生彙編命令clang -S LLVMOC。m -o LLVMOC。s// 生成目標。O檔案clang -c LLVMOC。m -o LLVMOC。o
swiftc
// 假設原始檔案為LLVMSwift。swift// 分析輸出ASTswiftc maLLVMSwiftin。swift -dump-parse// 分析並且檢查型別輸出ASTswiftc LLVMSwift。swift -dump-ast// 生成中間體語言(SIL),未最佳化swiftc LLVMSwift。swift -emit-silgen// 生成中間體語言(SIL),最佳化後的swiftc LLVMSwift。swift -emit-sil// 生成LLVM中間體語言 (。ll檔案)swiftc LLVMSwift。swift -emit-ir// 生成LLVM中間體語言 (。bc檔案)swiftc LLVMSwift。swift -emit-bc// 生成彙編swiftc LLVMSwift。swift -emit-assembly// 編譯生成可執行。out檔案swiftc -o LLVMSwift。o LLVMSwift。swift
擴充套件一下
既然講到了 LLVM,那就順便講一下 BitCode,上文也講到了 BitCode 其實就是 IR 程式碼的一種編碼形式。
需要說明的是 BitCode 是以 section 形式儲存在可執行檔案中。當我們把攜帶 BitCode 的 App 提交到 AppStore 後,蘋果會提取出可執行檔案中的 BitCode 段,然後針對不同的 CPU 架構編譯和連結成不同的可執行檔案變體(Variant),不同 CPU 架構的裝置會自動選擇合適的架構的變體進行下載。而在 BitCode 之前,我們都是把所有需要的 CPU 架構集合打包成一個 Fat Binary,結果就是使用者最終下載的安裝包之中有很多冗餘的 CPU 架構支援程式碼。開啟BitCode之後,編譯器後端(Backend)的工作都由 Apple 接管。
BitCode的一些具體說明及注意事項後面會在iOS瘦身最佳化中專門去講解。
有一個技術的圈子與一群同道眾人非常重要,來我的技術公眾號及部落格,這裡只聊技術乾貨。
微信公眾號:
CoderStar
部落格:CoderStar‘s Blog
推薦文章
- 匯源跌落神壇,只是命運的玩笑嗎?
2億港元收購匯源果汁,這是當時可口可樂在美國本土之外最大的一筆收購計劃,也是當時金額最大的外資企業全資收購中國企業的交易...
- 中國歷史上每個朝代的末代皇帝下場如何?
年少皇帝唐哀帝臆測畫像宋恭宗趙昰(宋朝)趙顯四歲繼位,宋室江山處於風雨飄搖之中...
- 從電瓶車到小汽車的進步
這款車型的內飾功能配置還是很豐富的,它的方向盤是屬於多功能方向盤,有換擋撥片,電子按鈕排檔,這些佈局的話都是比較科技感十足,而且很符合現在年輕人的用車需求,還有座椅它是有座椅加熱和電動座椅電動大燈電動尾門這些都是配備的,而且價格也是很親民優...