LLVM IR 操作数捆绑

操作数捆绑是可与某些LLVM指令相关联的SSA值的标签集(当前仅包含calls和invokes)。在某种程度上,它们就像元数据,但删除它们是不正确的,并且会改变程序的语义。

Syntax:

operand bundle set ::= '[' operand bundle (, operand bundle )* ']'
operand bundle ::= tag '(' [ bundle operand ] (, bundle operand )* ')'
bundle operand ::= SSA value
tag ::= string constant

操作数绑定不是函数签名的一部分,并且可以从具有不同类型操作数绑定的多个位置调用给定函数。这反映了操作数绑定在概念上是call(或invoke)的一部分,而不是被调度的被调用者。

操作数绑定是一种通用机制,旨在支持托管语言的类似运行时自反功能。虽然操作数绑定的确切语义取决于绑定标记,但操作数绑定的存在可以影响程序的语义有一定的限制。这些限制被描述为“unknown”操作数绑定的语义。只要操作数绑定的行为可以在这些限制内进行描述,LLVM就不需要对操作数绑定有特殊的了解,就不会错误地编译包含它的程序。

  • 未知操作数绑定的捆绑操作数在控制权转移给被调用者或调用者之前以未知方式转义。
  • 使用操作数绑定进行调用和调用对入口和出口处的堆(即使调用目标是readnone或readonly)在堆上具有未知的读/写效果
    ,除非它们被特定于调用点的属性覆盖。
  • 调用点的操作数绑定不能更改被调用函数的实现。只要它们考虑到头两个属性,程序间优化就像往常一样工作。

下面分别描述更为具体的操作数绑定:

逆优化(Deoptimization)操作数绑定

逆优化(Deoptimization)操作数绑定由”deopt“操作数绑定标签表征。这些操作数绑定表示它们所连接的调用点的替代“安全”延续,并且可以由适当的运行时使用,以便在指定的调用点对编译后的帧进行去优化。最多可以有一个”deopt“操作数绑定附加到调用点。逆优化(Deoptimization)的确切细节超出了语言参考的范围,但它通常涉及将编译帧重写为一组解释帧。

从编译器的角度来看,逆优化(Deoptimization)操作数绑定使得它们所连接的调用点至少是readonly。他们通读他们所有的指针类型操作数(即使它们没有被转义)和整个可见的堆。逆优化操作数绑定不会捕获它们的操作数,除非在逆优化过程中,在这种情况下,控制将不会返回到编译帧。

内联器知道如何通过具有逆优化操作数绑定的调用进行内联。就像通过一个正常的调用点进行内联,包括构成正常的和特殊的延续一样,通过调用点内联去耦优化操作数捆绑定需要适当地组成“安全”去优化延续。内联器通过在内联体中对每个逆优化延续预先实现父代的逆优化延续。例如内联@f@g在下面的例子中:

define void @f() {
  call void @x()  ;; no deopt state
  call void @y() [ "deopt"(i32 10) ]
  call void @y() [ "deopt"(i32 10), "unknown"(i8* null) ]
  ret void
}

define void @g() {
  call void @f() [ "deopt"(i32 20) ]
  ret void
}

会有下面的结果:

define void @g() {
  call void @x()  ;; still no deopt state
  call void @y() [ "deopt"(i32 20, i32 10) ]
  call void @y() [ "deopt"(i32 20, i32 10), "unknown"(i8* null) ]
  ret void
}

前端(frontend)的责任是以句法上将调用者的逆最优化状态预先加入到被调用者的逆最优化状态的方式来构造或编码逆最优化状态,这在语义上等同于在被调用者的逆最佳化延续之后构成调用者的逆最佳化延续。

Funclet操作数捆绑

Funclet操作数绑定由”funclet“操作数绑定标签表征。这些操作数绑定表明调用点位于特定funclet内。最多可以有一个funclet操作数绑定附加到调用点,并且它必须只有一个捆绑操作数。

如果任何funclet EH焊盘(pads)已被“entered”但不是“exited”(根据EH文档中的描述),则对下面的执行一个call或者invoke是未定义的行为:

  • 没有funclet捆绑,并且不是对nounwind intrinsic的call,或者
  • 有一个funclet绑定,它的操作数不是最近输入的尚未退出funclet EH板(pad)。

类似地,如果没有funclet EH焊盘(pads)进入但尚未退出,在一个funclet bundle中执行一个call或invoke是未定义的行为。

GC转换操作数绑定

GC转换操作数绑定由”gc-transition”操作数绑定标记表征。这些操作数绑定将一个调用标记为具有一个GC策略的函数与具有不同GC策略的函数之间的过渡。如果协调GC策略之间的转换需要在调用点生成额外的代码,则这些软件绑定可能包含生成的代码所需的任何值。有关更多详细信息,请参阅GC Transitions