| //===- InstrInfoEmitter.cpp - Generate a Instruction Set Desc. --*- C++ -*-===// | |
| // | |
| // The LLVM Compiler Infrastructure | |
| // | |
| // This file is distributed under the University of Illinois Open Source | |
| // License. See LICENSE.TXT for details. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This tablegen backend is responsible for emitting a description of the target | |
| // instruction set for the code generator. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "CodeGenDAGPatterns.h" | |
| #include "CodeGenInstruction.h" | |
| #include "CodeGenSchedule.h" | |
| #include "CodeGenTarget.h" | |
| #include "PredicateExpander.h" | |
| #include "SequenceToOffsetTable.h" | |
| #include "TableGenBackends.h" | |
| #include "llvm/ADT/ArrayRef.h" | |
| #include "llvm/ADT/StringExtras.h" | |
| #include "llvm/Support/Casting.h" | |
| #include "llvm/Support/raw_ostream.h" | |
| #include "llvm/TableGen/Error.h" | |
| #include "llvm/TableGen/Record.h" | |
| #include "llvm/TableGen/TableGenBackend.h" | |
| #include <cassert> | |
| #include <cstdint> | |
| #include <map> | |
| #include <string> | |
| #include <utility> | |
| #include <vector> | |
| using namespace llvm; | |
| namespace { | |
| class InstrInfoEmitter { | |
| RecordKeeper &Records; | |
| CodeGenDAGPatterns CDP; | |
| const CodeGenSchedModels &SchedModels; | |
| public: | |
| InstrInfoEmitter(RecordKeeper &R): | |
| Records(R), CDP(R), SchedModels(CDP.getTargetInfo().getSchedModels()) {} | |
| // run - Output the instruction set description. | |
| void run(raw_ostream &OS); | |
| private: | |
| void emitEnums(raw_ostream &OS); | |
| typedef std::map<std::vector<std::string>, unsigned> OperandInfoMapTy; | |
| /// The keys of this map are maps which have OpName enum values as their keys | |
| /// and instruction operand indices as their values. The values of this map | |
| /// are lists of instruction names. | |
| typedef std::map<std::map<unsigned, unsigned>, | |
| std::vector<std::string>> OpNameMapTy; | |
| typedef std::map<std::string, unsigned>::iterator StrUintMapIter; | |
| /// Generate member functions in the target-specific GenInstrInfo class. | |
| /// | |
| /// This method is used to custom expand TIIPredicate definitions. | |
| /// See file llvm/Target/TargetInstPredicates.td for a description of what is | |
| /// a TIIPredicate and how to use it. | |
| void emitTIIHelperMethods(raw_ostream &OS); | |
| /// Expand TIIPredicate definitions to functions that accept a const MCInst | |
| /// reference. | |
| void emitMCIIHelperMethods(raw_ostream &OS); | |
| void emitRecord(const CodeGenInstruction &Inst, unsigned Num, | |
| Record *InstrInfo, | |
| std::map<std::vector<Record*>, unsigned> &EL, | |
| const OperandInfoMapTy &OpInfo, | |
| raw_ostream &OS); | |
| void emitOperandTypesEnum(raw_ostream &OS, const CodeGenTarget &Target); | |
| void initOperandMapData( | |
| ArrayRef<const CodeGenInstruction *> NumberedInstructions, | |
| StringRef Namespace, | |
| std::map<std::string, unsigned> &Operands, | |
| OpNameMapTy &OperandMap); | |
| void emitOperandNameMappings(raw_ostream &OS, const CodeGenTarget &Target, | |
| ArrayRef<const CodeGenInstruction*> NumberedInstructions); | |
| // Operand information. | |
| void EmitOperandInfo(raw_ostream &OS, OperandInfoMapTy &OperandInfoIDs); | |
| std::vector<std::string> GetOperandInfo(const CodeGenInstruction &Inst); | |
| }; | |
| } // end anonymous namespace | |
| static void PrintDefList(const std::vector<Record*> &Uses, | |
| unsigned Num, raw_ostream &OS) { | |
| OS << "static const MCPhysReg ImplicitList" << Num << "[] = { "; | |
| for (Record *U : Uses) | |
| OS << getQualifiedName(U) << ", "; | |
| OS << "0 };\n"; | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // Operand Info Emission. | |
| //===----------------------------------------------------------------------===// | |
| std::vector<std::string> | |
| InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) { | |
| std::vector<std::string> Result; | |
| for (auto &Op : Inst.Operands) { | |
| // Handle aggregate operands and normal operands the same way by expanding | |
| // either case into a list of operands for this op. | |
| std::vector<CGIOperandList::OperandInfo> OperandList; | |
| // This might be a multiple operand thing. Targets like X86 have | |
| // registers in their multi-operand operands. It may also be an anonymous | |
| // operand, which has a single operand, but no declared class for the | |
| // operand. | |
| DagInit *MIOI = Op.MIOperandInfo; | |
| if (!MIOI || MIOI->getNumArgs() == 0) { | |
| // Single, anonymous, operand. | |
| OperandList.push_back(Op); | |
| } else { | |
| for (unsigned j = 0, e = Op.MINumOperands; j != e; ++j) { | |
| OperandList.push_back(Op); | |
| auto *OpR = cast<DefInit>(MIOI->getArg(j))->getDef(); | |
| OperandList.back().Rec = OpR; | |
| } | |
| } | |
| for (unsigned j = 0, e = OperandList.size(); j != e; ++j) { | |
| Record *OpR = OperandList[j].Rec; | |
| std::string Res; | |
| if (OpR->isSubClassOf("RegisterOperand")) | |
| OpR = OpR->getValueAsDef("RegClass"); | |
| if (OpR->isSubClassOf("RegisterClass")) | |
| Res += getQualifiedName(OpR) + "RegClassID, "; | |
| else if (OpR->isSubClassOf("PointerLikeRegClass")) | |
| Res += utostr(OpR->getValueAsInt("RegClassKind")) + ", "; | |
| else | |
| // -1 means the operand does not have a fixed register class. | |
| Res += "-1, "; | |
| // Fill in applicable flags. | |
| Res += "0"; | |
| // Ptr value whose register class is resolved via callback. | |
| if (OpR->isSubClassOf("PointerLikeRegClass")) | |
| Res += "|(1<<MCOI::LookupPtrRegClass)"; | |
| // Predicate operands. Check to see if the original unexpanded operand | |
| // was of type PredicateOp. | |
| if (Op.Rec->isSubClassOf("PredicateOp")) | |
| Res += "|(1<<MCOI::Predicate)"; | |
| // Optional def operands. Check to see if the original unexpanded operand | |
| // was of type OptionalDefOperand. | |
| if (Op.Rec->isSubClassOf("OptionalDefOperand")) | |
| Res += "|(1<<MCOI::OptionalDef)"; | |
| // Fill in operand type. | |
| Res += ", "; | |
| assert(!Op.OperandType.empty() && "Invalid operand type."); | |
| Res += Op.OperandType; | |
| // Fill in constraint info. | |
| Res += ", "; | |
| const CGIOperandList::ConstraintInfo &Constraint = | |
| Op.Constraints[j]; | |
| if (Constraint.isNone()) | |
| Res += "0"; | |
| else if (Constraint.isEarlyClobber()) | |
| Res += "(1 << MCOI::EARLY_CLOBBER)"; | |
| else { | |
| assert(Constraint.isTied()); | |
| Res += "((" + utostr(Constraint.getTiedOperand()) + | |
| " << 16) | (1 << MCOI::TIED_TO))"; | |
| } | |
| Result.push_back(Res); | |
| } | |
| } | |
| return Result; | |
| } | |
| void InstrInfoEmitter::EmitOperandInfo(raw_ostream &OS, | |
| OperandInfoMapTy &OperandInfoIDs) { | |
| // ID #0 is for no operand info. | |
| unsigned OperandListNum = 0; | |
| OperandInfoIDs[std::vector<std::string>()] = ++OperandListNum; | |
| OS << "\n"; | |
| const CodeGenTarget &Target = CDP.getTargetInfo(); | |
| for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) { | |
| std::vector<std::string> OperandInfo = GetOperandInfo(*Inst); | |
| unsigned &N = OperandInfoIDs[OperandInfo]; | |
| if (N != 0) continue; | |
| N = ++OperandListNum; | |
| OS << "static const MCOperandInfo OperandInfo" << N << "[] = { "; | |
| for (const std::string &Info : OperandInfo) | |
| OS << "{ " << Info << " }, "; | |
| OS << "};\n"; | |
| } | |
| } | |
| /// Initialize data structures for generating operand name mappings. | |
| /// | |
| /// \param Operands [out] A map used to generate the OpName enum with operand | |
| /// names as its keys and operand enum values as its values. | |
| /// \param OperandMap [out] A map for representing the operand name mappings for | |
| /// each instructions. This is used to generate the OperandMap table as | |
| /// well as the getNamedOperandIdx() function. | |
| void InstrInfoEmitter::initOperandMapData( | |
| ArrayRef<const CodeGenInstruction *> NumberedInstructions, | |
| StringRef Namespace, | |
| std::map<std::string, unsigned> &Operands, | |
| OpNameMapTy &OperandMap) { | |
| unsigned NumOperands = 0; | |
| for (const CodeGenInstruction *Inst : NumberedInstructions) { | |
| if (!Inst->TheDef->getValueAsBit("UseNamedOperandTable")) | |
| continue; | |
| std::map<unsigned, unsigned> OpList; | |
| for (const auto &Info : Inst->Operands) { | |
| StrUintMapIter I = Operands.find(Info.Name); | |
| if (I == Operands.end()) { | |
| I = Operands.insert(Operands.begin(), | |
| std::pair<std::string, unsigned>(Info.Name, NumOperands++)); | |
| } | |
| OpList[I->second] = Info.MIOperandNo; | |
| } | |
| OperandMap[OpList].push_back(Namespace.str() + "::" + | |
| Inst->TheDef->getName().str()); | |
| } | |
| } | |
| /// Generate a table and function for looking up the indices of operands by | |
| /// name. | |
| /// | |
| /// This code generates: | |
| /// - An enum in the llvm::TargetNamespace::OpName namespace, with one entry | |
| /// for each operand name. | |
| /// - A 2-dimensional table called OperandMap for mapping OpName enum values to | |
| /// operand indices. | |
| /// - A function called getNamedOperandIdx(uint16_t Opcode, uint16_t NamedIdx) | |
| /// for looking up the operand index for an instruction, given a value from | |
| /// OpName enum | |
| void InstrInfoEmitter::emitOperandNameMappings(raw_ostream &OS, | |
| const CodeGenTarget &Target, | |
| ArrayRef<const CodeGenInstruction*> NumberedInstructions) { | |
| StringRef Namespace = Target.getInstNamespace(); | |
| std::string OpNameNS = "OpName"; | |
| // Map of operand names to their enumeration value. This will be used to | |
| // generate the OpName enum. | |
| std::map<std::string, unsigned> Operands; | |
| OpNameMapTy OperandMap; | |
| initOperandMapData(NumberedInstructions, Namespace, Operands, OperandMap); | |
| OS << "#ifdef GET_INSTRINFO_OPERAND_ENUM\n"; | |
| OS << "#undef GET_INSTRINFO_OPERAND_ENUM\n"; | |
| OS << "namespace llvm {\n"; | |
| OS << "namespace " << Namespace << " {\n"; | |
| OS << "namespace " << OpNameNS << " {\n"; | |
| OS << "enum {\n"; | |
| for (const auto &Op : Operands) | |
| OS << " " << Op.first << " = " << Op.second << ",\n"; | |
| OS << "OPERAND_LAST"; | |
| OS << "\n};\n"; | |
| OS << "} // end namespace OpName\n"; | |
| OS << "} // end namespace " << Namespace << "\n"; | |
| OS << "} // end namespace llvm\n"; | |
| OS << "#endif //GET_INSTRINFO_OPERAND_ENUM\n\n"; | |
| OS << "#ifdef GET_INSTRINFO_NAMED_OPS\n"; | |
| OS << "#undef GET_INSTRINFO_NAMED_OPS\n"; | |
| OS << "namespace llvm {\n"; | |
| OS << "namespace " << Namespace << " {\n"; | |
| OS << "LLVM_READONLY\n"; | |
| OS << "int16_t getNamedOperandIdx(uint16_t Opcode, uint16_t NamedIdx) {\n"; | |
| if (!Operands.empty()) { | |
| OS << " static const int16_t OperandMap [][" << Operands.size() | |
| << "] = {\n"; | |
| for (const auto &Entry : OperandMap) { | |
| const std::map<unsigned, unsigned> &OpList = Entry.first; | |
| OS << "{"; | |
| // Emit a row of the OperandMap table | |
| for (unsigned i = 0, e = Operands.size(); i != e; ++i) | |
| OS << (OpList.count(i) == 0 ? -1 : (int)OpList.find(i)->second) << ", "; | |
| OS << "},\n"; | |
| } | |
| OS << "};\n"; | |
| OS << " switch(Opcode) {\n"; | |
| unsigned TableIndex = 0; | |
| for (const auto &Entry : OperandMap) { | |
| for (const std::string &Name : Entry.second) | |
| OS << " case " << Name << ":\n"; | |
| OS << " return OperandMap[" << TableIndex++ << "][NamedIdx];\n"; | |
| } | |
| OS << " default: return -1;\n"; | |
| OS << " }\n"; | |
| } else { | |
| // There are no operands, so no need to emit anything | |
| OS << " return -1;\n"; | |
| } | |
| OS << "}\n"; | |
| OS << "} // end namespace " << Namespace << "\n"; | |
| OS << "} // end namespace llvm\n"; | |
| OS << "#endif //GET_INSTRINFO_NAMED_OPS\n\n"; | |
| } | |
| /// Generate an enum for all the operand types for this target, under the | |
| /// llvm::TargetNamespace::OpTypes namespace. | |
| /// Operand types are all definitions derived of the Operand Target.td class. | |
| void InstrInfoEmitter::emitOperandTypesEnum(raw_ostream &OS, | |
| const CodeGenTarget &Target) { | |
| StringRef Namespace = Target.getInstNamespace(); | |
| std::vector<Record *> Operands = Records.getAllDerivedDefinitions("Operand"); | |
| OS << "#ifdef GET_INSTRINFO_OPERAND_TYPES_ENUM\n"; | |
| OS << "#undef GET_INSTRINFO_OPERAND_TYPES_ENUM\n"; | |
| OS << "namespace llvm {\n"; | |
| OS << "namespace " << Namespace << " {\n"; | |
| OS << "namespace OpTypes {\n"; | |
| OS << "enum OperandType {\n"; | |
| unsigned EnumVal = 0; | |
| for (const Record *Op : Operands) { | |
| if (!Op->isAnonymous()) | |
| OS << " " << Op->getName() << " = " << EnumVal << ",\n"; | |
| ++EnumVal; | |
| } | |
| OS << " OPERAND_TYPE_LIST_END" << "\n};\n"; | |
| OS << "} // end namespace OpTypes\n"; | |
| OS << "} // end namespace " << Namespace << "\n"; | |
| OS << "} // end namespace llvm\n"; | |
| OS << "#endif // GET_INSTRINFO_OPERAND_TYPES_ENUM\n\n"; | |
| } | |
| void InstrInfoEmitter::emitMCIIHelperMethods(raw_ostream &OS) { | |
| RecVec TIIPredicates = Records.getAllDerivedDefinitions("TIIPredicate"); | |
| if (TIIPredicates.empty()) | |
| return; | |
| CodeGenTarget &Target = CDP.getTargetInfo(); | |
| const StringRef TargetName = Target.getName(); | |
| formatted_raw_ostream FOS(OS); | |
| FOS << "#ifdef GET_GENINSTRINFO_MC_DECL\n"; | |
| FOS << "#undef GET_GENINSTRINFO_MC_DECL\n\n"; | |
| FOS << "namespace llvm {\n"; | |
| FOS << "class MCInst;\n\n"; | |
| FOS << "namespace " << TargetName << "_MC {\n\n"; | |
| for (const Record *Rec : TIIPredicates) { | |
| FOS << "bool " << Rec->getValueAsString("FunctionName") | |
| << "(const MCInst &MI);\n"; | |
| } | |
| FOS << "\n} // end " << TargetName << "_MC namespace\n"; | |
| FOS << "} // end llvm namespace\n\n"; | |
| FOS << "#endif // GET_GENINSTRINFO_MC_DECL\n\n"; | |
| FOS << "#ifdef GET_GENINSTRINFO_MC_HELPERS\n"; | |
| FOS << "#undef GET_GENINSTRINFO_MC_HELPERS\n\n"; | |
| FOS << "namespace llvm {\n"; | |
| FOS << "namespace " << TargetName << "_MC {\n\n"; | |
| PredicateExpander PE; | |
| PE.setExpandForMC(true); | |
| for (const Record *Rec : TIIPredicates) { | |
| FOS << "bool " << Rec->getValueAsString("FunctionName"); | |
| FOS << "(const MCInst &MI) {\n"; | |
| FOS << " return "; | |
| PE.expandPredicate(FOS, Rec->getValueAsDef("Pred")); | |
| FOS << ";\n}\n"; | |
| } | |
| FOS << "\n} // end " << TargetName << "_MC namespace\n"; | |
| FOS << "} // end llvm namespace\n\n"; | |
| FOS << "#endif // GET_GENISTRINFO_MC_HELPERS\n"; | |
| } | |
| void InstrInfoEmitter::emitTIIHelperMethods(raw_ostream &OS) { | |
| RecVec TIIPredicates = Records.getAllDerivedDefinitions("TIIPredicate"); | |
| if (TIIPredicates.empty()) | |
| return; | |
| formatted_raw_ostream FOS(OS); | |
| PredicateExpander PE; | |
| PE.setExpandForMC(false); | |
| PE.setIndentLevel(2); | |
| for (const Record *Rec : TIIPredicates) { | |
| FOS << "\n static bool " << Rec->getValueAsString("FunctionName"); | |
| FOS << "(const MachineInstr &MI) {\n"; | |
| FOS << " return "; | |
| PE.expandPredicate(FOS, Rec->getValueAsDef("Pred")); | |
| FOS << ";\n }\n"; | |
| } | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // Main Output. | |
| //===----------------------------------------------------------------------===// | |
| // run - Emit the main instruction description records for the target... | |
| void InstrInfoEmitter::run(raw_ostream &OS) { | |
| emitSourceFileHeader("Target Instruction Enum Values and Descriptors", OS); | |
| emitEnums(OS); | |
| OS << "#ifdef GET_INSTRINFO_MC_DESC\n"; | |
| OS << "#undef GET_INSTRINFO_MC_DESC\n"; | |
| OS << "namespace llvm {\n\n"; | |
| CodeGenTarget &Target = CDP.getTargetInfo(); | |
| const std::string &TargetName = Target.getName(); | |
| Record *InstrInfo = Target.getInstructionSet(); | |
| // Keep track of all of the def lists we have emitted already. | |
| std::map<std::vector<Record*>, unsigned> EmittedLists; | |
| unsigned ListNumber = 0; | |
| // Emit all of the instruction's implicit uses and defs. | |
| for (const CodeGenInstruction *II : Target.getInstructionsByEnumValue()) { | |
| Record *Inst = II->TheDef; | |
| std::vector<Record*> Uses = Inst->getValueAsListOfDefs("Uses"); | |
| if (!Uses.empty()) { | |
| unsigned &IL = EmittedLists[Uses]; | |
| if (!IL) PrintDefList(Uses, IL = ++ListNumber, OS); | |
| } | |
| std::vector<Record*> Defs = Inst->getValueAsListOfDefs("Defs"); | |
| if (!Defs.empty()) { | |
| unsigned &IL = EmittedLists[Defs]; | |
| if (!IL) PrintDefList(Defs, IL = ++ListNumber, OS); | |
| } | |
| } | |
| OperandInfoMapTy OperandInfoIDs; | |
| // Emit all of the operand info records. | |
| EmitOperandInfo(OS, OperandInfoIDs); | |
| // Emit all of the MCInstrDesc records in their ENUM ordering. | |
| // | |
| OS << "\nextern const MCInstrDesc " << TargetName << "Insts[] = {\n"; | |
| ArrayRef<const CodeGenInstruction*> NumberedInstructions = | |
| Target.getInstructionsByEnumValue(); | |
| SequenceToOffsetTable<std::string> InstrNames; | |
| unsigned Num = 0; | |
| for (const CodeGenInstruction *Inst : NumberedInstructions) { | |
| // Keep a list of the instruction names. | |
| InstrNames.add(Inst->TheDef->getName()); | |
| // Emit the record into the table. | |
| emitRecord(*Inst, Num++, InstrInfo, EmittedLists, OperandInfoIDs, OS); | |
| } | |
| OS << "};\n\n"; | |
| // Emit the array of instruction names. | |
| InstrNames.layout(); | |
| OS << "extern const char " << TargetName << "InstrNameData[] = {\n"; | |
| InstrNames.emit(OS, printChar); | |
| OS << "};\n\n"; | |
| OS << "extern const unsigned " << TargetName <<"InstrNameIndices[] = {"; | |
| Num = 0; | |
| for (const CodeGenInstruction *Inst : NumberedInstructions) { | |
| // Newline every eight entries. | |
| if (Num % 8 == 0) | |
| OS << "\n "; | |
| OS << InstrNames.get(Inst->TheDef->getName()) << "U, "; | |
| ++Num; | |
| } | |
| OS << "\n};\n\n"; | |
| // MCInstrInfo initialization routine. | |
| OS << "static inline void Init" << TargetName | |
| << "MCInstrInfo(MCInstrInfo *II) {\n"; | |
| OS << " II->InitMCInstrInfo(" << TargetName << "Insts, " | |
| << TargetName << "InstrNameIndices, " << TargetName << "InstrNameData, " | |
| << NumberedInstructions.size() << ");\n}\n\n"; | |
| OS << "} // end llvm namespace\n"; | |
| OS << "#endif // GET_INSTRINFO_MC_DESC\n\n"; | |
| // Create a TargetInstrInfo subclass to hide the MC layer initialization. | |
| OS << "#ifdef GET_INSTRINFO_HEADER\n"; | |
| OS << "#undef GET_INSTRINFO_HEADER\n"; | |
| std::string ClassName = TargetName + "GenInstrInfo"; | |
| OS << "namespace llvm {\n"; | |
| OS << "struct " << ClassName << " : public TargetInstrInfo {\n" | |
| << " explicit " << ClassName | |
| << "(int CFSetupOpcode = -1, int CFDestroyOpcode = -1, int CatchRetOpcode = -1, int ReturnOpcode = -1);\n" | |
| << " ~" << ClassName << "() override = default;\n"; | |
| emitTIIHelperMethods(OS); | |
| OS << "\n};\n} // end llvm namespace\n"; | |
| OS << "#endif // GET_INSTRINFO_HEADER\n\n"; | |
| OS << "#ifdef GET_INSTRINFO_CTOR_DTOR\n"; | |
| OS << "#undef GET_INSTRINFO_CTOR_DTOR\n"; | |
| OS << "namespace llvm {\n"; | |
| OS << "extern const MCInstrDesc " << TargetName << "Insts[];\n"; | |
| OS << "extern const unsigned " << TargetName << "InstrNameIndices[];\n"; | |
| OS << "extern const char " << TargetName << "InstrNameData[];\n"; | |
| OS << ClassName << "::" << ClassName | |
| << "(int CFSetupOpcode, int CFDestroyOpcode, int CatchRetOpcode, int ReturnOpcode)\n" | |
| << " : TargetInstrInfo(CFSetupOpcode, CFDestroyOpcode, CatchRetOpcode, ReturnOpcode) {\n" | |
| << " InitMCInstrInfo(" << TargetName << "Insts, " << TargetName | |
| << "InstrNameIndices, " << TargetName << "InstrNameData, " | |
| << NumberedInstructions.size() << ");\n}\n"; | |
| OS << "} // end llvm namespace\n"; | |
| OS << "#endif // GET_INSTRINFO_CTOR_DTOR\n\n"; | |
| emitOperandNameMappings(OS, Target, NumberedInstructions); | |
| emitOperandTypesEnum(OS, Target); | |
| emitMCIIHelperMethods(OS); | |
| } | |
| void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num, | |
| Record *InstrInfo, | |
| std::map<std::vector<Record*>, unsigned> &EmittedLists, | |
| const OperandInfoMapTy &OpInfo, | |
| raw_ostream &OS) { | |
| int MinOperands = 0; | |
| if (!Inst.Operands.empty()) | |
| // Each logical operand can be multiple MI operands. | |
| MinOperands = Inst.Operands.back().MIOperandNo + | |
| Inst.Operands.back().MINumOperands; | |
| OS << " { "; | |
| OS << Num << ",\t" << MinOperands << ",\t" | |
| << Inst.Operands.NumDefs << ",\t" | |
| << Inst.TheDef->getValueAsInt("Size") << ",\t" | |
| << SchedModels.getSchedClassIdx(Inst) << ",\t0"; | |
| CodeGenTarget &Target = CDP.getTargetInfo(); | |
| // Emit all of the target independent flags... | |
| if (Inst.isPseudo) OS << "|(1ULL<<MCID::Pseudo)"; | |
| if (Inst.isReturn) OS << "|(1ULL<<MCID::Return)"; | |
| if (Inst.isBranch) OS << "|(1ULL<<MCID::Branch)"; | |
| if (Inst.isIndirectBranch) OS << "|(1ULL<<MCID::IndirectBranch)"; | |
| if (Inst.isCompare) OS << "|(1ULL<<MCID::Compare)"; | |
| if (Inst.isMoveImm) OS << "|(1ULL<<MCID::MoveImm)"; | |
| if (Inst.isMoveReg) OS << "|(1ULL<<MCID::MoveReg)"; | |
| if (Inst.isBitcast) OS << "|(1ULL<<MCID::Bitcast)"; | |
| if (Inst.isAdd) OS << "|(1ULL<<MCID::Add)"; | |
| if (Inst.isTrap) OS << "|(1ULL<<MCID::Trap)"; | |
| if (Inst.isSelect) OS << "|(1ULL<<MCID::Select)"; | |
| if (Inst.isBarrier) OS << "|(1ULL<<MCID::Barrier)"; | |
| if (Inst.hasDelaySlot) OS << "|(1ULL<<MCID::DelaySlot)"; | |
| if (Inst.isCall) OS << "|(1ULL<<MCID::Call)"; | |
| if (Inst.canFoldAsLoad) OS << "|(1ULL<<MCID::FoldableAsLoad)"; | |
| if (Inst.mayLoad) OS << "|(1ULL<<MCID::MayLoad)"; | |
| if (Inst.mayStore) OS << "|(1ULL<<MCID::MayStore)"; | |
| if (Inst.isPredicable) OS << "|(1ULL<<MCID::Predicable)"; | |
| if (Inst.isConvertibleToThreeAddress) OS << "|(1ULL<<MCID::ConvertibleTo3Addr)"; | |
| if (Inst.isCommutable) OS << "|(1ULL<<MCID::Commutable)"; | |
| if (Inst.isTerminator) OS << "|(1ULL<<MCID::Terminator)"; | |
| if (Inst.isReMaterializable) OS << "|(1ULL<<MCID::Rematerializable)"; | |
| if (Inst.isNotDuplicable) OS << "|(1ULL<<MCID::NotDuplicable)"; | |
| if (Inst.Operands.hasOptionalDef) OS << "|(1ULL<<MCID::HasOptionalDef)"; | |
| if (Inst.usesCustomInserter) OS << "|(1ULL<<MCID::UsesCustomInserter)"; | |
| if (Inst.hasPostISelHook) OS << "|(1ULL<<MCID::HasPostISelHook)"; | |
| if (Inst.Operands.isVariadic)OS << "|(1ULL<<MCID::Variadic)"; | |
| if (Inst.hasSideEffects) OS << "|(1ULL<<MCID::UnmodeledSideEffects)"; | |
| if (Inst.isAsCheapAsAMove) OS << "|(1ULL<<MCID::CheapAsAMove)"; | |
| if (!Target.getAllowRegisterRenaming() || Inst.hasExtraSrcRegAllocReq) | |
| OS << "|(1ULL<<MCID::ExtraSrcRegAllocReq)"; | |
| if (!Target.getAllowRegisterRenaming() || Inst.hasExtraDefRegAllocReq) | |
| OS << "|(1ULL<<MCID::ExtraDefRegAllocReq)"; | |
| if (Inst.isRegSequence) OS << "|(1ULL<<MCID::RegSequence)"; | |
| if (Inst.isExtractSubreg) OS << "|(1ULL<<MCID::ExtractSubreg)"; | |
| if (Inst.isInsertSubreg) OS << "|(1ULL<<MCID::InsertSubreg)"; | |
| if (Inst.isConvergent) OS << "|(1ULL<<MCID::Convergent)"; | |
| // Emit all of the target-specific flags... | |
| BitsInit *TSF = Inst.TheDef->getValueAsBitsInit("TSFlags"); | |
| if (!TSF) | |
| PrintFatalError("no TSFlags?"); | |
| uint64_t Value = 0; | |
| for (unsigned i = 0, e = TSF->getNumBits(); i != e; ++i) { | |
| if (const auto *Bit = dyn_cast<BitInit>(TSF->getBit(i))) | |
| Value |= uint64_t(Bit->getValue()) << i; | |
| else | |
| PrintFatalError("Invalid TSFlags bit in " + Inst.TheDef->getName()); | |
| } | |
| OS << ", 0x"; | |
| OS.write_hex(Value); | |
| OS << "ULL, "; | |
| // Emit the implicit uses and defs lists... | |
| std::vector<Record*> UseList = Inst.TheDef->getValueAsListOfDefs("Uses"); | |
| if (UseList.empty()) | |
| OS << "nullptr, "; | |
| else | |
| OS << "ImplicitList" << EmittedLists[UseList] << ", "; | |
| std::vector<Record*> DefList = Inst.TheDef->getValueAsListOfDefs("Defs"); | |
| if (DefList.empty()) | |
| OS << "nullptr, "; | |
| else | |
| OS << "ImplicitList" << EmittedLists[DefList] << ", "; | |
| // Emit the operand info. | |
| std::vector<std::string> OperandInfo = GetOperandInfo(Inst); | |
| if (OperandInfo.empty()) | |
| OS << "nullptr"; | |
| else | |
| OS << "OperandInfo" << OpInfo.find(OperandInfo)->second; | |
| if (Inst.HasComplexDeprecationPredicate) | |
| // Emit a function pointer to the complex predicate method. | |
| OS << ", -1 " | |
| << ",&get" << Inst.DeprecatedReason << "DeprecationInfo"; | |
| else if (!Inst.DeprecatedReason.empty()) | |
| // Emit the Subtarget feature. | |
| OS << ", " << Target.getInstNamespace() << "::" << Inst.DeprecatedReason | |
| << " ,nullptr"; | |
| else | |
| // Instruction isn't deprecated. | |
| OS << ", -1 ,nullptr"; | |
| OS << " }, // Inst #" << Num << " = " << Inst.TheDef->getName() << "\n"; | |
| } | |
| // emitEnums - Print out enum values for all of the instructions. | |
| void InstrInfoEmitter::emitEnums(raw_ostream &OS) { | |
| OS << "#ifdef GET_INSTRINFO_ENUM\n"; | |
| OS << "#undef GET_INSTRINFO_ENUM\n"; | |
| OS << "namespace llvm {\n\n"; | |
| CodeGenTarget Target(Records); | |
| // We must emit the PHI opcode first... | |
| StringRef Namespace = Target.getInstNamespace(); | |
| if (Namespace.empty()) | |
| PrintFatalError("No instructions defined!"); | |
| OS << "namespace " << Namespace << " {\n"; | |
| OS << " enum {\n"; | |
| unsigned Num = 0; | |
| for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) | |
| OS << " " << Inst->TheDef->getName() << "\t= " << Num++ << ",\n"; | |
| OS << " INSTRUCTION_LIST_END = " << Num << "\n"; | |
| OS << " };\n\n"; | |
| OS << "} // end " << Namespace << " namespace\n"; | |
| OS << "} // end llvm namespace\n"; | |
| OS << "#endif // GET_INSTRINFO_ENUM\n\n"; | |
| OS << "#ifdef GET_INSTRINFO_SCHED_ENUM\n"; | |
| OS << "#undef GET_INSTRINFO_SCHED_ENUM\n"; | |
| OS << "namespace llvm {\n\n"; | |
| OS << "namespace " << Namespace << " {\n"; | |
| OS << "namespace Sched {\n"; | |
| OS << " enum {\n"; | |
| Num = 0; | |
| for (const auto &Class : SchedModels.explicit_classes()) | |
| OS << " " << Class.Name << "\t= " << Num++ << ",\n"; | |
| OS << " SCHED_LIST_END = " << Num << "\n"; | |
| OS << " };\n"; | |
| OS << "} // end Sched namespace\n"; | |
| OS << "} // end " << Namespace << " namespace\n"; | |
| OS << "} // end llvm namespace\n"; | |
| OS << "#endif // GET_INSTRINFO_SCHED_ENUM\n\n"; | |
| } | |
| namespace llvm { | |
| void EmitInstrInfo(RecordKeeper &RK, raw_ostream &OS) { | |
| InstrInfoEmitter(RK).run(OS); | |
| EmitMapTable(RK, OS); | |
| } | |
| } // end llvm namespace |