LLVM学习笔记(39)

3.5.2.3. 指令描述数组

这部分代码输出指令描述数组。首先看到385行的getInstructionsByEnumValue(),指令的这个遍历次序很重要。接着,我们看到387行的SequenceToOffsetTable类型的变量InstrNames,这意味着我们将要进行差分编码。391行则告诉我们,要进行差分编码的是指令的名字。

InstrInfoEmitter::run(续)

381       // Emit all of the MCInstrDesc records in their ENUM ordering.

382       //

383       OS << "\nextern const MCInstrDesc " << TargetName << "Insts[] = {\n";

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

385         Target.getInstructionsByEnumValue();

386    

387       SequenceToOffsetTable<std::string> InstrNames;

388       unsigned Num = 0;

389       for (const CodeGenInstruction *Inst : NumberedInstructions) {

390         // Keep a list of the instruction names.

391         InstrNames.add(Inst->TheDef->getName());

392         // Emit the record into the table.

393         emitRecord(*Inst, Num++, InstrInfo, EmittedLists, OperandInfoIDs, OS);

394       }

395       OS << "};\n\n";

注意在393行调用的emitRecord(),参数Num是指令的处理序号。记住我们总是以相同的次序遍历指令。参数InstrInfo就是X86InstrInfo(定义在X86.td)的Record对象,不过emitRecord()方法并没有用它。参数EmittedLists则是以指令定义中的Uses或Defs的Record对象为键值,给出这些对象输出所在ImplicitListNum数组的序号(即Num)。同样参数OpInfo以输出到OperandInfoNum数组的字符串为键值,给出该OperandInfoNum数组的序号(它是前面一节准备的OperandInfoIDs)。

464     void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num,

465                                       Record *InstrInfo,

466                              std::map<std::vector<Record*>, unsigned> &EmittedLists,

467                                       const OperandInfoMapTy &OpInfo,

