LLVM学习笔记(45)

栏目: 服务器 · 编程工具 · 发布时间: 5年前

3.7. 描述调用惯例的数据结构

选项“-gen-callingconv”用于生成处理函数调用惯例的代码。调用惯例是函数调用者与被调用者之间关于参数及返回值传递方式的一个共识。存在多个调用惯例,以适合各种机器架构。LLVM目前已经基本能完全通过TableGen生成处理调用惯例的代码。

3.7.1. TD的基本类型与描述

在文件TargetCallingConv.td里,首先出现的是CCAction。这是一个空类,作为表示调用惯例操作的基类。从它出发,有这些派生类:

19        class CCCustom <string fn> : CCAction {

20        string FuncName = fn;

21        }

CCCustom记录处理参数的定制方法。

25        class CCPredicateAction <CCAction A> : CCAction {

26        CCAction SubAction = A;

27        }

CCPredicateAction作为基类,用在检测特定谓词,在谓词成立时执行CCAction A的定义中。

31        class CCIfType <list<ValueType> vts, CCAction A> : CCPredicateAction<A> {

32        list<ValueType> VTs = vts;

33        }

CCPredicateAction派生类CCIfType用作判定指定类型,在指定类型之一出现时执行CCAction A。

36        class CCIf <string predicate, CCAction A> : CCPredicateAction<A> {

37        string Predicate = predicate;

38        }

而派生类CCIf作为基类,用在执行指定谓词代码片段,在成立时执行CCAction A的定义中。

42        class CCIfByVal <CCAction A> : CCIf<"ArgFlags.isByVal()", A> {

43        }

CCIf派生类CCIfByVal则固化了谓词代码片段——参数必须按值传递。

47        class CCIfConsecutiveRegs <CCAction A> : CCIf<"ArgFlags.isInConsecutiveRegs()", A> {

48        }

派生类CCIfConsecutiveRegs固化了另一种谓词代码片段——参数必须在连续的寄存器里。

51        class CCIfCC <string CC, CCAction A>

52        : CCIf<!strconcat("State.getCallingConv() == ", CC), A> {}

56        class CCIfInReg <CCAction A> : CCIf<"ArgFlags.isInReg()", A> {}

60        class CCIfNest <CCAction A> : CCIf<"ArgFlags.isNest()", A> {}

64        class CCIfSplit <CCAction A> : CCIf<"ArgFlags.isSplit()", A> {}

68        class CCIfSRet <CCAction A> : CCIf<"ArgFlags.isSRet()", A> {}

71        class CCIfVarArg <CCAction A> : CCIf<"State.isVarArg()", A> {}

74        class CCIfNotVarArg <CCAction A> : CCIf<"!State.isVarArg()", A> {}

上面出现的ArgFlags是源文件CallingConvLower.h及CallingConvLower.cpp中类型为ISD::ArgFlagsTy 的函数参数,TableGen使用这个类型来描述被编译函数的参数。

79        class CCAssignToReg <list<Register> regList> : CCAction {

80        list<Register> RegList = regList;

81        }

CCAssignToReg的语义由其名字隐含表述(即TableGen会解释如下):如果regList中仍有一个寄存器可用,就将值(定义中没有出现)赋给该寄存器并返回成功。

85        class CCAssignToRegWithShadow <list<Register> regList,

86        list<Register> shadowList> : CCAction {

87        list<Register> RegList = regList;

88        list<Register> ShadowRegList = shadowList;

89        }

CCAssignToRegWithShadow类似于CCAssignToReg,不过还包括了一组成功时将被屏蔽的寄存器。

95        class CCAssignToStack <int size, int align> : CCAction {

96        int Size = size;

97        int Align = align;

98        }

CCAssignToStack则总是使得TableGen产生将值赋给指定大小与对齐边界的栈区间。如果大小或对齐是0,使用ABI的定义值。

103      class CCAssignToStackWithShadow <int size,

104      int align,

105      list<Register> shadowList> : CCAction {

106      int Size = size;

107      int Align = align;

108      list<Register> ShadowRegList = shadowList;

109      }

同样CCAssignToStackWithShadow类似CCAssignToStack,但还包括一组成功时将被屏蔽的寄存器。

114      class CCPassByVal <int size, int align> : CCAction {

115      int Size = size;

116      int Align = align;

117      }

CCPassByVal则会使TableGen产生将在栈上按值传递聚集参数的代码。

121      class CCPromoteToType <ValueType destTy> : CCAction {

122      ValueType DestTy = destTy;

123      }

CCPromoteToType告诉TableGen产生将当前值(定义中没有出现)提升到destTy类型。

127      class CCPromoteToUpperBitsInType <ValueType destTy> : CCAction {

128      ValueType DestTy = destTy;

129      }

CCPromoteToUpperBitsInType类似CCPromoteToType,但还要将值移到高位。

133      class CCBitConvertToType <ValueType destTy> : CCAction {

134      ValueType DestTy = destTy;

135      }

CCBitConvertToType则是将当前值按位转换(bitconvert)到destTy类型。

139      class CCPassIndirect <ValueType destTy> : CCAction {

140      ValueType DestTy = destTy;

141      }

CCPassIndirect告诉TableGen产生将值(定义中没有出现)存入栈,将对应指针作为值传递的代码。

145      class CCDelegateTo <CallingConv cc> : CCAction {

146      CallingConv CC = cc;

147      }

CCDelegateTo指定所要委派执行的调用惯例。

接下来是描述调用惯例的基本类型。首先是CallingConv,它通过一组CCAction来刻画调用惯例的具体行为。

