LLVM函数定义由“define” 关键字,一个可选的链接标识,一个可选的可见性模式,一个可选的DLL存储类别,一个可选的调用约定,一个可选的 unnamed_addr 属性,一个返回值类型,一个可选的返回值的参数属性,一个函数名,一个(可能为空的)实参列表(每一个都带有可选的参数属性),可选的函数属性,一个可选的section,一个可选的对齐属性,一个可选垃圾回收期的名字,一个可选的前缀,一个左花括号,一个基本块列表和一个右花括号。
LLVM函数声明由 “declare” 关键字,一个可选的链接标识,一个可选的可见性模式,一个可选的DLL存储类型,一个可选的调用约定,一个可选的 unnamed_addr 属性,一个返回值类型,一个可选的返回值类型的参数属性,一个函数名,一个可能为空的实参列表,一个可选对齐属性,一个可选垃圾回收器名和一个可选的前缀。
一个函数定义包含一个基本块的列表,可以为函数形成CFG(控制流图形)。每一个基本块可以(可选的)开始于一个label(给定这个基本快一个符号表入口),包含一个指令列表,并且结束与一个终止指令(例如分支或函数返回)。如果一个明确的label不被提供,一个快会被分配到一个隐式的编号label,使用的计数器与匿名临时变量使用同一个计数器。例如,如果一个函数入口块不具有一个显示的label,他会被分配到一个label "%0",然后第一个在这个块中的匿名临时变量将会是“%1”。
函数中的第一基本块特殊在两个方面: 她是在函数进入后马上执行的,并且它是不允许有前置基本块(即函数入口块不能拥有任何分支)。因为这个块没有前置块,所以也不能有任何 PHI nodes.
LLVM允许函数指定一个明确的section。如果目标平台支持它,它会放散函数到这个指定块。
一个显示的对齐属性可能会被指定到一个函数。如果没有指定,或者对齐属性被设置为0,那么这个函数的对齐属性将会根据目标平台的需要设定。如果一个显式对齐属性被指定,这个函数被迫至少想指定的那么多对齐。所有对齐属性必须为2的次幂。
如果 unnamed_addr 属性被指定了,函数的地址会被认为是不重要的且两个相同的函数之间可以被合并。
语法:
define [linkage] [visibility] [DLLStorageClass] [cconv] [ret attrs] <ResultType> @<FunctionName> ([argument list]) [fn Attrs] [section "name"] [align N] [gc] [prefix Constant] { ... }
别名作为可别名对象(包括函数,全局变量,另一个别名或全局值的bitcast)的“second name”。别名可以拥有一个可选的链接标识,一个可选的可见性模式,一个可选的DLL存储类别。
语法:
@<Name> = [Visibility] [DLLStorageClass] alias [Linkage] <AliaseeTy> @<Aliasee>
链接标识必须是 private, linker_private, linker_private_weak, internal, linkonce, weak, linkonce_odr, weak_odr, external.中的其中一个。注意一些系统链接器可能会不正确地处理一个降级的弱符号作为非弱别名。
具名元数据是一个元数据的集合。Metadata nodes (但非元数据字符串) 是唯一对于具名元数据有效的操作数。
语法:
; Some unnamed metadata nodes, which are referenced by the named metadata.
!0 = metadata !{metadata !"zero"}
!1 = metadata !{metadata !"one"}
!2 = metadata !{metadata !"two"}
; A named metadata.
!name = !{!0, !1, !2}
这个返回类型和每一个函数的参数类型可能拥有一个参数属性集。参数属性是用于交流函数的返回值和参数的额外信息。参数类型被认为是函数的一部分,但不是函数类型的一部分,所以用不同的参数属性的函数可以拥有同一个函数类型。
参数属性是是以下的一些跟在类型后的简单的关键字。如果需要多个参数属性,他们需要被空白符分隔开。
例如:
declare i32 @printf(i8* noalias nocapture, ...)
declare i32 @atoi(i8 zeroext)
declare signext i8 @returns_signed_char()
注意,任何对于函数结果nounwind, readonly)属性跟随在实参列表后。
当前,仅有以下的参数属性被定义:
inalloca
注意
这个特性是不稳定的且没有完全实现。
inalloca 实参属性允许调用者带有即将离开stack的实参地址。一个 inalloca 实参必须是一个使用 alloca 指令创建指向栈内存的指针的地址。这个分配的堆栈空间或实参分配必须也以inalloca关键字标识。只有过去的实参可以使用inalloca属性且这个实参保证在内存中传递。
一个实参分配可能被函数调用使用至少一次因为这个函数调用可能会释放它。这个 inalloca 属性不可能与其他会影响实参存储的属性结合使用,像inreg, nest, sret, or byval。这个 inalloca 属性也禁止LLVM隐式降低大型聚合返回值,这意味着前端作者必须通过 sret 降低他们。
当到达调用地点时,实参分配必须是仍然活的最新栈分配,或者结果是未定义的。在一个实参分配后和这个实参的调用地点前额外分配堆栈空间是可能的,但这必须清除llvm.stackrestore。
详见 Design and Usage of the InAlloca Attribute