468                                       raw_ostream &OS) {

469       int MinOperands = 0;

470       if (!Inst.Operands.empty())

471         // Each logical operand can be multiple MI operands.

472         MinOperands = Inst.Operands.back().MIOperandNo +

473                      Inst.Operands.back().MINumOperands;

474    

475       OS << "  { ";

476       OS << Num << ",\t" << MinOperands << ",\t"

477          << Inst.Operands.NumDefs << ",\t"

478          << Inst.TheDef->getValueAsInt("Size") << ",\t"

479          << SchedModels.getSchedClassIdx(Inst) << ",\t0";

480    

481       // Emit all of the target independent flags...

482       if (Inst.isPseudo)           OS << "|(1ULL<<MCID::Pseudo)";

483       if (Inst.isReturn)           OS << "|(1ULL<<MCID::Return)";

484       if (Inst.isBranch)           OS << "|(1ULL<<MCID::Branch)";

485       if (Inst.isIndirectBranch)   OS << "|(1ULL<<MCID::IndirectBranch)";

486       if (Inst.isCompare)          OS << "|(1ULL<<MCID::Compare)";

487       if (Inst.isMoveImm)          OS << "|(1ULL<<MCID::MoveImm)";

  if (Inst.isMoveReg)          OS << "|(1ULL<<MCID::MoveReg)";                                         <- v7.0增加

488       if (Inst.isBitcast)          OS << "|(1ULL<<MCID::Bitcast)";

  if (Inst.isAdd)              OS << "|(1ULL<<MCID::Add)";                                                         <- v7.0增加

  if (Inst.isTrap)             OS << "|(1ULL<<MCID::Trap)";

489       if (Inst.isSelect)           OS << "|(1ULL<<MCID::Select)";

490       if (Inst.isBarrier)          OS << "|(1ULL<<MCID::Barrier)";

491       if (Inst.hasDelaySlot)       OS << "|(1ULL<<MCID::DelaySlot)";

492       if (Inst.isCall)             OS << "|(1ULL<<MCID::Call)";

493       if (Inst.canFoldAsLoad)      OS << "|(1ULL<<MCID::FoldableAsLoad)";

494       if (Inst.mayLoad)            OS << "|(1ULL<<MCID::MayLoad)";

495       if (Inst.mayStore)           OS << "|(1ULL<<MCID::MayStore)";

496       if (Inst.isPredicable)       OS << "|(1ULL<<MCID::Predicable)";

497       if (Inst.isConvertibleToThreeAddress) OS << "|(1ULL<<MCID::ConvertibleTo3Addr)";

498       if (Inst.isCommutable)       OS << "|(1ULL<<MCID::Commutable)";

499       if (Inst.isTerminator)       OS << "|(1ULL<<MCID::Terminator)";

500       if (Inst.isReMaterializable) OS << "|(1ULL<<MCID::Rematerializable)";

501       if (Inst.isNotDuplicable)    OS << "|(1ULL<<MCID::NotDuplicable)";

502       if (Inst.Operands.hasOptionalDef) OS << "|(1ULL<<MCID::HasOptionalDef)";

503       if (Inst.usesCustomInserter) OS << "|(1ULL<<MCID::UsesCustomInserter)";

504       if (Inst.hasPostISelHook)    OS << "|(1ULL<<MCID::HasPostISelHook)";

505       if (Inst.Operands.isVariadic)OS << "|(1ULL<<MCID::Variadic)";

506       if (Inst.hasSideEffects)     OS << "|(1ULL<<MCID::UnmodeledSideEffects)";

507       if (Inst.isAsCheapAsAMove)   OS << "|(1ULL<<MCID::CheapAsAMove)";

508       if (Inst.hasExtraSrcRegAllocReq) OS << "|(1ULL<<MCID::ExtraSrcRegAllocReq)";         <- v7.0删除

509       if (Inst.hasExtraDefRegAllocReq) OS << "|(1ULL<<MCID::ExtraDefRegAllocReq)";

  if (!Target.getAllowRegisterRenaming() || Inst.hasExtraSrcRegAllocReq)                      <- v7.0增加

    OS << "|(1ULL<<MCID::ExtraSrcRegAllocReq)";

  if (!Target.getAllowRegisterRenaming() || Inst.hasExtraDefRegAllocReq)

    OS << "|(1ULL<<MCID::ExtraDefRegAllocReq)";

510       if (Inst.isRegSequence) OS << "|(1ULL<<MCID::RegSequence)";

511       if (Inst.isExtractSubreg) OS << "|(1ULL<<MCID::ExtractSubreg)";

512       if (Inst.isInsertSubreg) OS << "|(1ULL<<MCID::InsertSubreg)";

513       if (Inst.isConvergent) OS << "|(1ULL<<MCID::Convergent)";

514    

515       // Emit all of the target-specific flags...

516       BitsInit *TSF = Inst.TheDef->getValueAsBitsInit("TSFlags");

517       if (!TSF)

518         PrintFatalError("no TSFlags?");

519       uint64_t Value = 0;

520       for (unsigned i = 0, e = TSF->getNumBits(); i != e; ++i) {

521         if (BitInit *Bit = dyn_cast<BitInit>(TSF->getBit(i)))

522           Value |= uint64_t(Bit->getValue()) << i;

523         else

524           PrintFatalError("Invalid TSFlags bit in " + Inst.TheDef->getName());

525       }

526       OS << ", 0x";

527       OS.write_hex(Value);

528       OS << "ULL, ";

529    

530       // Emit the implicit uses and defs lists...

531       std::vector<Record*> UseList = Inst.TheDef->getValueAsListOfDefs("Uses");

532       if (UseList.empty())

533         OS << "nullptr, ";

534       else

535         OS << "ImplicitList" << EmittedLists[UseList] << ", ";

536    

537       std::vector<Record*> DefList = Inst.TheDef->getValueAsListOfDefs("Defs");

538       if (DefList.empty())

539         OS << "nullptr, ";

540       else

541         OS << "ImplicitList" << EmittedLists[DefList] << ", ";

542    

543       // Emit the operand info.

544       std::vector<std::string> OperandInfo = GetOperandInfo(Inst);

545       if (OperandInfo.empty())

546         OS << "nullptr";

547       else

548         OS << "OperandInfo" << OpInfo.find(OperandInfo)->second;

549    

550       CodeGenTarget &Target = CDP.getTargetInfo();

551       if (Inst.HasComplexDeprecationPredicate)

552         // Emit a function pointer to the complex predicate method.

553         OS << ", -1 "

554            << ",&get" << Inst.DeprecatedReason << "DeprecationInfo";

555       else if (!Inst.DeprecatedReason.empty())

556         // Emit the Subtarget feature.

557         OS << ", " << Target.getInstNamespace() << "::" << Inst.DeprecatedReason

558            << " ,nullptr";

559       else

560         // Instruction isn't deprecated.

561         OS << ", -1 ,nullptr";

562    

563       OS << " },  // Inst #" << Num << " = " << Inst.TheDef->getName() << "\n";

564     }

