3.7. 描述调用惯例的数据结构
选项“-gen-callingconv”用于生成处理函数调用惯例的代码。调用惯例是函数调用者与被调用者之间关于参数及返回值传递方式的一个共识。存在多个调用惯例,以适合各种机器架构。LLVM目前已经基本能完全通过TableGen生成处理调用惯例的代码。
3.7.1. TD的基本类型与描述
在文件TargetCallingConv.td里,首先出现的是CCAction。这是一个空类,作为表示调用惯例操作的基类。从它出发,有这些派生类:
19 class CCCustom
20 string FuncName = fn;
21 }
CCCustom记录处理参数的定制方法。
25 class CCPredicateAction
26 CCAction SubAction = A;
27 }
CCPredicateAction作为基类,用在检测特定谓词,在谓词成立时执行CCAction A的定义中。
31 class CCIfType vts, CCAction A> : CCPredicateAction {
32 list
33 }
CCPredicateAction派生类CCIfType用作判定指定类型,在指定类型之一出现时执行CCAction A。
36 class CCIf
37 string Predicate = predicate;
38 }
而派生类CCIf作为基类,用在执行指定谓词代码片段,在成立时执行CCAction A的定义中。
42 class CCIfByVal
43 }
CCIf派生类CCIfByVal则固化了谓词代码片段——参数必须按值传递。
47 class CCIfConsecutiveRegs
48 }
派生类CCIfConsecutiveRegs固化了另一种谓词代码片段——参数必须在连续的寄存器里。
51 class CCIfCC
52 : CCIf {}
56 class CCIfInReg
60 class CCIfNest
64 class CCIfSplit
68 class CCIfSRet
71 class CCIfVarArg
74 class CCIfNotVarArg
上面出现的ArgFlags是源文件CallingConvLower.h及CallingConvLower.cpp中类型为ISD::ArgFlagsTy 的函数参数,TableGen使用这个类型来描述被编译函数的参数。
79 class CCAssignToReg regList> : CCAction {
80 list
81 }
CCAssignToReg的语义由其名字隐含表述(即TableGen会解释如下):如果regList中仍有一个寄存器可用,就将值(定义中没有出现)赋给该寄存器并返回成功。
85 class CCAssignToRegWithShadow regList,
86 list
87 list
88 list
89 }
CCAssignToRegWithShadow类似于CCAssignToReg,不过还包括了一组成功时将被屏蔽的寄存器。
95 class CCAssignToStack
96 int Size = size;
97 int Align = align;
98 }
CCAssignToStack则总是使得TableGen产生将值赋给指定大小与对齐边界的栈区间。如果大小或对齐是0,使用ABI的定义值。
103 class CCAssignToStackWithShadow 104 int align, 105 list 106 int Size = size; 107 int Align = align; 108 list 109 } 同样CCAssignToStackWithShadow类似CCAssignToStack,但还包括一组成功时将被屏蔽的寄存器。 114 class CCPassByVal 115 int Size = size; 116 int Align = align; 117 } CCPassByVal则会使TableGen产生将在栈上按值传递聚集参数的代码。 121 class CCPromoteToType 122 ValueType DestTy = destTy; 123 } CCPromoteToType告诉TableGen产生将当前值(定义中没有出现)提升到destTy类型。 127 class CCPromoteToUpperBitsInType 128 ValueType DestTy = destTy; 129 } CCPromoteToUpperBitsInType类似CCPromoteToType,但还要将值移到高位。 133 class CCBitConvertToType 134 ValueType DestTy = destTy; 135 } CCBitConvertToType则是将当前值按位转换(bitconvert)到destTy类型。 139 class CCPassIndirect 140 ValueType DestTy = destTy; 141 } CCPassIndirect告诉TableGen产生将值(定义中没有出现)存入栈,将对应指针作为值传递的代码。 145 class CCDelegateTo 146 CallingConv CC = cc; 147 } CCDelegateTo指定所要委派执行的调用惯例。 接下来是描述调用惯例的基本类型。首先是CallingConv,它通过一组CCAction来刻画调用惯例的具体行为。 151 class CallingConv 152 list 153 bit Custom = 0; 154 } 然后是CustomCallingConv。它表示使用LLVM中同名的函数来处理该调用惯例(这是少数不能由机器描述生成处理调用惯例代码的例子)。 158 class CustomCallingConv : CallingConv<[]> { 159 let Custom = 1; 160 } 最后就是CalleeSavedRegs的定义,描述被调用者保存的寄存器,我们在被调用者保存寄存器一节中已经看过它的定义,以及X86对应的派生定义。 3.7.2. X86调用惯例的TD描述 X86调用惯例的描述在文件X86CallingConv.td中。首先是CCIfSubtarget定义,它用于判定目标机器是否具有指定的特征(feature)。 16 class CCIfSubtarget 17 : CCIfstrconcat("static_cast 18 "(State.getMachineFunction().getSubtarget()).", F), 19 A>; 这里State是CCState类型的对象,我们后面会详细了解这个类。 V7.0由上面的定义,引申出CCIfSubtargetNot: 22 class CCIfNotSubtarget 23 : CCIfstrconcat("!static_cast 24 "(State.getMachineFunction().getSubtarget()).", F), 3.7.2.1. 返回值惯例 接着是定义如何传递返回值的返回值惯例。首先是RetCC_X86Common,它是所有X86都适用的通用惯例。下面的注释很详细地说明了规则的细节。 26 def RetCC_X86Common : CallingConv<[ 27 // Scalar values are returned in AX first, then DX. For i8, the ABI 28 // requires the values to be in AL and AH, however this code uses AL and DL 29 // instead. This is because using AH for the second register conflicts with 30 // the way LLVM does multiple return values -- a return of {i16,i8} would end 31 // up in AX and AH, which overlap. Front-ends wishing to conform to the ABI 32 // for functions that return two i8 values are currently expected to pack the 33 // values into an i16 (which uses AX, and thus AL:AH). 34 // 35 // For code that doesn't care about the ABI, we allow returning more than two 36 // integer values in registers. 37 CCIfType<[i1], CCPromoteToType 38 CCIfType<[i8] , CCAssignToReg<[AL, DL, CL]>>, 39 CCIfType<[i16], CCAssignToReg<[AX, DX, CX]>>, 40 CCIfType<[i32], CCAssignToReg<[EAX, EDX, ECX]>>, 41 CCIfType<[i64], CCAssignToReg<[RAX, RDX, RCX]>>, 42 43 // Boolean vectors of AVX-512 are returned in SIMD registers. 44 // The call from AVX to AVX-512 function should work, 45 // since the boolean types in AVX/AVX2 are promoted by default. 46 CCIfType<[v2i1], CCPromoteToType 47 CCIfType<[v4i1], CCPromoteToType 48 CCIfType<[v8i1], CCPromoteToType 49 CCIfType<[v16i1], CCPromoteToType 50 CCIfType<[v32i1], CCPromoteToType 51 CCIfType<[v64i1], CCPromoteToType 52 53 // Vector types are returned in XMM0 and XMM1, when they fit. XMM2 and XMM3 54 // can only be used by ABI non-compliant code. If the target doesn't have XMM 55 // registers, it won't have vector types. 56 CCIfType<[v16i8, v8i16, v4i32, v2i64, v4f32, v2f64], 57 CCAssignToReg<[XMM0,XMM1,XMM2,XMM3]>>, 58 59 // 256-bit vectors are returned in YMM0 and XMM1, when they fit. YMM2 and YMM3 60 // can only be used by ABI non-compliant code. This vector type is only 61 // supported while using the AVX target feature. 62 CCIfType<[v32i8, v16i16, v8i32, v4i64, v8f32, v4f64], 63 CCAssignToReg<[YMM0,YMM1,YMM2,YMM3]>>, 64 65 // 512-bit vectors are returned in ZMM0 and ZMM1, when they fit. ZMM2 and ZMM3 66 // can only be used by ABI non-compliant code. This vector type is only 67 // supported while using the AVX-512 target feature. 68 CCIfType<[v64i8, v32i16, v16i32, v8i64, v16f32, v8f64], 69 CCAssignToReg<[ZMM0,ZMM1,ZMM2,ZMM3]>>, 70 71 // MMX vector types are always returned in MM0. If the target doesn't have 72 // MM0, it doesn't support these vector types. 73 CCIfType<[x86mmx], CCAssignToReg<[MM0]>>, 74 75 76 // Long double types are always returned in FP0 (even with SSE), <- v7.0增加 // except on Win64. CCIfNotSubtarget<"isTargetWin64()", CCIfType<[f80], CCAssignToReg<[FP0, FP1]>>> 77 ]>; 这个调用惯例由一系列CCIfType定义组成,这使得其定义十分清晰。比如37行的CCIfType定义说明,如果当前参数类型是i1,把它提升至i8(即字节类型)。这些CCIfType在TableGen生成代码时将被展开为一系列的if语句块。 接着是32位的C返回值惯例RetCC_X86_32_C。除了类型为f32或f64的参数,其他处理它交由RetCC_X86Common来代劳。 80 def RetCC_X86_32_C : CallingConv<[ 81 // The X86-32 calling convention returns FP values in FP0, unless marked 82 // with "inreg" (used here to distinguish one kind of reg from another, 83 // weirdly; this is really the sse-regparm calling convention) in which 84 // case they use XMM0, otherwise it is the same as the common X86 calling 85 // conv. 86 CCIfInReg 87 CCIfType<[f32, f64], CCAssignToReg<[XMM0,XMM1,XMM2]>>>>, 88 CCIfType<[f32,f64], CCAssignToReg<[FP0, FP1]>>, 89 CCDelegateTo 90 ]>; 然后是32位的FastCC返回值惯例RetCC_X86_32_Fast。 93 def RetCC_X86_32_Fast : CallingConv<[ 94 // The X86-32 fastcc returns 1, 2, or 3 FP values in XMM0-2 if the target has 95 // SSE2. 96 // This can happen when a float, 2 x float, or 3 x float vector is split by 97 // target lowering, and is returned in 1-3 sse regs. 98 CCIfType<[f32], CCIfSubtarget<"hasSSE2()", CCAssignToReg<[XMM0,XMM1,XMM2]>>>, 99 CCIfType<[f64], CCIfSubtarget<"hasSSE2()", CCAssignToReg<[XMM0,XMM1,XMM2]>>>, 100 101 // For integers, ECX can be used as an extra return register 102 CCIfType<[i8], CCAssignToReg<[AL, DL, CL]>>, 103 CCIfType<[i16], CCAssignToReg<[AX, DX, CX]>>, 104 CCIfType<[i32], CCAssignToReg<[EAX, EDX, ECX]>>, 105 106 // Otherwise, it is the same as the common X86 calling convention. 107 CCDelegateTo 108 ]>; 以及Intel_OCL_BI的返回值惯例RetCC_Intel_OCL_BI(Intel OpenCL内置函数的调用惯例)。 111 def RetCC_Intel_OCL_BI : CallingConv<[ 112 // Vector types are returned in XMM0,XMM1,XMMM2 and XMM3. 113 CCIfType<[f32, f64, v4i32, v2i64, v4f32, v2f64], 114 CCAssignToReg<[XMM0,XMM1,XMM2,XMM3]>>, 115 116 // 256-bit FP vectors 117 // No more than 4 registers 118 CCIfType<[v8f32, v4f64, v8i32, v4i64], 119 CCAssignToReg<[YMM0,YMM1,YMM2,YMM3]>>, 120 121 // 512-bit FP vectors 122 CCIfType<[v16f32, v8f64, v16i32, v8i64], 123 CCAssignToReg<[ZMM0,ZMM1,ZMM2,ZMM3]>>, 124 125 // i32, i64 in the standard way 126 CCDelegateTo 127 ]>; 32位HiPE返回值惯例RetCC_X86_32_HiPE(高性能Erlang编译器的调用惯例)。 130 def RetCC_X86_32_HiPE : CallingConv<[ 131 // Promote all types to i32 132 CCIfType<[i8, i16], CCPromoteToType 133 134 // Return: HP, P, VAL1, VAL2 135 CCIfType<[i32], CCAssignToReg<[ESI, EBP, EAX, EDX]>> 136 ]>; 32位MSVC返回值惯例RetCC_X86_32_VectorCall,通过SSE寄存器传递向量。 139 def RetCC_X86_32_VectorCall : CallingConv<[ 140 // Vector types are returned in XMM0,XMM1,XMMM2 and XMM3. 141 CCIfType<[f32, f64, v16i8, v8i16, v4i32, v2i64, v4f32, v2f64], 142 CCAssignToReg<[XMM0,XMM1,XMM2,XMM3]>>, 143 144 145 146 147 148 149 150 151 152 // Return integers in the standard way. 153 CCDelegateTo 154 ]>; X86-64的C返回值惯例RetCC_X86_64_C。 157 def RetCC_X86_64_C : CallingConv<[ 158 // The X86-64 calling convention always returns FP values in XMM0. 159 CCIfType<[f32], CCAssignToReg<[XMM0, XMM1]>>, 160 CCIfType<[f64], CCAssignToReg<[XMM0, XMM1]>>, CCIfType<[f128], CCAssignToReg<[XMM0, XMM1]>>, <- v7.0增加 161 162 // MMX vector types are always returned in XMM0. 163 CCIfType<[x86mmx], CCAssignToReg<[XMM0, XMM1]>>, CCIfSwiftError 164 CCDelegateTo 165 ]>; 64位Windows返回值惯例RetCC_X86_Win64_C。 168 def RetCC_X86_Win64_C : CallingConv<[ 169 // The X86-Win64 calling convention always returns __m64 values in RAX. 170 CCIfType<[x86mmx], CCBitConvertToType 171 172 // Otherwise, everything is the same as 'normal' X86-64 C CC. 173 CCDelegateTo 174 ]>; V7.0支持x86-64的向量调用返回值惯例: 354 def RetCC_X86_64_Vectorcall : CallingConv<[ 355 // Vectorcall calling convention always returns FP values in XMMs. 356 CCIfType<[f32, f64, f128], 357 CCAssignToReg<[XMM0, XMM1, XMM2, XMM3]>>, 358 359 // Otherwise, everything is the same as Windows X86-64 C CC. 360 CCDelegateTo 361 ]>; 64位HiPE返回值惯例RetCC_X86_64_HiPE。 177 def RetCC_X86_64_HiPE : CallingConv<[ 178 // Promote all types to i64 179 CCIfType<[i8, i16, i32], CCPromoteToType 180 181 // Return: HP, P, VAL1, VAL2 182 CCIfType<[i64], CCAssignToReg<[R15, RBP, RAX, RDX]>> 183 ]>; 64位JScript返回值惯例RetCC_X86_64_WebKit_JS。 186 def RetCC_X86_64_WebKit_JS : CallingConv<[ 187 // Promote all types to i64 188 CCIfType<[i8, i16, i32], CCPromoteToType 189 190 // Return: RAX 191 CCIfType<[i64], CCAssignToReg<[RAX]>> 192 ]>; V7.0增加了支持64位Swift的RetCC_X86_64_Swift: 381 def RetCC_X86_64_Swift : CallingConv<[ 382 383 CCIfSwiftError 384 385 // For integers, ECX, R8D can be used as extra return registers. 386 CCIfType<[v1i1], CCPromoteToType 387 CCIfType<[i1], CCPromoteToType 388 CCIfType<[i8] , CCAssignToReg<[AL, DL, CL, R8B]>>, 389 CCIfType<[i16], CCAssignToReg<[AX, DX, CX, R8W]>>, 390 CCIfType<[i32], CCAssignToReg<[EAX, EDX, ECX, R8D]>>, 391 CCIfType<[i64], CCAssignToReg<[RAX, RDX, RCX, R8]>>, 392 393 // XMM0, XMM1, XMM2 and XMM3 can be used to return FP values. 394 CCIfType<[f32], CCAssignToReg<[XMM0, XMM1, XMM2, XMM3]>>, 395 CCIfType<[f64], CCAssignToReg<[XMM0, XMM1, XMM2, XMM3]>>, 396 CCIfType<[f128], CCAssignToReg<[XMM0, XMM1, XMM2, XMM3]>>, 397 398 // MMX vector types are returned in XMM0, XMM1, XMM2 and XMM3. 399 CCIfType<[x86mmx], CCAssignToReg<[XMM0, XMM1, XMM2, XMM3]>>, 400 CCDelegateTo 401 ]>; AnyReg返回值惯例RetCC_X86_64_AnyReg。它允许寄存器分配器选择任何空闲的寄存器。中Debug build时,RetCC_X86_64_AnyReg将产生一个assert,在Release build时,会落入C惯例。 201 def RetCC_X86_64_AnyReg : CallingConv<[ 202 CCCustom<"CC_X86_AnyReg_Error"> 203 ]>; V7.0增加了支持HHVM的RetCC_X86_64_HHVM: 415 def RetCC_X86_64_HHVM: CallingConv<[ 416 // Promote all types to i64 417 CCIfType<[i8, i16, i32], CCPromoteToType 418 419 // Return: could return in any GP register save RSP and R12. 420 CCIfType<[i64], CCAssignToReg<[RBX, RBP, RDI, RSI, RDX, RCX, R8, R9, 421 RAX, R10, R11, R13, R14, R15]>> 422 ]>; 下面的定义将生成最终的返回值处理分派函数。 206 def RetCC_X86_32 : CallingConv<[ 207 // If FastCC, use RetCC_X86_32_Fast. 208 CCIfCC<"CallingConv::Fast", CCDelegateTo 209 // If HiPE, use RetCC_X86_32_HiPE. 210 CCIfCC<"CallingConv::HiPE", CCDelegateTo 211 CCIfCC<"CallingConv::X86_VectorCall", CCDelegateTo 212 213 // Otherwise, use RetCC_X86_32_C. 214 CCDelegateTo 215 ]>; 218 def RetCC_X86_64 : CallingConv<[ 219 // HiPE uses RetCC_X86_64_HiPE 220 CCIfCC<"CallingConv::HiPE", CCDelegateTo 221 222 // Handle JavaScript calls. 223 CCIfCC<"CallingConv::WebKit_JS", CCDelegateTo 224 CCIfCC<"CallingConv::AnyReg", CCDelegateTo // Handle Swift calls. <- v7.0增加 CCIfCC<"CallingConv::Swift", CCDelegateTo 225 226 // Handle explicit CC selection 227 CCIfCC<"CallingConv::X86_64_Win64", CCDelegateTo 228 CCIfCC<"CallingConv::X86_64_SysV", CCDelegateTo 229 // Handle Vectorcall CC <- v7.0增加 CCIfCC<"CallingConv::X86_VectorCall", CCDelegateTo // Handle HHVM calls. CCIfCC<"CallingConv::HHVM", CCDelegateTo CCIfCC<"CallingConv::X86_RegCall", CCIfSubtarget<"isTargetWin64()", CCDelegateTo CCIfCC<"CallingConv::X86_RegCall", CCDelegateTo 230 // Mingw64 and native Win64 use Win64 CC 231 CCIfSubtarget<"isTargetWin64()", CCDelegateTo 232 233 // Otherwise, drop to normal X86-64 CC 234 CCDelegateTo 235 ]>; 整个调用惯例的入口则是下面的定义: 238 def RetCC_X86 : CallingConv<[ 239 240 // Check if this is the Intel OpenCL built-ins calling convention 241 CCIfCC<"CallingConv::Intel_OCL_BI", CCDelegateTo 242 243 CCIfSubtarget<"is64Bit()", CCDelegateTo 244 CCDelegateTo 245 ]>; actions> {
// Long double types are always returned in FP0 (even with SSE). <- v7.0删除CCIfType<[f80], CCAssignToReg<[FP0, FP1]>>// 256-bit FP vectorsCCIfType<[v32i8, v16i16, v8i32, v4i64, v8f32, v4f64], <- v7.0删除CCAssignToReg<[YMM0,YMM1,YMM2,YMM3]>>,// 512-bit FP vectorsCCIfType<[v64i8, v32i16, v16i32, v8i64, v16f32, v8f64],CCAssignToReg<[ZMM0,ZMM1,ZMM2,ZMM3]>>,