Skip to content

[TableGen] Improvements to Named operands in InstrInfoEmitter #124960

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 30, 2025
Merged
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
124 changes: 57 additions & 67 deletions llvm/utils/TableGen/InstrInfoEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@

using namespace llvm;

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

/// The keys of this map are maps which have OpName enum values as their keys
/// and instruction operand indices as their values. The values of this map
/// are lists of instruction names.
typedef std::map<std::map<unsigned, unsigned>, std::vector<std::string>>
OpNameMapTy;
typedef std::map<std::string, unsigned>::iterator StrUintMapIter;

/// Generate member functions in the target-specific GenInstrInfo class.
///
/// This method is used to custom expand TIIPredicate definitions.
Expand All @@ -95,15 +88,9 @@ class InstrInfoEmitter {
void emitOperandTypeMappings(
raw_ostream &OS, const CodeGenTarget &Target,
ArrayRef<const CodeGenInstruction *> NumberedInstructions);
void
initOperandMapData(ArrayRef<const CodeGenInstruction *> NumberedInstructions,
StringRef Namespace,
std::map<std::string, unsigned> &Operands,
OpNameMapTy &OperandMap);
void emitOperandNameMappings(
raw_ostream &OS, const CodeGenTarget &Target,
ArrayRef<const CodeGenInstruction *> NumberedInstructions);

void emitLogicalOperandSizeMappings(
raw_ostream &OS, StringRef Namespace,
ArrayRef<const CodeGenInstruction *> NumberedInstructions);
Expand Down Expand Up @@ -239,35 +226,6 @@ void InstrInfoEmitter::EmitOperandInfo(raw_ostream &OS,
}
}

/// Initialize data structures for generating operand name mappings.
///
/// \param Operands [out] A map used to generate the OpName enum with operand
/// names as its keys and operand enum values as its values.
/// \param OperandMap [out] A map for representing the operand name mappings for
/// each instructions. This is used to generate the OperandMap table as
/// well as the getNamedOperandIdx() function.
void InstrInfoEmitter::initOperandMapData(
ArrayRef<const CodeGenInstruction *> NumberedInstructions,
StringRef Namespace, std::map<std::string, unsigned> &Operands,
OpNameMapTy &OperandMap) {
unsigned NumOperands = 0;
for (const CodeGenInstruction *Inst : NumberedInstructions) {
if (!Inst->TheDef->getValueAsBit("UseNamedOperandTable"))
continue;
std::map<unsigned, unsigned> OpList;
for (const auto &Info : Inst->Operands) {
StrUintMapIter I = Operands.find(Info.Name);

if (I == Operands.end()) {
I = Operands.insert(Operands.begin(), {Info.Name, NumOperands++});
}
OpList[I->second] = Info.MIOperandNo;
}
OperandMap[OpList].push_back(Namespace.str() +
"::" + Inst->TheDef->getName().str());
}
}

/// Generate a table and function for looking up the indices of operands by
/// name.
///
Expand All @@ -283,22 +241,52 @@ void InstrInfoEmitter::emitOperandNameMappings(
raw_ostream &OS, const CodeGenTarget &Target,
ArrayRef<const CodeGenInstruction *> NumberedInstructions) {
StringRef Namespace = Target.getInstNamespace();
// Map of operand names to their enumeration value. This will be used to
// generate the OpName enum.
std::map<std::string, unsigned> Operands;
OpNameMapTy OperandMap;

initOperandMapData(NumberedInstructions, Namespace, Operands, OperandMap);
/// 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.
std::map<StringRef, unsigned> OperandNameToID;
// Map from operand name enum value -> ID.
std::vector<unsigned> OperandEnumToID;

/// 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
/// instructions that have identical OpName -> Operand index mapping.
std::map<std::map<unsigned, unsigned>, std::vector<StringRef>> OperandMap;

// Max operand index seen.
unsigned MaxOperandNo = 0;

for (const CodeGenInstruction *Inst : NumberedInstructions) {
if (!Inst->TheDef->getValueAsBit("UseNamedOperandTable"))
continue;
std::map<unsigned, unsigned> OpList;
for (const auto &Info : Inst->Operands) {
unsigned ID =
OperandNameToID.try_emplace(Info.Name, OperandNameToID.size())
.first->second;
OpList[ID] = Info.MIOperandNo;
MaxOperandNo = std::max(MaxOperandNo, Info.MIOperandNo);
}
OperandMap[OpList].push_back(Inst->TheDef->getName());
}

const size_t NumOperandNames = OperandNameToID.size();
OperandEnumToID.reserve(NumOperandNames);
for (const auto &Op : OperandNameToID)
OperandEnumToID.push_back(Op.second);

OS << "#ifdef GET_INSTRINFO_OPERAND_ENUM\n";
OS << "#undef GET_INSTRINFO_OPERAND_ENUM\n";
OS << "namespace llvm::" << Namespace << "::OpName {\n";
OS << "enum {\n";
for (const auto &Op : Operands)
OS << " " << Op.first << " = " << Op.second << ",\n";

OS << " OPERAND_LAST";
OS << "\n};\n";
for (const auto &[I, Op] : enumerate(OperandNameToID))
OS << " " << Op.first << " = " << I << ",\n";
OS << "};\n";
OS << "} // end namespace llvm::" << Namespace << "::OpName\n";
OS << "#endif //GET_INSTRINFO_OPERAND_ENUM\n\n";

Expand All @@ -307,28 +295,30 @@ void InstrInfoEmitter::emitOperandNameMappings(
OS << "namespace llvm::" << Namespace << " {\n";
OS << "LLVM_READONLY\n";
OS << "int16_t getNamedOperandIdx(uint16_t Opcode, uint16_t NamedIdx) {\n";
if (!Operands.empty()) {
OS << " static const int16_t OperandMap [][" << Operands.size()
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 &Entry : OperandMap) {
const std::map<unsigned, unsigned> &OpList = Entry.first;
OS << "{";

// Emit a row of the OperandMap table
for (unsigned i = 0, e = Operands.size(); i != e; ++i)
OS << (OpList.count(i) == 0 ? -1 : (int)OpList.find(i)->second) << ", ";

// Emit a row of the OperandMap table.
OS << " {";
for (unsigned ID : OperandEnumToID) {
auto Iter = OpList.find(ID);
OS << (Iter != OpList.end() ? (int)Iter->second : -1) << ", ";
}
OS << "},\n";
}
OS << "};\n";
OS << " };\n";

OS << " switch(Opcode) {\n";
unsigned TableIndex = 0;
for (const auto &Entry : OperandMap) {
for (const std::string &Name : Entry.second)
OS << " case " << Name << ":\n";

OS << " return OperandMap[" << TableIndex++ << "][NamedIdx];\n";
for (const auto &[TableIndex, Entry] : enumerate(OperandMap)) {
for (StringRef Name : Entry.second)
OS << " case " << Namespace << "::" << Name << ":\n";
OS << " return OperandMap[" << TableIndex << "][NamedIdx];\n";
}
OS << " default: return -1;\n";
OS << " }\n";
Expand Down