emitRecord()要输出的是一个元素类型为MCInstrDesc的数组。显然,MCInstrDesc是MC用于描述指令的类型,它有如下的数据成员:

138     class MCInstrDesc {

139     public:

140       unsigned short Opcode;        // The opcode number

141       unsigned short NumOperands;   // Num of args (may be more if variable_ops)

142       unsigned char NumDefs;        // Num of args that are definitions

143       unsigned char Size;           // Number of bytes in encoding.

144       unsigned short SchedClass;    // enum identifying instr sched class

145       uint64_t Flags;               // Flags identifying machine instr class

146       uint64_t TSFlags;             // Target Specific Flag values

147       const uint16_t *ImplicitUses; // Registers implicitly read by this instr

148       const uint16_t *ImplicitDefs; // Registers implicitly defined by this instr

149       const MCOperandInfo *OpInfo;  // 'NumOperands' entries about operands

150       // Subtarget feature that this is deprecated on, if any

151       // -1 implies this is not deprecated by any single feature. It may still be

152       // deprecated due to a "complex" reason, below.

153       int64_t DeprecatedFeature;

在emitRecord()的输出里,140行的Opcode是该MCInstrDesc实例在输出数组中的索引号。143行的Size则是该指令的编码大小。144行的SchedClass实际上是指令调度类型在CodeGenSchedModels的SchedClasses容器里的序号(getSchedClassIdx()方法通过InstrClassMap来确定指令的调度类型,这些调度类型都是第一部分类型,即由指令直接定义的)。147~149行的ImplicitUses,ImplicitDefs,OpInfo分别在535,541及548行由EmittedLists及OpInfo负责填充。为了使用OpInfo,在544行调用了GetOperandInfo()以获取作为键值的字符串。输出的内容的例子:

extern const MCInstrDesc X86Insts[] = {

  …

  { 31, 6, 1, 0, 0, 0|(1ULL<<MCID::MayLoad), 0x0ULL, nullptr, nullptr, OperandInfo15, -1 ,nullptr },  // Inst #31 = ACQUIRE_MOV16rm

  { 32, 6, 1, 0, 0, 0|(1ULL<<MCID::MayLoad), 0x0ULL, nullptr, nullptr, OperandInfo16, -1 ,nullptr },  // Inst #32 = ACQUIRE_MOV32rm

  { 33, 6, 1, 0, 0, 0|(1ULL<<MCID::MayLoad), 0x0ULL, nullptr, nullptr, OperandInfo17, -1 ,nullptr },  // Inst #33 = ACQUIRE_MOV64rm

  …

  { 12100, 0,   0, 0, 0, 0|(1ULL<<MCID::UnmodeledSideEffects), 0x80004036ULL, nullptr, ImplicitList3, nullptr, -1 ,nullptr },  // Inst #12100 = XTEST

};

注意这个数组与前面在X86名字空间里输出的匿名枚举常量是一一对应的,因为它们以相同的次序遍历指令集。因此140行Opcode的值实际上就是这些匿名枚举常量。

3.5.2.4. 指令名差分表

指令名字里存在大量重复的片段,因此使用差分表可以实现不错的压缩率。下面398~411行输出名为X86InstrNameData的差分表及X86InstrNameIndices的差分索引表。

InstrInfoEmitter::run(续)

397       // Emit the array of instruction names.

398       InstrNames.layout();

399       OS << "extern const char " << TargetName << "InstrNameData[] = {\n";

400       InstrNames.emit(OS, printChar);

401       OS << "};\n\n";

402    

403       OS << "extern const unsigned " << TargetName <<"InstrNameIndices[] = {";

404       Num = 0;

405       for (const CodeGenInstruction *Inst : NumberedInstructions) {

406         // Newline every eight entries.

407         if (Num % 8 == 0)

408           OS << "\n    ";

409       OS << InstrNames.get(Inst->TheDef->getName()) << "U, ";

410         ++Num;

411       }

412    

413       OS << "\n};\n\n";

414    

415       // MCInstrInfo initialization routine.

416       OS << "static inline void Init" << TargetName

417          << "MCInstrInfo(MCInstrInfo *II) {\n";

418       OS << "  II->InitMCInstrInfo(" << TargetName << "Insts, "

419          << TargetName << "InstrNameIndices, " << TargetName << "InstrNameData, "

420          << NumberedInstructions.size() << ");\n}\n\n";

421    

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

423    

424       OS << "#endif // GET_INSTRINFO_MC_DESC\n\n";

425    

426       // Create a TargetInstrInfo subclass to hide the MC layer initialization.

427       OS << "\n#ifdef GET_INSTRINFO_HEADER\n";

428       OS << "#undef GET_INSTRINFO_HEADER\n";

429    

430       std::string ClassName = TargetName + "GenInstrInfo";

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

432       OS << "struct " << ClassName << " : public TargetInstrInfo {\n"

433          << "  explicit " << ClassName

434          << "(int CFSetupOpcode = -1, int CFDestroyOpcode = -1);\n"                                        <- v7.0删除

435          << "  virtual ~" << ClassName << "();\n"

436          << "};\n";

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

     << "(int CFSetupOpcode = -1, int CFDestroyOpcode = -1, int CatchRetOpcode = -1, int ReturnOpcode = -1);\n"   <- v7.0增加 

     << "  ~" << ClassName << "() override = default;\n";

 

  emitTIIHelperMethods(OS);

438    

439       OS << "#endif // GET_INSTRINFO_HEADER\n\n";

440    

441       OS << "\n#ifdef GET_INSTRINFO_CTOR_DTOR\n";

442       OS << "#undef GET_INSTRINFO_CTOR_DTOR\n";

443    

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

445       OS << "extern const MCInstrDesc " << TargetName << "Insts[];\n";

446       OS << "extern const unsigned " << TargetName << "InstrNameIndices[];\n";

447       OS << "extern const char " << TargetName << "InstrNameData[];\n";

448       OS << ClassName << "::" << ClassName

449          << "(int CFSetupOpcode, int CFDestroyOpcode)\n"

450          << "  : TargetInstrInfo(CFSetupOpcode, CFDestroyOpcode) {\n"

451          << "  InitMCInstrInfo(" << TargetName << "Insts, " << TargetName

452          << "InstrNameIndices, " << TargetName << "InstrNameData, "

453          << NumberedInstructions.size() << ");\n}\n"

454          << ClassName << "::~" << ClassName << "() {}\n";

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

456    

457       OS << "#endif // GET_INSTRINFO_CTOR_DTOR\n\n";

458    

459       emitOperandNameMappings(OS, Target, NumberedInstructions);

460    

461       emitOperandTypesEnum(OS, Target);

 

  emitMCIIHelperMethods(OS);                                                                                                <- v7.0增加

462     }

