LLVM一些語法規則


LLVM一些語法規則

LLVM文檔

LLVM編譯器基礎架構支持廣泛的項目,從工業強度編譯器到專門的JIT應用程序,再到小型研究項目。

同樣,文檔分為幾個針對不同受眾的高級別分組:

LLVM設計概述

幾篇介紹性論文和演講。

用戶指南

這些內容適用於那些剛剛接觸LLVM系統的人。

注意:如果是僅對使用基於LLVM的編譯器感興趣的用戶,則應該查看Clang。此處的文檔適用於需要使用中間LLVM表示的用戶。

編程文檔

對於使用LLVM作為庫的應用程序的開發人員。

子系統文檔

適用於API客戶端和LLVM開發人員。

LLVM IR 鏈接類型

在LLVM程序中,所有全局變量和函數都具有以下類型的鏈接之一:

private

“private”鏈接的全局值,只能由當前模塊中的對象直接訪問。特別地,鏈接代碼到一個包含”private”全局值的模塊時,在必要情況下,可能會造成”private”全局值rename來避免沖突。因為這個symbol是對當前模塊私有的,所以,所有對這個全局值的引用,都可以被更新(名字)。這並不會在object file的任何symbol table中展示出來。

internal

與”private”相似,但該值在object file表現為local symbol (STB_LOCAL in the case of ELF) . 這對應於C中的“static”的關鍵字的概念。

available_externally

帶有available_externally鏈接標識的全局變量,不會存放到當前object file相應的LLVM模塊。存在是為了內聯和其它優化行為的發生,提供當前模塊的一份全局定義,這份定義是從一個外部模塊中獲得的。帶有available_externally鏈接標志的全局變量,允許在任意時刻丟棄,而其它方面與”linkonce_odr”相似。這個鏈接類型,只允許在定義中使用,不允許在聲明中使用。

linkonce

帶有linkonce鏈接標識的全局變量,在鏈接過程中與其它同名的全局變量合並。這可以被用於實現內聯函數,模板,或其它必須在每一個編譯單元內使用的代碼的形式,但主體可以被一個更詳細的定義覆蓋。

全局用linkonce聯動,合並具有相同名稱的其它全局聯動時發生。這可以被用來實現某些形式的內聯函數,模板,或者必須在使用每個轉換單元中生成的,但其中的主體,可以具有更明確的定義,以后被覆蓋其它代碼。

weak

除了未被引用的帶”weak”鏈接標識的全局變量,可能會被拋棄外,“weak”鏈接標識,擁有與”linkonce”相同的合並語義。這個標志被使用於在C源代碼中,聲明為”weak”的全局變量。

common

“common” 鏈接標識與“weak”鏈接標識很相似,但“common”鏈接標識被使用於C中的tentative definition,例如 int X;在全局作用域。帶有“common”鏈接標識的符號,以一種與weak symbols相同的方式被合並,但這些符號,即使未被引用也不會被刪除。 common 符號可能不會有一個明確的section,必須被0值初始化(根據ELF鏈接規則,0值初始化的符號只通過“.bss section”提供長度占位,但不在文件中占有位置),不可能被標志為constant。Functions和aliases 不可以帶有“common” 鏈接標識。(因為Functions和aliases,不可能被tentative definition)。

appending

“appending”鏈接標識,只能用於數組類型的指針全局變量。但兩個帶有“appending”鏈接標識的全局變量被鏈接到一起,這兩個全局數組,追加合並到一起。 may This is the LLVM, typesafe, equivalent of having the system linker append together “sections” with identical names when .o files are linked.

不幸的是,這與.o文件中的任何功能都不對應,只能用於llvm.global_ctors llvm特別解釋的變量。

extern_weak

這個鏈接標識的語義,遵循ELF object file模型:除非被鏈接,否則帶有extern_weak的symbol是弱的,如果沒有被鏈接,該符號會變為null,而不是作為未定義引用。

linkonce_odr, weak_odr

某些語言允許不同的全局變量被合並,例如具有不同的語義的兩個函數。其它語言,如C++ ,確保只等效的全局變量才可以合並( “one definition rule” – “ ODR ”)。這些語言可以使用linkonce_odr和weak_odr鏈接標識,表明全局變量將只與等效的全局變量合並。這些鏈接標識類型的其它語義,與其非ODR版本相同。

external

如果上述標識符都沒被使用,該全局變量的是外部可見的,意味着它參與鏈接,可用於解析外部符號引用。

一個函數聲明擁有除external 或 extern_weak以外的鏈接標識是不合法的。

LLVM IR 模塊結構

LLVM程序由Module’s組成,每個程序模塊都是輸入程序的翻譯單元。每個模塊由函數,全局變量和符號表條目組成。模塊可以與LLVM鏈接器組合在一起,LLVM鏈接器合並函數(和全局變量)定義,解析前向聲明,合並符號表條目。

