[llvm] [TableGen] Implement getNamedOperandIdx with another table lookup. NFC. (PR #151116)

Jay Foad via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 29 02:57:05 PDT 2025


https://github.com/jayfoad created https://github.com/llvm/llvm-project/pull/151116

Use direct table lookup instead of a switch over all opcodes.

In my Release+Asserts build this reduced the code size for
AMDGPU::getNamedOperandIdx from 11422 to 80 bytes, and the total size of
all its tables (including the jump table for the switch) from 243564 to
155020 bytes.


>From d53e9b2da99d4a0fb315e1de1badef5d3fbd066d Mon Sep 17 00:00:00 2001
From: Jay Foad <jay.foad at amd.com>
Date: Tue, 29 Jul 2025 08:19:13 +0100
Subject: [PATCH] [TableGen] Implement getNamedOperandIdx with another table
 lookup. NFC.

Use direct table lookup instead of a switch over all opcodes.

In my Release+Asserts build this reduced the code size for
AMDGPU::getNamedOperandIdx from 11422 to 80 bytes, and the total size of
all its tables (including the jump table for the switch) from 243564 to
155020 bytes.
---
 llvm/test/TableGen/get-named-operand-idx.td | 12 ++---
 llvm/utils/TableGen/InstrInfoEmitter.cpp    | 51 +++++++++++----------
 2 files changed, 31 insertions(+), 32 deletions(-)

diff --git a/llvm/test/TableGen/get-named-operand-idx.td b/llvm/test/TableGen/get-named-operand-idx.td
index f5c5d93f9e522..ab23edd54c723 100644
--- a/llvm/test/TableGen/get-named-operand-idx.td
+++ b/llvm/test/TableGen/get-named-operand-idx.td
@@ -72,14 +72,10 @@ def InstD : InstBase {
 // CHECK:      {0, 1, 2, -1, -1, },
 // CHECK:      {-1, -1, -1, 0, 1, },
 // CHECK:    };
-// CHECK:    switch(Opcode) {
-// CHECK:    case MyNamespace::InstA:
-// CHECK:      return OperandMap[0][static_cast<unsigned>(Name)];
-// CHECK:    case MyNamespace::InstB:
-// CHECK:    case MyNamespace::InstC:
-// CHECK:      return OperandMap[1][static_cast<unsigned>(Name)];
-// CHECK:    default: return -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
diff --git a/llvm/utils/TableGen/InstrInfoEmitter.cpp b/llvm/utils/TableGen/InstrInfoEmitter.cpp
index fa38d01dd9518..6f72b51963f87 100644
--- a/llvm/utils/TableGen/InstrInfoEmitter.cpp
+++ b/llvm/utils/TableGen/InstrInfoEmitter.cpp
@@ -250,29 +250,38 @@ void InstrInfoEmitter::emitOperandNameMappings(
   // Map of operand names to their ID.
   MapVector<StringRef, unsigned> OperandNameToID;
 
-  /// The keys of this map is a map which have OpName ID values as their keys
-  /// and instruction operand indices as their values. The values of this map
-  /// are lists of instruction names. This map helps to unique entries among
+  /// A key in this map is a vector mapping OpName ID values to instruction
+  /// operand indices or -1 (but without any trailing -1 values which will be
+  /// added later). The corresponding value in this map is the index of that row
+  /// in the emitted OperandMap table. This map helps to unique entries among
   /// instructions that have identical OpName -> Operand index mapping.
-  std::map<std::map<unsigned, unsigned>, std::vector<StringRef>> OperandMap;
+  MapVector<SmallVector<int>, unsigned> OperandMap;
 
   // Max operand index seen.
   unsigned MaxOperandNo = 0;
 
   // Fixed/Predefined instructions do not have UseNamedOperandTable enabled, so
-  // we can just skip them.
+  // add a dummy map entry for them.
+  OperandMap.try_emplace({}, 0);
+  unsigned FirstTargetVal = TargetInstructions.front()->EnumVal;
+  SmallVector<unsigned> InstructionIndex(FirstTargetVal, 0);
   for (const CodeGenInstruction *Inst : TargetInstructions) {
-    if (!Inst->TheDef->getValueAsBit("UseNamedOperandTable"))
+    if (!Inst->TheDef->getValueAsBit("UseNamedOperandTable")) {
+      InstructionIndex.push_back(0);
       continue;
-    std::map<unsigned, unsigned> OpList;
+    }
+    SmallVector<int> OpList;
     for (const auto &Info : Inst->Operands) {
       unsigned ID =
           OperandNameToID.try_emplace(Info.Name, OperandNameToID.size())
               .first->second;
+      OpList.resize(std::max((unsigned)OpList.size(), ID + 1), -1);
       OpList[ID] = Info.MIOperandNo;
       MaxOperandNo = std::max(MaxOperandNo, Info.MIOperandNo);
     }
-    OperandMap[OpList].push_back(Inst->TheDef->getName());
+    auto [It, Inserted] =
+        OperandMap.try_emplace(std::move(OpList), OperandMap.size());
+    InstructionIndex.push_back(It->second);
   }
 
   const size_t NumOperandNames = OperandNameToID.size();
@@ -302,28 +311,22 @@ void InstrInfoEmitter::emitOperandNameMappings(
     StringRef Type = MaxOperandNo <= INT8_MAX ? "int8_t" : "int16_t";
     OS << "  static constexpr " << Type << " OperandMap[][" << NumOperandNames
        << "] = {\n";
-    for (const auto &Entry : OperandMap) {
-      const std::map<unsigned, unsigned> &OpList = Entry.first;
-
+    for (const auto &[OpList, _] : OperandMap) {
       // Emit a row of the OperandMap table.
       OS << "    {";
-      for (unsigned ID = 0; ID < NumOperandNames; ++ID) {
-        auto Iter = OpList.find(ID);
-        OS << (Iter != OpList.end() ? (int)Iter->second : -1) << ", ";
-      }
+      for (unsigned ID = 0; ID < NumOperandNames; ++ID)
+        OS << (ID < OpList.size() ? OpList[ID] : -1) << ", ";
       OS << "},\n";
     }
     OS << "  };\n";
 
-    OS << "  switch(Opcode) {\n";
-    for (const auto &[TableIndex, Entry] : enumerate(OperandMap)) {
-      for (StringRef Name : Entry.second)
-        OS << "  case " << Namespace << "::" << Name << ":\n";
-      OS << "    return OperandMap[" << TableIndex
-         << "][static_cast<unsigned>(Name)];\n";
-    }
-    OS << "  default: return -1;\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";
+
+    OS << "  return OperandMap[InstructionIndex[Opcode]][(unsigned)Name];\n";
   } else {
     // There are no operands, so no need to emit anything
     OS << "  return -1;\n";



More information about the llvm-commits mailing list