416~422行输出下面的方法:

static inline void InitX86MCInstrInfo(MCInstrInfo *II) {

  II->InitMCInstrInfo(X86Insts, X86InstrNameIndices, X86InstrNameData, 12101);

}

MCInstrInfo::InitMCInstrInfo()方法是一个很简单的方法,却是LLVM通用处理框架与目标机器之间的一个重要接口。MCInstrInfo定义如下:

24       class MCInstrInfo {

25         const MCInstrDesc *Desc;          // Raw array to allow static init'n

26         const unsigned *InstrNameIndices; // Array for name indices in InstrNameData

27         const char *InstrNameData;        // Instruction name string pool

28         unsigned NumOpcodes;              // Number of entries in the desc array

29      

30       public:

31         /// \brief Initialize MCInstrInfo, called by TableGen auto-generated routines.

32         /// *DO NOT USE*.

33         void InitMCInstrInfo(const MCInstrDesc *D, const unsigned *NI, const char *ND,

34                              unsigned NO) {

35           Desc = D;

36           InstrNameIndices = NI;

37           InstrNameData = ND;

38           NumOpcodes = NO;

39         }

40      

41         unsigned getNumOpcodes() const { return NumOpcodes; }

42      

43         /// \brief Return the machine instruction descriptor that corresponds to the

44         /// specified instruction opcode.

45         const MCInstrDesc &get(unsigned Opcode) const {

46           assert(Opcode < NumOpcodes && "Invalid opcode!");

47           return Desc[Opcode];

48         }

49      

50         /// \brief Returns the name for the instructions with the given opcode.

51         const char *getName(unsigned Opcode) const {

52           assert(Opcode < NumOpcodes && "Invalid opcode!");

53           return &InstrNameData[InstrNameIndices[Opcode]];

54         }

55       };

