Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 4 additions & 8 deletions llvm/test/TableGen/get-named-operand-idx.td
Original file line number Diff line number Diff line change
Expand Up @@ -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
51 changes: 27 additions & 24 deletions llvm/utils/TableGen/InstrInfoEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Copy link
Contributor

@jurahul jurahul Jul 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like there are ~316 generic opcodes, so we could squeeze the tables by another 316/632 bytes if desired by not encoding their index in the InstructionIndex table and doing:

   if (Opcode < FirstTargetVal)
      return -1;
   return OperandMap[InstructionIndex[Opcode - FirstTargetVal]][(unsigned)Name];

WDYT? Is it wodth the addition 1/2 a KB?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In addition, there could be some additional coincidental compression. For AMDGPU, AV_MOV_B32_IMM_PSEUDO, the first opcode after the generic ones, does not have any named operands, so its index need not be encoded in the table as well..

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();
Expand Down Expand Up @@ -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";
Expand Down