151      class CallingConv <list<CCAction> actions> {

152      list<CCAction> Actions = actions;

153      bit Custom = 0;

154      }

然后是CustomCallingConv。实际使用上从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 <string F, CCAction A>

17        : CCIf<!strconcat("static_cast<const X86Subtarget&>"

18        "(State.getMachineFunction().getSubtarget()).", F),

这里State是CCState类型的对象,我们后面会详细了解这个类。

3.7.2.1. 返回值惯例

接着是定义如何传递返回值的返回值惯例。首先是RetCC_X86Common。

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        <[i1], <i8>>,

38        CCIfType<[i8] ,<[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<v2i64>>,

47        CCIfType<[v4i1],  CCPromoteToType<v4i32>>,

48        CCIfType<[v8i1],  CCPromoteToType<v8i16>>,

49        CCIfType<[v16i1], CCPromoteToType<v16i8>>,

50        CCIfType<[v32i1], CCPromoteToType<v32i8>>,

51        CCIfType<[v64i1], CCPromoteToType<v64i8>>,

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        // Long double types are always returned in FP0 (even with SSE).

76        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        <<"hasSSE2()",

87        CCIfType<[f32, f64], CCAssignToReg<[XMM0,XMM1,XMM2]>>>>,

88        CCIfType<[f32,f64], CCAssignToReg<[FP0, FP1]>>,

89        <RetCC_X86Common>

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<RetCC_X86Common>

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<RetCC_X86Common>

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<i32>>,

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        // 256-bit FP vectors

145      CCIfType<[v32i8, v16i16, v8i32, v4i64, v8f32, v4f64],

146      CCAssignToReg<[YMM0,YMM1,YMM2,YMM3]>>,

147     

148        // 512-bit FP vectors

149      CCIfType<[v64i8, v32i16, v16i32, v8i64, v16f32, v8f64],

150      CCAssignToReg<[ZMM0,ZMM1,ZMM2,ZMM3]>>,

151     

152        // Return integers in the standard way.

153      CCDelegateTo<RetCC_X86Common>

154      ]>;

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]>>,

161     

162        // MMX vector types are always returned in XMM0.

163      CCIfType<[x86mmx], CCAssignToReg<[XMM0, XMM1]>>,

164      CCDelegateTo<RetCC_X86Common>

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<i64>>,

171     

172        // Otherwise, everything is the same as 'normal' X86-64 C CC.

173      CCDelegateTo<RetCC_X86_64_C>

174      ]>;

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<i64>>,

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<i64>>,

189     

190        // Return: RAX

191      CCIfType<[i64], CCAssignToReg<[RAX]>>

192      ]>;

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      ]>;

最后三个定义将生成最终的返回值处理分派函数。

206      def RetCC_X86_32 : CallingConv<[

207        // If FastCC, use RetCC_X86_32_Fast.

208      CCIfCC<"CallingConv::Fast", CCDelegateTo<RetCC_X86_32_Fast>>,

209        // If HiPE, use RetCC_X86_32_HiPE.

210      CCIfCC<"CallingConv::HiPE", CCDelegateTo<RetCC_X86_32_HiPE>>,

211      CCIfCC<"CallingConv::X86_VectorCall", CCDelegateTo<RetCC_X86_32_VectorCall>>,

212     

213        // Otherwise, use RetCC_X86_32_C.

214      CCDelegateTo<RetCC_X86_32_C>

215      ]>;

218      def RetCC_X86_64 : CallingConv<[

219        // HiPE uses RetCC_X86_64_HiPE

220      CCIfCC<"CallingConv::HiPE", CCDelegateTo<RetCC_X86_64_HiPE>>,

221     

222        // Handle JavaScript calls.

223      CCIfCC<"CallingConv::WebKit_JS", CCDelegateTo<RetCC_X86_64_WebKit_JS>>,

224      CCIfCC<"CallingConv::AnyReg", CCDelegateTo<RetCC_X86_64_AnyReg>>,

225     

226        // Handle explicit CC selection

227      CCIfCC<"CallingConv::X86_64_Win64", CCDelegateTo<RetCC_X86_Win64_C>>,

228      CCIfCC<"CallingConv::X86_64_SysV", CCDelegateTo<RetCC_X86_64_C>>,

229     

230        // Mingw64 and native Win64 use Win64 CC

231      CCIfSubtarget<"isTargetWin64()", CCDelegateTo<RetCC_X86_Win64_C>>,

232     

233        // Otherwise, drop to normal X86-64 CC

234      CCDelegateTo<RetCC_X86_64_C>

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<RetCC_Intel_OCL_BI>>,

242     

243      CCIfSubtarget<"is64Bit()", CCDelegateTo<RetCC_X86_64>>,

244      CCDelegateTo<RetCC_X86_32>

245      ]>;


以上所述就是小编给大家介绍的《LLVM学习笔记(45)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

C语言接口与实现

C语言接口与实现

David R. Hanson / 郭旭 / 人民邮电出版社 / 2011-9 / 75.00元

《C语言接口与实现:创建可重用软件的技术》概念清晰、实例详尽,是一本有关设计、实现和有效使用C语言库函数,掌握创建可重用C语言软件模块技术的参考指南。书中提供了大量实例,重在阐述如何用一种与语言无关的方法将接口设计实现独立出来,从而用一种基于接口的设计途径创建可重用的API。 《C语言接口与实现:创建可重用软件的技术》是所有C语言程序员不可多得的好书,也是所有希望掌握可重用软件模块技术的人员......一起来看看 《C语言接口与实现》 这本书的介绍吧!

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试