OSDN Git Service

[TableGen] Generate offsets into a flat array for getOperandType
authorJustin Bogner <mail@justinbogner.com>
Tue, 16 Jul 2019 22:39:18 +0000 (22:39 +0000)
committerJustin Bogner <mail@justinbogner.com>
Tue, 16 Jul 2019 22:39:18 +0000 (22:39 +0000)
Rather than an array of std::initializer_list, generate a table of
offsets and a flat array of the operands for getOperandType. This is a
bit more efficient on platforms that don't manage to get the array of
inintializer_lists initialized at link time (I'm looking at you
macOS). It's also quite quite a bit faster to compile.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@366278 91177308-0d34-0410-b5e6-96231b3b80d8

test/TableGen/get-operand-type.td
utils/TableGen/InstrInfoEmitter.cpp

index 5be2c77..69bcde3 100644 (file)
@@ -35,6 +35,6 @@ def InstB : Instruction {
 }
 
 // CHECK: #ifdef GET_INSTRINFO_OPERAND_TYPE
-// CHECK: { OpTypes::OpA, OpTypes::OpB, OpTypes::i32imm, }
-// CHECK-NEXT: { OpTypes::i32imm, -1, }
+// CHECK:        OpTypes::OpA, OpTypes::OpB, OpTypes::i32imm,
+// CHECK-NEXT:   OpTypes::i32imm, -1,
 // CHECK: #endif //GET_INSTRINFO_OPERAND_TYPE
index d925856..2d367f5 100644 (file)
@@ -213,7 +213,7 @@ void InstrInfoEmitter::EmitOperandInfo(raw_ostream &OS,
 }
 
 /// 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
@@ -360,41 +360,54 @@ void InstrInfoEmitter::emitOperandTypeMappings(
   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";
+    std::vector<int> OperandOffsets;
+    std::vector<Record *> OperandRecords;
+    int CurrentOffset = 0;
     for (const CodeGenInstruction *Inst : NumberedInstructions) {
-      OS << "    { ";
+      OperandOffsets.push_back(CurrentOffset);
       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);
+          OperandRecords.push_back(Op.Rec);
+          ++CurrentOffset;
         } 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 (Init *Arg : make_range(MIOI->arg_begin(), MIOI->arg_end())) {
+            OperandRecords.push_back(cast<DefInit>(Arg)->getDef());
+            ++CurrentOffset;
           }
         }
-
-        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";
     }
+
+    // Emit the table of offsets for the opcode lookup.
+    OS << "  const int Offsets[] = {\n";
+    for (int I = 0, E = OperandOffsets.size(); I != E; ++I)
+      OS << "    " << OperandOffsets[I] << ",\n";
     OS << "  };\n";
-    OS << "  return OpcodeOperandTypes[Opcode].begin()[OpIdx];\n";
+
+    // Add an entry for the end so that we don't need to special case it below.
+    OperandOffsets.push_back(OperandRecords.size());
+    // Emit the actual operand types in a flat table.
+    OS << "  const int OpcodeOperandTypes[] = {\n    ";
+    for (int I = 0, E = OperandRecords.size(), CurOffset = 1; I != E; ++I) {
+      // We print each Opcode's operands in its own row.
+      if (I == OperandOffsets[CurOffset]) {
+        OS << "\n    ";
+        // If there are empty rows, mark them with an empty comment.
+        while (OperandOffsets[++CurOffset] == I)
+          OS << "/**/\n    ";
+      }
+      Record *OpR = OperandRecords[I];
+      if (OpR->isSubClassOf("Operand") && !OpR->isAnonymous())
+        OS << "OpTypes::" << OpR->getName();
+      else
+        OS << -1;
+      OS << ", ";
+    }
+    OS << "\n  };\n";
+
+    OS << "  return OpcodeOperandTypes[Offsets[Opcode] + OpIdx];\n";
   } else {
     OS << "  llvm_unreachable(\"No instructions defined\");\n";
   }