427~457行输出目标机器特定的TargetInstrInfo派生类。

#ifdef GET_INSTRINFO_HEADER

#undef GET_INSTRINFO_HEADER

namespace llvm {

struct X86GenInstrInfo : public TargetInstrInfo {

  explicit X86GenInstrInfo(int CFSetupOpcode = -1, int CFDestroyOpcode = -1);

  virtual ~X86GenInstrInfo();

};

} // End llvm namespace

#endif // GET_INSTRINFO_HEADER

 

#ifdef GET_INSTRINFO_CTOR_DTOR

#undef GET_INSTRINFO_CTOR_DTOR

namespace llvm {

extern const MCInstrDesc X86Insts[];

extern const unsigned X86InstrNameIndices[];

extern const char X86InstrNameData[];

X86GenInstrInfo::X86GenInstrInfo(int CFSetupOpcode, int CFDestroyOpcode)

  : TargetInstrInfo(CFSetupOpcode, CFDestroyOpcode) {

  InitMCInstrInfo(X86Insts, X86InstrNameIndices, X86InstrNameData, 12101);

}

X86GenInstrInfo::~X86GenInstrInfo() {}

} // End llvm namespace

#endif // GET_INSTRINFO_CTOR_DTOR

V7.0在定义类X86GenInstrInfo时还调用了emitTIIHelperMethods()来展开x86目标机器特定的谓词定义。其处理的TIIPredicate在TD里定义是:

179     class TIIPredicate<string Target, string Name, MCInstPredicate P> : MCInstPredicate {

180       string TargetName = Target;

181       string FunctionName = Name;

182       MCInstPredicate Pred = P;

183     }

基类InstPredicate是一个空类。它用于描述在一条指令上操作符或操作数上的约束。每个MCInstPredicate类都有广为人知的语义,并且它被一个PredicateExpander用来为MachineInstr以及/或MCInst生成代码。

MCInstPredicate定义可用于构造MCSchedPredicate定义。在定义由一个处理器调度模型使用的SchedReadVariant与SchedWriteVariant时,MCSchedPredicate可替代SchedPredicate。

下面是MCInstPredicate定义的一个例子:

def MCInstPredicateExample : CheckAll<[

    CheckOpcode<[BLR]>,

    CheckIsRegOperand<0>,

    CheckNot<CheckRegOperand<0, LR>>]>;

谓词MCInstPredicateExample检查输入的机器指令是一条BLR,索引0处的操作数的寄存器LR。该谓词可用于重写以下定义(来自AArch64SchedExynosM3.td):

def M3BranchLinkFastPred  : SchedPredicate<[{

    MI->getOpcode() == AArch64::BLR &&

    MI->getOperand(0).isReg() &&

    MI->getOperand(0).getReg() != AArch64::LR}]>;

MCSchedPredicate可由SchedVar用来将一个谓词关联到一组SchedReadWrites。注意SchedVar用于创建SchedVariant定义。

每个MCInstPredicate类用众所周知的语义。例如,CheckOpcode仅用于检查指令操作码值。MCInstPredicate类允许以一个声明性的方式定义谓词。这些谓词不要求定制的C++块,可用于定义指令上的条件,而无需限制为特定的表示(比如MachineInstr或MCInst)。这也意味着TableGen后端必须知道如何解析它们,并将它们展开为在MCInst(或MachineInst)上奏效的代码。

类PredicateExpander的实例知道如何展开一个谓词。对每个MCInstPredicate类,在PredicateExpander接口里必须有一个“展开”方法。例如,使用方法PredicateExpander:: expandCheckOpcode()展开CheckOpcode谓词。

因此,在MCInstPredicate的基础上派生出了若干Check*定义,类似于SDTypeConstraint使用的那些定义。比如上面的TIIPredicate。在x86里,v7.0目前只定义了一个TIIPredicate派生定义——IsThreeOperandsLEAFn,用于检查输入的机器指令是否为一条3操作数LEA。

48       def IsThreeOperandsLEAFn :

49           TIIPredicate<"X86", "isThreeOperandsLEA", IsThreeOperandsLEAPredicate>;

其中IsThreeOperandsLEAPredicate是这样定义的:

