LLVM IR 参数属性

返回类型和函数类型的每个参数都可能具有一组与其关联的参数属性。参数属性用于传递有关函数结果或参数的附加信息。参数属性被认为是函数的一部分,而不是函数类型,所以具有不同参数属性的函数可以具有相同的函数类型。

参数属性是遵循指定类型的简单关键字。如果需要多个参数属性,则它们是空格分隔的。例如:

declare i32 @printf(i8* noalias nocapture, ...)
declare i32 @atoi(i8 zeroext)
declare signext i8 @returns_signed_char()

目前,仅定义了以下参数属性:

  • zeroext

    这向代码生成器指示参数或返回值应该被调用者(对于参数)或被调用者(对于返回值)被零扩展到目标机ABI所需的范围。

  • signext

    这向代码生成器指示参数或返回值应该由调用方(对于参数)或被调用方(对于返回值)进行符号扩展到目标机的ABI(通常为32位)所需的范围内。

  • inreg

    这表明这个参数或返回值应该以特定的与目标机相关的方式处理,同时为函数调用或返回发送代码(通常通过将其放入寄存器而不是内存中,尽管有些目标机使用它来区分两个不同类型的寄存器)。使用此属性是特定于目标机的。

  • byval

    这表明指针参数应该真的按值传递给函数。该属性意味着指向者的隐藏拷贝在调用者和被调用者之间建立,所以被调用者无法修改调用者中的值。该属性仅对LLVM指针参数有效。它通常用于按值传递结构和数组,但在指向标量的指针上也是有效的。复制被认为属于调用者而不是被调用者(例如,readonly函数不应写入byval参数)。这不是返回值的有效属性。

    byval属性还支持使用align属性指定对齐方式。它指示要形成的堆栈槽的对齐以及指定给调用点的指针的已知对齐。如果未指定对齐,则代码生成器会进行特定于目标机的假设。

  • inalloca

    inalloca参数属性允许调用者采取传出栈参数的地址。一个inalloca参数必须是堆栈内存指针,alloca指令生成堆栈内存。alloca或参数分配也必须使用inalloca关键字进行标记。只有最后一个参数可能具有该inalloca属性,并且该参数保证在内存中传递。

    参数分配最多可以由一个调用使用一次,因为调用可能会释放它。影响参数存储的属性,象inregnestsret,或byvalinalloca属性不能结合这些属性一起使用。inalloca属性还禁止LLVM隐式降低大型聚合返回值,这意味着前端作者必须用sret指针降低它们(意思就是不要直接返回大型的值,改用返回指针)。

    到达呼叫点时,参数分配必须是最新的还存活的堆栈分配,否则结果未定义。可以在参数分配之后、其调用点之前分配额外的堆栈空间,但必须使用llvm.stackrestore清除它。

    有关如何使用此属性的更多信息,请参阅InAlloca属性的设计和使用

  • sret

    这表明指针参数指定了作为源程序中函数返回值的结构地址。该指针必须由调用者保证是有效的:加载和存储到结构可以由被调用者假定不要陷入并且被正确对齐。这不是返回值的有效属性。

  • align

    这表明优化器可能会假定指针值具有指定的对齐方式。如果指针值没有指定的对齐方式,则行为未定义。
    请注意,该属性在与byval属性组合时具有额外的语义 。

  • noalias

    这表明,通过基于所述参数或返回值的指针值访问的对象不可以访问,该函数的执行过程中,通过不基于所述参数或返回值的指针值。返回值的属性也具有下面描述的附加语义。调用方与被调用方分担责任,确保满足这些要求。有关更多详细信息,请参阅别名分析中NoAlias回应的讨论。

    请注意,这个noalias定义有意地类似于C99中用于函数参数的restrict定义。

    对于函数返回值,C99的restrict意义不大,而对LLVM的noalias是有意义的。此外,在函数参数上使用时,返回值上的noalias属性的语义强于该属性的语义。在函数返回值上,noalias属性指示该函数的作用类似于系统内存分配函数,它返回一个指针,指向调用者可访问的任何其他对象的存储器的已分配存储空间。

  • nocapture

    这表明被调用者不会创建超出被调用者本身的指针的任何副本。这不是返回值的有效属性。在易变的操作中使用的地址被认为是被捕获的。

  • nest

    这表明指针参数可以使用弹性(trampoline)内联函数删除。这不是返回值的有效属性,只能应用于一个参数。

  • returned

    这表明函数总是返回参数作为其返回值。这是在生成调用者时使用的优​​化器和代码生成器的提示,允许值传播,尾部调用优化以及在某些情况下省略寄存器保存和恢复;在生成被调用者时不检查或强制执行。该参数和函数返回类型必须是bitcast指令的有效操作数。这不是返回值的有效属性,只能应用于一个参数。

  • nonnull

    这表明参数或返回指针不为null。该属性可能只适用于指针型参数。这不是LLVM检查或执行的,调用者必须确保传入的指针非空,或者被调用者必须确保返回的指针非空。

  • dereferenceable()

    这表明参数或返回指针是可逆向引用的(dereferenceable,就是用*pr引用值)。该属性可能只适用于指针型参数。一个可逆向引用的指针可以从投机加载而没有陷入的风险。已知可逆向引用的字节数必须在括号中提供。字节数小于指点人类型的大小是合法的。该nonnull属性并不意味着可引用性(考虑一个指向数组末尾的一个元素的指针),但是dereferenceable(<n>)暗含nonnulladdrspace(0)中(这是默认地址空间)。

  • dereferenceable_or_null()

    这表明参数或返回值不能同时为非空和不可逆向引用(达到<n>字节)。标记为dereferenceable_or_null(<n>)的所有非空指针是dereferenceable(<n>)。对于地址空间0 dereferenceable_or_null(<n>)意味着一个指针是正好一个dereferenceable(<n>)或null;在其它的地址空间dereferenceable_or_null(<n>) 意味着一个指针中的至少一个dereferenceable(<n>)null(它也可以是nulldereferenceable(<n>))。该属性可能只适用于指针型参数。

  • swiftself

    这表明该参数是self/context参数。这不是返回值的有效属性,只能应用于一个参数。

  • swifterror

    这个属性被激发来模拟和优化Swift错误处理。它可以应用于指针指向指针类型或指针大小的alloca的参数。在调用点,与参数相对应的实际swifterror参数必须来自swifterrorallocaswifterror调用者的参数。甲swifterror值(参数或ALLOCA)只能加载和存储的,或用作一个swifterror参数。这不是返回值的有效属性,只能应用于一个参数。

    这些约束允许调用约定swifterror通过将它们与在调用边界的特定寄存器相关联来优化对变量的访问,

    而不是将它们放置在内存中。由于这确实改变了调用约定,所以swifterror在参数上使用属性的函数不是ABI兼容的。

    这些约束条件还允许LLVM假定swifterror参数不会在函数swifterror中使其他内存可见,并且作为参数传递的alloca不会转义。

  • immarg

    这表示该参数必须是立即值。这必须是一个简单的立即整数或浮点常数。Undef或常量表达式无效。这仅对内部声明有效,不能应用于调用站点或任意函数。