LLVM language 参考手册(译)(1)

LLVM Language Reference Manual

摘要

  这个文档是一个LLVM汇编语言的参考手册。LLVM是一个基于Static Single Assignment(SSA - 静态单赋值)表示,提供了类型安全,低级别操做,灵活性和表现“全部”高级语言的能力。他是在LLVM编译策略的各个阶段中使用的通用代码表示。html

介绍

  LLVM的代码表示形式被设计为使用三种不一样的格式:一、表示为在内存中编译器中间语言,表示为在磁盘上的位码(适合于即时编译器的快速加载) ,表示为人类可读的汇编语言。LLVM为编译器的高效转换和分析提供了强大的中间语言,同时提供一个天然的方法来调试和可视化的转换。LLVM的这三种不一样形式的代码表示的都是等价的。本文档描述了人类可读的表明性和符号。正则表达式

  LLVM表示法的目标是实现轻量和低级别同时是有表现力的,类型化,可扩展。它的目标是成为一个“通用IR”的排序,由是在一个足够低的水平是高层次的思想能够被清晰地映射到它(相似于微处理器是如何“万能IR的” ,这让不少源语言被映射到它们) 。经过提供类型信息, LLVM能够做为优化的目的:例如,经过指针分析能够证实,一个C的自动变量是历来没有被当前函数之外的地方访问,那么就可让它被提高到一个简单的SSA值中而不是存储单元中。数组

  Well-Formness(规范化)  

注意这个文档描述规范化的LLVM汇编语言。这有区别于“能够被解释的就是(well-formed)格式良好的” 的概念。例如,下面的指令在语法上是OK的,但不是'well form'(格式良好的)的:  安全

    %x = add i32 1, %x

这是由于%x的定义不能支配到全部使用了%X的地方。 LLVM的架构提供了一个verification pass,用于验证一个LLVM模块是否规范化。这个pass将自动于解释器解释输入汇编以后和优化程序输出bitcode以前。被verifier pass指出的违规行为表现为在transformation passes或解释器的输入的bug架构

Identifiers

  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

  它也代表了一个在这个文档咱们应该遵循的约定。当演示指令的时候,咱们应该使一个定义了被建立的值的类型和名称的注释紧跟这条指令后面

高层结构(High Level Structure)

  模块结构(Module Structure) 

; 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之一

(连接类型)Linkage Types

(如下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”联动合并具备相同名称的其余全局联动时发生。这能够被用来实现某些形式的内联函数,模板,或者它必须在使用它的每一个转换单元中生成的,但其中的主体能够具备更明确的定义之后被覆盖其余代码。

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.
extern_weak
这个连接标识的语义遵循ELF object file模型:除非被连接,不然带有extern_weak的symbol是弱的,若是没有被连接该符号会变为null而不是做为未定义引用。
linkonce_odrweak_odr
某些语言容许不一样的全局变量被合并,例如具备不一样的语义的两个函数。其余语言,如C + + ,确保只等效的全局变量才能够合并( “one definition rule” - “ ODR ” ) 。这些语言可使用linkonce_odr和weak_odr连接标识来代表全局变量将只与等效的全局变量合并。这些连接标识类型的其余语义与其非ODR版本相同。
external
若是上述标识符都没被使用,那么该全局变量的是外部可见的,这意味着它参与连接,可用于解析外部符号引用。

一个函数声明拥有除“external" 或 “extern_weak"之外的连接标识是不合法的。

相关文章
相关标签/搜索