24       def IsThreeOperandsLEAPredicate: CheckAll<[

25         CheckOpcode<[LEA32r, LEA64r, LEA64_32r, LEA16r]>,

26      

27         // isRegOperand(Base)

28         CheckIsRegOperand<1>,

29         CheckNot<CheckInvalidRegOperand<1>>,

30      

31         // isRegOperand(Index)

32         CheckIsRegOperand<3>,

33         CheckNot<CheckInvalidRegOperand<3>>,

34      

35         // hasLEAOffset(Offset)

36         CheckAny<[

37           CheckAll<[

38             CheckIsImmOperand<4>,

39             CheckNot<CheckZeroOperand<4>>

40           ]>,

41           CheckNonPortable<"MI.getOperand(4).isGlobal()">

42         ]>

43       ]>;

下面的方法emitTIIHelperMethods()用于解析这个定义,并生成代码。

403     void InstrInfoEmitter::emitTIIHelperMethods(raw_ostream &OS) {

404       RecVec TIIPredicates = Records.getAllDerivedDefinitions("TIIPredicate");

405       if (TIIPredicates.empty())

406         return;

407    

408       formatted_raw_ostream FOS(OS);

409       PredicateExpander PE;

410       PE.setExpandForMC(false);

411       PE.setIndentLevel(2);

412    

413       for (const Record *Rec : TIIPredicates) {

414         FOS << "\n  static bool " << Rec->getValueAsString("FunctionName");

415         FOS << "(const MachineInstr &MI) {\n";

416         FOS << "    return ";

417         PE.expandPredicate(FOS, Rec->getValueAsDef("Pred"));

418         FOS << ";\n  }\n";

419       }

420     }

417行的expandPredicate()并不复杂,这里不进入细节。emitTIIHelperMethods()将输出这样的代码(是X86GenInstrInfo的静态方法):

  static bool isThreeOperandsLEA(const MachineInstr &MI) {

    return (

      (

        MI.getOpcode() == X86::LEA32r

        || MI.getOpcode() == X86::LEA64r

        || MI.getOpcode() == X86::LEA64_32r

        || MI.getOpcode() == X86::LEA16r

      )

      && MI.getOperand(1).isReg()

      && MI.getOperand(1).getReg() != 0

      && MI.getOperand(3).isReg()

      && MI.getOperand(3).getReg() != 0

      && (

        (

          MI.getOperand(4).isImm()

          && MI.getOperand(4).getImm() != 0

        )

        || (MI.getOperand(4).isGlobal())

      )

    );

  }

3.5.2.5. getNamedOperandIdx()方法与操作数类型


在run()的459行调用的emitOperandNameMappings()来为某些特别的目标机器(X86不在内)实现一个带有优化性质的方法getNamedOperandIdx()。

236     void InstrInfoEmitter::emitOperandNameMappings(raw_ostream &OS,

237                const CodeGenTarget &Target,

238                const std::vector<const CodeGenInstruction*> &NumberedInstructions) {

239    

240     const std::string &Namespace = Target.getInstNamespace();

241       std::string OpNameNS = "OpName";

242       // Map of operand names to their enumeration value.  This will be used to

243       // generate the OpName enum.

244       std::map<std::string, unsigned> Operands;

245       OpNameMapTy OperandMap;

246    

247       initOperandMapData(NumberedInstructions, Namespace, Operands, OperandMap);

248    

249       OS << "#ifdef GET_INSTRINFO_OPERAND_ENUM\n";

250       OS << "#undef GET_INSTRINFO_OPERAND_ENUM\n";

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

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

253       OS << "namespace " << OpNameNS << " { \n";

254       OS << "enum {\n";

255       for (const auto &Op : Operands)

256         OS << "  " << Op.first << " = " << Op.second << ",\n";

257    

258       OS << "OPERAND_LAST";

259       OS << "\n};\n";

260       OS << "} // End namespace OpName\n";

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

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

263       OS << "#endif //GET_INSTRINFO_OPERAND_ENUM\n";

264    

265       OS << "#ifdef GET_INSTRINFO_NAMED_OPS\n";

266       OS << "#undef GET_INSTRINFO_NAMED_OPS\n";

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

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

269       OS << "LLVM_READONLY\n";

270       OS << "int16_t getNamedOperandIdx(uint16_t Opcode, uint16_t NamedIdx) {\n";

271       if (!Operands.empty()) {

272         OS << "  static const int16_t OperandMap [][" << Operands.size()

273            << "] = {\n";

274         for (const auto &Entry : OperandMap) {

275           const std::map<unsigned, unsigned> &OpList = Entry.first;

276           OS << "{";

277    

278           // Emit a row of the OperandMap table

279           for (unsigned i = 0, e = Operands.size(); i != e; ++i)

280             OS << (OpList.count(i) == 0 ? -1 : (int)OpList.find(i)->second) << ", ";

281    

282           OS << "},\n";

283         }

284         OS << "};\n";

285    

286         OS << "  switch(Opcode) {\n";

287         unsigned TableIndex = 0;

288         for (const auto &Entry : OperandMap) {

289           for (const std::string &Name : Entry.second)

290             OS << "  case " << Name << ":\n";

291    

292           OS << "    return OperandMap[" << TableIndex++ << "][NamedIdx];\n";

293         }

294         OS << "    default: return -1;\n";

295         OS << "  }\n";

296       } else {

297         // There are no operands, so no need to emit anything

298         OS << "  return -1;\n";

299       }

300       OS << "}\n";

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

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

303       OS << "#endif //GET_INSTRINFO_NAMED_OPS\n";

304    

305     }

