LLVM学习笔记(13)

来源:互联网 发布:免费下载美图秀秀软件 编辑:程序博客网 时间:2024/06/04 23:24

3.3.6.  输出代码

3.3.6.1.       枚举常量

回到RegisterInfoEmitter::run,现在可以调用RegisterInfoEmitter::runEnums来向输出文件导出枚举常量了。这个输出文件被命名为TargetGenRegisterInfo.inc。以X86机器为例,产生的文件就是X86GenRegisterInfo.inc。首先,向这个文件输出的是若干枚举类型定义以标识寄存器、寄存器类,以及寄存器索引。

71        void RegisterInfoEmitter::runEnums(raw_ostream&OS,

72                                          CodeGenTarget &Target, CodeGenRegBank &Bank) {

73          const auto &Registers = Bank.getRegisters();

74       

75          // Register enumsare stored as uint16_t in the tables. Make sure we'll fit.

76          assert(Registers.size()<= 0xffff && "Too many regs to fit in tables");

77       

78          std::string Namespace =

79             Registers.front().TheDef->getValueAsString("Namespace");

80       

81          emitSourceFileHeader("Target RegisterEnum Values", OS);

82       

83          OS << "\n#ifdefGET_REGINFO_ENUM\n";

84          OS << "#undefGET_REGINFO_ENUM\n";

85       

86          OS << "namespace llvm {\n\n";

87       

88          OS << "classMCRegisterClass;\n"

89             << "extern constMCRegisterClass " << Namespace

90             <<"MCRegisterClasses[];\n\n";

91       

92          if (!Namespace.empty())

93            OS << "namespace " <<Namespace << " {\n";

94          OS << "enum {\n  NoRegister,\n";

95       

96          for (const auto &Reg :Registers)

97            OS << "  " << Reg.getName() << "= " << Reg.EnumValue << ",\n";

98          assert(Registers.size()== Registers.back().EnumValue &&

99                 "Register enum valuemismatch!");

100        OS << "  NUM_TARGET_REGS \t// " <<Registers.size()+1 << "\n";

101        OS << "};\n";

102        if (!Namespace.empty())

103          OS << "}\n";

104     

105        const auto &RegisterClasses = Bank.getRegClasses();

106        if (!RegisterClasses.empty()) {

107     

108          //RegisterClass enums are stored as uint16_t in the tables.

109          assert(RegisterClasses.size()<= 0xffff &&

110                 "Too many register classes tofit in tables");

111     

112          OS << "\n// Registerclasses\n";

113          if (!Namespace.empty())

114            OS << "namespace "<< Namespace << " {\n";

115          OS << "enum {\n";

116          for (const auto &RC :RegisterClasses)

117            OS << "  " << RC.getName() <<"RegClassID"

118               << " = " <<RC.EnumValue << ",\n";

119          OS << "\n  };\n";

120          if (!Namespace.empty())

121            OS << "}\n";

122        }

123     

124        conststd::vector<Record*> &RegAltNameIndices =Target.getRegAltNameIndices();

125        // If the onlydefinition is the default NoRegAltName, we don't need to

126       // emit anything.

127        if (RegAltNameIndices.size() > 1) {

128          OS << "\n// Register alternatename indices\n";

129          if (!Namespace.empty())

130            OS << "namespace "<< Namespace << " {\n";

131          OS << "enum {\n";

132          for(unsigned i = 0, e = RegAltNameIndices.size(); i != e; ++i)

133            OS << "  " <<RegAltNameIndices[i]->getName() << ",\t// " << i<< "\n";

134          OS << "  NUM_TARGET_REG_ALT_NAMES = " <<RegAltNameIndices.size() << "\n";

135          OS << "};\n";

136          if (!Namespace.empty())

137            OS << "}\n";

138        }

139     

140        auto &SubRegIndices= Bank.getSubRegIndices();

141        if (!SubRegIndices.empty()) {

142          OS << "\n// Subregisterindices\n";

143          std::string Namespace =SubRegIndices.front().getNamespace();

144          if (!Namespace.empty())

145            OS << "namespace "<< Namespace << " {\n";

146          OS << "enum {\n  NoSubRegister,\n";

147          unsigned i = 0;

148          for (const auto &Idx :SubRegIndices)

149            OS << "  " << Idx.getName() <<",\t// " << ++i << "\n";

150          OS << "  NUM_TARGET_SUBREGS\n};\n";

151          if (!Namespace.empty())

152            OS << "}\n";

153        }

154     

155        OS << "} // End llvmnamespace\n";

156        OS << "#endif //GET_REGINFO_ENUM\n\n";

157      }

81行的emitSourceFileHeader为文件输出了位于头部的注释。接着是输出条件控制宏指令。在LLVM里,总是这样来包括这个输出文件的(以X86为例,文件X86MCTargetDesc.h):

#define GET_REGINFO_ENUM

#include "X86GenRegisterInfo.inc"

这是因为TargetGenRegisterInfo.inc是一个很大的文件,它包括了很多内容,而通常只需要包含其中的一部分。为此,每一部分都由类似的条件宏来包含。

TD文件里的Register类的Namespace域,作为包含寄存器枚举常量及寄存器类别枚举常量的名字空间,这里在X86GenRegisterInfo.inc文件里输出这样的语句:

classMCRegisterClass;

externconst MCRegisterClass X86MCRegisterClasses[];

比如X86MCRegisterClasses是由X86寄存器的名字空间“X86”与“MCRegisterClasses”合成的名字。这个数组定义在X86GenRegisterInfo.inc文件的下面。92~103行输出表示寄存器的枚举常量,输出的枚举常量类似于(以X86为例):

namespace X86{

enum {

  NoRegister,

  AH = 1,

  AL = 2,

 

  NUM_TARGET_REGS    // 246

};

}

这些枚举常量是以寄存器名字的顺序输出的。106~122行则输出代表寄存器类的枚举常量(以X86为例),注意CodeGenRegisterClass在容器中的索引与其EnumValue-1是一致的:

namespace X86{

enum {

  GR8RegClassID =0,

 GR8_NOREXRegClassID = 1,

 

 VR512_with_sub_xmm_in_FR32RegClassID = 79,

  };

}

X86目标机器没有使用RegAltNameIndex定义,跳过124~138行代码。余下代码则输出代表寄存器索引的枚举常量,以X86为例:

namespace X86{

enum {

  NoSubRegister,

  sub_8bit,           // 1

  sub_8bit_hi,     // 2

  sub_16bit,        // 3

  sub_32bit,        // 4

  sub_xmm,         // 5

  sub_ymm,        // 6

 NUM_TARGET_SUBREGS

};

}

} // End llvm namespace

#endif //GET_REGINFO_ENUM

3.3.6.2.       MC使用的寄存器描述

