LLVM language 参考手册(5)

 

垃圾回收器名称(Garbage Collector Names

每一个函数可以制定一个垃圾回收期的名称,这个名称是一个简单的字符串:

define void @f() gc "name" { ... }

编译器声明了这个名字的可能值。指定一个收集器将会导致编译器会为了支持这个垃圾回收算法修改它的输出。

前置数据(Prefix Data

前置数据是一种与函数相关的数据,在函数主体之前代码生成器会马上发散这种数据。这个特性的目的是为了让允许在前端分配语言指定的在指定函数中运行期元数据,并且可以通过函数指针来获得这个数据的同时这个函数指针仍然是可调用的。对一个给定的函数来访问这个数据,程序可以通过bitcast转换这个函数指针到一个常量类型的指针。这是意味着这个IR符号指向这个前置数据的开始。

为了维持普通函数调用的语义,这个前置数据必须有一个实际格式。具体来说,这必须开始于一段bytes序列,且可以从中解码到一段用于该模块目标的机器指令序列,这个点的传送控制紧随这个前缀数据,而不执行任何其他的可见动作。这就允许内联器和其他pass来推论这是一个函数定义语义而不是需要一个前置数据。显而易见地,这使前置数据的格式高度依赖于目标平台。

前置数据的定义,类似于一个前缀数据类型的全局变量的初始化式。在前置数据和函数主体之间没有自动填充的数据。如果有填充要求,那么它必须是前置数据的一部分。

这是一个很小的有效前置数据,其对于X86体系结构的值为144,类型为i8,则会被编码为 nop 指令。

define void @f() prefix i8 144 { ... }

一般来说,前置数据可以跳过元数据通过编码一个相关的branch指令,就像下面这个例子中的对于X86_64体系有效的前置数据,它的前两个byte将被编码jmp.+10

%0 = type <{ i8, i8, i8* }>



define void @f() prefix %0 <{ i8 235, i8 8, i8* @md}> { ... }

函数可能只拥有前置数据但没有主体。这与 available_externally 链接标识有着相同的语义,即数据可能会被优化器使用的不会被发散到对象文件中。

属性组(Attribute Groups

属性组是在IR中的对象引用的属性的集合。他们对于保持 .ll 可读有着重要意义,因为许都函数会使用相同的属性集。在退化的情况下一个 .ll 文件对应着单一的 .c 文件,这个单一的属性组讲捕获那些用于构建这个文件的重要命令行标识。

一个属性组是一个模块层次的对象。要使用一个属性组,一个对象可以引用这个属性组的ID(例如 #37)。一个对象可能引用超过一个属性组。在这种情况下来自于不同属性组的属性会被合并。

这里有一个规定一个函数应该内联的属性组的例子,并拥有一个堆栈对齐属性值为4,且不使用SSE指令

; Target-independent attributes:

attributes #0 = { alwaysinline alignstack=4 }



; Target-dependent attributes:

attributes #1 = { "no-sse" }



; Function @f has attributes: alwaysinline, alignstack=4, and "no-sse".

define void @f() #0 #1 { ... }

函数属性(Function Attributes

函数属性用于函数交流额外信息的。函数属性被认为是函数的一部分,而不是函数类型的一部分,所以拥有不同函数属性的函数可以对应着同一个函数类型。

函数属性是紧跟在指定的函数类型后的简单的关键字。如果以后需要指定多个函数属性,那么使用空格符分隔它们。例如:

define void @f() noinline { ... }

define void @f() alwaysinline { ... }

define void @f() alwaysinline optsize { ... }

define void @f() optsize { ... }
alignstack(<n>)
这个属性指明了,当发散序言和后记,后端应该强制对齐堆栈指针。在括号中指定所希望的对齐属性,其值必须是2的幂。
alwaysinline
该属性指明了内联器应该尽可能地内联这个函数到调用者中,而忽略这个调用者有效的内联阙值。
builtin
这表明,在调用点被调用函数应该被认定为内建函数,即使该函数的声明使用了  nobuiltin 属性。这只在直接调用了声明了  nobuiltin 属性的函数的调用地点有效。
cold
该属性表明了这个函数将很少被调用。在计算边权重时,被一个cold函数所控制的基本块也被认为是cold的,因此将被给予低权重。
inlinehint
该属性表明,这份源代码包含一个提示,即内联函数是可行的(如C / C + +中的“inline”关键字)。这仅仅是一个提示,它不对内联器做出任何要求。
minsize
该属性建议优化器pass和代码生成器pass保持函数的代码长度尽量的小且牺牲运行时效率来最小化生成的代码来进行优化。
naked
这个属性禁止函数的序言/结尾发散。产生的结果是特定于系统的。
nobuiltin
这表明,在调用点被调用函数不被识别为一个内建函数。 LLVM将保留原来的调用,而不是使用基于内建函数语义等价的代码替换它,除非调用点使用了  builtin 的属性。这个属性对于调用点和函数的声明和定义都是有效的。、
noduplicate

该属性表明,函数的调用不能被复制。一个 noduplicate 函数的调用可能被移动到父函数​​,但不能被复制到父函数。

一个包含 noduplicate 函数仍然可能被内联,条件是该调用没有被重复内联。这意味着,该函数具有 internal 链接标识,并只有一个调用点,所以内联后,原始调用被删除。

noimplicitfloat
该属性表明,禁用隐式的浮点指令
noinline
此属性表明,在任何情况下,内联器都不应该内联该函数。此属性不能与 alwaysinline 属性一起使用。
nonlazybind
此属性表明,抑制函数的延迟绑定符号特性。如果函数在程序启动时不被调用,那么程序启动会耗费额外的启动时间,但这可能会使函数调用更快。
noredzone
此属性表明,即使目标平台指定的ABI通常允许,该属性指示代码生成器也不应该使用一个red zone,。
noreturn
此属性表明,该函数从不正常返回。如果该函数动态返回,这将产生不确定的运行期行为,。
nounwind
此属性表明,该函数从不返回展开的或异常的控制流。如果函数不展开,其运行时的行为是未定义的。
optnone

此此属性表明,该函数不能被除了过程间优化 pass 外的任何优化或代码生成器 pass 优化。这个属性不能与一起 alwaysinline 属性使用;这个属性也与 minsize 属性和 optsize 属性不兼容。( minsize 与 optsize 要求优化)

此属性要求在函数中同时指定该属性和 noinline 属性,所以该函数从不内联到任何调用者。只有具备alwaysinline 属性的函数才能内联到这个函数。

optsize
此属性表明,优化 pass 和代码生成器 pass 应该保持这个函数的代码长度较小,否则进行特定的优化,不显著影响运行期性能的情况下减少代码长度。
readnone

对于一个函数,这个属性表明该函数严格基于它的参数计算其结果(或决定展开异常),而不通过解引用任何指针参数或以其他方式访问任何调用者可见的可变状态(如内存,控制寄存器等)。它不通过任何指针参数(包括 byval 参数)写入和从不改变调用者可见的任何状态。这意味着它无法通过调用C + +的异常throw的方法展开异常。

对于一个参数,这个属性表明,该函数不能解引用指针参数,尽管如果通过其他指针它可以读取或写入指针参数指向内存(因为调用者可见的是指针的值而不是指针指向的值)。

readonly

对于一个函数,这个属性表明该函数不通过任何指针参数(包括 byval 参数)或写其他方式修改任何调用者函数可见的状态(如内存,控制寄存器等)。它可能会解引用指针参数和读取在调用者中设置的状态。在使用相同的函数集和全局状态时,一个只读函数总是返回相同的值(或展开相同的异常)。它无法通过调用C + +的异常throw的方法展开异常。

上一个参数,这个属性表示该函数不通过这个指针参数写的,即使它可能写入内存的指针指向。

returns_twice
该属性表明,该函数可以返回两次。该C  setjmp 的是这样一种函数的一个例子。编译器禁用这些函数的调用者一些优化(如尾调用)。
sanitize_address
该属性表明,为函数启用AddressSanitizer检查(动态地址安全分析)。
sanitize_memory
该属性表明,为函数启用MemorySanitizer检查(未初始化内存访问的动态检测)
sanitize_thread
该属性表明,为函数启用ThreadSanitizer检查(动态线程安全性分析)
ssp

该属性表明,该函数应该发散一个堆栈溢出保护功能。它有一个“canary”形式 —( a random value placed on the stack before the local variables that’s checked upon return from the function to see if it has been overwritten.)。一个启发式用来确定一个函数需要的堆栈保护与否。在以下情况,这个被使用了启发式将启用函数保护器:

字符数组比 ssp-buffer-size 大(默认值为8)。
字符数组的集合比 ssp-buffer-size 大。
调用alloca()的变量长度或常量长度(alloca的参数)大于 ssp-buffer-size 。

被识别为需要保护的变量将被安排在堆栈,使得对于堆栈保护器它们是连续的。

如果一个函数,它有一个SSP属性被内联到一个不具有SSP属性的函数,然后将得到的函数将具有一个SSP属性。

sspreq

该属性表明,该函数应该发散一个堆栈溢出保护功能。这将覆盖 ssp 函数属性。

被识别为需要保护的变量将被安排在堆栈,使得对于堆栈保护器它们是连续的。具体布局规则是:

1、大数组和含大数组的结构体(>= sp-buffer-size)是最接近堆栈保护器的。
2、小数组和含小数组的结构体(< sp-buffer-size)是第二接近堆栈保护器的。 

3、采取了它们的地址的变量是第三接近堆栈保护器的

如果一个函数,它有一个 sspreq 属性被内联到一个不具有 sspreq 属性或具有 ssp 或 sspstrong 属性的函数,那么得到的结果函数将具有 sspreq 属性。

sspstrong

该属性表明,该函数应该发散一个堆栈溢出保护功能。在确定函数是否需要的堆栈保护器时,此属性会使用一个强有力的试探法。强大的启发式将为函数启用保护器:

任何长度和类型的数组
任何长度和类型的数组的集合。
调用了alloca( ) 。
采取了它们的地址的局部变量。

被识别为需要保护的变量将被安排在堆栈,使得对于堆栈保护器它们是连续的。具体布局规则是:

1、大数组和含大数组的结构体(>= sp-buffer-size)是最接近堆栈保护器的。 
2、小数组和含小数组的结构体(< sp-buffer-size)是第二接近堆栈保护器的。 

3、采取了它们的地址的变量是第三接近堆栈保护器的

这将覆盖 ssp 功能属性。

如果一个函数,它有一个 sspstrong 属性被内联到一个不具有 sspstrong 属性的函数,那么最后得到的函数将具有 sspstrong 属性。

uwtable
该属性表明,被指定的ABI要求为这个函数展开表实体,即使我们可以表明没有异常会被这个函数传递。。这通常是针对于ELF x86-64 ABI的情况,但是它可以为某些编译单元被禁用。

你可能感兴趣的:(language)