类似的,如果存在相当数量的指令操作数,而且相当数量的指令使用同一组操作数,TableGen提供了一个优化的方式。通过将指令定义的UseNamedOperandTable设置为1,TableGen将生成名为getNamedOperandIdx()的方法,可以基于一个操作数的名字(实际上是一个枚举常量),查找在一条指令(MachineInstr)里该操作数的索引。目前只有ADMGPU使用了这个功能。

201     void InstrInfoEmitter::initOperandMapData(

202             const std::vector<const CodeGenInstruction *> &NumberedInstructions,

203             const std::string &Namespace,

204             std::map<std::string, unsigned> &Operands,

205             OpNameMapTy &OperandMap) {

206    

207       unsigned NumOperands = 0;

208       for (const CodeGenInstruction *Inst : NumberedInstructions) {

209         if (!Inst->TheDef->getValueAsBit("UseNamedOperandTable"))

210           continue;

211         std::map<unsigned, unsigned> OpList;

212         for (const auto &Info : Inst->Operands) {

213           StrUintMapIter I = Operands.find(Info.Name);

214    

215           if (I == Operands.end()) {

216             I = Operands.insert(Operands.begin(),

217                         std::pair<std::string, unsigned>(Info.Name, NumOperands++));

218           }

219           OpList[I->second] = Info.MIOperandNo;

220         }

221         OperandMap[OpList].push_back(Namespace + "::" + Inst->TheDef->getName());

222       }

223     }

这个机制最重要的数据结构是一个[Instruction定义中UseNamedOperandTable域为1的指令数]✕[所涉及操作数个数]的数组。以指令Opcode作为第一维索引,该指令操作数的相关枚举常量作为第二维,对应项给出该操作数在这个指令里的索引号。

initOperandMapData()方法就是准备这个数组的内容。而emitOperandNameMappings()就是根据initOperandMapData()准备的数据生成getNamedOperandIdx()方法以实现上述的查表。

在InstrInfoEmitter::run()的最后,调用下面的方法输出代表目标机器所有指令操作数类型的枚举常量。这些枚举常量实际上是.td文件里目标机器Operand派生定义按名字排序的次序。另外,匿名指令操作数不在考虑之列。

310     void InstrInfoEmitter::emitOperandTypesEnum(raw_ostream &OS,

311                                                 const CodeGenTarget &Target) {

312    

313     const std::string &Namespace = Target.getInstNamespace();

314       std::vector<Record *> Operands = Records.getAllDerivedDefinitions("Operand");

315    

316       OS << "\n#ifdef GET_INSTRINFO_OPERAND_TYPES_ENUM\n";

317       OS << "#undef GET_INSTRINFO_OPERAND_TYPES_ENUM\n";

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

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

320       OS << "namespace OpTypes { \n";

321       OS << "enum OperandType {\n";

322    

323       unsigned EnumVal = 0;

324       for (const Record *Op : Operands) {

325         if (!Op->isAnonymous())

326           OS << "  " << Op->getName() << " = " << EnumVal << ",\n";

327         ++EnumVal;

328       }

329    

330       OS << "  OPERAND_TYPE_LIST_END" << "\n};\n";

331       OS << "} // End namespace OpTypes\n";

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

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

334       OS << "#endif // GET_INSTRINFO_OPERAND_TYPES_ENUM\n";

335     }

对X86目标机器而言,这些操作数类型定义都在X86InstrInfo.td文件里,一共有79个,没有匿名定义(v7.0则是91)。