这部分输出代码将构成新的部分,因此由宏GET_REGINFO_MC_DESC包含。MC(machinecode)使用这些代码来描述寄存器。MC是一个雄心勃勃的目标文件与汇编(object-file-and-assembly)框架。它在几年前已是LLVM的一部分,以替换之前的汇编生成器。目前MC用于所有的(或至少重要的)LLVM目标机器汇编与目标文件的生成。MC还启动了“MCJIT”,这是一个基于MC层的JIT框架。(http://blog.llvm.org/2010/04/intro-to-llvm-mc-project.html有MC子项目的一个概述)。

3.3.6.2.1. MC对寄存器的定义

MC对寄存器的封装与抽象是类MCRegisterInfo,它比较重要的成员有以下这些。如何对目标机器填充作为基类部分的MCRegisterInfo实例,正是这部分代码生成的重要任务。

135      classMCRegisterInfo {

136      public:

137        typedef const MCRegisterClass *regclass_iterator;

138     

139        ///DwarfLLVMRegPair - Emitted by tablegen so Dwarf<->LLVM reg mappings canbe

140       /// performedwith a binary search.

141        structDwarfLLVMRegPair {

142          unsigned FromReg;

143          unsigned ToReg;

144     

145          bool operator<(DwarfLLVMRegPairRHS) const { returnFromReg < RHS.FromReg; }

146        };

147     

148        ///SubRegCoveredBits - Emitted by tablegen: bit range covered by a subreg

149       /// index, -1 inany being invalid.

150        structSubRegCoveredBits {

151          uint16_t Offset;

152          uint16_t Size;

153        };

154      private:

155        constMCRegisterDesc *Desc;                 // Pointer to the descriptor array

156        unsigned NumRegs;                          // Number of entries in the array

157        unsigned RAReg;                            // Return address register

158        unsigned PCReg;                            // Program counter register

159        constMCRegisterClass *Classes;             // Pointer to the regclass array

160        unsigned NumClasses;                       // Number of entries in the array

161        unsigned NumRegUnits;                      //Number of regunits.

162        constMCPhysReg (*RegUnitRoots)[2];         // Pointer to regunit root table.

163        constMCPhysReg *DiffLists;                 // Pointer to the difflists array

164        constunsigned *RegUnitMaskSequences;       // Pointer to lane mask sequences

165                                                   // for register units.

166        const char*RegStrings;                     // Pointer to the string table.

167        const char*RegClassStrings;                // Pointer to the class strings.

168        constuint16_t *SubRegIndices;              // Pointer to the subreg lookup

169                                                   // array.

170        constSubRegCoveredBits *SubRegIdxRanges;   // Pointer to the subreg covered

171                                                   // bit ranges array.

172        unsigned NumSubRegIndices;                 //Number of subreg indices.

173        constuint16_t *RegEncodingTable;           // Pointer to array of register

174                                                   // encodings.

175     

176        unsigned L2DwarfRegsSize;

177        unsigned EHL2DwarfRegsSize;

178        unsigned Dwarf2LRegsSize;

179        unsigned EHDwarf2LRegsSize;

180        constDwarfLLVMRegPair *L2DwarfRegs;        // LLVM to Dwarf regs mapping

181        constDwarfLLVMRegPair *EHL2DwarfRegs;      // LLVM to Dwarf regs mapping EH

182        constDwarfLLVMRegPair *Dwarf2LRegs;        // Dwarf to LLVM regs mapping

183        constDwarfLLVMRegPair *EHDwarf2LRegs;      // Dwarf to LLVM regs mapping EH

184        DenseMap<unsigned, int> L2SEHRegs;         // LLVMto SEH regs mapping

185     

186      public:

187        ///DiffListIterator - Base iterator class that can traverse the

188       ///differentially encoded register and regunit lists in DiffLists.

189       /// Don't usethis class directly, use one of the specialized sub-classes

190       /// definedbelow.

191        classDiffListIterator {

192          uint16_t Val;

193          constMCPhysReg *List;

194     

195        protected:

196          /// Create aninvalid iterator. Call init() to point to something useful.

197          DiffListIterator() : Val(0), List(nullptr){}

198     

199         /// init -Point the iterator to InitVal, decoding subsequent values from

200         /// DiffList.The iterator will initially point to InitVal, sub-classes are

201         /// responsiblefor skipping the seed value if it is not part of the list.

202          void init(MCPhysReg InitVal,const MCPhysReg *DiffList) {

203            Val = InitVal;

204            List = DiffList;

205          }

206     

207          /// advance -Move to the next list position, return the applied

208         ///differential. This function does not detect the end of the list, that

209         /// is thecaller's responsibility (by checking for a 0 return value).

210          unsigned advance() {

211            assert(isValid()&& "Cannot move off the end of the list.");

212            MCPhysReg D = *List++;

213            Val += D;

214            return D;

215          }

216     

217        public:

218     

219          /// isValid -returns true if this iterator is not yet at the end.

220          bool isValid() const{ return List; }

221     

222          /// Dereferencethe iterator to get the value at the current position.

223          unsigned operator*()const { returnVal; }

224     

225          /// Pre-incrementto move to the next position.

226          void operator++(){

227           // The end ofthe list is encoded as a 0 differential.

228            if (!advance())

229              List = nullptr;

230          }

231        };

232     

233        // Theseiterators are allowed to sub-class DiffListIterator and access

234       // internal listpointers.

235        friend class MCSubRegIterator;

236        friend class MCSubRegIndexIterator;

237        friend class MCSuperRegIterator;

238        friend class MCRegUnitIterator;

239        friend class MCRegUnitMaskIterator;

240        friend class MCRegUnitRootIterator;

下面我们将要看到,在寄存器可以通过唯一的数值区分时(CodeGenRegister中的EnumValue)。寄存器间的关系就可以通过一系列的数值数组来表示。因此,上面的MCPhysReg实际上是uint16_t的typedef。

为了使这些数值表示有较小的冗余度,而且有高的访问效率,TableGen使用差分编码表来记录这些关系,155行MCRegisterDesc类型的Desc成员将记录这些差分表的使用情况。191行的嵌套类DiffListIterator为各个差分表的迭代器(235~240行的迭代器)提供了基类与基本的差分表遍历实现。

类似的,MC使用类MCRegisterClass来描述寄存器类。MCRegisterClass包含的数据成员有这些:

30        classMCRegisterClass {

31        public:

32          typedef const MCPhysReg* iterator;

33          typedef const MCPhysReg* const_iterator;

34       

35          constiterator RegsBegin;

36          const uint8_t*const RegSet;

37          constuint32_t NameIdx;

38          constuint16_t RegsSize;

39          constuint16_t RegSetSize;

40          constuint16_t ID;

41          constuint16_t RegSize, Alignment; // Size &Alignment of register in bytes

42          const int8_tCopyCost;

43          const boolAllocatable;

这里的代码生成将为目标机器产生MCRegisterClass所需的内容,并生成对应的MCRegisterClass数组。

1.3.6.2.2. 差分编码

因为寄存器、寄存器索引及寄存器类的EnumValue都是连续的正整数,那么使用遵循一定顺序(即尽量与EnumValue的分配次序一致)的差分编码将能得到很好的编码效率。差分编码是这样的一个序列:d1,d2, d3, …, dn。给定一个初始值Init,将得到这样一个序列:Init+d1, Init+d1+d2,Init+d1+d2+d3, …, Init+d1+d2+..+dn。

进一步的,我们也可以不从序列的头部开始,比如给定另一个初始值init2,并指定从差分序列的偏移3处开始,那么可以得到序列:Init2+d3,Init2+d3+d4, Init2+d3+d4+…+dn。

这样,使用不同的操作数,不同的偏移,若干序列可以通过同一个差分序列生成。因此,只要编码得当,就可以得到可观的压缩率。下面RegisterInfoEmitter::runMCDesc的主要工作就是生成合适的(多个)差分序列。

782      void

783     RegisterInfoEmitter::runMCDesc(raw_ostream&OS, CodeGenTarget &Target,

784                                     CodeGenRegBank&RegBank) {

785        emitSourceFileHeader("MC RegisterInformation", OS);

786

787        OS << "\n#ifdefGET_REGINFO_MC_DESC\n";

788        OS << "#undef GET_REGINFO_MC_DESC\n";

789     

790        const auto &Regs = RegBank.getRegisters();

791     

792        auto&SubRegIndices = RegBank.getSubRegIndices();

793        // The lists ofsub-registers and super-registers go in the same array.  That

794       // allows us toshare suffixes.

795        typedef std::vector<const CodeGenRegister*> RegVec;

796     

797        // Differentiallyencoded lists.

798        SequenceToOffsetTable<DiffVec>DiffSeqs;

799        SmallVector<DiffVec, 4>SubRegLists(Regs.size());

800        SmallVector<DiffVec, 4>SuperRegLists(Regs.size());

801        SmallVector<DiffVec, 4>RegUnitLists(Regs.size());

802        SmallVector<unsigned, 4>RegUnitInitScale(Regs.size());

803     

804        // List of lanemasks accompanying register unit sequences.

805        SequenceToOffsetTable<MaskVec>LaneMaskSeqs;

806        SmallVector<MaskVec, 4>RegUnitLaneMasks(Regs.size());

807     

808        // Keep track ofsub-register names as well. These are not differentially

809       // encoded.

810        typedefSmallVector<const CodeGenSubRegIndex*, 4>SubRegIdxVec;

811        SequenceToOffsetTable<SubRegIdxVec, deref<llvm::less>>SubRegIdxSeqs;

812        SmallVector<SubRegIdxVec, 4>SubRegIdxLists(Regs.size());

813     

814        SequenceToOffsetTable<std::string>RegStrings;

815     

816        // Precomputeregister lists for the SequenceToOffsetTable.

817        unsigned i = 0;

818        for (auto I = Regs.begin(), E = Regs.end(); I != E; ++I,++i) {

819          const auto &Reg = *I;

820          RegStrings.add(Reg.getName());

821     

822          // Compute theordered sub-register list.

823          SetVector<constCodeGenRegister*> SR;

824          Reg.addSubRegsPreOrder(SR, RegBank);

825          diffEncode(SubRegLists[i],Reg.EnumValue, SR.begin(), SR.end());

826          DiffSeqs.add(SubRegLists[i]);

827     

828          // Compute thecorresponding sub-register indexes.

829          SubRegIdxVec &SRIs = SubRegIdxLists[i];

830          for(unsigned j = 0, je = SR.size(); j != je; ++j)

831            SRIs.push_back(Reg.getSubRegIndex(SR[j]));

832          SubRegIdxSeqs.add(SRIs);

833     

834          //Super-registers are already computed.

835          constRegVec &SuperRegList = Reg.getSuperRegs();

836          diffEncode(SuperRegLists[i],Reg.EnumValue, SuperRegList.begin(),

837                     SuperRegList.end());

838          DiffSeqs.add(SuperRegLists[i]);

839     

840          //Differentially encode the register unit list, seeded by register number.

841         // Firstcompute a scale factor that allows more diff-lists to be reused:

842         //

843         //   D0 -> (S0, S1)

844         //   D1 -> (S2, S3)

845         //

846         // A scalefactor of 2 allows D0 and D1 to share a diff-list. The initial

847         // value forthe differential decoder is the register number multiplied by

848         // the scale.

849         //

850         // Check theneighboring registers for arithmetic progressions.

851          unsigned ScaleA = ~0u, ScaleB = ~0u;

852          SparseBitVector<> RUs =Reg.getNativeRegUnits();

853          if (I != Regs.begin() &&

854             std::prev(I)->getNativeRegUnits().count() == RUs.count())

855            ScaleB = *RUs.begin() -*std::prev(I)->getNativeRegUnits().begin();

856          if (std::next(I) != Regs.end() &&

857             std::next(I)->getNativeRegUnits().count() == RUs.count())

858            ScaleA =*std::next(I)->getNativeRegUnits().begin() - *RUs.begin();

859          unsigned Scale = std::min(ScaleB, ScaleA);

860          // Default thescale to 0 if it can't be encoded in 4 bits.

861          if (Scale >= 16)

862            Scale = 0;

863          RegUnitInitScale[i] = Scale;

864          DiffSeqs.add(diffEncode(RegUnitLists[i],Scale * Reg.EnumValue, RUs));

865     

866          const auto &RUMasks = Reg.getRegUnitLaneMasks();

867          MaskVec &LaneMaskVec =RegUnitLaneMasks[i];

868          assert(LaneMaskVec.empty());

869          LaneMaskVec.insert(LaneMaskVec.begin(),RUMasks.begin(), RUMasks.end());

870          // Terminatormask should not be used inside of the list.

871      #ifndefNDEBUG

872          for(unsigned M : LaneMaskVec) {

873            assert(M!= ~0u && "terminator mask should not be part of the list");

874          }

875      #endif

876          LaneMaskSeqs.add(LaneMaskVec);

877        }

878     

879        // Compute thefinal layout of the sequence table.

880        DiffSeqs.layout();

881        LaneMaskSeqs.layout();

882        SubRegIdxSeqs.layout();

模板类SequenceToOffsetTable提供差分编码的实作。因此,有几个SequenceToOffsetTable的具现类就将有几个差分编码表。这里,将用到789行的DiffSeqs(以SmallVector<uint16_t,4>,DiffVec具现),814行的RegStrings(以std::string具现),及945行的RegClassStrings(以std::string具现)。

SequenceToOffsetTable::add方法提供了向差分编码表添加序列的功能。

69          void add(constSeqT &Seq) {

70            assert(Entries== 0 && "Cannot call add() after layout()");

71            typenameSeqMap::iterator I = Seqs.lower_bound(Seq);

72       

73            // If SeqMapcontains a sequence that has Seq as a suffix, I will be

74           // pointing toit.

75            if (I != Seqs.end() &&isSuffix(Seq, I->first))

76              return;

77       

78            I = Seqs.insert(I, std::make_pair(Seq,0u));

79       

80            // The entrybefore I may be a suffix of Seq that can now be erased.

81            if (I != Seqs.begin() &&isSuffix((--I)->first, Seq))

82              Seqs.erase(I);

83          }

SequenceToOffsetTable成员Seqs是类型SeqMap(std::map<SeqT,unsigned, SeqLess>,SeqT是具现时的模板实参)。71行的lower_bound返回第一个不小于Seq的迭代器,SeqLess执行比较操作:

41          struct SeqLess : publicstd::binary_function<SeqT, SeqT, bool> {

42            Less L;

43            bool operator()(const SeqT &A, constSeqT &B) const {

44              returnstd::lexicographical_compare(A.rbegin(), A.rend(),

45                                                 B.rbegin(), B.rend(), L);

46            }

47          };

这是个嵌套在SequenceToOffsetTable定义中的仿函数,42行的Less是SequenceToOffsetTable的模板参数,缺省为std::less<typenameSeqT::value_type>(比如SeqT是DiffVec,SeqT::value_type就是uint16_t)。比较按字母、数字序,从尾到头进行。

在SequenceToOffsetTable::add的75行,如果Seq是找到的序列的后缀(即一部分),那么可以忽略Seq。否则,插入一个“ (Seq, 0) ”。另外,如果找到序列前一个序列是Seq的后缀,也要删除这个序列。这样可以保证一个最唯一大序列。isSuffix的定义是这样的:

60          static bool isSuffix(const SeqT &A,constSeqT &B) {

61            returnA.size() <= B.size() && std::equal(A.rbegin(), A.rend(),B.rbegin());

62          }

在823行开始,对子寄存器进行差分编码。首先要对寄存器DAG进行排序,以生成效果理想的差分编码表。因此函数CodeGenRegister::addSubRegsPreOrder以前序遍历当前寄存器为根的寄存器DAG,将子寄存器保存入参数OSet中。之所以要前序遍历,因为寄存器的RegUnit就是在前序遍历寄存器DAG的过程中生成的。这样能得到更高效的差分编码表。

508      void

509     CodeGenRegister::addSubRegsPreOrder(SetVector<const CodeGenRegister*> &OSet,

510                                         CodeGenRegBank &RegBank)const {

511        assert(SubRegsComplete&& "Must precompute sub-registers");

512        for (unsignedi = 0, e = ExplicitSubRegs.size(); i != e; ++i) {

513          CodeGenRegister *SR = ExplicitSubRegs[i];

514          if (OSet.insert(SR))

515            SR->addSubRegsPreOrder(OSet, RegBank);

516        }

517        // Add any secondarysub-registers that weren't part of the explicit tree.

518        for(SubRegMap::const_iterator I = SubRegs.begin(), E = SubRegs.end();

519             I != E; ++I)

520          OSet.insert(I->second);

521      }

diffEncode方法输出一个差分序列,序列的初始值由第二个参数指定(对子寄存器表,初始值是寄存器的EnumValue)。这个序列通过SequenceToOffsetTable::add添加到差分表DiffSeqs。

575      static

576      DiffVec &diffEncode(DiffVec &V, unsigned InitVal,SparseBitVector<> List) {

577        assert(V.empty()&& "Clear DiffVec before diffEncode.");

578        uint16_t Val = uint16_t(InitVal);

579     

580        for (uint16_tCur : List) {

581          V.push_back(Cur - Val);

582          Val = Cur;

583        }

584        return V;

585      }

接着是对寄存器索引的差分编码,差分序列保存在SubRegIdxSeqs。在836行对包含当前寄存器的寄存器集进行差分编码,结果也保存在DiffSeqs中。

接下来对寄存器单元(实际上是RegUnit的序号)进行差分编码,这里仅考虑TD文件中定义的寄存器,不包括因调整权重加入的单元。840~750行注释谈到使用比例因子可以提高差分列表的重用率,这个比例因子应用于初始值上。以843~844行的例子来说,假定D0、D1的EnumValue是相邻的,S0~S3的EnumValue也是相邻的(因为在TD文件中,它们通常是顺序定义的),如果对D0、D1进行差分编码,假定D0是5,D1是6,S0~S3分别是1~4,那么对应子寄存器的差分序列分别是-4(5-4, S0),1(5-4+1, S1)与-3 (6-3, S2),1 (6-3+1, S3)。而如果将初始值扩大2倍,则得到两个都是-9,1的序列,这里的2得自S3-S1。因此,853~859行分别计算该寄存器与前后寄存器第一个单元序号的差值(以D0、D1为例,就是S2-S0)。

接下来866~876行将寄存器的Lane掩码保存入另一个SequenceToOffsetTable—LaneMaskSeqs。Lane掩码都是一个向量(866行的getRegUnitLaneMasks返回一个ArrayRef<unsigned>容器)。

最后,调用SequenceToOffsetTable::layout方法使SequenceToOffsetTable对象最终定型。这个方法每个SequenceToOffsetTable实例只能调用一次。

93          void layout() {

94            assert(Entries== 0 && "Can only call layout() once");

95            // Lay out thetable in Seqs iteration order.

96            for (typename SeqMap::iterator I = Seqs.begin(), E =Seqs.end(); I != E;

97                 ++I) {

98              I->second = Entries;

99              // Includespace for a terminator.

100            Entries += I->first.size() + 1;

101          }

102        }

在通过SequenceToOffsetTable::add方法添加差分序列时,上面98行的I->second设为0,现在则是差分表的当前累计大小(用于下面输出的差分表的注释里,提高生成代码的可读性)。

3.3.6.2.3. 生成的差分编码表

RegisterInfoEmitter::runMCDesc的余下部分就是输出前面准备的差分编码表。

RegisterInfoEmitter::runMCDesc(续)

884        OS <<"namespace llvm {\n\n";

885     

886        conststd::string &TargetName = Target.getName();

887     

888        // Emit theshared table of differential lists.

889        OS << "extern const MCPhysReg" << TargetName << "RegDiffLists[] = {\n";

890        DiffSeqs.emit(OS,printDiff16);

891        OS << "};\n\n";

892     

893        // Emit theshared table of regunit lane mask sequences.

894        OS << "extern const unsigned" << TargetName << "LaneMaskLists[] = {\n";

895        LaneMaskSeqs.emit(OS, printMask,"~0u");

896        OS << "};\n\n";

897     

898        // Emit the tableof sub-register indexes.

899        OS << "extern const uint16_t" << TargetName << "SubRegIdxLists[] = {\n";

900        SubRegIdxSeqs.emit(OS, printSubRegIndex);

901        OS << "};\n\n";

902     

903        // Emit the tableof sub-register index sizes.

904        OS << "extern constMCRegisterInfo::SubRegCoveredBits "

905           << TargetName <<"SubRegIdxRanges[] = {\n";

906        OS << "  { " << (uint16_t)-1 <<", " << (uint16_t)-1 << " },\n";

907        for (const auto &Idx :SubRegIndices) {

908          OS << "  { " << Idx.Offset << "," << Idx.Size << " },\t// "

909             << Idx.getName() <<"\n";

910        }

911        OS << "};\n\n";

912     

913        // Emit thestring table.

914        RegStrings.layout();

915        OS << "extern const char "<< TargetName << "RegStrings[] = {\n";

916        RegStrings.emit(OS, printChar);

917        OS << "};\n\n";

918     

919        OS << "extern const MCRegisterDesc" << TargetName

920           << "RegDesc[] = { //Descriptors\n";

921        OS << "  { " <<RegStrings.get("") << ", 0, 0, 0, 0, 0 },\n";

922     

923        // Emit theregister descriptors now.

924        i = 0;

925        for (const auto &Reg :Regs) {

926          OS << "  { " <<RegStrings.get(Reg.getName()) << ", "

927             << DiffSeqs.get(SubRegLists[i])<< ", " << DiffSeqs.get(SuperRegLists[i])

928             << ", " <<SubRegIdxSeqs.get(SubRegIdxLists[i]) << ", "

929             << (DiffSeqs.get(RegUnitLists[i])* 16 + RegUnitInitScale[i]) << ", "

930             <<LaneMaskSeqs.get(RegUnitLaneMasks[i]) << " },\n";

931          ++i;

932        }

933        OS << "};\n\n";      // End ofregister descriptors...

934     

935        // Emit the tableof register unit roots. Each regunit has one or two root

936       // registers.

937        OS << "extern const MCPhysReg" << TargetName << "RegUnitRoots[][2] = {\n";

938        for (unsignedi = 0, e = RegBank.getNumNativeRegUnits(); i != e; ++i) {

939          ArrayRef<constCodeGenRegister*> Roots = RegBank.getRegUnit(i).getRoots();

940          assert(!Roots.empty()&& "All regunits must have a root register.");

941          assert(Roots.size()<= 2 && "More than two roots not supported yet.");

942          OS << "  { " <<getQualifiedName(Roots.front()->TheDef);

943          for (unsigned r = 1; r != Roots.size(); ++r)

944            OS << ", " <<getQualifiedName(Roots[r]->TheDef);

945          OS << " },\n";

946        }

947        OS << "};\n\n";

948     

949        const auto &RegisterClasses = RegBank.getRegClasses();

950     

951        // Loop over allof the register classes... emitting each one.

952        OS << "namespace {     // Register classes...\n";

953     

954        SequenceToOffsetTable<std::string>RegClassStrings;

955     

956        // Emit theregister enum value arrays for each RegisterClass

957        for (const auto &RC :RegisterClasses) {

958          ArrayRef<Record*> Order =RC.getOrder();

959     

960          // Give theregister class a legal C name if it's anonymous.

961          std::string Name = RC.getName();

962     

963          RegClassStrings.add(Name);

964     

965          // Emit the registerlist now.

966          OS << "  // " << Name << "Register Class...\n"

967             << "  const MCPhysReg " << Name

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

969          for(unsigned i = 0, e = Order.size(); i != e; ++i) {

970            Record *Reg = Order[i];

971            OS << getQualifiedName(Reg)<< ", ";

972          }

973          OS << "\n  };\n\n";

974     

975          OS << "  // " << Name << " Bitset.\n"

976             << "  const uint8_t " << Name

977             << "Bits[] = {\n    ";

978          BitVectorEmitter BVE;

979          for(unsigned i = 0, e = Order.size(); i != e; ++i) {

980            Record *Reg = Order[i];

981           BVE.add(Target.getRegBank().getReg(Reg)->EnumValue);

982          }

983          BVE.print(OS);

984          OS << "\n  };\n\n";

985     

986        }

987        OS << "}\n\n";

988     

989        RegClassStrings.layout();

990        OS << "extern const char "<< TargetName << "RegClassStrings[] = {\n";

991        RegClassStrings.emit(OS, printChar);

992        OS << "};\n\n";

差分编码表通过SequenceToOffsetTable的emit方法输出。

115        void emit(raw_ostream &OS,

116                  void (*Print)(raw_ostream&,ElemT),

117                  constchar *Term = "0") const {

118          assert(Entries&& "Call layout() before emit()");

119          for (typename SeqMap::const_iterator I = Seqs.begin(), E =Seqs.end();

120               I != E; ++I) {

121            OS << "  /* " << I->second <<" */ ";

122            for (typename SeqT::const_iterator SI =I->first.begin(),

123                   SE = I->first.end(); SI != SE;++SI) {

124              Print(OS, *SI);

125              OS << ", ";

126            }

127            OS << Term <<",\n";

128          }

129        }

X96目标机器的寄存器编码差分表的内容如下。它包含了这几部分内容:子寄存器、上级寄存器、寄存器单元列表。

externconst MCPhysReg X86RegDiffLists[] = {

  /* 0 */ 0, 1, 0,

  /* 3 */ 2, 1, 0,

  /* 6 */ 5, 1, 0,

  /* 9 */ 65522, 16, 1, 0,

  /* 13 */65522, 17, 1, 0,

  /* 17 */65427, 1, 0,

  /* 20 */65475, 1, 0,

  /* 23 */65520, 65522, 1, 0,

  /* 27 */65520, 65527, 1, 0,

  /* 31 */8, 2, 0,

  /* 34 */4, 0,

  /* 36 */65521, 8, 0,

  /* 39 */9, 0,

  /* 41 */13, 0,

  /* 43 */65535, 65519, 14, 0,

  /* 47 */65535, 65520, 14, 0,

  /* 51 */65528, 15, 0,

  /* 54 */2, 6, 16, 0,

  /* 58 */5, 6, 16, 0,

  /* 62 */65535, 9, 16, 0,

  /* 66 */2, 10, 16, 0,

  /* 70 */3, 10, 16, 0,

  /* 74 */3, 13, 16, 0,

  /* 78 */4, 13, 16, 0,

  /* 82 */65535, 14, 16, 0,

  /* 86 */1, 16, 16, 0,

  /* 90 */2, 16, 16, 0,

  /* 94 */ 17, 0,

  /* 96 */32, 32, 0,

  /* 99 */65221, 0,

  /* 101 */65381, 0,

  /* 103 */65389, 0,

  /* 105 */65397, 0,

  /* 107 */16, 65528, 65416, 0,

  /* 111 */65445, 0,

  /* 113 */ 65477, 0,

  /* 115 */65504, 65504, 0,

  /* 118 */65509, 0,

  /* 120 */120, 8, 65520, 0,

  /* 124 */65523, 0,

  /* 126 */65530, 0,

  /* 128 */ 65531,0,

  /* 130 */65532, 0,

  /* 132 */65520, 65530, 65534, 65533, 0,

  /* 137 */65534, 0,

  /* 139 */65520, 65523, 65533, 65535, 0,

  /* 144 */65520, 65526, 65534, 65535, 0,

  /* 149 */65520, 65520, 65535, 65535, 0,

};

注意,这些序列都是以0结尾,因此利用这个差分表的序列不能出现重复的元素(因为重复元素的差分是0)。另外该数组的类型是uint16_t,因此数组内超过32767的实际上都是负数。

X86目标机器的寄存器Lane掩码差分表则包含如下内容:

externconst unsigned X86LaneMaskLists[] = {

  /* 0 */ 0x00000000, ~0u,

  /* 2 */ 0x00000002,0x00000001, ~0u,

  /* 5 */ 0x00000003, ~0u,

  /* 7 */ 0x00000004, ~0u,

};

因为存在差分0,这些序列以~0u结尾。差分表的内容总是最长的序列,在序列重复后缀多的情形下,这个表就会很小,比如这个Lane掩码差分表。

第三张差分表是寄存器索引表。

externconst uint16_t X86SubRegIdxLists[] = {

  /* 0 */ 4, 3, 1, 0,

  /* 4 */ 4, 3, 1, 2, 0,

  /* 9 */ 4, 3, 0,

  /* 12 */6, 5, 0,

};

X86目标机器的寄存器相当有规律,因此这张表也是很小的(上面的Lane掩码也是这个原因)。下一张表给出则是所有寄存器索引的位置与大小。注意!这张表不是差分表,其中第一项是保留不用的。其他项中第1个数字是该索引对应子寄存器的偏移,第2个数字则是该子寄存器的大小。

externconst MCRegisterInfo::SubRegCoveredBitsX86SubRegIdxRanges[] = {

  { 65535, 65535},

  { 0, 8 },                //sub_8bit

  { 8, 8 },                //sub_8bit_hi

  { 0, 16 },             //sub_16bit

  { 0, 32 },             //sub_32bit

  { 0, 128 },           //sub_xmm

  { 0, 256 },           //sub_ymm

};

可见X86目标机器使用的寄存器索引并不多。

最后的表X86RegStrings也是一张差分表,内容是组成寄存器名字的字符(一共219行):

externconst char X86RegStrings[] = {

  /* 0 */ 'X', 'M','M', '1', '0', 0,

  /* 6 */ 'Y', 'M', 'M', '1', '0', 0,

  /* 12 */ 'Z', 'M','M', '1', '0', 0,

  /* 18 */'C', 'R', '1', '0', 0,

 

  /* 1051 */'R', 'I', 'Z', 0,

};

现在对寄存器的各种描述变成了对这些差分表内容的援引,类MCRegisterDesc就是这样的一个定义:

105      structMCRegisterDesc {

106        uint32_t Name;      // Printablename for the reg (for debugging)

107        uint32_t SubRegs;   // Sub-registerset, described above

108        uint32_t SuperRegs; //Super-register set, described above

109     

110        // Offset intoMCRI::SubRegIndices of a list of sub-register indices for each

111       // sub-registerin SubRegs.

112        uint32_t SubRegIndices;

113     

114        // RegUnits -Points to the list of register units. The low 4 bits holds the

115       // Scale, thehigh bits hold an offset into DiffLists. See MCRegUnitIterator.

116        uint32_t RegUnits;

117     

118        /// Index intolist with lane mask sequences. The sequence contains a lanemask

119       /// for everyregister unit.

120        uint16_t RegUnitLaneMasks;

121      };

每一个寄存器(包含子寄存器)都对应一个MCRegisterDesc对象,这个对象给出在上述表中的偏移,根据这些偏移就可以获取这个寄存器的相关信息。

由SequenceToOffsetTable::get方法向每个MCRegisterDesc实例给出这些偏移值。

105        unsigned get(constSeqT &Seq) const {

106          assert(Entries&& "Call layout() before get()");

107          typenameSeqMap::const_iterator I = Seqs.lower_bound(Seq);

108          assert(I !=Seqs.end() && isSuffix(Seq, I->first) &&

109                 "get() called with sequencethat wasn't added first");

100          returnI->second + (I->first.size() - Seq.size());

101        }

因为SequenceToOffsetTable的编码方式是保留最长序列,较短但是最长序列后缀的序列由最长序列来表示,因此104行的I->first.size()- Seq.size()是使用最长序列所需要的、必要的调整。因此会导出这样的数组。第一行是保留不用的,因为这个数组的下标实际上是寄存器的EnumValue(从1开始)。这张表的有效项有245个。

externconst MCRegisterDesc X86RegDesc[] = { // Descriptors

  { 5, 0, 0, 0,0, 0 },

  { 870, 2, 90,3, 2273, 0 },

  { 898, 2, 86,3, 2273, 0 },

  { 1016, 151,87, 6, 0, 2 },

 

  { 997, 122,108, 2, 1617, 3 },

};

以第二行为例。X86RegStrings的偏移870是“AH”。X86RegDiffLists的偏移2是终结符,表示没有子寄存器。X86RegDiffLists的偏移90是:2, 16,16, 0。还原差分后,得到的寄存器EnumValue是1+2=3 (AX),1+2+16=19(EAX),1+2+16+16=35(RAX)。X86SubRegIdxLists的偏移3也是终结符。2273除以16后得142余1(起始值是1*EnumValue),142仍然是X86RegDiffLists的偏移,对应65535,由RegUnit-1*EnumValue得到,因此RegUnit=0。最后的0是在X86LaneMaskLists的偏移。

在第三行,898对应“AL”。2对应没有子寄存器。86得到寄存器2+1=3(AX),2+1+16=19(EAX),2+1+16+16=35(RAX)。X86SubRegIdxLists的偏移3也是终结符。第5个数仍然是2273,但RegUnit-1*EnumValue中EnumValue=2,所以RegUnit=1。最后的0是在X86LaneMaskLists的偏移。

在第四行,1016指向X86RegStrings中的“AX”,151在X86RegDiffLists对应序列:65535,65535。得到寄存器的EnumValue:3-1=2 (AL),3-1-1=1(AH)。87对应X86RegDiffLists序列:16,16。得到寄存器的EnumValue:3+16=19(EAX),3+16+16=35(RAX)。6对应X86SubRegIdxLists序列:1, 2。即子寄存器索引的编号。0对应X86RegDiffLists序列:0, 1。起始值为0(0*EnumValue),则第一个RegUnit是0,第二个RegUnit是1。

这里2~4行正好描述了两个子寄存器与包含它们的上级寄存器。

在CodeGen时,MCRegisterInfo需要这样解读X86RegDesc,这些操作由迭代器MCSubRegIterator,MCSubRegIndexIterator,MCSuperRegIterator,MCRegUnitIterator,MCRegUnitMaskIterator,MCRegUnitRootIterator,MCRegAliasIterator来实现。

接下来输出描述每个RegUnit所在DAG跟的数组,当前版本LLVM不支持超过1个根的DAG(但更早的版本是支持的)。对X86目标机器,这个数组包含100个项。

externconst MCPhysReg X86RegUnitRoots[][2] = {

  { X86::AH },

  { X86::AL },

  { X86::BH },

  { X86::BL },

  { X86::BPL },

  

  { X86::XMM30 },

  { X86::XMM31 },

};

接着,输出描述各个寄存器类别的数组。RegisterClass中的Order容器规定了这个类别中寄存器的分配(使用)次序。下面的GR8是其中一个例子:

  const uint16_t GR8[] = {

    X86::AL,X86::CL, X86::DL, X86::AH, X86::CH, X86::DH, X86::BL, X86::BH, X86::SIL,X86::DIL, X86::BPL, X86::SPL, X86::R8B, X86::R9B, X86::R10B, X86::R11B,X86::R14B, X86::R15B, X86::R12B, X86::R13B,

  };

这些数组封装在一个匿名名字空间内。X86::AL等都是由前面的RegisterInfoEmitter::runEnums输出的代表寄存器ID的枚举常量(CodeGenRegister的EnumValue)。

另外还有一个数组,这个数组也是定义了寄存器类中寄存器的分配(使用)顺序,不过它是这样的格式:将数组视为连续的内存,第一个元素位于低址,最后的元素位于内存高址。对某一寄存器,将该数组第EnumValue/8字节的第EnumValue%8比特置为1:

  const uint8_t GR8Bits[] = {

    0xb6, 0xa6,0x01, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,0x3f,

  };

以第一个字节为例,它的二进制形式是:10110110 (0xb6),代表寄存器X86::AH,X86::AL,X86::BL,X86::BH,X86::BPL(EnumValue分别是1,2,4,5,7)。

每个寄存器类别都会输出这样两个数组。

跟着输出的是保存了寄存器类名字的字符数组X86RegClassStrings。

externconst char X86RegClassStrings[] = {

  /* 0 */ 'R', 'F', 'P', '8', '0', 0,

  /* 6 */ 'V', 'K','1', 0,

  /* 10 */'V', 'R', '5', '1', '2', 0,

  /* 16 */'V', 'K', '3', '2', 0,

 

  /* 912 */'G', 'R', '6', '4', '_', 'w', 'i', 't','h', '_', 's', 'u', 'b', '_', '8', 'b', 'i', 't', 0,

};

RegisterInfoEmitter::runMCDesc(续)

994        OS <<"extern const MCRegisterClass " << TargetName

995           << "MCRegisterClasses[] ={\n";

996     

997        for (const auto &RC :RegisterClasses) {

998          // Asserts tomake sure values will fit in table assuming types from

999         //MCRegisterInfo.h

1000       assert((RC.SpillSize/8)<= 0xffff && "SpillSize too large.");

1001       assert((RC.SpillAlignment/8)<= 0xffff && "SpillAlignment too large.");

1002       assert(RC.CopyCost>= -128 && RC.CopyCost <= 127 && "Copy cost toolarge.");

1003  

1004       OS << "  { " << RC.getName() <<", " << RC.getName() << "Bits, "

1005          <<RegClassStrings.get(RC.getName()) << ", "

1006          << RC.getOrder().size() <<", sizeof(" << RC.getName() << "Bits), "

1007          << RC.getQualifiedName() +"RegClassID" << ", "

1008          << RC.SpillSize/8 << ","

1009          << RC.SpillAlignment/8 <<", "

1010          << RC.CopyCost << ","

1011          << RC.Allocatable << "},\n";

1012     }

1013  

1014     OS << "};\n\n";

1015  

1016     EmitRegMappingTables(OS,Regs, false);

1017  

1018     // Emit Regencoding table

1019     OS << "extern const uint16_t" << TargetName;

1020     OS << "RegEncodingTable[] ={\n";

1021     // Add entry forNoRegister

1022     OS << "  0,\n";

1023     for (const auto &RE :Regs) {

1024       Record *Reg = RE.TheDef;

1025       BitsInit *BI =Reg->getValueAsBitsInit("HWEncoding");

1026       uint64_t Value = 0;

1027       for (unsignedb = 0, be = BI->getNumBits(); b != be; ++b) {

1028         if (BitInit *B =dyn_cast<BitInit>(BI->getBit(b)))

1029           Value |= (uint64_t)B->getValue()<< b;

1030       }

1031       OS << "  " << Value <<",\n";

1032     }

1033     OS << "};\n";       // End of HWencoding table

1034  

1035     // MCRegisterInfoinitialization routine.

1036     OS << "static inline voidInit" << TargetName

1037        <<"MCRegisterInfo(MCRegisterInfo *RI, unsigned RA, "

1038        << "unsigned DwarfFlavour = 0,unsigned EHFlavour = 0, unsigned PC = 0) "

1039           "{\n"

1040        << "  RI->InitMCRegisterInfo(" <<TargetName << "RegDesc, "

1041        << Regs.size() + 1 << ",RA, PC, " << TargetName << "MCRegisterClasses, "

1042        << RegisterClasses.size() <<", " << TargetName << "RegUnitRoots, "

1043        << RegBank.getNumNativeRegUnits()<< ", " << TargetName << "RegDiffLists, "

1044        << TargetName <<"LaneMaskLists, " << TargetName << "RegStrings,"

1045        << TargetName <<"RegClassStrings, " << TargetName << "SubRegIdxLists,"

1046        <<(std::distance(SubRegIndices.begin(), SubRegIndices.end()) + 1) <<",\n"

1047        << TargetName <<"SubRegIdxRanges, " << TargetName

1048        <<"RegEncodingTable);\n\n";

1049  

1050     EmitRegMapping(OS,Regs, false);

1051  

1052     OS << "}\n\n";

1053  

1054     OS << "} // End llvmnamespace\n";

1055     OS << "#endif //GET_REGINFO_MC_DESC\n\n";

1056   }

997行循环输出的寄存器类描述数组大致上是这样:

externconst MCRegisterClass X86MCRegisterClasses[] = {

  { GR8, GR8Bits,130, 20, sizeof(GR8Bits), X86::GR8RegClassID,1, 1, 1, 1 },

  { GR8_NOREX,GR8_NOREXBits, 902, 8, sizeof(GR8_NOREXBits),X86::GR8_NOREXRegClassID, 1, 1, 1, 1 },

  { VK1, VK1Bits,6, 8, sizeof(VK1Bits), X86::VK1RegClassID, 1,1, 1, 1 },

  

  {VR512_with_sub_xmm_in_FR32, VR512_with_sub_xmm_in_FR32Bits, 27, 16,sizeof (VR512_with_sub_xmm_in_FR32Bits),X86::VR512_with_sub_xmm_in_FR32RegClassID, 64, 64, 1, 1 },

};

GR8与GR8Bits都是前面842~874行输出的数组,GR8RegClassID等则是由RegisterInfoEmitter::runEnums输出的枚举常量。每组中第三个输出的数字是RegClassStrings差分表中的偏移。

3.3.6.2.4. 与GCC/GDB编号间的映射

在TableGen的Register定义中,存在一个DwarfNumbers域(list<int>类型),不过这没有不使用。TableGen另外定义了一个DwarfRegNum类,它也提供了一个DwarfNumbers域(list<int>类型),以实现从llvm的寄存器编号到gcc/gdb寄存器编号的映射。需要使用这个功能的寄存器需要同时从Register及DwarfRegNum派生。

这些映射表由RegisterInfoEmitter::EmitRegMappingTables输出。

320      void RegisterInfoEmitter::EmitRegMappingTables(

321          raw_ostream &OS, const std::deque<CodeGenRegister> &Regs,bool isCtor) {

322        // Collect allinformation about dwarf register numbers

323        typedefstd::map<Record*, std::vector<int64_t>, LessRecordRegister>DwarfRegNumsMapTy;

324        DwarfRegNumsMapTy DwarfRegNums;

325     

326        // First, justpull all provided information to the map

327        unsigned maxLength = 0;

328        for (auto &RE : Regs) {

329          Record *Reg = RE.TheDef;

330          std::vector<int64_t> RegNums =Reg->getValueAsListOfInts("DwarfNumbers");

331          maxLength = std::max((size_t)maxLength, RegNums.size());

332          if (DwarfRegNums.count(Reg))

333            PrintWarning(Reg->getLoc(),Twine("DWARF numbers for register ") +

334                         getQualifiedName(Reg) +"specified multiple times");

335          DwarfRegNums[Reg] = RegNums;

336        }

337     

338        if (!maxLength)

339          return;

340     

341        // Now we knowmaximal length of number list. Append -1's, where needed

342        for(DwarfRegNumsMapTy::iterator

343             I = DwarfRegNums.begin(), E =DwarfRegNums.end(); I != E; ++I)

344          for(unsigned i = I->second.size(), e = maxLength; i != e; ++i)

345            I->second.push_back(-1);

346     

347        std::string Namespace =Regs.front().TheDef->getValueAsString("Namespace");

348     

349        OS << "// " <<Namespace << " Dwarf<->LLVM register mappings.\n";

350     

351        // Emit reverseinformation about the dwarf register numbers.

352        for (unsignedj = 0; j < 2; ++j) {

353          for(unsigned i = 0, e = maxLength; i != e; ++i) {

354            OS << "extern constMCRegisterInfo::DwarfLLVMRegPair " << Namespace;

355            OS << (j == 0 ? "DwarfFlavour": "EHFlavour");

356            OS << i <<"Dwarf2L[]";

357     

358            if (!isCtor) {

359              OS << " = {\n";

360     

361              // Storethe mapping sorted by the LLVM reg num so lookup can be done

362             // with abinary search.

363              std::map<uint64_t, Record*>Dwarf2LMap;

364              for(DwarfRegNumsMapTy::iterator

365                     I = DwarfRegNums.begin(), E =DwarfRegNums.end(); I != E; ++I) {

366                int DwarfRegNo = I->second[i];

367                if (DwarfRegNo < 0)

368                  continue;

369                Dwarf2LMap[DwarfRegNo] = I->first;

370              }

371     

372              for(std::map<uint64_t, Record*>::iterator

373                     I = Dwarf2LMap.begin(), E =Dwarf2LMap.end(); I != E; ++I)

374                OS << "  { " << I->first <<"U, " << getQualifiedName(I->second)

375                   << " },\n";

376     

377              OS << "};\n";

378            } else {

379              OS << ";\n";

380            }

381     

382            // We have tostore the size in a const global, it's used in multiple

383           // places.

384            OS << "extern const unsigned" << Namespace

385               << (j == 0 ?"DwarfFlavour" : "EHFlavour") << i <<"Dwarf2LSize";

386            if (!isCtor)

387              OS << " =array_lengthof(" << Namespace

388                 << (j == 0 ?"DwarfFlavour" : "EHFlavour") << i

389                 << "Dwarf2L);\n\n";

390            else

391              OS << ";\n\n";

392          }

393        }

394     

395        for (auto &RE : Regs) {

396          Record *Reg = RE.TheDef;

397          constRecordVal *V = Reg->getValue("DwarfAlias");

398          if (!V || !V->getValue())

399            continue;

400     

401          DefInit *DI =cast<DefInit>(V->getValue());

402          Record *Alias = DI->getDef();

403          DwarfRegNums[Reg] = DwarfRegNums[Alias];

404        }

405     

406        // Emitinformation about the dwarf register numbers.

407        for (unsignedj = 0; j < 2; ++j) {

408          for(unsigned i = 0, e = maxLength; i != e; ++i) {

409            OS << "extern constMCRegisterInfo::DwarfLLVMRegPair " << Namespace;

410            OS << (j == 0 ?"DwarfFlavour" : "EHFlavour");

411            OS << i << "L2Dwarf[]";

412            if (!isCtor) {

413              OS << " = {\n";

414              // Storethe mapping sorted by the Dwarf reg num so lookup can be done

415             // with abinary search.

416              for(DwarfRegNumsMapTy::iterator

417                     I = DwarfRegNums.begin(), E =DwarfRegNums.end(); I != E; ++I) {

418                int RegNo = I->second[i];

419                if (RegNo == -1)// -1 is the default value, don't emit a mapping.

420                  continue;

421     

422                OS << "  { " << getQualifiedName(I->first)<< ", " << RegNo

423                   << "U },\n";

424              }

425              OS << "};\n";

426            } else {

427              OS << ";\n";

428            }

429     

430            // We have tostore the size in a const global, it's used in multiple

431           // places.

432            OS << "extern const unsigned" << Namespace

433               << (j == 0 ?"DwarfFlavour" : "EHFlavour") << i <<"L2DwarfSize";

434            if (!isCtor)

435              OS << " =array_lengthof(" << Namespace

436                 << (j == 0 ?"DwarfFlavour" : "EHFlavour") << i <<"L2Dwarf);\n\n";

437            else

438              OS << ";\n\n";

439          }

440        }

441      }

328行循环获取寄存器的DwarfNumbers列表保存入DwarfRegNums容器,获取DwarfNumbers列表的最大尺寸。在目前的LLVM中,对于X86机器,这个列表对应3种Dwarf变种。第一列是X86_64,第二列是X86_32_DarwinEH,第三列是X86_32_Generic。在342行的循环将DwarfRegNums所有的元素都调整为相同大小,多出部分由-1填充(-1表示gcc的编号未定义)。

352行循环对X86机器输出数组X86DwarfFlavour0Dwarf2L,X86DwarfFlavour1Dwarf2L,X86DwarfFlavour2Dwarf2L,X86EHFlavour0Dwarf2L,X86EHFlavour1Dwarf2L及X86EHFlavour2Dwarf2L(其中*EHFlavour*数组的使用对象是DarwinEH系统,它与对应的*DwarfFlavour*数组内容没有差别),它们的类型都是DwarfLLVMRegPair,实现从dwarf到llvm的映射。DwarfLLVMRegPair的定义是:

141        struct DwarfLLVMRegPair {

142          unsigned FromReg;

143          unsigned ToReg;

144     

145          bool operator<(DwarfLLVMRegPairRHS) const { returnFromReg < RHS.FromReg; }

146        };

358行的isCtor是EmitRegMappingTables的最后一个参数,在这里的调用上下文里是false,表示不是为目标机器的TargetGenRegisterInfo构造函数生成代码。363行的Dwarf2LMap与DwarfRegNums相反,它把Dwarf数(由i下标指定)映射到LLVM的寄存器编号,注释说这样可以进行二分查找。接着在372行的循环输出Dwarf2LMap的内容。输出的数组大致是这个样子:

externconst MCRegisterInfo::DwarfLLVMRegPairX86DwarfFlavour1Dwarf2L[] = {

  { 0U, X86::EAX},

  { 1U, X86::ECX},

  { 2U, X86::EDX},

  

  { 36U, X86::MM7},

};

384~391行则输出一个全局常量,其值是对应数组的大小。比如:

externconst unsignedX86DwarfFlavour1Dwarf2LSize = array_lengthof(X86DwarfFlavour1Dwarf2L);

接下来,DwarfAlias提供了一个方式,使得两个Register可以共享相同的dwarf编号。需要的寄存器必须从DwarfAlias派生,并指定共享的寄存器(由这个寄存器来提供DwarfNumbers定义,参考下面的403行)。

407行的循环输出另一个方向的映射数组(从LLVM到DWARF)。类似地它会输出数组X86DwarfFlavour0L2Dwarf,X86DwarfFlavour1L2Dwarf,X86DwarfFlavour2L2Dwarf,X86EHFlavour0L2Dwarf,X86EHFlavour1L2Dwarf及X86EHFlavour2L2Dwarf。同样,431~439行会输出一个全局常量,值是对应数组的大小。

注意,在这些数组中,-1是不输出内容的,因为它表示gcc的编号没有定义。但会输出-2,像这样(-2表示这个寄存器编号对于该模式/变种是无效的):

externconst MCRegisterInfo::DwarfLLVMRegPairX86EHFlavour0L2Dwarf[] = {

  { X86::EAX, -2U},

  { X86::EBP, -2U},

  { X86::EBX, -2U},

    …

  { X86::ZMM31,75U },

};

回到RegisterInfoEmitter::runMCDesc。跟着是输出寄存器在目标机器上的硬件编码表。1025行的HWEncoding就是在TD文件里定义寄存器必须要填写的域。这个数组的内容是小端序的(当前版本有246项,每项对应一个寄存器):

externconst uint16_t X86RegEncodingTable[] = {

  0,

  4,

  0,

 

  15,

};

这些数值在汇编指令中用于指定寄存器(目前数组中最大的值是31)。

1036~1048行输出函数InitX86MCRegisterInfo的定义的第一部分。

staticinlinevoid InitX86MCRegisterInfo(MCRegisterInfo*RI, unsigned RA, unsigned DwarfFlavour = 0, unsigned EHFlavour = 0, unsignedPC = 0) {

  RI->InitMCRegisterInfo(X86RegDesc, 161,RA, PC, X86MCRegisterClasses, 59, X86RegUnitRoots, 87, X86RegDiffLists,X86RegStrings, X86SubRegIdxLists, 6,

  X86RegEncodingTable);

InitMCRegisterInfo是平台通用的初始化函数,它将目标机器所要使用的寄存器描述以及差分表保存到相应的MCRegisterInfo(基类)对象中。InitX86MCRegisterInfo在其基础上进行额外的初始化工作,这部分代码由下面的函数输出。

443      void RegisterInfoEmitter::EmitRegMapping(

444          raw_ostream &OS, const std::deque<CodeGenRegister> &Regs,bool isCtor) {

445        // Emit theinitializer so the tables from EmitRegMappingTables get wired up

446       // to theMCRegisterInfo object.

447        unsigned maxLength = 0;

448        for (auto &RE : Regs) {

449          Record *Reg = RE.TheDef;

450          maxLength = std::max((size_t)maxLength,

451                              Reg->getValueAsListOfInts("DwarfNumbers").size());

452        }

453     

454        if (!maxLength)

455          return;

456     

457        std::string Namespace =Regs.front().TheDef->getValueAsString("Namespace");

458     

459        // Emit reverseinformation about the dwarf register numbers.

460        for (unsignedj = 0; j < 2; ++j) {

461          OS << "  switch (";

462          if (j== 0)

463            OS << "DwarfFlavour";

464          else

465            OS << "EHFlavour";

466          OS << ") {\n"

467           << "  default:\n"

468           << "    llvm_unreachable(\"Unknown DWARFflavour\");\n";

469     

470          for(unsigned i = 0, e = maxLength; i != e; ++i) {

471            OS << "  case " << i <<":\n";

472            OS << "    ";

473            if (!isCtor)

474              OS << "RI->";

475            std::string Tmp;

476            raw_string_ostream(Tmp) <<Namespace

477                                    << (j == 0? "DwarfFlavour" : "EHFlavour") << i

478                                    <<"Dwarf2L";

479            OS <<"mapDwarfRegsToLLVMRegs(" << Tmp << ", "<< Tmp << "Size, ";

480            if (j == 0)

481                OS << "false";

482              else

483                OS << "true";

484            OS << ");\n";

485            OS << "    break;\n";

486          }

487          OS << "  }\n";

488        }

489     

490        // Emitinformation about the dwarf register numbers.

491        for (unsignedj = 0; j < 2; ++j) {

492          OS << "  switch (";

493          if (j == 0)

494            OS << "DwarfFlavour";

495          else

496            OS << "EHFlavour";

497          OS << ") {\n"

498             << "  default:\n"

499             << "    llvm_unreachable(\"Unknown DWARFflavour\");\n";

500     

501          for(unsigned i = 0, e = maxLength; i != e; ++i) {

502            OS << "  case " << i <<":\n";

503            OS << "    ";

504            if (!isCtor)

505              OS << "RI->";

506            std::string Tmp;

507            raw_string_ostream(Tmp) <<Namespace

508                                    << (j == 0? "DwarfFlavour" : "EHFlavour") << i

509                                    <<"L2Dwarf";

510            OS <<"mapLLVMRegsToDwarfRegs(" << Tmp << ", "<< Tmp << "Size, ";

511            if (j == 0)

512                OS << "false";

513              else

514                OS << "true";

515            OS << ");\n";

516            OS << "    break;\n";

517          }

518          OS << "  }\n";

519        }

520      }

输出的将是两组switch case语句,分别根据DwarfFlavour来调用mapDwarfRegsToLLVMRegs或者mapLLVMRegsToDwarfRegs,把上述的映射表关联到MCRegisterInfo对象相应的成员。

原创粉丝点击