OSDN Git Service

[TableGen] Add "getOperandType" to get operand types from opcode/opidx
authorJustin Bogner <mail@justinbogner.com>
Tue, 16 Jul 2019 22:10:16 +0000 (22:10 +0000)
committerJustin Bogner <mail@justinbogner.com>
Tue, 16 Jul 2019 22:10:16 +0000 (22:10 +0000)
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 [new file with mode: 0644]
utils/TableGen/InstrInfoEmitter.cpp

diff --git a/test/TableGen/get-operand-type.td b/test/TableGen/get-operand-type.td
new file mode 100644 (file)
index 0000000..5be2c77
--- /dev/null
@@ -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<i32>;
+def OpB : Operand<i32>;
+
+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
index a4d66bb..d925856 100644 (file)
@@ -76,7 +76,9 @@ private:
                   std::map<std::vector<Record*>, 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<const CodeGenInstruction *> NumberedInstructions);
   void initOperandMapData(
             ArrayRef<const CodeGenInstruction *> 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<const CodeGenInstruction *> NumberedInstructions) {
 
   StringRef Namespace = Target.getInstNamespace();
   std::vector<Record *> 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<int> 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<CGIOperandList::OperandInfo> 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<DefInit>(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);
 }