#ifdef GET_INSTRINFO_OPERAND_TYPES_ENUM

#undef GET_INSTRINFO_OPERAND_TYPES_ENUM

namespace llvm {

namespace X86 {

namespace OpTypes {

enum OperandType {

  AVX512ICC = 0,

  AVX512RC = 1,

  AVXCC = 2,

  …

  vz64mem = 79,

  OPERAND_TYPE_LIST_END

};

} // End namespace OpTypes

} // End namespace X86

} // End namespace llvm

#endif // GET_INSTRINFO_OPERAND_TYPES_ENUM

至此,对X86GenInstrInfo.inc的输出完成。不过,我们并没有看到有关调度器输出。这是因为LLVM是一个“很有规矩的”项目,X86GenInstrInfo.inc只能给出关于X86指令的数据。调度器数据必须输出到X86GenSubtargetInfo.inc文件,这是下一节的目标。

V7.0最后调用emitMCIIHelperMethods()在名字空间X86_MC输出isThreeOperandsLEA(),它与类X86GenInstrInfo里的方法isThreeOperandsLEA()同名,但参数不同(前者参数类型是const MachineInstr &,后者是const MCInst &)。

354     void InstrInfoEmitter::emitMCIIHelperMethods(raw_ostream &OS) {

355       RecVec TIIPredicates = Records.getAllDerivedDefinitions("TIIPredicate");

356       if (TIIPredicates.empty())

357         return;

358    

359       CodeGenTarget &Target = CDP.getTargetInfo();

360       const StringRef TargetName = Target.getName();

361       formatted_raw_ostream FOS(OS);

362    

363       FOS << "#ifdef GET_GENINSTRINFO_MC_DECL\n";

364       FOS << "#undef GET_GENINSTRINFO_MC_DECL\n\n";

365    

366       FOS << "namespace llvm {\n";

367       FOS << "class MCInst;\n\n";

368    

369       FOS << "namespace " << TargetName << "_MC {\n\n";

370    

371       for (const Record *Rec : TIIPredicates) {

372         FOS << "bool " << Rec->getValueAsString("FunctionName")

373             << "(const MCInst &MI);\n";

374       }

375    

376       FOS << "\n} // end " << TargetName << "_MC namespace\n";

377       FOS << "} // end llvm namespace\n\n";

378    

379       FOS << "#endif // GET_GENINSTRINFO_MC_DECL\n\n";

380    

381       FOS << "#ifdef GET_GENINSTRINFO_MC_HELPERS\n";

382       FOS << "#undef GET_GENINSTRINFO_MC_HELPERS\n\n";

383    

384       FOS << "namespace llvm {\n";

385       FOS << "namespace " << TargetName << "_MC {\n\n";

386    

387       PredicateExpander PE;

388       PE.setExpandForMC(true);

389       for (const Record *Rec : TIIPredicates) {

390         FOS << "bool " << Rec->getValueAsString("FunctionName");

391         FOS << "(const MCInst &MI) {\n";

392         FOS << "  return ";

393         PE.expandPredicate(FOS, Rec->getValueAsDef("Pred"));

394         FOS << ";\n}\n";

395       }

396    

397       FOS << "\n} // end " << TargetName << "_MC namespace\n";

398       FOS << "} // end llvm namespace\n\n";

399    

400       FOS << "#endif // GET_GENISTRINFO_MC_HELPERS\n";

401     }

因为这次是对MCInst展开的,因此388setExpandForMC()的参数是true。最终得到这样的输出方法:

namespace llvm {

namespace X86_MC {

 

bool isThreeOperandsLEA(const MCInst &MI) {

  return (

    (

      MI.getOpcode() == X86::LEA32r

      || MI.getOpcode() == X86::LEA64r

      || MI.getOpcode() == X86::LEA64_32r

      || MI.getOpcode() == X86::LEA16r

    )

    && MI.getOperand(1).isReg()

    && MI.getOperand(1).getReg() != 0

    && MI.getOperand(3).isReg()

    && MI.getOperand(3).getReg() != 0

    && (

      (

        MI.getOperand(4).isImm()

        && MI.getOperand(4).getImm() != 0

      )

      || false

    )

  );

}

 

} // end X86_MC namespace

} // end llvm namespace

X86GenInstrInfo:: isThreeOperandsLEA()最大的差别是最后的false,它来自CheckNonPortable部分。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值