LLVM学习笔记(38)

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        emitEnums(OS);

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

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

568     

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

扫描二维码关注公众号,回复: 2812204 查看本文章

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的来源有两种,第一种来自指令定义,包括createInstRWClass方法从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(它与基类InstrInfo的内容是一致的)。

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) PrintDefList(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        EmitOperandInfo(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 = GetOperandInfo(*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数组元素的成员。

猜你喜欢

转载自blog.csdn.net/wuhui_gdnt/article/details/81560391