LLVM学习笔记(47)

3.7.3. TableGen的处理

3.7.3.1. 基本数据结构

在文件CallingConvLower.h中定义了两个基本的数据结构:CCValAssign与CCState。CCValAssign在编译期间用于记录参数或返回值向寄存器或栈赋值的细节,它定义了以下成员:

32        class CCValAssign {

33        public:

34          enum LocInfo {

35            Full,      // The value fills the full location.

36            SExt,      // The value is sign extended in the location.

37            ZExt,      // The value is zero extended in the location.

38            AExt,      // The value is extended with undefined upper bits.

39            SExtUpper, // The value is in the upper bits of the location and should be

40                       // sign extended when retrieved.

41            ZExtUpper, // The value is in the upper bits of the location and should be

42                       // zero extended when retrieved.

43            AExtUpper, // The value is in the upper bits of the location and should be

44                       // extended with undefined upper bits when retrieved.

45            BCvt,      // The value is bit-converted in the location.

46            VExt,      // The value is vector-widened in the location.

47                       // FIXME: Not implemented yet. Code that uses AExt to mean

48                       // vector-widen should be fixed to use VExt instead.

49            FPExt,     // The floating-point value is fp-extended in the location.

50            Indirect   // The location contains pointer to the value.

51            // TODO: a subset of the value is in the location.

52          };

53       

54        private:

55          /// ValNo - This is the value number begin assigned (e.g. an argument number).

56          unsigned ValNo;

57       

58          /// Loc is either a stack offset or a register number.

59          unsigned Loc;

60       

61          /// isMem - True if this is a memory loc, false if it is a register loc.

62          unsigned isMem : 1;

63       

64          /// isCustom - True if this arg/retval requires special handling.

65          unsigned isCustom : 1;

66       

67          /// Information about how the value is assigned.

68          LocInfo HTP : 6;

69       

70          /// ValVT - The type of the value being assigned.

71          MVT ValVT;

72       

73          /// LocVT - The type of the location being assigned to.

74          MVT LocVT;

其中枚举类型LocInfo用于描述对该内存的占用形式,是否全占满、符号扩展、还是零扩展等。

CCState则是用于辅助参数与返回值的降级,CCState定义了以下成员:

189      typedef enum { Unknown, Prologue, Call } ParmContext;

190     

191      /// CCState - This class holds information needed while lowering arguments and

192      /// return values.  It captures which registers are already assigned and which

193      /// stack slots are used.  It provides accessors to allocate these values.

194      class CCState {

195      private:

196        CallingConv::ID CallingConv;

197        bool IsVarArg;

198        MachineFunction &MF;

199        const TargetRegisterInfo &TRI;

200        SmallVectorImpl<CCValAssign> &Locs;

201        LLVMContext &Context;

202     

203        unsigned StackOffset;

204        SmallVector<uint32_t, 16> UsedRegs;

205        SmallVector<CCValAssign, 4> PendingLocs;

206     

207        // ByValInfo and SmallVector<ByValInfo, 4> ByValRegs:

208        //

209        // Vector of ByValInfo instances (ByValRegs) is introduced for byval registers

210        // tracking.

211        // Or, in another words it tracks byval parameters that are stored in

212        // general purpose registers.

213        //

214        // For 4 byte stack alignment,

215        // instance index means byval parameter number in formal

216        // arguments set. Assume, we have some "struct_type" with size = 4 bytes,

217        // then, for function "foo":

218        //

219        // i32 foo(i32 %p, %struct_type* %r, i32 %s, %struct_type* %t)

220        //

221        // ByValRegs[0] describes how "%r" is stored (Begin == r1, End == r2)

222        // ByValRegs[1] describes how "%t" is stored (Begin == r3, End == r4).

223        //

224        // In case of 8 bytes stack alignment,

225        // ByValRegs may also contain information about wasted registers.

226        // In function shown above, r3 would be wasted according to AAPCS rules.

227        // And in that case ByValRegs[1].Waste would be "true".

228        // ByValRegs vector size still would be 2,

229        // while "%t" goes to the stack: it wouldn't be described in ByValRegs.

230        //

231        // Supposed use-case for this collection:

232        // 1. Initially ByValRegs is empty, InRegsParamsProcessed is 0.

233        // 2. HandleByVal fillups ByValRegs.

234        // 3. Argument analysis (LowerFormatArguments, for example). After

235        // some byval argument was analyzed, InRegsParamsProcessed is increased.

236        struct ByValInfo {

237          ByValInfo(unsigned B, unsigned E, bool IsWaste = false) :

238            Begin(B), End(E), Waste(IsWaste) {}

239          // First register allocated for current parameter.

240          unsigned Begin;

241     

242          // First after last register allocated for current parameter.

243          unsigned End;

244     

245         // Means that current range of registers doesn't belong to any

246          // parameters. It was wasted due to stack alignment rules.

247          // For more information see:

248          // AAPCS, 5.5 Parameter Passing, Stage C, C.3.

249          bool Waste;

250        };

251        SmallVector<ByValInfo, 4 > ByValRegs;

252     

253        // InRegsParamsProcessed - shows how many instances of ByValRegs was proceed

254        // during argument analysis.

255        unsigned InRegsParamsProcessed;

256     

257      protected:

258        ParmContext CallOrPrologue;

CCState只定义了一个构造函数,它的成员Locs必须是外面传入容器,CCState只是代管。

28        CCState::CCState(CallingConv::ID CC, bool isVarArg, MachineFunction &mf,

29                         SmallVectorImpl<CCValAssign> &locs, LLVMContext &C)

30            : CallingConv(CC), IsVarArg(isVarArg), MF(mf),

31              TRI(*MF.getSubtarget().getRegisterInfo()), Locs(locs), Context(C),

32              CallOrPrologue(Unknown) {

33          // No stack is used.

34          StackOffset = 0;

35       

36          clearByValRegsInfo();

37          UsedRegs.resize((TRI.getNumRegs()+31)/32);

38        }

其中StackOffset记录所代表函数调用参数使用栈的大小,UsedRegs则记录寄存器的使用情况。

​​​​​​​3.7.1.2. 代码的生成

TableGen代码生成的入口是EmitCallingConv方法。

279      void EmitCallingConv(RecordKeeper &RK, raw_ostream &OS) {

280        emitSourceFileHeader("Calling Convention Implementation Fragment", OS);

281        CallingConvEmitter(RK).run(OS);

282      }

类似的,主要工作由CallingConvEmitter的run方法完成(CallingConvEmitter构造函数本身是平凡的)。

37        void CallingConvEmitter::run(raw_ostream &O) {

38          std::vector<Record*> CCs = Records.getAllDerivedDefinitions("CallingConv");

39       

40          // Emit prototypes for all of the non-custom CC's so that they can forward ref

41          // each other.

42          for (unsigned i = 0, e = CCs.size(); i != e; ++i) {

43            if (!CCs[i]->getValueAsBit("Custom")) {

44              O << "static bool " << CCs[i]->getName()

45                << "(unsigned ValNo, MVT ValVT,\n"

46                << std::string(CCs[i]->getName().size() + 13, ' ')

47                << "MVT LocVT, CCValAssign::LocInfo LocInfo,\n"

48                << std::string(CCs[i]->getName().size() + 13, ' ')

49                << "ISD::ArgFlagsTy ArgFlags, CCState &State);\n";

50            }

51          }

52       

53          // Emit each non-custom calling convention description in full.

54          for (unsigned i = 0, e = CCs.size(); i != e; ++i) {

55            if (!CCs[i]->getValueAsBit("Custom"))

56              EmitCallingConv(CCs[i], O);

57          }

58        }

在42行循环,如果当前CallingConv定义中没有设置Custom位(Custom表示该调用惯例由同名的定制函数处理),就为它输出一个函数声明,形如:

static bool CC_X86_64_C(unsigned ValNo, MVT ValVT,

                        MVT LocVT, CCValAssign::LocInfo LocInfo,

                        ISD::ArgFlagsTy ArgFlags, CCState &State);

而这些CallingConv定义的处理方法则由56行的EmitCallingConv方法输出。

61        void CallingConvEmitter::EmitCallingConv(Record *CC, raw_ostream &O) {

62          ListInit *CCActions = CC->getValueAsListInit("Actions");

63          Counter = 0;

64       

65          O << "\n\nstatic bool " << CC->getName()

66            << "(unsigned ValNo, MVT ValVT,\n"

67            << std::string(CC->getName().size()+13, ' ')

68            << "MVT LocVT, CCValAssign::LocInfo LocInfo,\n"

69            << std::string(CC->getName().size()+13, ' ')

70            << "ISD::ArgFlagsTy ArgFlags, CCState &State) {\n";

71          // Emit all of the actions, in order.

72          for (unsigned i = 0, e = CCActions->size(); i != e; ++i) {

73            O << "\n";

74            EmitAction(CCActions->getElementAsRecord(i), 2, O);

75          }

76         

77          O << "\n  return true;  // CC didn't match.\n";

78          O << "}\n";

79        }

CallingConv定义里最主要的部分就是Actions,它确定了对该调用惯例的处理方式,因此它实际决定了该处理方法的定义。因为CallingConv中Actions是一个list,因此需要在一个循环里调用下面的EmitAction方法。

81        void CallingConvEmitter::EmitAction(Record *Action,

82                                            unsigned Indent, raw_ostream &O) {

83          std::string IndentStr = std::string(Indent, ' ');

84         

85          if (Action->isSubClassOf("CCPredicateAction")) {

86            O << IndentStr << "if (";

87           

88            if (Action->isSubClassOf("CCIfType")) {

89              ListInit *VTs = Action->getValueAsListInit("VTs");

90              for (unsigned i = 0, e = VTs->size(); i != e; ++i) {

91                Record *VT = VTs->getElementAsRecord(i);

92                if (i != 0) O << " ||\n    " << IndentStr;

93                O << "LocVT == " << getEnumName(getValueType(VT));

94              }

95       

96            } else if (Action->isSubClassOf("CCIf")) {

97              O << Action->getValueAsString("Predicate");

98            } else {

99              Action->dump();

100            PrintFatalError("Unknown CCPredicateAction!");

101          }

102         

103          O << ") {\n";

104          EmitAction(Action->getValueAsDef("SubAction"), Indent+2, O);

105          O << IndentStr << "}\n";

106        } else {

107          if (Action->isSubClassOf("CCDelegateTo")) {

108            Record *CC = Action->getValueAsDef("CC");

109            O << IndentStr << "if (!" << CC->getName()

110              << "(ValNo, ValVT, LocVT, LocInfo, ArgFlags, State))\n"

111              << IndentStr << "  return false;\n";

112          } else if (Action->isSubClassOf("CCAssignToReg")) {

113            ListInit *RegList = Action->getValueAsListInit("RegList");

114            if (RegList->size() == 1) {

115              O << IndentStr << "if (unsigned Reg = State.AllocateReg(";

116              O << getQualifiedName(RegList->getElementAsRecord(0)) << ")) {\n";

117            } else {

118              O << IndentStr << "static const MCPhysReg RegList" << ++Counter

119                << "[] = {\n";

120              O << IndentStr << "  ";

121              for (unsigned i = 0, e = RegList->size(); i != e; ++i) {

122                if (i != 0) O << ", ";

123                O << getQualifiedName(RegList->getElementAsRecord(i));

124              }

125              O << "\n" << IndentStr << "};\n";

126              O << IndentStr << "if (unsigned Reg = State.AllocateReg(RegList"

127                << Counter << ")) {\n";

128            }

129            O << IndentStr << "  State.addLoc(CCValAssign::getReg(ValNo, ValVT, "

130              << "Reg, LocVT, LocInfo));\n";

131            O << IndentStr << "  return false;\n";

132            O << IndentStr << "}\n";

133          } else if (Action->isSubClassOf("CCAssignToRegWithShadow")) {

134            ListInit *RegList = Action->getValueAsListInit("RegList");

135            ListInit *ShadowRegList = Action->getValueAsListInit("ShadowRegList");

136            if (!ShadowRegList->empty() && ShadowRegList->size() != RegList->size())

137              PrintFatalError("Invalid length of list of shadowed registers");

138     

139            if (RegList->size() == 1) {

140              O << IndentStr << "if (unsigned Reg = State.AllocateReg(";

141              O << getQualifiedName(RegList->getElementAsRecord(0));

142              O << ", " << getQualifiedName(ShadowRegList->getElementAsRecord(0));

143              O << ")) {\n";

144            } else {

145              unsigned RegListNumber = ++Counter;

146              unsigned ShadowRegListNumber = ++Counter;

147     

148              O << IndentStr << "static const MCPhysReg RegList" << RegListNumber

149                << "[] = {\n";

150              O << IndentStr << "  ";

151              for (unsigned i = 0, e = RegList->size(); i != e; ++i) {

152                if (i != 0) O << ", ";

153                O << getQualifiedName(RegList->getElementAsRecord(i));

154              }

155              O << "\n" << IndentStr << "};\n";

156     

157              O << IndentStr << "static const MCPhysReg RegList"

158                << ShadowRegListNumber << "[] = {\n";

159              O << IndentStr << "  ";

160              for (unsigned i = 0, e = ShadowRegList->size(); i != e; ++i) {

161                if (i != 0) O << ", ";

162                O << getQualifiedName(ShadowRegList->getElementAsRecord(i));

163              }

164              O << "\n" << IndentStr << "};\n";

165     

166              O << IndentStr << "if (unsigned Reg = State.AllocateReg(RegList"

167                << RegListNumber << ", " << "RegList" << ShadowRegListNumber

168                << ")) {\n";

169            }

170            O << IndentStr << "  State.addLoc(CCValAssign::getReg(ValNo, ValVT, "

171              << "Reg, LocVT, LocInfo));\n";

172            O << IndentStr << "  return false;\n";

173            O << IndentStr << "}\n";

174          } else if (Action->isSubClassOf("CCAssignToStack")) {

175            int Size = Action->getValueAsInt("Size");

176            int Align = Action->getValueAsInt("Align");

177     

178            O << IndentStr << "unsigned Offset" << ++Counter

179              << " = State.AllocateStack(";

180            if (Size)

181              O << Size << ", ";

182            else

183              O << "\n" << IndentStr

184                << "  State.getMachineFunction().getTarget().getDataLayout()"

185                   "->getTypeAllocSize(EVT(LocVT).getTypeForEVT(State.getContext())),"

186                   " ";

187            if (Align)

188              O << Align;

189            else

190              O << "\n" << IndentStr

191                << "  State.getMachineFunction().getTarget().getDataLayout()"

192                   "->getABITypeAlignment(EVT(LocVT).getTypeForEVT(State.getContext()"

193                   "))";

194            O << ");\n" << IndentStr

195              << "State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset"

196              << Counter << ", LocVT, LocInfo));\n";

197            O << IndentStr << "return false;\n";

198          } else if (Action->isSubClassOf("CCAssignToStackWithShadow")) {

199            int Size = Action->getValueAsInt("Size");

200            int Align = Action->getValueAsInt("Align");

201            ListInit *ShadowRegList = Action->getValueAsListInit("ShadowRegList");

202     

203            unsigned ShadowRegListNumber = ++Counter;

204     

205            O << IndentStr << "static const MCPhysReg ShadowRegList"

206                << ShadowRegListNumber << "[] = {\n";

207            O << IndentStr << "  ";

208            for (unsigned i = 0, e = ShadowRegList->size(); i != e; ++i) {

209              if (i != 0) O << ", ";

210              O << getQualifiedName(ShadowRegList->getElementAsRecord(i));

211            }

212            O << "\n" << IndentStr << "};\n";

213     

214            O << IndentStr << "unsigned Offset" << ++Counter

215              << " = State.AllocateStack("

216              << Size << ", " << Align << ", "

217              << "ShadowRegList" << ShadowRegListNumber << ");\n";

218            O << IndentStr << "State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset"

219              << Counter << ", LocVT, LocInfo));\n";

220            O << IndentStr << "return false;\n";

221          } else if (Action->isSubClassOf("CCPromoteToType")) {

222            Record *DestTy = Action->getValueAsDef("DestTy");

223            MVT::SimpleValueType DestVT = getValueType(DestTy);

224            O << IndentStr << "LocVT = " << getEnumName(DestVT) <<";\n";

225            if (MVT(DestVT).isFloatingPoint()) {

226              O << IndentStr << "LocInfo = CCValAssign::FPExt;\n";

227            } else {

228              O << IndentStr << "if (ArgFlags.isSExt())\n"

229                << IndentStr << IndentStr << "LocInfo = CCValAssign::SExt;\n"

230                << IndentStr << "else if (ArgFlags.isZExt())\n"

231                << IndentStr << IndentStr << "LocInfo = CCValAssign::ZExt;\n"

232                << IndentStr << "else\n"

233                << IndentStr << IndentStr << "LocInfo = CCValAssign::AExt;\n";

234            }

235          } else if (Action->isSubClassOf("CCPromoteToUpperBitsInType")) {

236            Record *DestTy = Action->getValueAsDef("DestTy");

237            MVT::SimpleValueType DestVT = getValueType(DestTy);

238            O << IndentStr << "LocVT = " << getEnumName(DestVT) << ";\n";

239            if (MVT(DestVT).isFloatingPoint()) {

240              PrintFatalError("CCPromoteToUpperBitsInType does not handle floating "

241                              "point");

242            } else {

243              O << IndentStr << "if (ArgFlags.isSExt())\n"

244                << IndentStr << IndentStr << "LocInfo = CCValAssign::SExtUpper;\n"

245                << IndentStr << "else if (ArgFlags.isZExt())\n"

246                << IndentStr << IndentStr << "LocInfo = CCValAssign::ZExtUpper;\n"

247                << IndentStr << "else\n"

248                << IndentStr << IndentStr << "LocInfo = CCValAssign::AExtUpper;\n";

249            }

250          } else if (Action->isSubClassOf("CCBitConvertToType")) {

251            Record *DestTy = Action->getValueAsDef("DestTy");

252            O << IndentStr << "LocVT = " << getEnumName(getValueType(DestTy)) <<";\n";

253            O << IndentStr << "LocInfo = CCValAssign::BCvt;\n";

254          } else if (Action->isSubClassOf("CCPassIndirect")) {

255            Record *DestTy = Action->getValueAsDef("DestTy");

256            O << IndentStr << "LocVT = " << getEnumName(getValueType(DestTy)) <<";\n";

257            O << IndentStr << "LocInfo = CCValAssign::Indirect;\n";

258          } else if (Action->isSubClassOf("CCPassByVal")) {

259            int Size = Action->getValueAsInt("Size");

260            int Align = Action->getValueAsInt("Align");

261            O << IndentStr

262              << "State.HandleByVal(ValNo, ValVT, LocVT, LocInfo, "

263              << Size << ", " << Align << ", ArgFlags);\n";

264           O << IndentStr << "return false;\n";

265          } else if (Action->isSubClassOf("CCCustom")) {

266            O << IndentStr

267              << "if (" << Action->getValueAsString("FuncName") << "(ValNo, ValVT, "

268              << "LocVT, LocInfo, ArgFlags, State))\n";

269            O << IndentStr << IndentStr << "return false;\n";

270          } else {

271            Action->dump();

272            PrintFatalError("Unknown CCAction!");

273          }

274        }

275      }

EmitAction方法虽然比较大,但逻辑并不复杂,实际上从TableGen描述到生成代码间的映射相当简单。以CC_X86_32_C为例(注意它与对应的调用惯例定义同名),生成的函数形式如下(如果与TableGen的描述对比,可以看到明显的对应关系):

314      static bool CC_X86_32_C(unsigned ValNo, MVT ValVT,

315                              MVT LocVT, CCValAssign::LocInfo LocInfo,

316                              ISD::ArgFlagsTy ArgFlags, CCState &State) {

317     

318        if (LocVT == MVT::i1 ||

319            LocVT == MVT::i8 ||

320            LocVT == MVT::i16) {

321          LocVT = MVT::i32;

322          if (ArgFlags.isSExt())

323              LocInfo = CCValAssign::SExt;

324          else if (ArgFlags.isZExt())

325              LocInfo = CCValAssign::ZExt;

326          else

327              LocInfo = CCValAssign::AExt;

328        }

329     

330        if (ArgFlags.isNest()) {

331          if (unsigned Reg = State.AllocateReg(X86::ECX)) {

332            State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));

333            return false;

334          }

335        }

336     

337        if (!State.isVarArg()) {

338          if (ArgFlags.isInReg()) {

339            if (LocVT == MVT::i32) {

340              static const MCPhysReg RegList1[] = {

341                X86::EAX, X86::EDX, X86::ECX

342              };

343              if (unsigned Reg = State.AllocateReg(RegList1)) {

344                State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));

345                return false;

346              }

347            }

348          }

