[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