Skip to content

Commit 2d5a3c8

Browse files
ro-iarsenm
andauthored
[TableGen] Implement getOperandIdxName (llvm#154944)
This is meant as the inverse of getNamedOperandIdx and returns the OpName for a given operand index for a given opcode. --------- Co-authored-by: Matt Arsenault <[email protected]>
1 parent abf9144 commit 2d5a3c8

File tree

3 files changed

+192
-69
lines changed

3 files changed

+192
-69
lines changed

llvm/test/TableGen/get-named-operand-idx.td

Lines changed: 66 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -48,34 +48,70 @@ def InstD : InstBase {
4848
let UseNamedOperandTable = 0;
4949
}
5050

51-
// CHECK: #ifdef GET_INSTRINFO_OPERAND_ENUM
52-
// CHECK: #undef GET_INSTRINFO_OPERAND_ENUM
53-
// CHECK: namespace llvm::MyNamespace {
54-
// CHECK: enum class OpName {
55-
// CHECK: a = 0,
56-
// CHECK: b = 1,
57-
// CHECK: c = 2,
58-
// CHECK: d = 3,
59-
// CHECK: x = 4,
60-
// CHECK: NUM_OPERAND_NAMES = 5,
61-
// CHECK: }; // enum class OpName
62-
// CHECK: } // end namespace llvm::MyNamespace
63-
// CHECK: #endif //GET_INSTRINFO_OPERAND_ENUM
51+
// CHECK-LABEL: #ifdef GET_INSTRINFO_OPERAND_ENUM
52+
// CHECK-NEXT: #undef GET_INSTRINFO_OPERAND_ENUM
53+
// CHECK-NEXT: namespace llvm::MyNamespace {
54+
// CHECK-NEXT: enum class OpName : uint8_t {
55+
// CHECK-NEXT: a = 0,
56+
// CHECK-NEXT: b = 1,
57+
// CHECK-NEXT: c = 2,
58+
// CHECK-NEXT: d = 3,
59+
// CHECK-NEXT: x = 4,
60+
// CHECK-NEXT: NUM_OPERAND_NAMES = 5,
61+
// CHECK-NEXT: }; // enum class OpName
62+
// CHECK-EMPTY:
63+
// CHECK-NEXT: LLVM_READONLY int16_t getNamedOperandIdx(uint16_t Opcode, OpName Name);
64+
// CHECK-NEXT: LLVM_READONLY OpName getOperandIdxName(uint16_t Opcode, int16_t Idx);
65+
// CHECK-NEXT: } // end namespace llvm::MyNamespace
66+
// CHECK-NEXT: #endif //GET_INSTRINFO_OPERAND_ENUM
6467

65-
// CHECK: #ifdef GET_INSTRINFO_NAMED_OPS
66-
// CHECK: #undef GET_INSTRINFO_NAMED_OPS
67-
// CHECK: namespace llvm::MyNamespace {
68-
// CHECK: LLVM_READONLY
69-
// CHECK: int16_t getNamedOperandIdx(uint16_t Opcode, OpName Name) {
70-
// CHECK: assert(Name != OpName::NUM_OPERAND_NAMES);
71-
// CHECK: static constexpr int8_t OperandMap[][5] = {
72-
// CHECK: {0, 1, 2, -1, -1, },
73-
// CHECK: {-1, -1, -1, 0, 1, },
74-
// CHECK: };
75-
// CHECK: static constexpr uint8_t InstructionIndex[] = {
76-
// CHECK: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
77-
// CHECK: };
78-
// CHECK: return OperandMap[InstructionIndex[Opcode]][(unsigned)Name];
79-
// CHECK: }
80-
// CHECK: } // end namespace llvm::MyNamespace
81-
// CHECK: #endif //GET_INSTRINFO_NAMED_OPS
68+
// CHECK-LABEL: #ifdef GET_INSTRINFO_NAMED_OPS
69+
// CHECK-NEXT: #undef GET_INSTRINFO_NAMED_OPS
70+
// CHECK-NEXT: namespace llvm::MyNamespace {
71+
// CHECK-NEXT: LLVM_READONLY static uint8_t getInstructionIndexForOpLookup(uint16_t Opcode) {
72+
// CHECK-NEXT: static constexpr uint8_t InstructionIndex[] = {
73+
// CHECK-NEXT: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
74+
// CHECK-NEXT: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
75+
// CHECK-NEXT: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
76+
// CHECK-NEXT: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
77+
// CHECK-NEXT: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
78+
// CHECK-NEXT: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
79+
// CHECK-NEXT: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
80+
// CHECK-NEXT: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
81+
// CHECK-NEXT: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
82+
// CHECK-NEXT: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
83+
// CHECK-NEXT: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
84+
// CHECK-NEXT: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
85+
// CHECK-NEXT: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
86+
// CHECK-NEXT: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
87+
// CHECK-NEXT: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
88+
// CHECK-NEXT: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
89+
// CHECK-NEXT: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
90+
// CHECK-NEXT: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
91+
// CHECK-NEXT: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
92+
// CHECK-NEXT: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0,
93+
// CHECK-NEXT: };
94+
// CHECK-NEXT: return InstructionIndex[Opcode];
95+
// CHECK-NEXT: }
96+
// CHECK-NEXT: LLVM_READONLY int16_t getNamedOperandIdx(uint16_t Opcode, OpName Name) {
97+
// CHECK-NEXT: assert(Name != OpName::NUM_OPERAND_NAMES);
98+
// CHECK-NEXT: static constexpr int8_t OperandMap[][5] = {
99+
// CHECK-NEXT: {-1, -1, -1, -1, -1, },
100+
// CHECK-NEXT: {0, 1, 2, -1, -1, },
101+
// CHECK-NEXT: {-1, -1, -1, 0, 1, },
102+
// CHECK-NEXT: };
103+
// CHECK-NEXT: unsigned InstrIdx = getInstructionIndexForOpLookup(Opcode);
104+
// CHECK-NEXT: return OperandMap[InstrIdx][(unsigned)Name];
105+
// CHECK-NEXT: }
106+
// CHECK-NEXT: LLVM_READONLY OpName getOperandIdxName(uint16_t Opcode, int16_t Idx) {
107+
// CHECK-NEXT: assert(Idx >= 0 && Idx < 3);
108+
// CHECK-NEXT: static constexpr OpName OperandMap[][3] = {
109+
// CHECK-NEXT: {OpName::NUM_OPERAND_NAMES, OpName::NUM_OPERAND_NAMES, OpName::NUM_OPERAND_NAMES, },
110+
// CHECK-NEXT: {OpName::a, OpName::b, OpName::c, },
111+
// CHECK-NEXT: {OpName::d, OpName::x, OpName::NUM_OPERAND_NAMES, },
112+
// CHECK-NEXT: };
113+
// CHECK-NEXT: unsigned InstrIdx = getInstructionIndexForOpLookup(Opcode);
114+
// CHECK-NEXT: return OperandMap[InstrIdx][(unsigned)Idx];
115+
// CHECK-NEXT: }
116+
// CHECK-NEXT: } // end namespace llvm::MyNamespace
117+
// CHECK-NEXT: #endif //GET_INSTRINFO_NAMED_OPS

llvm/unittests/Target/AMDGPU/AMDGPUUnitTests.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,3 +320,23 @@ TEST(AMDGPU, TestReverseComposeSubRegIndices) {
320320
}
321321
}
322322
}
323+
324+
TEST(AMDGPU, TestGetNamedOperandIdx) {
325+
std::unique_ptr<const GCNTargetMachine> TM =
326+
createAMDGPUTargetMachine("amdgcn-amd-", "gfx900", "");
327+
if (!TM)
328+
return;
329+
const MCInstrInfo *MCII = TM->getMCInstrInfo();
330+
331+
for (unsigned Opcode = 0, E = MCII->getNumOpcodes(); Opcode != E; ++Opcode) {
332+
const MCInstrDesc &Desc = MCII->get(Opcode);
333+
for (unsigned Idx = 0; Idx < Desc.getNumOperands(); ++Idx) {
334+
AMDGPU::OpName OpName = AMDGPU::getOperandIdxName(Opcode, Idx);
335+
if (OpName == AMDGPU::OpName::NUM_OPERAND_NAMES)
336+
continue;
337+
int16_t RetrievedIdx = AMDGPU::getNamedOperandIdx(Opcode, OpName);
338+
EXPECT_EQ(Idx, RetrievedIdx)
339+
<< "Opcode " << Opcode << " (" << MCII->getName(Opcode) << ')';
340+
}
341+
}
342+
}