以下是“hello world”模塊的示例:

; 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], [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
!0 = !{i32 42, null, !"string"}
!foo = !{!0}

這個例子由一個全局變量”.str”,一個”puts”函數的外部聲明,一個”main”函數的函數定義和一個具名元數據”foo”組成。

LLVM IR 標識符

LLVM IR 標識符有兩種基本類型:

  • 全局標識符(函數,全局變量)以’@’字符開頭。
  • 本地標識符(寄存器名稱,類型)以’%’字符開頭。

標識符有三種不同的格式,分別用於不同的目的:

  1. 命名值表示為帶有前綴的字符串。例如%foo,@DivisionByZero,%a.really.long.identifier。使用的實際正則表達式是’
    [%@][-a-zA-Z$._][-a-zA-Z$._0-9]*’。名稱中需要其它字符的標識符,可以用引號括起來。可以使用十六進制字符的ASCII代碼”\xx”,轉義特殊字符xx。通過這種方式,任何字符都可以在名稱值中使用,甚至可以引用自己。該”\01″前綴可以在全局值可用於壓制截斷。
  2. 未命名的值表示為帶有前綴的無符號數值。例如%12,@2,%44。
  3. 常量,將在后面的關於常量的部分進行描述。

LLVM要求值以一個前綴開始有兩個原因:

  • 編譯器不需要擔心值的名稱會和保留字(reserved words)沖突,保留字(reserved word)集,可以在未來擴展的時候不會出現懲罰(penalty,不會發生沖突)。
  • 非命名的identifier,允許編譯器快速找出一個臨時變量,不會造成符號表沖突。

LLVM中的保留字與其它語言的保留字非常相似。有相應的關鍵字對應着不同的操作碼,有(add, bitcast, ret, etc…),原始類型名(void, i32,etc…)和其它。這些保留字不會與變量名沖突,沒有一個是以前綴(% or @)開頭的。

這里有一個表示用8乘上一個整型變量%x的LLVM代碼例子:

#The easy way:    

%result = mul i32 %X, 8

#在強度折減后:

%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的幾個重要的詞法特點:

  1. 注解是以 ; 分隔,直到當前行的結尾
  2. 當計算的結果不能被賦值的一個具名值的時候,非命名臨時變量被創建
  3. 非具名臨時變量,按順序編號的(使用一個遞增計數器,從0開始)。注意整個基本塊,都被包含在這種編號方法中。例如,如果一個基本塊的入口,沒有被給予一個標簽名,那么,就會獲得一個編號0。

也表明了一個在這個文檔,應該遵循的約定。當演示指令的時候,應該使一個定義了被創建的值的類型和名稱的注釋,緊跟這條指令后面。

 

LLVM語言參考手冊

LLVM是一個基於SSA(靜態單賦值)表示,提供了類型安全,低級別操作,靈活性和表現“所有”高級語言的能力。他是在LLVM編譯策略的各個階段中使用的通用代碼表示。

LLVM的代碼表示形式被設計為使用三種不同的格式:

  • 表示為在內存中編譯器中間語言;
  • 表示為在磁盤上的位碼(適合於即時編譯器的快速加載);
  • 表示為人類可讀的匯編語言。

LLVM為編譯器的高效轉換和分析,提供了強大的中間語言,同時提供一個自然的方法來調試和可視化的轉換。LLVM的這三種不同形式的代碼表示的,都是等價的。本文檔描述了人類可讀的代表性和符號。

LLVM IR的目標是實現輕量和低級別同時是有表現力的,類型化,可擴展。目標是成為一個“通用IR”的序列,在一個足夠低的水平是高層次的思想,可以被清晰地映射到(類似於微處理器是如何“萬能的IR”,這讓很多源語言被映射到) 。通過提供類型信息,LLVM可以作為優化的目的:例如,通過指針分析可以證明,一個C的自動變量,從來沒有被當前函數以外的地方訪問,就可以被提升到一個簡單的SSA值中,而不是存儲單元中。

注意這個文檔描述規范化的LLVM匯編語言。這有區別於“可以被解釋的就是(well-formed)格式良好的”的概念。例如,下面的指令在語法上是OK的,但不是’well form’(格式良好的)的:  

%x = add i32 1, %x

這是因為%x的定義不能支配到所有使用了%x的地方。
LLVM的架構,提供了一個驗證過程,用於驗證一個LLVM模塊是否規范化。這個pass,將自動用解釋器解釋,輸入匯編之后和優化程序輸出bitcode之前。
驗證程序驗證過程中,指出的違規暗示轉換過程中的錯誤,或輸入到解析器中的錯誤。

 

參考鏈接:

https://llvm.liuxfe.com/docs/

http://llvm.org/docs/LangRef.htm

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM