LLVM学习笔记(13)

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

内容简介:LLVM学习笔记(13)

3.3.6.  输出代码

3.3.6.1.       枚举常量

回到RegisterInfoEmitter::run,现在可以调用RegisterInfoEmitter::runEnums来向输出文件导出枚举常量了。这个输出文件被命名为 Target GenRegisterInfo.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      const std::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"

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

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

class MCRegisterClass;

extern const 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      class MCRegisterInfo {

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      struct DwarfLLVMRegPair {

142      unsigned FromReg;

143      unsigned ToReg;

144     

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

146      };

147     

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

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

150      struct SubRegCoveredBits {

151      uint16_t Offset;

152      uint16_t Size;

153      };

154      private :

155      const MCRegisterDesc *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      const MCRegisterClass *Classes;             // Pointer to the regclass array

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

161      unsigned NumRegUnits;                       //Number of regunits.

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

163      const MCPhysReg *DiffLists;                 // Pointer to the difflists array

164      const unsigned *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      const uint16_t *SubRegIndices;              // Pointer to the subreg lookup

169                                // array.

170      const SubRegCoveredBits *SubRegIdxRanges;   // Pointer to the subreg covered

171                                                    // bit ranges array.

172      unsigned NumSubRegIndices;                  //Number of subreg indices.

173      const uint16_t *RegEncodingTable;           // Pointer to array of register

174                                                    // encodings.

175     

176      unsigned L2DwarfRegsSize;

177      unsigned EHL2DwarfRegsSize;

178      unsigned Dwarf2LRegsSize;

179      unsigned EHDwarf2LRegsSize;

180      const DwarfLLVMRegPair *L2DwarfRegs;        // LLVM to Dwarf regs mapping

181      const DwarfLLVMRegPair *EHL2DwarfRegs;      // LLVM to Dwarf regs mapping EH

182      const DwarfLLVMRegPair *Dwarf2LRegs;        // Dwarf to LLVM regs mapping

183      const DwarfLLVMRegPair *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      class DiffListIterator {

192      uint16_t Val;

193      const MCPhysReg *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 { return Val; }

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        class MCRegisterClass {

31        public :

32        typedef const MCPhysReg* iterator;

33        typedef const MCPhysReg* const_iterator;

34       

35        const iterator RegsBegin;

36        const uint8_t* const RegSet;

37        const uint32_t NameIdx;

38        const uint16_t RegsSize;

39        const uint16_t RegSetSize;

40        const uint16_t ID;

41        const uint16_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      typedef SmallVector< 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.(Reg.getName());

821     

822      // Compute theordered sub-register list.

823      SetVector< const CodeGenRegister*> SR;

824      Reg.(SR, RegBank);

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

826      DiffSeqs.(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      const RegVec &SuperRegList = Reg.getSuperRegs();

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

837      SuperRegList.end());

838      DiffSeqs.(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.((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      #ifndef NDEBUG

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.();

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( const SeqT &Seq) {

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

71        typename SeqMap::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() &&(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 : public std::binary_function<SeqT, SeqT, bool> {

42        Less L;

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

44        return std::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, const SeqT &B) {

61        return A.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      const std::string &TargetName = Target.getName();

887     

888      // Emit theshared table of differential lists.

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

890      DiffSeqs.(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< const CodeGenRegister*> 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      const char *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目标机器的寄存器编码差分表的内容如下。它包含了这几部分内容:子寄存器、上级寄存器、寄存器单元列表。

extern const 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掩码差分表则包含如下内容:

extern const unsigned X86LaneMaskLists[] = {

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

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

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

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

};

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

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

extern const 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个数字则是该子寄存器的大小。

extern const 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行):

extern const 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      struct MCRegisterDesc {

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 ( const SeqT &Seq) const {

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

107      typename SeqMap::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      return I->second + (I->first.size() - Seq.size());

101      }

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

extern const 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个项。

extern const 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。

extern const 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   (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   (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行循环输出的寄存器类描述数组大致上是这样:

extern const 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      typedef std::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      const RecordVal *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 { return FromReg < RHS.FromReg; }

146      };

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

extern const MCRegisterInfo::DwarfLLVMRegPairX86DwarfFlavour1Dwarf2L[] = {

{ 0U, X86::EAX},

{ 1U, X86::ECX},

{ 2U, X86::EDX},

{ 36U, X86::MM7},

};

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

extern const 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表示这个寄存器编号对于该模式/变种是无效的):

extern const MCRegisterInfo::DwarfLLVMRegPairX86EHFlavour0L2Dwarf[] = {

{ X86::EAX, -2U},

{ X86::EBP, -2U},

{ X86::EBX, -2U},

{ X86::ZMM31,75U },

};

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

extern const uint16_t X86RegEncodingTable[] = {

0,

4,

0,

15,

};

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

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

static inline void 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对象相应的成员。


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

查看所有标签

猜你喜欢:

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

程序设计基础

程序设计基础

谢书良 / 2010-5 / 29.50元

《程序设计基础》是为从来没有接触过程序设计的读者编写的“零起点”入门教材。全书共分8章,第1章主要介绍程序设计的概念和程序运行的环境,第2章介绍了基本的数据类型、运算符与表达式,第3章介绍面向过程程序的顺序、分支选择和循环三种控制结构,第4章至第7章分别介绍了数组、指针的概念,结构体和其他数据类型,函数及其调用,内容涵盖了C++面向过程程序设计内容,与C语言教材完全兼容。第8章是体现《程序设计基础......一起来看看 《程序设计基础》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

MD5 加密
MD5 加密

MD5 加密工具