每个函数能够制定一个垃圾回收期的名称,这个名称是一个简单的字符串:html
define void @f() gc "name" { ... }
编译器声明了这个名字的可能值。指定一个收集器将会致使编译器会为了支持这个垃圾回收算法修改它的输出。前端
前置数据是一种与函数相关的数据,在函数主体以前代码生成器会立刻发散这种数据。这个特性的目的是为了让容许在前端分配语言指定的在指定函数中运行期元数据,而且能够经过函数指针来得到这个数据的同时这个函数指针仍然是可调用的。对一个给定的函数来访问这个数据,程序能够经过bitcast转换这个函数指针到一个常量类型的指针。这是意味着这个IR符号指向这个前置数据的开始。算法
为了维持普通函数调用的语义,这个前置数据必须有一个实际格式。具体来讲,这必须开始于一段bytes序列,且能够从中解码到一段用于该模块目标的机器指令序列,这个点的传送控制紧随这个前缀数据,而不执行任何其余的可见动做。这就容许内联器和其余pass来推论这是一个函数定义语义而不是须要一个前置数据。显而易见地,这使前置数据的格式高度依赖于目标平台。后端
前置数据的定义,相似于一个前缀数据类型的全局变量的初始化式。在前置数据和函数主体之间没有自动填充的数据。若是有填充要求,那么它必须是前置数据的一部分。数组
这是一个很小的有效前置数据,其对于X86体系结构的值为144,类型为i8,则会被编码为 nop 指令。安全
define void @f() prefix i8 144 { ... }
通常来讲,前置数据能够跳过元数据经过编码一个相关的branch指令,就像下面这个例子中的对于X86_64体系有效的前置数据,它的前两个byte将被编码jmp.+10dom
%0 = type <{ i8, i8, i8* }>
define void @f() prefix %0 <{ i8 235, i8 8, i8* @md}> { ... }
函数可能只拥有前置数据但没有主体。这与 available_externally 连接标识有着相同的语义,即数据可能会被优化器使用的不会被发散到对象文件中。函数
属性组是在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 { ... }
函数属性用于函数交流额外信息的。函数属性被认为是函数的一部分,而不是函数类型的一部分,因此拥有不一样函数属性的函数能够对应着同一个函数类型。
函数属性是紧跟在指定的函数类型后的简单的关键字。若是之后须要指定多个函数属性,那么使用空格符分隔它们。例如:
define void @f() noinline { ... }
define void @f() alwaysinline { ... }
define void @f() alwaysinline optsize { ... }
define void @f() optsize { ... }
该属性代表,函数的调用不能被复制。一个 noduplicate 函数的调用可能被移动到父函数,但不能被复制到父函数。
一个包含 noduplicate 函数仍然可能被内联,条件是该调用没有被重复内联。这意味着,该函数具备 internal 连接标识,并只有一个调用点,因此内联后,原始调用被删除。
此此属性代表,该函数不能被除了过程间优化 pass 外的任何优化或代码生成器 pass 优化。这个属性不能与一块儿 alwaysinline 属性使用;这个属性也与 minsize 属性和 optsize 属性不兼容。( minsize 与 optsize 要求优化)
此属性要求在函数中同时指定该属性和 noinline 属性,因此该函数从不内联到任何调用者。只有具有alwaysinline 属性的函数才能内联到这个函数。
对于一个函数,这个属性代表该函数严格基于它的参数计算其结果(或决定展开异常),而不经过解引用任何指针参数或以其余方式访问任何调用者可见的可变状态(如内存,控制寄存器等)。它不经过任何指针参数(包括 byval 参数)写入和从不改变调用者可见的任何状态。这意味着它没法经过调用C + +的异常throw的方法展开异常。
对于一个参数,这个属性代表,该函数不能解引用指针参数,尽管若是经过其余指针它能够读取或写入指针参数指向内存(由于调用者可见的是指针的值而不是指针指向的值)。
对于一个函数,这个属性代表该函数不经过任何指针参数(包括 byval 参数)或写其余方式修改任何调用者函数可见的状态(如内存,控制寄存器等)。它可能会解引用指针参数和读取在调用者中设置的状态。在使用相同的函数集和全局状态时,一个只读函数老是返回相同的值(或展开相同的异常)。它没法经过调用C + +的异常throw的方法展开异常。
上一个参数,这个属性表示该函数不经过这个指针参数写的,即便它可能写入内存的指针指向。
该属性代表,该函数应该发散一个堆栈溢出保护功能。它有一个“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属性。
该属性代表,该函数应该发散一个堆栈溢出保护功能。这将覆盖 ssp 函数属性。
被识别为须要保护的变量将被安排在堆栈,使得对于堆栈保护器它们是连续的。具体布局规则是:
一、大数组和含大数组的结构体(>= sp-buffer-size)是最接近堆栈保护器的。
二、小数组和含小数组的结构体(< sp-buffer-size)是第二接近堆栈保护器的。
三、采起了它们的地址的变量是第三接近堆栈保护器的。
若是一个函数,它有一个 sspreq 属性被内联到一个不具备 sspreq 属性或具备 ssp 或 sspstrong 属性的函数,那么获得的结果函数将具备 sspreq 属性。
该属性代表,该函数应该发散一个堆栈溢出保护功能。在肯定函数是否须要的堆栈保护器时,此属性会使用一个强有力的试探法。强大的启发式将为函数启用保护器:
任何长度和类型的数组
任何长度和类型的数组的集合。
调用了alloca( ) 。
采起了它们的地址的局部变量。
被识别为须要保护的变量将被安排在堆栈,使得对于堆栈保护器它们是连续的。具体布局规则是:
一、大数组和含大数组的结构体(>= sp-buffer-size)是最接近堆栈保护器的。
二、小数组和含小数组的结构体(< sp-buffer-size)是第二接近堆栈保护器的。
三、采起了它们的地址的变量是第三接近堆栈保护器的。
这将覆盖 ssp 功能属性。
若是一个函数,它有一个 sspstrong 属性被内联到一个不具备 sspstrong 属性的函数,那么最后获得的函数将具备 sspstrong 属性。