[llvm] [TableGen] Implement getOperandIdxName (PR #154944)

via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 22 06:25:48 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-tablegen

Author: Robert Imschweiler (ro-i)

<details>
<summary>Changes</summary>

This is meant as the inverse of getNamedOperandIdx and returns the OpName for a given operand index for a given opcode.

---
Full diff: https://github.com/llvm/llvm-project/pull/154944.diff


2 Files Affected:

- (modified) llvm/test/TableGen/get-named-operand-idx.td (+71-30) 
- (modified) llvm/utils/TableGen/InstrInfoEmitter.cpp (+100-38) 


``````````diff
diff --git a/llvm/test/TableGen/get-named-operand-idx.td b/llvm/test/TableGen/get-named-operand-idx.td
index ab23edd54c723..3d07ba1278a53 100644
--- a/llvm/test/TableGen/get-named-operand-idx.td
+++ b/llvm/test/TableGen/get-named-operand-idx.td
@@ -48,34 +48,75 @@ def InstD : InstBase {
   let UseNamedOperandTable = 0;
 }
 
-// CHECK: #ifdef GET_INSTRINFO_OPERAND_ENUM
-// CHECK: #undef GET_INSTRINFO_OPERAND_ENUM
-// CHECK: namespace llvm::MyNamespace {
-// CHECK: enum class OpName {
-// CHECK:   a = 0,
-// CHECK:   b = 1,
-// CHECK:   c = 2,
-// CHECK:   d = 3,
-// CHECK:   x = 4,
-// CHECK:   NUM_OPERAND_NAMES = 5,
-// CHECK: }; // enum class OpName
-// CHECK: } // end namespace llvm::MyNamespace
-// CHECK: #endif //GET_INSTRINFO_OPERAND_ENUM
+// CHECK-LABEL: #ifdef GET_INSTRINFO_OPERAND_ENUM
+// CHECK-NEXT:  #undef GET_INSTRINFO_OPERAND_ENUM
+// CHECK-NEXT:  namespace llvm::MyNamespace {
+// CHECK-NEXT:  enum class OpName {
+// CHECK-NEXT:    a = 0,
+// CHECK-NEXT:    b = 1,
+// CHECK-NEXT:    c = 2,
+// CHECK-NEXT:    d = 3,
+// CHECK-NEXT:    x = 4,
+// CHECK-NEXT:    NUM_OPERAND_NAMES = 5,
+// CHECK-NEXT:  }; // enum class OpName
+// CHECK-EMPTY:
+// CHECK-NEXT:  LLVM_READONLY
+// CHECK-NEXT:  int16_t getNamedOperandIdx(uint16_t Opcode, OpName Name);
+// CHECK-NEXT:  LLVM_READONLY
+// CHECK-NEXT:  OpName getOperandIdxName(uint16_t Opcode, int16_t Idx);
+// CHECK-NEXT:  } // end namespace llvm::MyNamespace
+// CHECK-NEXT:  #endif //GET_INSTRINFO_OPERAND_ENUM
 
-// CHECK: #ifdef GET_INSTRINFO_NAMED_OPS
-// CHECK: #undef GET_INSTRINFO_NAMED_OPS
-// CHECK: namespace llvm::MyNamespace {
-// CHECK: LLVM_READONLY
-// CHECK: int16_t getNamedOperandIdx(uint16_t Opcode, OpName Name) {
-// CHECK:  assert(Name != OpName::NUM_OPERAND_NAMES);
-// CHECK:  static constexpr int8_t OperandMap[][5] = {
-// CHECK:      {0, 1, 2, -1, -1, },
-// CHECK:      {-1, -1, -1, 0, 1, },
-// CHECK:    };
-// CHECK:    static constexpr uint8_t InstructionIndex[] = {
-// CHECK:      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// CHECK:    };
-// CHECK:    return OperandMap[InstructionIndex[Opcode]][(unsigned)Name];
-// CHECK:  }
-// CHECK:  } // end namespace llvm::MyNamespace
-// CHECK:  #endif //GET_INSTRINFO_NAMED_OPS
+// CHECK-LABEL: #ifdef GET_INSTRINFO_NAMED_OPS
+// CHECK-NEXT:  #undef GET_INSTRINFO_NAMED_OPS
+// CHECK-NEXT:  namespace llvm::MyNamespace {
+// CHECK-NEXT:  LLVM_READONLY
+// CHECK-NEXT:  static uint8_t getInstructionIndexForOpLookup(uint16_t Opcode) {
+// CHECK-NEXT:    static constexpr uint8_t InstructionIndex[] = {
+// CHECK-NEXT:      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// CHECK-NEXT:      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// CHECK-NEXT:      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// CHECK-NEXT:      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// CHECK-NEXT:      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// CHECK-NEXT:      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// CHECK-NEXT:      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// CHECK-NEXT:      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// CHECK-NEXT:      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// CHECK-NEXT:      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// CHECK-NEXT:      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// CHECK-NEXT:      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// CHECK-NEXT:      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// CHECK-NEXT:      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// CHECK-NEXT:      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// CHECK-NEXT:      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// CHECK-NEXT:      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// CHECK-NEXT:      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// CHECK-NEXT:      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// CHECK-NEXT:      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0,
+// CHECK-NEXT:    };
+// CHECK-NEXT:    return InstructionIndex[Opcode];
+// CHECK-NEXT:  }
+// CHECK-NEXT:  LLVM_READONLY
+// CHECK-NEXT:  int16_t getNamedOperandIdx(uint16_t Opcode, OpName Name) {
+// CHECK-NEXT:    assert(Name != OpName::NUM_OPERAND_NAMES);
+// CHECK-NEXT:    static constexpr int8_t OperandMap[][5] = {
+// CHECK-NEXT:      {-1, -1, -1, -1, -1, },
+// CHECK-NEXT:      {0, 1, 2, -1, -1, },
+// CHECK-NEXT:      {-1, -1, -1, 0, 1, },
+// CHECK-NEXT:    };
+// CHECK-NEXT:    unsigned InstrIdx = getInstructionIndexForOpLookup(Opcode);
+// CHECK-NEXT:    return OperandMap[InstrIdx][(unsigned)Name];
+// CHECK-NEXT:  }
+// CHECK-NEXT:  LLVM_READONLY
+// CHECK-NEXT:  OpName getOperandIdxName(uint16_t Opcode, int16_t Idx) {
+// CHECK-NEXT:    assert(Idx >= 0 && Idx < 3);
+// CHECK-NEXT:    static constexpr uint8_t OperandMap[][3] = {
+// CHECK-NEXT:      {5, 5, 5, },
+// CHECK-NEXT:      {0, 1, 2, },
+// CHECK-NEXT:      {3, 4, 5, },
+// CHECK-NEXT:    };
+// CHECK-NEXT:    unsigned InstrIdx = getInstructionIndexForOpLookup(Opcode);
+// CHECK-NEXT:    return (OpName) OperandMap[InstrIdx][(unsigned)Idx];
+// CHECK-NEXT:  }
+// CHECK-NEXT:  } // end namespace llvm::MyNamespace
+// CHECK-NEXT:  #endif //GET_INSTRINFO_NAMED_OPS
diff --git a/llvm/utils/TableGen/InstrInfoEmitter.cpp b/llvm/utils/TableGen/InstrInfoEmitter.cpp
index 6f72b51963f87..eedceb19e5783 100644
--- a/llvm/utils/TableGen/InstrInfoEmitter.cpp
+++ b/llvm/utils/TableGen/InstrInfoEmitter.cpp
@@ -223,17 +223,104 @@ void InstrInfoEmitter::EmitOperandInfo(raw_ostream &OS,
   }
 }
 
