LLVM学习笔记(13)

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

内容简介: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)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

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

Bandit Algorithms for Website Optimization

Bandit Algorithms for Website Optimization

John Myles White / O'Reilly Media / 2013-1-3 / USD 19.99

This book shows you how to run experiments on your website using A/B testing - and then takes you a huge step further by introducing you to bandit algorithms for website optimization. Author John Myle......一起来看看 《Bandit Algorithms for Website Optimization》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

SHA 加密
SHA 加密

SHA 加密工具

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

UNIX 时间戳转换