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";

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

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

V7.0版本的指令数增加到15503,调度种类增加到1203种。

​​​​​​​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数组元素(类型MCInstrDesc)的成员(v7.0的数组有107)。

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行看到,这个容器的第一项是不使用的。其中std::vector<std::string>是MCOperandInfo的字符串版,unsigned部分用作序号,用于关联MCOperandInfo数组实例与X86Insts数组元素。

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()) {                                        <- v7.0删除

  for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) {         <- v7.0增加

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); }

 

  bool isGenericType() const {                                                                                                       <- v7.0增加

    return OperandType >= MCOI::OPERAND_FIRST_GENERIC &&

           OperandType <= MCOI::OPERAND_LAST_GENERIC;

  }

 

  unsigned getGenericTypeIndex() const {

    assert(isGenericType() && "non-generic types don't have an index");

    return OperandType - MCOI::OPERAND_FIRST_GENERIC;

  }

86       };

这是MC用来描述指令操作数的定义,也是我们需要为每个指令操作数所输出的类型。V7.0增加的部分用于GlobalISel,因为GlobalISel使用不同于MVTLLT类型系统,它使用Generic类型来表示操作数类型。所谓Generic就是定义指令的时候,不指定确切的类型,只区分类型是否相同(共6种不同Generic类型供使用,即每条指令可以使用7种不同的操作数类型,这应该是足够了),在后面构建目标机器的TargetInfo时具体来设置(参考后面的对GlobalISel的支持一节)。

另外,在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,

 

  OPERAND_FIRST_GENERIC = 6,                                                                                        ß v7.0增加

  OPERAND_GENERIC_0 = 6,

  OPERAND_GENERIC_1 = 7,

  OPERAND_GENERIC_2 = 8,

  OPERAND_GENERIC_3 = 9,

  OPERAND_GENERIC_4 = 10,

  OPERAND_GENERIC_5 = 11,

  OPERAND_LAST_GENERIC = 11,

 

50         OPERAND_FIRST_TARGET = 5 12

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数组元素的成员(v7.0该数组有959)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值