+static void emitGetInstructionIndexForOpLookup(
+    raw_ostream &OS, const MapVector<SmallVector<int>, unsigned> &OperandMap,
+    ArrayRef<unsigned> InstructionIndex) {
+  StringRef Type = OperandMap.size() <= UINT8_MAX + 1 ? "uint8_t" : "uint16_t";
+  OS << "LLVM_READONLY\n";
+  OS << "static " << Type
+     << " getInstructionIndexForOpLookup(uint16_t Opcode) {\n";
+  OS << "  static constexpr " << Type << " InstructionIndex[] = {";
+  for (auto [TableIndex, Entry] : enumerate(InstructionIndex))
+    OS << (TableIndex % 16 == 0 ? "\n    " : " ") << Entry << ',';
+  OS << "\n  };\n";
+  OS << "  return InstructionIndex[Opcode];\n";
+  OS << "}\n";
+}
+
+static void
+emitGetNamedOperandIdx(raw_ostream &OS, StringRef Namespace,
+                       const MapVector<StringRef, unsigned> &OperandNameToID,
+                       const MapVector<SmallVector<int>, unsigned> &OperandMap,
+                       unsigned MaxOperandNo, unsigned NumOperandNames) {
+  OS << "LLVM_READONLY\n";
+  OS << "int16_t getNamedOperandIdx(uint16_t Opcode, OpName Name) {\n";
+  OS << "  assert(Name != OpName::NUM_OPERAND_NAMES);\n";
+  if (!NumOperandNames) {
+    // There are no operands, so no need to emit anything
+    OS << "  return -1;\n}\n";
+    return;
+  }
+  assert(MaxOperandNo <= INT16_MAX &&
+         "Too many operands for the operand name -> index table");
+  StringRef Type = MaxOperandNo <= INT8_MAX ? "int8_t" : "int16_t";
+  OS << "  static constexpr " << Type << " OperandMap[][" << NumOperandNames
+     << "] = {\n";
+  for (const auto &[OpList, _] : OperandMap) {
+    // Emit a row of the OperandMap table.
+    OS << "    {";
+    for (unsigned ID = 0; ID < NumOperandNames; ++ID)
+      OS << (ID < OpList.size() ? OpList[ID] : -1) << ", ";
+    OS << "},\n";
+  }
+  OS << "  };\n";
+
+  OS << "  unsigned InstrIdx = getInstructionIndexForOpLookup(Opcode);\n";
+  OS << "  return OperandMap[InstrIdx][(unsigned)Name];\n";
+  OS << "}\n";
+}
+
+static void
+emitGetOperandIdxName(raw_ostream &OS, StringRef Namespace,
+                      const MapVector<StringRef, unsigned> &OperandNameToID,
+                      const MapVector<SmallVector<int>, unsigned> &OperandMap,
+                      unsigned MaxOperandNo, unsigned NumOperandNames) {
+  OS << "LLVM_READONLY\n";
+  OS << "OpName getOperandIdxName(uint16_t Opcode, int16_t Idx) {\n";
+  OS << "  assert(Idx >= 0 && Idx < " << MaxOperandNo << ");\n";
+  if (!MaxOperandNo) {
+    // There are no operands, so no need to emit anything
+    OS << "  return -1;\n}\n";
+    return;
+  }
+  assert(NumOperandNames <= UINT16_MAX &&
+         "Too many operands for the operand index -> name table");
+  StringRef Type = NumOperandNames <= UINT8_MAX ? "uint8_t" : "uint16_t";
+  OS << "  static constexpr " << Type << " OperandMap[][" << MaxOperandNo
+     << "] = {\n";
+  for (const auto &[OpList, _] : OperandMap) {
+    SmallVector<unsigned> IDs(MaxOperandNo, NumOperandNames);
+    for (const auto &[ID, Idx] : enumerate(OpList)) {
+      if (Idx >= 0)
+        IDs[Idx] = ID;
+    }
+    // Emit a row of the OperandMap table. Map operand indices to enum values.
+    OS << "    {";
+    for (unsigned ID : IDs)
+      OS << ID << ", ";
+    OS << "},\n";
+  }
+  OS << "  };\n";
+
+  OS << "  unsigned InstrIdx = getInstructionIndexForOpLookup(Opcode);\n";
+  OS << "  return (OpName) OperandMap[InstrIdx][(unsigned)Idx];\n";
+  OS << "}\n";
+}
+
 /// 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)
