LLVM学习笔记(38)

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

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

查看所有标签

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

Writing Apache Modules with Perl and C

Writing Apache Modules with Perl and C

Lincoln Stein、Doug MacEachern / O'Reilly Media, Inc. / 1999-03 / USD 39.95

Apache is the most popular Web server on the Internet because it is free, reliable, and extensible. The availability of the source code and the modular design of Apache makes it possible to extend Web......一起来看看 《Writing Apache Modules with Perl and C》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

SHA 加密
SHA 加密

SHA 加密工具

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

RGB CMYK 互转工具