llvm/utils/TableGen/InstrInfoEmitter.cpp

Lines changed: 106 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -223,17 +223,104 @@ void InstrInfoEmitter::EmitOperandInfo(raw_ostream &OS,
223223
}
224224
}
225225

226+
static void emitGetInstructionIndexForOpLookup(
227+
raw_ostream &OS, const MapVector<SmallVector<int>, unsigned> &OperandMap,
228+
ArrayRef<unsigned> InstructionIndex) {
229+
StringRef Type = OperandMap.size() <= UINT8_MAX + 1 ? "uint8_t" : "uint16_t";
230+
OS << "LLVM_READONLY static " << Type
231+
<< " getInstructionIndexForOpLookup(uint16_t Opcode) {\n"
232+
" static constexpr "
233+
<< Type << " InstructionIndex[] = {";
234+
for (auto [TableIndex, Entry] : enumerate(InstructionIndex))
235+
OS << (TableIndex % 16 == 0 ? "\n " : " ") << Entry << ',';
236+
OS << "\n };\n"
237+
" return InstructionIndex[Opcode];\n"
238+
"}\n";
239+
}
240+
241+
static void
242+
emitGetNamedOperandIdx(raw_ostream &OS,
243+
const MapVector<SmallVector<int>, unsigned> &OperandMap,
244+
unsigned MaxOperandNo, unsigned NumOperandNames) {
245+
OS << "LLVM_READONLY int16_t getNamedOperandIdx(uint16_t Opcode, OpName "
246+
"Name) {\n";
247+
OS << " assert(Name != OpName::NUM_OPERAND_NAMES);\n";
248+
if (!NumOperandNames) {
249+
// There are no operands, so no need to emit anything
250+
OS << " return -1;\n}\n";
251+
return;
252+
}
253+
assert(MaxOperandNo <= INT16_MAX &&
254+
"Too many operands for the operand name -> index table");
255+
StringRef Type = MaxOperandNo <= INT8_MAX ? "int8_t" : "int16_t";
256+
OS << " static constexpr " << Type << " OperandMap[][" << NumOperandNames
257+
<< "] = {\n";
258+
for (const auto &[OpList, _] : OperandMap) {
259+
// Emit a row of the OperandMap table.
260+
OS << " {";
261+
for (unsigned ID = 0; ID < NumOperandNames; ++ID)
262+
OS << (ID < OpList.size() ? OpList[ID] : -1) << ", ";
263+
OS << "},\n";
264+
}
265+
OS << " };\n";
266+
267+
OS << " unsigned InstrIdx = getInstructionIndexForOpLookup(Opcode);\n"
268+
" return OperandMap[InstrIdx][(unsigned)Name];\n"
269+
"}\n";
270+
}
271+
272+
static void
273+
emitGetOperandIdxName(raw_ostream &OS,
274+
MapVector<StringRef, unsigned> OperandNameToID,
275+
const MapVector<SmallVector<int>, unsigned> &OperandMap,
276+
unsigned MaxNumOperands, unsigned NumOperandNames) {
277+
OS << "LLVM_READONLY OpName getOperandIdxName(uint16_t Opcode, int16_t Idx) "
278+
"{\n";
279+
OS << " assert(Idx >= 0 && Idx < " << MaxNumOperands << ");\n";
280+
if (!MaxNumOperands) {
281+
// There are no operands, so no need to emit anything
282+
OS << " return -1;\n}\n";
283+
return;
284+
}
285+
OS << " static constexpr OpName OperandMap[][" << MaxNumOperands
286+
<< "] = {\n";
287+
for (const auto &[OpList, _] : OperandMap) {
288+
SmallVector<unsigned> IDs(MaxNumOperands, NumOperandNames);
289+
for (const auto &[ID, Idx] : enumerate(OpList)) {
290+
if (Idx >= 0)
291+
IDs[Idx] = ID;
292+
}
293+
// Emit a row of the OperandMap table. Map operand indices to enum values.
294+
OS << " {";
295+
for (unsigned ID : IDs) {
296+
if (ID == NumOperandNames)
297+
OS << "OpName::NUM_OPERAND_NAMES, ";
298+
else
299+
OS << "OpName::" << OperandNameToID.getArrayRef()[ID].first << ", ";
300+
}
301+
OS << "},\n";
302+
}
303+
OS << " };\n";
304+
305+
OS << " unsigned InstrIdx = getInstructionIndexForOpLookup(Opcode);\n"
306+
" return OperandMap[InstrIdx][(unsigned)Idx];\n"
307+
"}\n";
308+
}
309+
226310
/// Generate a table and function for looking up the indices of operands by
227311
/// name.
228312
///
229313
/// This code generates:
230314
/// - An enum in the llvm::TargetNamespace::OpName namespace, with one entry
231315
/// for each operand name.
232-
/// - A 2-dimensional table called OperandMap for mapping OpName enum values to
233-
/// operand indices.
234-
/// - A function called getNamedOperandIdx(uint16_t Opcode, uint16_t NamedIdx)
316+
/// - A 2-dimensional table for mapping OpName enum values to operand indices.
317+
/// - A function called getNamedOperandIdx(uint16_t Opcode, OpName Name)
235318
/// for looking up the operand index for an instruction, given a value from
236319
/// OpName enum
320+
/// - A 2-dimensional table for mapping operand indices to OpName enum values.
321+
/// - A function called getOperandIdxName(uint16_t Opcode, int16_t Idx)
322+
/// for looking up the OpName enum for an instruction, given the operand
323+
/// index. This is the inverse of getNamedOperandIdx().
237324
///
238325
/// Fixed/Predefined instructions do not have UseNamedOperandTable enabled, so
239326
/// we can just skip them. Hence accept just the TargetInstructions.
@@ -242,11 +329,6 @@ void InstrInfoEmitter::emitOperandNameMappings(
242329
ArrayRef<const CodeGenInstruction *> TargetInstructions) {
243330
StringRef Namespace = Target.getInstNamespace();
244331

245-
/// To facilitate assigning OpName enum values in the sorted alphabetical
246-
/// order, we go through an indirection from OpName -> ID, and Enum -> ID.
247-
/// This allows us to build the OpList and assign IDs to OpNames in a single
248-
/// scan of the instructions below.
249-
250332
// Map of operand names to their ID.
251333
MapVector<StringRef, unsigned> OperandNameToID;
252334

@@ -285,53 +367,38 @@ void InstrInfoEmitter::emitOperandNameMappings(
285367
}
286368

287369
const size_t NumOperandNames = OperandNameToID.size();
370+
const unsigned MaxNumOperands = MaxOperandNo + 1;
288371

289372
OS << "#ifdef GET_INSTRINFO_OPERAND_ENUM\n";
290373
OS << "#undef GET_INSTRINFO_OPERAND_ENUM\n";
291374
OS << "namespace llvm::" << Namespace << " {\n";
292-
OS << "enum class OpName {\n";
375+
376+
assert(NumOperandNames <= UINT16_MAX &&
377+
"Too many operands for the operand index -> name table");
378+
StringRef EnumType = getMinimalTypeForRange(NumOperandNames);
379+
OS << "enum class OpName : " << EnumType << " {\n";
293380
for (const auto &[Op, I] : OperandNameToID)
294381
OS << " " << Op << " = " << I << ",\n";
295382
OS << " NUM_OPERAND_NAMES = " << NumOperandNames << ",\n";
296383
OS << "}; // enum class OpName\n\n";
297-
OS << "LLVM_READONLY\n";
298-
OS << "int16_t getNamedOperandIdx(uint16_t Opcode, OpName Name);\n";
384+
385+
OS << "LLVM_READONLY int16_t getNamedOperandIdx(uint16_t Opcode, OpName "
386+
"Name);\n";
387+
OS << "LLVM_READONLY OpName getOperandIdxName(uint16_t Opcode, int16_t "
388+
"Idx);\n";
299389
OS << "} // end namespace llvm::" << Namespace << '\n';
300390
OS << "#endif //GET_INSTRINFO_OPERAND_ENUM\n\n";
301391

302392
OS << "#ifdef GET_INSTRINFO_NAMED_OPS\n";
303393
OS << "#undef GET_INSTRINFO_NAMED_OPS\n";
304394
OS << "namespace llvm::" << Namespace << " {\n";
305-
OS << "LLVM_READONLY\n";
306-
OS << "int16_t getNamedOperandIdx(uint16_t Opcode, OpName Name) {\n";
307-
OS << " assert(Name != OpName::NUM_OPERAND_NAMES);\n";
308-
if (NumOperandNames != 0) {
309-
assert(MaxOperandNo <= INT16_MAX &&
310-
"Too many operands for the operand name -> index table");
311-
StringRef Type = MaxOperandNo <= INT8_MAX ? "int8_t" : "int16_t";
312-
OS << " static constexpr " << Type << " OperandMap[][" << NumOperandNames
313-
<< "] = {\n";
314-
for (const auto &[OpList, _] : OperandMap) {
315-
// Emit a row of the OperandMap table.
316-
OS << " {";
317-
for (unsigned ID = 0; ID < NumOperandNames; ++ID)
318-
OS << (ID < OpList.size() ? OpList[ID] : -1) << ", ";
319-
OS << "},\n";
320-
}
321-
OS << " };\n";
322395

323-
Type = OperandMap.size() <= UINT8_MAX + 1 ? "uint8_t" : "uint16_t";
324-
OS << " static constexpr " << Type << " InstructionIndex[] = {";
325-
for (auto [TableIndex, Entry] : enumerate(InstructionIndex))
326-
OS << (TableIndex % 16 == 0 ? "\n " : " ") << Entry << ',';
327-
OS << "\n };\n";
396+
emitGetInstructionIndexForOpLookup(OS, OperandMap, InstructionIndex);
397+
398+
emitGetNamedOperandIdx(OS, OperandMap, MaxOperandNo, NumOperandNames);
399+
emitGetOperandIdxName(OS, OperandNameToID, OperandMap, MaxNumOperands,
400+
NumOperandNames);
328401

329-
OS << " return OperandMap[InstructionIndex[Opcode]][(unsigned)Name];\n";
330-
} else {
331-
// There are no operands, so no need to emit anything
332-
OS << " return -1;\n";
333-
}
334-
OS << "}\n";
335402
OS << "} // end namespace llvm::" << Namespace << '\n';
336403
OS << "#endif //GET_INSTRINFO_NAMED_OPS\n\n";
337404
}

0 commit comments

Comments
 (0)