From 8a6db15ff251a73f47ebf135010b5da90f352aa7 Mon Sep 17 00:00:00 2001 From: Justin Bogner Date: Tue, 16 Jul 2019 22:10:16 +0000 Subject: [PATCH] [TableGen] Add "getOperandType" to get operand types from opcode/opidx The InstrInfoEmitter outputs an enum called "OperandType" which gives numerical IDs to each operand type. This patch makes use of this enum to define a function called "getOperandType", which allows looking up the type of an operand given its opcode and operand index. Patch by Nicolas Guillemot. Thanks! Differential Revision: https://reviews.llvm.org/D63320 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@366274 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/TableGen/get-operand-type.td | 40 +++++++++++++++++++ utils/TableGen/InstrInfoEmitter.cpp | 61 +++++++++++++++++++++++++++-- 2 files changed, 97 insertions(+), 4 deletions(-) create mode 100644 test/TableGen/get-operand-type.td diff --git a/test/TableGen/get-operand-type.td b/test/TableGen/get-operand-type.td new file mode 100644 index 00000000000..5be2c777c8a --- /dev/null +++ b/test/TableGen/get-operand-type.td @@ -0,0 +1,40 @@ +// RUN: llvm-tblgen -gen-instr-info -I %p/../../include %s | FileCheck %s + +// Check that getOperandType has the expected info in it + +include "llvm/Target/Target.td" + +def archInstrInfo : InstrInfo { } + +def arch : Target { + let InstructionSet = archInstrInfo; +} + +def Reg : Register<"reg">; +def RegClass : RegisterClass<"foo", [i32], 0, (add Reg)>; + +def OpA : Operand; +def OpB : Operand; + +def InstA : Instruction { + let Size = 1; + let OutOperandList = (outs OpA:$a); + let InOperandList = (ins OpB:$b, i32imm:$c); + field bits<8> Inst; + field bits<8> SoftFail = 0; + let Namespace = "MyNamespace"; +} + +def InstB : Instruction { + let Size = 1; + let OutOperandList = (outs i32imm:$d); + let InOperandList = (ins unknown:$x); + field bits<8> Inst; + field bits<8> SoftFail = 0; + let Namespace = "MyNamespace"; +} + +// CHECK: #ifdef GET_INSTRINFO_OPERAND_TYPE +// CHECK: { OpTypes::OpA, OpTypes::OpB, OpTypes::i32imm, } +// CHECK-NEXT: { OpTypes::i32imm, -1, } +// CHECK: #endif //GET_INSTRINFO_OPERAND_TYPE diff --git a/utils/TableGen/InstrInfoEmitter.cpp b/utils/TableGen/InstrInfoEmitter.cpp index a4d66bb871c..d92585685e1 100644 --- a/utils/TableGen/InstrInfoEmitter.cpp +++ b/utils/TableGen/InstrInfoEmitter.cpp @@ -76,7 +76,9 @@ private: std::map, unsigned> &EL, const OperandInfoMapTy &OpInfo, raw_ostream &OS); - void emitOperandTypesEnum(raw_ostream &OS, const CodeGenTarget &Target); + void emitOperandTypeMappings( + raw_ostream &OS, const CodeGenTarget &Target, + ArrayRef NumberedInstructions); void initOperandMapData( ArrayRef NumberedInstructions, StringRef Namespace, @@ -324,8 +326,9 @@ void InstrInfoEmitter::emitOperandNameMappings(raw_ostream &OS, /// 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) { +void InstrInfoEmitter::emitOperandTypeMappings( + raw_ostream &OS, const CodeGenTarget &Target, + ArrayRef NumberedInstructions) { StringRef Namespace = Target.getInstNamespace(); std::vector Operands = Records.getAllDerivedDefinitions("Operand"); @@ -349,6 +352,56 @@ void InstrInfoEmitter::emitOperandTypesEnum(raw_ostream &OS, OS << "} // end namespace " << Namespace << "\n"; OS << "} // end namespace llvm\n"; OS << "#endif // GET_INSTRINFO_OPERAND_TYPES_ENUM\n\n"; + + OS << "#ifdef GET_INSTRINFO_OPERAND_TYPE\n"; + OS << "#undef GET_INSTRINFO_OPERAND_TYPE\n"; + OS << "namespace llvm {\n"; + OS << "namespace " << Namespace << " {\n"; + OS << "LLVM_READONLY\n"; + OS << "int getOperandType(uint16_t Opcode, uint16_t OpIdx) {\n"; + if (!NumberedInstructions.empty()) { + OS << " static const std::initializer_list OpcodeOperandTypes[] = " + "{\n"; + for (const CodeGenInstruction *Inst : NumberedInstructions) { + OS << " { "; + for (const 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 OperandList; + + const 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(MIOI->getArg(j))->getDef(); + OperandList.back().Rec = OpR; + } + } + + for (unsigned j = 0, e = OperandList.size(); j != e; ++j) { + Record *OpR = OperandList[j].Rec; + if (OpR->isSubClassOf("Operand") && !OpR->isAnonymous()) + OS << "OpTypes::" << OpR->getName(); + else + OS << -1; + OS << ", "; + } + } + OS << "},\n"; + } + OS << " };\n"; + OS << " return OpcodeOperandTypes[Opcode].begin()[OpIdx];\n"; + } else { + OS << " llvm_unreachable(\"No instructions defined\");\n"; + } + OS << "}\n"; + OS << "} // end namespace " << Namespace << "\n"; + OS << "} // end namespace llvm\n"; + OS << "#endif //GET_INSTRINFO_OPERAND_TYPE\n\n"; } void InstrInfoEmitter::emitMCIIHelperMethods(raw_ostream &OS, @@ -560,7 +613,7 @@ void InstrInfoEmitter::run(raw_ostream &OS) { emitOperandNameMappings(OS, Target, NumberedInstructions); - emitOperandTypesEnum(OS, Target); + emitOperandTypeMappings(OS, Target, NumberedInstructions); emitMCIIHelperMethods(OS, TargetName); } -- 2.40.0