+/// - A 2-dimensional table for mapping OpName enum values to operand indices.
+/// - A function called getNamedOperandIdx(uint16_t Opcode, OpName Name)
 ///   for looking up the operand index for an instruction, given a value from
 ///   OpName enum
+/// - A 2-dimensional table for mapping operand indices to OpName enum values.
+/// - A function called getOperandIdxName(uint16_t Opcode, int16_t Idx)
+///   for looking up the OpName enum for an instruction, given the operand
+///   index. This is the inverse of getNamedOperandIdx().
 ///
 /// Fixed/Predefined instructions do not have UseNamedOperandTable enabled, so
 /// we can just skip them. Hence accept just the TargetInstructions.
@@ -242,11 +329,6 @@ void InstrInfoEmitter::emitOperandNameMappings(
     ArrayRef<const CodeGenInstruction *> TargetInstructions) {
   StringRef Namespace = Target.getInstNamespace();
 
-  /// To facilitate assigning OpName enum values in the sorted alphabetical
-  /// order, we go through an indirection from OpName -> ID, and Enum -> ID.
-  /// This allows us to build the OpList and assign IDs to OpNames in a single
-  /// scan of the instructions below.
-
   // Map of operand names to their ID.
   MapVector<StringRef, unsigned> OperandNameToID;
 
@@ -257,7 +339,7 @@ void InstrInfoEmitter::emitOperandNameMappings(
   /// instructions that have identical OpName -> Operand index mapping.
   MapVector<SmallVector<int>, unsigned> OperandMap;
 
-  // Max operand index seen.
+  // Max operand index seen + 1.
   unsigned MaxOperandNo = 0;
 
   // Fixed/Predefined instructions do not have UseNamedOperandTable enabled, so
@@ -277,7 +359,7 @@ void InstrInfoEmitter::emitOperandNameMappings(
               .first->second;
       OpList.resize(std::max((unsigned)OpList.size(), ID + 1), -1);
       OpList[ID] = Info.MIOperandNo;
-      MaxOperandNo = std::max(MaxOperandNo, Info.MIOperandNo);
+      MaxOperandNo = std::max(MaxOperandNo, Info.MIOperandNo + 1);
     }
     auto [It, Inserted] =
         OperandMap.try_emplace(std::move(OpList), OperandMap.size());
@@ -296,42 +378,22 @@ void InstrInfoEmitter::emitOperandNameMappings(
   OS << "}; // enum class OpName\n\n";
   OS << "LLVM_READONLY\n";
   OS << "int16_t getNamedOperandIdx(uint16_t Opcode, OpName Name);\n";
+  OS << "LLVM_READONLY\n";
+  OS << "OpName getOperandIdxName(uint16_t Opcode, int16_t Idx);\n";
   OS << "} // end namespace llvm::" << Namespace << '\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::" << Namespace << " {\n";
-  OS << "LLVM_READONLY\n";
-  OS << "int16_t getNamedOperandIdx(uint16_t Opcode, OpName Name) {\n";
-  OS << "  assert(Name != OpName::NUM_OPERAND_NAMES);\n";
-  if (NumOperandNames != 0) {
-    assert(MaxOperandNo <= INT16_MAX &&
-           "Too many operands for the operand name -> index table");
-    StringRef Type = MaxOperandNo <= INT8_MAX ? "int8_t" : "int16_t";
-    OS << "  static constexpr " << Type << " OperandMap[][" << NumOperandNames
-       << "] = {\n";
-    for (const auto &[OpList, _] : OperandMap) {
-      // Emit a row of the OperandMap table.
-      OS << "    {";
-      for (unsigned ID = 0; ID < NumOperandNames; ++ID)
-        OS << (ID < OpList.size() ? OpList[ID] : -1) << ", ";
-      OS << "},\n";
-    }
-    OS << "  };\n";
 
-    Type = OperandMap.size() <= UINT8_MAX + 1 ? "uint8_t" : "uint16_t";
-    OS << "  static constexpr " << Type << " InstructionIndex[] = {";
-    for (auto [TableIndex, Entry] : enumerate(InstructionIndex))
-      OS << (TableIndex % 16 == 0 ? "\n    " : " ") << Entry << ',';
-    OS << "\n  };\n";
+  emitGetInstructionIndexForOpLookup(OS, OperandMap, InstructionIndex);
+
+  emitGetNamedOperandIdx(OS, Namespace, OperandNameToID, OperandMap,
+                         MaxOperandNo, NumOperandNames);
+  emitGetOperandIdxName(OS, Namespace, OperandNameToID, OperandMap,
+                        MaxOperandNo, NumOperandNames);
 
-    OS << "  return OperandMap[InstructionIndex[Opcode]][(unsigned)Name];\n";
-  } else {
-    // There are no operands, so no need to emit anything
-    OS << "  return -1;\n";
-  }
-  OS << "}\n";
   OS << "} // end namespace llvm::" << Namespace << '\n';
   OS << "#endif //GET_INSTRINFO_NAMED_OPS\n\n";
 }

``````````

</details>


https://github.com/llvm/llvm-project/pull/154944


More information about the llvm-commits mailing list