這個文檔是一個LLVM彙編語言的參考手冊。LLVM是一個基於Static Single Assignment(SSA - 靜態單賦值)表示,提供了類型安全,低級別操做,靈活性和表現「全部」高級語言的能力。他是在LLVM編譯策略的各個階段中使用的通用代碼表示。html
LLVM的代碼表示形式被設計爲使用三種不一樣的格式:一、表示爲在內存中編譯器中間語言,表示爲在磁盤上的位碼(適合於即時編譯器的快速加載) ,表示爲人類可讀的彙編語言。LLVM爲編譯器的高效轉換和分析提供了強大的中間語言,同時提供一個天然的方法來調試和可視化的轉換。LLVM的這三種不一樣形式的代碼表示的都是等價的。本文檔描述了人類可讀的表明性和符號。正則表達式
LLVM表示法的目標是實現輕量和低級別同時是有表現力的,類型化,可擴展。它的目標是成爲一個「通用IR」的排序,由是在一個足夠低的水平是高層次的思想能夠被清晰地映射到它(相似於微處理器是如何「萬能IR的」 ,這讓不少源語言被映射到它們) 。經過提供類型信息, LLVM能夠做爲優化的目的:例如,經過指針分析能夠證實,一個C的自動變量是歷來沒有被當前函數之外的地方訪問,那麼就可讓它被提高到一個簡單的SSA值中而不是存儲單元中。數組
注意這個文檔描述規範化的LLVM彙編語言。這有區別於「能夠被解釋的就是(well-formed)格式良好的」 的概念。例如,下面的指令在語法上是OK的,但不是'well form'(格式良好的)的: 安全
%x = add i32 1, %x
這是由於%x的定義不能支配到全部使用了%X的地方。 LLVM的架構提供了一個verification pass,用於驗證一個LLVM模塊是否規範化。這個pass將自動於解釋器解釋輸入彙編以後和優化程序輸出bitcode以前。被verifier pass指出的違規行爲表現爲在transformation passes或解釋器的輸入的bug架構
LLVM的identifier有兩種基本類型:global和local。Global identifiers(函數,全局變量)以「@」字符開頭。Local identifiers(寄存器名稱,類型)「%」字符開頭。此外,有三個不一樣的格式identifiers,用於不一樣的目的:app
一、具名值表示爲一段字符串加上他們的前綴。例如,%foo, @DivisionByZero, %a.really.long.identifier. 其正則表達式爲 ‘[%@][a-zA-Z$._][a-zA-Z$._0-9]*‘ide
(前綴後的字符串不能以數字開頭)identifier當須要在名稱中的其餘字符的時候能夠用引號包圍該字符。特殊字符可使用「\ XX」,其中xx是字符的十六進制的 ASCII碼進行轉義。以這種方式,任何字符能夠在名稱中被使用,甚至「字符也能夠。函數
二、非具名值表示爲一個無符號數值加上他的前綴,例如,%12, @2, %44。優化
三、常量,詳細描述在下面的Constant部分。ui
LLVM要求值以一個前綴開始有兩個緣由:一、編譯器不須要擔憂值的名稱會和保留字(reserved words)衝突,保留字(reserved word)集能夠在將來擴展的 時候不會出現懲罰(penalty,不會發生衝突)。除此之外,非命名的identifier容許編譯器快速找出一個臨時變量且不會形成符號表衝突。
LLVM中的reserved words與其餘語言的reserved words很是類似。有相應的關鍵字對應着不一樣的操做碼有 (‘add‘, ‘bitcast‘, ‘ret‘, etc...),原始類型名(‘void‘, ‘i32‘, etc...)和其餘。這些保留字不會與變量名衝突,由於他們之中沒有一個是之前綴 ('%' or '@')開頭的。
這裏有一個表示用8乘上一個整型變量‘%X‘ 的LLVM代碼例子:
The easy way:
%result = mul i32 %X, 8
在強度折減後:(關於強度折減你們能夠經過SSA的頁面連接去了解一下)
%result = shl i32 %X, 3
And the hard way:
%0 = add i32 %X, %X ; yields {i32}:%0
%1 = add i32 %0, %0 ; yields {i32}:%1
%result = add i32 %1, %1
用8乘上%X‘的最後的方式說明了LLVM的幾個重要的詞法特色:
一、註解是以 ‘;‘ 分隔且直到當前行的結尾
二、當計算的結果不能被賦值的一個具名值的時候,非命名臨時變量被建立
三、非具名臨時變量是按順序編號的(使用一個遞增計數器,從0開始)。注意整個基本塊都被包含在這種編號方法中。例如,若是一個基本塊的入口沒有被給予 一個標籤名,那麼它就會得到一個編號0
它也代表了一個在這個文檔咱們應該遵循的約定。當演示指令的時候,咱們應該使一個定義了被建立的值的類型和名稱的註釋緊跟這條指令後面
; Declare the string constant as a global constant.
@.str = private unnamed_addr constant [13 x i8] c"hello world\0A\00"
; External declaration of the puts function
declare i32 @puts(i8* nocapture) nounwind
; Definition of main function
define i32 @main() { ; i32()*
; Convert [13 x i8]* to i8 *...
%cast210 = getelementptr [13 x i8]* @.str, i64 0, i64 0
; Call puts function to write out the string to stdout.
call i32 @puts(i8* %cast210)
ret i32 0
}
; Named metadata
!1 = metadata !{i32 42}
!foo = !{!1, null}
這個例子由一個全局變量".str",一個"puts"函數的外部聲明,一個"main"函數的函數定義和一個具名元數據"foo"組成。
通常狀況下,一個模塊由全局值(函數和全局變量都是全局值)的列表組成,全局值經過存儲單元的指針表示(在這種狀況下,一個指針指向字符數組,一個指針指向一個函數)並具備如下的linkage type之一
(如下symbol譯做符號,identifier譯做標識符,但二者意義基本相同,如不可互換時會加以註釋)
全部的全局變量和函數有聯繫的下列類型之一:
private
"private"連接的全局值只能由當前模塊中的對象直接訪問。特別地,連接代碼到一個包含"private"全局值的模塊時在必要狀況下可能會形成"private"全局值rename來避免衝突。由於這個symbol是對當前模塊私有的,因此全部對這個全局值的引用均可以被更新(名字)。這並不會在object file的任何symbol table中展現出來。"
linker_private
與"private"類似,但該symbol會傳遞到assembler(彙編器)中並經過linker(連接器)求值。不一樣於普通的強符號,它們會連接器從最終連接映像(可執行文件或動態庫)中被移除。(但處於不一樣模塊的linker_private symbol(符號)不會被合併)
linker_private_weak
與"linker_private"類似,可是這個symbol是weak的(弱符號)。注意 linker_private_weak symbol是受連接器合併的。 它們會連接器從最終連接映像(可執行文件或動態庫)中被移除。
internal
與"private"類似,但該值在object file表現爲local symbol (STB_LOCAL in the case of ELF) . 這對應於C中的「static」的關鍵字的概念。
在這裏複習一下連接的知識:http://www.cnblogs.com/kirito/p/3561900.html
available_externally
帶有"available_externally"連接標識的全局變量不會存放到當前object file相應的LLVM模塊。他們的存在是爲了內聯和其餘優化行爲的發生提供當前模塊的一份全局定義,切這份定義是從一個外部模塊中得到的。帶有"available_externally "連接標誌的全局變量容許在任意時刻丟棄,而其餘方面與"linkonce_odr"類似。這個連接類型只容許在定義中使用,不容許在聲明中使用。
linkonce
帶有"linkonce"連接標識的全局變量會在連接過程當中與其餘同名的全局變量合併。這能夠被用於實現內聯函數,模板,或其餘必須在每個編譯單元內使用的代碼的形式,但主體能夠被一個更詳細的定義覆。蓋
全局用「的linkonce」聯動合併具備相同名稱的其餘全局聯動時發生。這能夠被用來實現某些形式的內聯函數,模板,或者它必須在使用它的每一個轉換單元中生成的,但其中的主體能夠具備更明確的定義之後被覆蓋其餘代碼。
一個函數聲明擁有除「external" 或 「extern_weak"之外的連接標識是不合法的。