[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