Skip to content

Commit fdfd979

Browse files
authored
[TableGen] Improvements to Named operands in InstrInfoEmitter (#124960)
- Assign `OpName` enum values in the same alphabetical order in which they are emitted. - Get rid of OPERAND_LAST which is not used anywhere. - Inline `initOperandMapData` into `emitOperandNameMappings` to help see clearly how various maps are computed. - Emit the static `OperandMap` table as int8_t when possible. This should help reduce the static size by 50% in the common case. - Change maps/vectors to use StringRef instead of std::string to avoid unnecessary copies.
1 parent 55815b6 commit fdfd979

File tree

1 file changed

+57
-67
lines changed

1 file changed

+57
-67
lines changed

llvm/utils/TableGen/InstrInfoEmitter.cpp

Lines changed: 57 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040

4141
using namespace llvm;
4242

43-
cl::OptionCategory InstrInfoEmitterCat("Options for -gen-instr-info");
43+
static cl::OptionCategory InstrInfoEmitterCat("Options for -gen-instr-info");
4444
static cl::opt<bool> ExpandMIOperandInfo(
4545
"instr-info-expand-mi-operand-info",
4646
cl::desc("Expand operand's MIOperandInfo DAG into suboperands"),
@@ -67,13 +67,6 @@ class InstrInfoEmitter {
6767
typedef std::vector<OperandInfoTy> OperandInfoListTy;
6868
typedef std::map<OperandInfoTy, unsigned> OperandInfoMapTy;
6969

70-
/// The keys of this map are maps which have OpName enum values as their keys
71-
/// and instruction operand indices as their values. The values of this map
72-
/// are lists of instruction names.
73-
typedef std::map<std::map<unsigned, unsigned>, std::vector<std::string>>
74-
OpNameMapTy;
75-
typedef std::map<std::string, unsigned>::iterator StrUintMapIter;
76-
7770
/// Generate member functions in the target-specific GenInstrInfo class.
7871
///
7972
/// This method is used to custom expand TIIPredicate definitions.
@@ -95,15 +88,9 @@ class InstrInfoEmitter {
9588
void emitOperandTypeMappings(
9689
raw_ostream &OS, const CodeGenTarget &Target,
9790
ArrayRef<const CodeGenInstruction *> NumberedInstructions);
98-
void
99-
initOperandMapData(ArrayRef<const CodeGenInstruction *> NumberedInstructions,
100-
StringRef Namespace,
101-
std::map<std::string, unsigned> &Operands,
102-
OpNameMapTy &OperandMap);
10391
void emitOperandNameMappings(
10492
raw_ostream &OS, const CodeGenTarget &Target,
10593
ArrayRef<const CodeGenInstruction *> NumberedInstructions);
106-
10794
void emitLogicalOperandSizeMappings(
10895
raw_ostream &OS, StringRef Namespace,
10996
ArrayRef<const CodeGenInstruction *> NumberedInstructions);
@@ -239,35 +226,6 @@ void InstrInfoEmitter::EmitOperandInfo(raw_ostream &OS,
239226
}
240227
}
241228

242-
/// Initialize data structures for generating operand name mappings.
243-
///
244-
/// \param Operands [out] A map used to generate the OpName enum with operand
245-
/// names as its keys and operand enum values as its values.
246-
/// \param OperandMap [out] A map for representing the operand name mappings for
247-
/// each instructions. This is used to generate the OperandMap table as
248-
/// well as the getNamedOperandIdx() function.
249-
void InstrInfoEmitter::initOperandMapData(
250-
ArrayRef<const CodeGenInstruction *> NumberedInstructions,
251-
StringRef Namespace, std::map<std::string, unsigned> &Operands,
252-
OpNameMapTy &OperandMap) {
253-
unsigned NumOperands = 0;
254-
for (const CodeGenInstruction *Inst : NumberedInstructions) {
255-
if (!Inst->TheDef->getValueAsBit("UseNamedOperandTable"))
256-
continue;
257-
std::map<unsigned, unsigned> OpList;
258-
for (const auto &Info : Inst->Operands) {
259-
StrUintMapIter I = Operands.find(Info.Name);
260-
261-
if (I == Operands.end()) {
262-
I = Operands.insert(Operands.begin(), {Info.Name, NumOperands++});
263-
}
264-
OpList[I->second] = Info.MIOperandNo;
265-
}
266-
OperandMap[OpList].push_back(Namespace.str() +
267-
"::" + Inst->TheDef->getName().str());
268-
}
269-
}
270-
271229
/// Generate a table and function for looking up the indices of operands by
272230
/// name.
273231
///
@@ -283,22 +241,52 @@ void InstrInfoEmitter::emitOperandNameMappings(
283241
raw_ostream &OS, const CodeGenTarget &Target,
284242
ArrayRef<const CodeGenInstruction *> NumberedInstructions) {
285243
StringRef Namespace = Target.getInstNamespace();
286-
// Map of operand names to their enumeration value. This will be used to
287-
// generate the OpName enum.
288-
std::map<std::string, unsigned> Operands;
289-
OpNameMapTy OperandMap;
290244

291-
initOperandMapData(NumberedInstructions, Namespace, Operands, OperandMap);
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+
250+
// Map of operand names to their ID.
251+
std::map<StringRef, unsigned> OperandNameToID;
252+
// Map from operand name enum value -> ID.
253+
std::vector<unsigned> OperandEnumToID;
254+
255+
/// The keys of this map is a map which have OpName ID values as their keys
256+
/// and instruction operand indices as their values. The values of this map
257+
/// are lists of instruction names. This map helps to unique entries among
258+
/// instructions that have identical OpName -> Operand index mapping.
259+
std::map<std::map<unsigned, unsigned>, std::vector<StringRef>> OperandMap;
260+
261+
// Max operand index seen.
262+
unsigned MaxOperandNo = 0;
263+
264+
for (const CodeGenInstruction *Inst : NumberedInstructions) {
265+
if (!Inst->TheDef->getValueAsBit("UseNamedOperandTable"))
266+
continue;
267+
std::map<unsigned, unsigned> OpList;
268+
for (const auto &Info : Inst->Operands) {
269+
unsigned ID =
270+
OperandNameToID.try_emplace(Info.Name, OperandNameToID.size())
271+
.first->second;
272+
OpList[ID] = Info.MIOperandNo;
273+
MaxOperandNo = std::max(MaxOperandNo, Info.MIOperandNo);
274+
}
275+
OperandMap[OpList].push_back(Inst->TheDef->getName());
276+
}
277+
278+
const size_t NumOperandNames = OperandNameToID.size();
279+
OperandEnumToID.reserve(NumOperandNames);
280+
for (const auto &Op : OperandNameToID)
281+
OperandEnumToID.push_back(Op.second);
292282

293283
OS << "#ifdef GET_INSTRINFO_OPERAND_ENUM\n";
294284
OS << "#undef GET_INSTRINFO_OPERAND_ENUM\n";
295285
OS << "namespace llvm::" << Namespace << "::OpName {\n";
296286
OS << "enum {\n";
297-
for (const auto &Op : Operands)
298-
OS << " " << Op.first << " = " << Op.second << ",\n";
299-
300-
OS << " OPERAND_LAST";
301-
OS << "\n};\n";
287+
for (const auto &[I, Op] : enumerate(OperandNameToID))
288+
OS << " " << Op.first << " = " << I << ",\n";
289+
OS << "};\n";
302290
OS << "} // end namespace llvm::" << Namespace << "::OpName\n";
303291
OS << "#endif //GET_INSTRINFO_OPERAND_ENUM\n\n";
304292

@@ -307,28 +295,30 @@ void InstrInfoEmitter::emitOperandNameMappings(
307295
OS << "namespace llvm::" << Namespace << " {\n";
308296
OS << "LLVM_READONLY\n";
309297
OS << "int16_t getNamedOperandIdx(uint16_t Opcode, uint16_t NamedIdx) {\n";
310-
if (!Operands.empty()) {
311-
OS << " static const int16_t OperandMap [][" << Operands.size()
298+
if (NumOperandNames != 0) {
299+
assert(MaxOperandNo <= INT16_MAX &&
300+
"Too many operands for the operand name -> index table");
301+
StringRef Type = MaxOperandNo <= INT8_MAX ? "int8_t" : "int16_t";
302+
OS << " static constexpr " << Type << " OperandMap[][" << NumOperandNames
312303
<< "] = {\n";
313304
for (const auto &Entry : OperandMap) {
314305
const std::map<unsigned, unsigned> &OpList = Entry.first;
315-
OS << "{";
316-
317-
// Emit a row of the OperandMap table
318-
for (unsigned i = 0, e = Operands.size(); i != e; ++i)
319-
OS << (OpList.count(i) == 0 ? -1 : (int)OpList.find(i)->second) << ", ";
320306

307+
// Emit a row of the OperandMap table.
308+
OS << " {";
309+
for (unsigned ID : OperandEnumToID) {
310+
auto Iter = OpList.find(ID);
311+
OS << (Iter != OpList.end() ? (int)Iter->second : -1) << ", ";
312+
}
321313
OS << "},\n";
322314
}
323-
OS << "};\n";
315+
OS << " };\n";
324316

325317
OS << " switch(Opcode) {\n";
326-
unsigned TableIndex = 0;
327-
for (const auto &Entry : OperandMap) {
328-
for (const std::string &Name : Entry.second)
329-
OS << " case " << Name << ":\n";
330-
331-
OS << " return OperandMap[" << TableIndex++ << "][NamedIdx];\n";
318+
for (const auto &[TableIndex, Entry] : enumerate(OperandMap)) {
319+
for (StringRef Name : Entry.second)
320+
OS << " case " << Namespace << "::" << Name << ":\n";
321+
OS << " return OperandMap[" << TableIndex << "][NamedIdx];\n";
332322
}
333323
OS << " default: return -1;\n";
334324
OS << " }\n";

0 commit comments

Comments
 (0)