LLVM学习笔记(38)

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

3.5.2. 代码生成

这部分代码输出到文件X86GenInstrInfo.inc中。

​​​​​​​3.5.2.1. 枚举常量

从InstrInfoEmitter的构造函数返回到EmitInstrInfo,接下来调用的InstrInfoEmitter::run方法来输出相关的代码。

342      void InstrInfoEmitter::run (raw_ostream &OS) {

343      emitSourceFileHeader("Target Instruction Enum Values", OS);

344      (OS);

一如既往,首先需要输出枚举常量的定义。583行的getInstructionsByEnumValue方法以名字序返回指令的CodeGenInstruction对象集(除了部分有指定次序的指令,参考一节)。

567      void InstrInfoEmitter::emitEnums (raw_ostream &OS) {

568     

569      OS << "\n#ifdef GET_INSTRINFO_ENUM\n";

570      OS << "#undef GET_INSTRINFO_ENUM\n";

571     

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

573     

574      CodeGenTarget Target(Records);

575     

576      // We must emit the PHI opcode first...

577      std::string Namespace = Target.getInstNamespace();

578     

579      if (Namespace.empty())

580      PrintFatalError("No instructions defined!");

581     

582      const std::vector< const CodeGenInstruction*> &NumberedInstructions =

583      Target. getInstructionsByEnumValue ();

584     

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

586      OS << "  enum {\n";

587      unsigned Num = 0;

588      for ( const CodeGenInstruction *Inst : NumberedInstructions)

589      OS << "    " << Inst->TheDef->getName() << "\t= " << Num++ << ",\n";

590      OS << "    INSTRUCTION_LIST_END = " << NumberedInstructions.size() << "\n";

591      OS << "  };\n\n";

592      OS << "namespace Sched {\n";

593      OS << "  enum {\n";

594      Num = 0;

595      for ( const auto &Class : SchedModels.explicit_classes())

596      OS << "    " << Class.Name << "\t= " << Num++ << ",\n";

597      OS << "    SCHED_LIST_END = " << SchedModels.numInstrSchedClasses() << "\n";

598      OS << "  };\n";

599      OS << "} // End Sched namespace\n";

600      OS << "} // End " << Namespace << " namespace\n";

601      OS << "} // End llvm namespace \n";

602     

603      OS << "#endif // GET_INSTRINFO_ENUM\n\n";

604      }

585~591行输出代表指令的枚举常量,其输出结果是:

namespace X86 {

enum {

PHI             = 0,

INLINEASM            = 1,

CFI_INSTRUCTION               = 2,

EH_LABEL                = 3,

GC_LABEL               = 4,

XSHA256  = 12098,

XSTORE    = 12099,

XTEST        = 12100,

INSTRUCTION_LIST_END = 12101

};

X86家族的指令数真是令人印象深刻(这意味着有X86家族的各种处理器一共贡献了12100个Instruction定义,为此X86使用了20个指令描述文件)。相比之下,ARM家族的指令数是2822条。

CodeGenSchedModels的容器SchedClasses保存了已知的所有调度类型,CodeGenSchedClass的来源有两种,第一种来自指令定义,包括方法从InstRW定义直接得到的类型,它们优先保存在SchedClasses容器,其他推导自ItinRW,InstRW及指令定义中的SchedVariant定义。CodeGenSchedModels成员NumInstrSchedClasses记录了第一种CodeGenSchedClass对象的个数(即597行numInstrSchedClasses方法所返回的值)。因此,592~600行输出第一种调度类型的枚举值。

namespace Sched {

enum {

NoInstrModel       = 0,

IIC_AAA_WriteMicrocoded             = 1,

IIC_AAD_WriteMicrocoded             = 2,

IIC_AAM_WriteMicrocoded            = 3,

IIC_AAS_WriteMicrocoded              = 4,

ANDNPDrm_ANDNPSrm_ANDPDrm_ANDPSrm_ORPDrm_ORPSrm_VANDNPDYrm_VANDNPDrm_VANDNPSYrm_VANDNPSrm_VANDPDYrm_VANDPDrm_VANDPSYrm_VANDPSrm_VORPDYrm_VORPDrm_VORPSYrm_VORPSrm_VXORPDYrm_VXORPDrm_VXORPSYrm_VXORPSrm_XORPDrm_XORPSrm     = 945,

VZEROUPPER        = 946,

VZEROALL               = 947,

LDMXCSR_VLDMXCSR       = 948,

STMXCSR_VSTMXCSR        = 949,

SCHED_LIST_END = 950

};

} // End Sched namespace

} // End X86 namespace

在这些定义里我们能看到一个来自InstrRW定义的调度类型,它枚举值是945。这样调度类型的名字是由对应InstRW定义所援引的指令名合成而来。另外,枚举值为1的调度类型则是一个通过指令定义得到的调度类型,这些指令使用执行步骤IIC_AAA,资源使用情况由WriteMicrocoded描述。

​​​​​​​​​​​​​​3.5.2.2. 操作数描述数组

在InstrInfoEmitter::run接下来输出所谓的“目标机器指令描述符”。在355行获取目标机器的指令集描述,对X86目标机器就是定义X86InstrInfo(它与基类的内容是一致的)。

InstrInfoEmitter::run(续)

346      emitSourceFileHeader("Target Instruction Descriptors", OS);

347     

348      OS << "\n#ifdef GET_INSTRINFO_MC_DESC\n";

349      OS << "#undef GET_INSTRINFO_MC_DESC\n";

350     

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

352     

353      CodeGenTarget &Target = CDP.getTargetInfo();

354      const std::string &TargetName = Target.getName();

355      Record *InstrInfo = Target.getInstructionSet();

356     

357      // Keep track of all of the def lists we have emitted already.

358      std::map<std::vector<Record*>, unsigned> EmittedLists;

359      unsigned ListNumber = 0;

360     

361      // Emit all of the instruction's implicit uses and defs.

362      for ( const CodeGenInstruction *II : Target.instructions()) {

363      Record *Inst = II->TheDef;

364      std::vector<Record*> Uses = Inst->getValueAsListOfDefs("Uses");

365      if (!Uses.empty()) {

366      unsigned &IL = EmittedLists[Uses];

367      if (!IL)(Uses, IL = ++ListNumber, OS);

368      }

369      std::vector<Record*> Defs = Inst->getValueAsListOfDefs("Defs");

370      if (!Defs.empty()) {

371      unsigned &IL = EmittedLists[Defs];

372      if (!IL) PrintDefList(Defs, IL = ++ListNumber, OS);

373      }

374      }

375     

376      OperandInfoMapTy OperandInfoIDs;

377     

378      // Emit all of the operand info records.

379      (OS, OperandInfoIDs);

在指令定义中Uses与Defs分别表示该指令缺省使用及改写的非操作数寄存器。首先通过下面的PrintDefList方法输出一系列ImplicitList为前缀的数组。而容器EmittedLists则关联了这些寄存器与所输出的数组(367行)。

75        static void PrintDefList ( const std::vector<Record*> &Uses,

76        unsigned Num, raw_ostream &OS) {

77        OS << "static const uint16_t ImplicitList" << Num << "[] = { ";

78        for (unsigned i = 0, e = Uses.size(); i != e; ++i)

79        OS << getQualifiedName(Uses[i]) << ", ";

80        OS << "0 };\n";

81        }

对X86目标机器,当前版本一共会输出95个数组,我们只给出几个例子,不一一列举。它们将作为后面输出的X86Insts数组元素的成员。

static const uint16_t ImplicitList1[] = { X86::FPSW, 0 };

static const uint16_t ImplicitList2[] = { X86::AX, X86::EFLAGS, 0 };

static const uint16_t ImplicitList3[] = { X86::EFLAGS, 0 };

static const uint16_t ImplicitList4[] = { X86::EAX, X86::EFLAGS, 0 };

376行的OperandInfoMapTy是std::map<std::vector<std::string>, unsigned>的typedef,它的实例OperandInfoIDs作为379行EmitOperandInfo方法的一个参数。在下面的176行看到,这个容器的第一项是不使用的。

172      void InstrInfoEmitter::EmitOperandInfo (raw_ostream &OS,

173      OperandInfoMapTy &OperandInfoIDs) {

174      // ID #0 is for no operand info.

175      unsigned OperandListNum = 0;

176      OperandInfoIDs[std::vector<std::string>()] = ++OperandListNum;

177     

178      OS << "\n";

179      const CodeGenTarget &Target = CDP.getTargetInfo();

180      for ( const CodeGenInstruction *Inst : Target.instructions()) {

181      std::vector<std::string> OperandInfo =(*Inst);

182      unsigned &N = OperandInfoIDs[OperandInfo];

183      if (N != 0) continue ;

184     

185      N = ++OperandListNum;

186      OS << "static const MCOperandInfo OperandInfo" << N << "[] = { ";

187      for ( const std::string &Info : OperandInfo)

188      OS << "{ " << Info << " }, ";

189      OS << "};\n";

190      }

191      }

在180行遍历所有指令定义的CodeGenInstruction 实例,以该实例为参数,在181行调用下面的GetOperandInfo方法来获取描述类型MCOperandInfo的字符串。类型MCOperandInfo是这样定义的:

56        class MCOperandInfo {

57        public :

58        /// \brief This specifies the register class enumeration of the operand

59          /// if the operand is a register.  If isLookupPtrRegClass is set, then this is

60          /// an index that is passed to TargetRegisterInfo::getPointerRegClass(x) to

61          /// get a dynamic register class.

62        int16_t RegClass;

63       

64        /// \brief These are flags from the MCOI::OperandFlags enum.

65        uint8_t Flags;

66       

67        /// \brief Information about the type of the operand.

68        uint8_t OperandType;

69          /// \brief The lower 16 bits are used to specify which constraints are set.

70          /// The higher 16 bits are used to specify the value of constraints (4 bits

71          /// each).

72        uint32_t Constraints;

73       

74        /// \brief Set if this operand is a pointer value and it requires a callback

75          /// to look up its register class.

76        bool isLookupPtrRegClass() const {

77        return Flags & (1 << MCOI::LookupPtrRegClass);

78        }

79       

80        /// \brief Set if this is one of the operands that made up of the predicate

81          /// operand that controls an isPredicable() instruction.

82        bool isPredicate() const { return Flags & (1 << MCOI::Predicate); }

83       

84        /// \brief Set if this operand is a optional def.

85        bool isOptionalDef() const { return Flags & (1 << MCOI::OptionalDef); }

86        };

这是MC用来描述指令操作数的定义,也是我们需要为每个指令操作数所输出的类型。另外,在InstrInfoEmitter::GetOperandInfo用到的嵌套类CGIOperandList::OperandInfo定义如下:

65        struct OperandInfo {

66        /// Rec - The definition this operand is declared as.

67              ///

68        Record *Rec;

69       

70        /// Name - If this operand was assigned a symbolic name, this is it,

71              /// otherwise, it's empty.

72        std::string Name;

73       

74        /// PrinterMethodName - The method used to print operands of this type in

75              /// the asmprinter.

76        std::string PrinterMethodName;

77       

78        /// EncoderMethodName - The method used to get the machine operand value

79              /// for binary encoding. "getMachineOpValue" by default.

80        std::string EncoderMethodName;

81       

82        /// OperandType - A value from MCOI::OperandType representing the type of

83              /// the operand.

84        std::string OperandType;

85       

86        /// MIOperandNo - Currently (this is meant to be phased out), some logical

87              /// operands correspond to multiple MachineInstr operands.  In the X86

88              /// target for example, one address operand is represented as 4

89              /// MachineOperands.  Because of this, the operand number in the

90              /// OperandList may not match the MachineInstr operand num.  Until it

91              /// does, this contains the MI operand index of this operand.

92        unsigned MIOperandNo;

93        unsigned MINumOperands;   // The number of operands.

94       

95        /// DoNotEncode - Bools are set to true in this vector for each operand in

96              /// the DisableEncoding list.  These should not be emitted by the code

97              /// emitter.

98        std::vector<bool> DoNotEncode;

99       

100      /// MIOperandInfo - Default MI operand type. Note an operand may be made

101            /// up of multiple MI operands.

102      DagInit *MIOperandInfo;

103     

104      /// Constraint info for this operand.  This operand can have pieces, so we

105            /// track constraint info for each.

106      std::vector<ConstraintInfo> Constraints;

107     

108      OperandInfo(Record *R, const std::string &N, const std::string &PMN,

109      const std::string &EMN, const std::string &OT, unsigned MION,

110      unsigned MINO, DagInit *MIOI)

111      : Rec(R), Name(N), PrinterMethodName(PMN), EncoderMethodName(EMN),

112      OperandType(OT), MIOperandNo(MION), MINumOperands(MINO),

113      MIOperandInfo(MIOI) {}

114     

115     

116      /// getTiedOperand - If this operand is tied to another one, return the

117            /// other operand number.  Otherwise, return -1.

118      int getTiedRegister() const {

119      for (unsigned j = 0, e = Constraints.size(); j != e; ++j) {

120      const CGIOperandList::ConstraintInfo &CI = Constraints[j];

121      if (CI.isTied()) return CI.getTiedOperand();

122      }

123      return -1;

124      }

125      };

下面91行的循环变量Op的类型也是CGIOperandList::OperandInfo。我们已经知道有些复杂指令使用的操作数是包含子操作数的。这些子操作数在.td文件里构成了以ops为操作符的一个dag值。在解析.td文件时,这个dag值被记录在相应OperandInfo对象的MIOperandInfo成员(上面102行)。缺省地,MIOperandInfo在.td文件里是(ops),满足下面的102条件。而对于具有子操作数的情形,这些子操作数都被记录到容器OperandList里,这时OperandInfo定义里68行的Record被借用来记录子操作数的Record对象。

87        std::vector<std::string>

88        InstrInfoEmitter::GetOperandInfo ( const CodeGenInstruction &Inst) {

89        std::vector<std::string> Result;

90       

91        for ( auto &Op : Inst.Operands) {

92        // Handle aggregate operands and normal operands the same way by expanding

93            // either case into a list of operands for this op.

94        std::vector<CGIOperandList::OperandInfo> OperandList;

95       

96        // This might be a multiple operand thing.  Targets like X86 have

97            // registers in their multi-operand operands.  It may also be an anonymous

98            // operand, which has a single operand, but no declared class for the

99            // operand.

100      DagInit *MIOI = Op.MIOperandInfo;

101     

102      if (!MIOI || MIOI->getNumArgs() == 0) {

103      // Single, anonymous, operand.

104      OperandList.push_back(Op);

105      } else {

106      for (unsigned j = 0, e = Op.MINumOperands; j != e; ++j) {

107      OperandList.push_back(Op);

108     

109      Record *OpR = cast<DefInit>(MIOI->getArg(j))->getDef();

110      OperandList.back().Rec = OpR;

111      }

112      }

113     

114      for (unsigned j = 0, e = OperandList.size(); j != e; ++j) {

115      Record *OpR = OperandList[j].Rec;

116      std::string Res;

117     

118      if (OpR->isSubClassOf("RegisterOperand"))

119      OpR = OpR->getValueAsDef("RegClass");

120      if (OpR->isSubClassOf("RegisterClass"))

121      Res += getQualifiedName(OpR) + "RegClassID, ";

122      else if (OpR->isSubClassOf("PointerLikeRegClass"))

123      Res += utostr(OpR->getValueAsInt("RegClassKind")) + ", ";

124      else

125      // -1 means the operand does not have a fixed register class.

126      Res += "-1, ";

127     

128      // Fill in applicable flags.

129      Res += "0";

130     

131      // Ptr value whose register class is resolved via callback.

132      if (OpR->isSubClassOf("PointerLikeRegClass"))

133      Res += "|(1<<MCOI::LookupPtrRegClass)";

134     

135      // Predicate operands.  Check to see if the original unexpanded operand

136            // was of type PredicateOp.

137      if (Op.Rec->isSubClassOf("PredicateOp"))

138      Res += "|(1<<MCOI::Predicate)";

139     

140      // Optional def operands.  Check to see if the original unexpanded operand

141            // was of type OptionalDefOperand.

142      if (Op.Rec->isSubClassOf("OptionalDefOperand"))

143      Res += "|(1<<MCOI::OptionalDef)";

144     

145      // Fill in operand type.

146      Res += ", ";

147      assert (!Op.OperandType.empty() && "Invalid operand type.");

148      Res += Op.OperandType;

149     

150      // Fill in constraint info.

151      Res += ", ";

152     

153      const CGIOperandList::ConstraintInfo &Constraint =

154      Op.Constraints[j];

155      if (Constraint.isNone())

156      Res += "0";

157      else if (Constraint.isEarlyClobber())

158      Res += "(1 << MCOI::EARLY_CLOBBER)";

159      else {

160      assert (Constraint.isTied());

161      Res += "((" + utostr(Constraint.getTiedOperand()) +

162      " << 16) | (1 << MCOI::TIED_TO))";

163      }

164     

165      Result.push_back(Res);

166      }

167      }

168     

169      return Result;

170      }

接下来遍历OperandList容器,根据下列枚举常量定义,输出对应的字符串。

31        namespace MCOI {

32        // Operand constraints

33        enum OperandConstraint {

34        TIED_TO = 0,  // Must be allocated the same register as.

35        EARLY_CLOBBER // Operand is an early clobber register operand

36        };

37       

38        /// \brief These are flags set on operands, but should be considered

39        /// private, all access should go through the MCOperandInfo accessors.

40        /// See the accessors for a description of what these are.

41        enum OperandFlags { LookupPtrRegClass = 0, Predicate, OptionalDef };

42       

43        /// \brief Operands are tagged with one of the values of this enum.

44        enum OperandType {

45        OPERAND_UNKNOWN = 0,

46        OPERAND_IMMEDIATE = 1,

47        OPERAND_REGISTER = 2,

48        OPERAND_MEMORY = 3,

49        OPERAND_PCREL = 4,

50        OPERAND_FIRST_TARGET = 5

51        };

52        }

从GetOperandInfo回到EmitOperandInfo,返回值OperandInfo进而保存在OperandInfoIDs容器里作为键值,而与键值对应的则是输出MCOperandInfo的序号(0是不使用的)。因此,我们得到以下的输出(仅列举作为例子)。

static const MCOperandInfo OperandInfo2[] = { { -1, 0, MCOI::OPERAND_IMMEDIATE, 0 }, };

static const MCOperandInfo OperandInfo3[] = { { -1, 0, MCOI::OPERAND_UNKNOWN, 0 }, { -1, 0, MCOI::OPERAND_UNKNOWN, 0 }, { -1, 0, MCOI::OPERAND_IMMEDIATE, 0 }, };

static const MCOperandInfo OperandInfo4[] = { { -1, 0, MCOI::OPERAND_UNKNOWN, 0 }, { -1, 0, MCOI::OPERAND_UNKNOWN, ((0 << 16) | (1 << MCOI::TIED_TO)) }, { -1, 0, MCOI::OPERAND_UNKNOWN, 0 }, { -1, 0, MCOI::OPERAND_IMMEDIATE, 0 }, };

static const MCOperandInfo OperandInfo5[] = { { -1, 0, MCOI::OPERAND_UNKNOWN, 0 }, };

static const MCOperandInfo OperandInfo12[] = { { X86::RFP32RegClassID, 0, MCOI::OPERAND_REGISTER, 0 }, { X86::RFP32RegClassID, 0, MCOI::OPERAND_REGISTER, 0 }, };

操作数由几个子操作数构成,这个数组就有多长。另外,注意EmitOperandInfo的180行,Target.instructions()实际上是返回由getInstructionsByEnumValue方法给出的迭代器范围,因此我们遍历指令的次序还是相同的。

对X86目标机器来说,这次输出的数组有821个,这也是.td文件里给出的Operand定义的个数。它们也将作为后面输出的X86Insts数组元素的成员。


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

查看所有标签

猜你喜欢:

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

Linux命令行大全

Linux命令行大全

绍茨 (William E.Shotts) / 郭光伟、郝记生 / 人民邮电出版社 / 2013-3-1 / 69.00元

《Linux命令行大全》主要介绍Linux命令行的使用,循序渐进,深入浅出,引导读者全面掌握命令行的使用方法。 《Linux命令行大全》分为四部分。第一部分开始了对命令行基本语言的学习之旅,包括命令结构、文件系统的导引、命令行的编辑以及关于命令的帮助系统和使用手册。第二部分主要讲述配置文件的编辑,用于计算机操作的命令行控制。第三部分讲述了从命令行开始执行的常规任务。类UNIX操作系统,比如L......一起来看看 《Linux命令行大全》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具