開始學習之前,可以先看看llvm的一些基本命令用途,因為接下來會用到。
官網介紹:https://releases.llvm.org/11.0.0/docs/GettingStarted.html
所有的命令介紹:https://llvm.org/docs/CommandGuide/index.html
代碼格式之間的轉換如圖所示:
LLVM IR究竟是什麼?它的全稱是LLVM Intermediate Representation,也就是LLVM的中間表示,可以理解為LLVM自己的彙編,LLVM的優化都在IR層進行處理;它有三種等價的表達形式:內存表示(Instruction類等)、被壓縮的磁碟表示(bitcode文件)、人工可讀的磁碟表示(LLVM彙編碼文件)
下圖可見IR的重要性
關於llvm IR的結構
以下結構示意圖來自於《LLVM IR Tutorial - Phis, GEPs and other things, oh my!》的報告,可以看到IR的結構,pdf下載地址:http://llvm.org/devmtg/2019-04/slides/Tutorial-Bridgers-LLVM_IR_tutorial.pdf有興趣也可以直接去油管訂閱llvm官方頻道看視頻,有很多有用的分享。
結構示意圖
注:以下文字內容來源於網絡(https://www.leadroyal.cn/?p=701)[
Module:可以被視為一個.c文件的 IR 表示,如果用Java的描述的話, Module相當於Java裡的類,是獨立存在的一個東西。
每個 Module都是相對獨立的東西,主要包含了聲明或者定義的函數、聲明或定義的全局變量、當前 Module的基本信息。
多個 Module之間是相互隔離的、無法獲取對方的內容,跟Java裡類的設定真的非常像。平時為了獲取 Module 的主要信息,使用它的 M.dump() 方法就會在屏幕上列印出全部信息。
Function:是Module中以List的方式存放的,如果用Java的描述的話, Function相當於Java裡的Method,無法單獨存在,必須是在某個 Module裡的。主要包含了大量 BasicBlock 、參數和返回值類型、可變參數列表、函數的attribute和其他函數的基本信息(例如函數名、所在 Module等)。
BasicBlock:是 Function 中以List方式存放的,無法單獨存在,必須是在某個Function裡的,是真正存放可執行代碼的容器。主要包含了大量的 Instruction ,前驅、後繼的 BasicBlock,以及一些基本信息(例如名字什麼的),相比 Function ,它的校驗也更加嚴格,例如不可以憑空出現、不可以處於游離狀態。
BasicBlock由很多 Instruction組成,按照是否為 TerminatorInst 可以將指令分為兩類,一類是普通的指令,一類是可以成為 TerminatorInst 的指令;因此 BasicBlock一定要以 TerminatorInst類的指令結尾,而且除了最後一個指令是 TerminatorInst,其他指令都是普通指令。每個 BasicBlock都可以視為一段順序執行的代碼,完全不會有任何的分支,有分支就會通過 TerminatorInst進行跳轉。
Instruction:就是上面提到過的「指令」,LLVM IR的最基本的單位,Instruction被包含在BasicBlock中,一個BasicBlock可以有多條Instruction
注:以上文字內容來源於網絡(https://www.leadroyal.cn/?p=701)]
foo.c ==> foo.ll
int foo(int i){ return i;}
1.IR的高級結構
01~04行:當前模塊信息,比如ID,源文件名等
06~10行:foo()函數定義
12~12行:全局屬性
14~18行:命名元數據
2.目標信息
以下圖參考對照
3.IR語法
注釋以分號 ; 開頭
全局標識符以@開頭,局部標識符以%開頭
alloca,在當前函數棧幀中分配內存
i32,32bit,4個字節的意思
align,內存對齊
store,寫入數據
load,讀取數據
本文的介紹僅是滄海一粟,關於IR語法更多的學習可以看https://llvm.org/docs/LangRef.html
4.Function
開始於關鍵字define
返回值類型i32,32bit整型
@foo:全局作用域函數foo()
foo()後一般還帶有Function Attributes,如下
參數列表:type-var對列表,此例中是i32類型的%arg
Basic Block:bb是Basic Block的開始標籤
Instruction:表示return的ret指令,有一個i32類型的參數
5.全局屬性attributes
nounwind:表示該函數不會引發異常
uwtable:unwind符號表,記錄與函數相關的debug信息
6.Named Metadata
llvm.module.flags元數據包含一個元數據列表,以傳達有關整個模塊的信息
llvm.ident是llvm標識符的縮寫,可以看到!1即是clang的版本號
每一個元數據包含三個元素:
behavior flag:指定兩個(或多個)模塊合併在一起時的行為,並且可能遇到具有相同ID的元數據。該值可以是1到7,表示不同的行為,例如發出錯誤,發出警告,使用指定的值覆蓋,附加兩個值等
metadata string:元數據的唯一ID作為其名稱
value of the flag:元數據的值。它用於與另一個模塊的元數據值進行比較並觸發指定的行為。
此例:
metadata !0的ID即為wchar_size,值為4,行為標誌為1,如果兩個值不同發出錯誤。
metadata !1的flag和value都為空,只包含一個ID即字符串名字
7.修改IR文件
IR文件可以直接修改運行,比如,修改world改為azima
結語:
好吧,這一篇就水到這裡吧,實在水不動了😄,英文的視頻文檔看的頭大...不過好在看完以上的這些應該就對IR有了一個模糊的印象了,更加深入的內容隨著學習會逐漸明朗起來的,加油。