349        }

350     

351        if (!CC_X86_32_Common(ValNo, ValVT, LocVT, LocInfo, ArgFlags, State))

352          return false;

353     

354        return true;  // CC didn't match.

355      }

315行的CCValAssign::LocInfo是一个枚举类型,描述对所要赋值内存的占用情况。这个枚举值随后传递给CCValAssign的getReg方法,用于构建CCValAssign实例。CCValAssign::getReg方法用来分配一个代表寄存器赋值的CCValAssign实例。

77          static CCValAssign getReg(unsigned ValNo, MVT ValVT,

78                                    unsigned RegNo, MVT LocVT,

79                                    LocInfo HTP) {

80            CCValAssign Ret;

81            Ret.ValNo = ValNo;

82            Ret.Loc = RegNo;

83            Ret.isMem = false;

84            Ret.isCustom = false;

85            Ret.HTP = HTP;

86            Ret.ValVT = ValVT;

87            Ret.LocVT = LocVT;

88            return Ret;

89          }

CCState的addLoc方法则只是将这个CCValAssign实例记录在Locs容器里(实际上是在构造这个CCState实例时传入的容器)。

注意343行,如果调用惯例不是可变参数,且参数是通过寄存器传递的i32类型,则需使用EAX,EDX或ECX之一。CCState成员UsedRegs来记录寄存器的使用情况,通过AllocateReg方法在UsedRegs中标定已经被使用的寄存器。

而余下情形,则需要351行调用CC_X86_32_Common方法来处理。

猜你喜欢

转载自blog.csdn.net/wuhui_gdnt/article/details/84872157