Skip to content

[NFCI][TableGen][DecoderEmitter] Cull Op handling when possible #142974

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 3 commits into from
Jun 17, 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
114 changes: 71 additions & 43 deletions llvm/utils/TableGen/DecoderEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,10 +222,11 @@ class DecoderEmitter {
DecoderEmitter(const RecordKeeper &R, StringRef PredicateNamespace)
: RK(R), Target(R), PredicateNamespace(PredicateNamespace) {}

// Emit the decoder state machine table.
void emitTable(formatted_raw_ostream &OS, DecoderTable &Table, indent Indent,
unsigned BitWidth, StringRef Namespace,
const EncodingIDsVec &EncodingIDs) const;
// Emit the decoder state machine table. Returns a mask of MCD decoder ops
// that were emitted.
unsigned emitTable(formatted_raw_ostream &OS, DecoderTable &Table,
indent Indent, unsigned BitWidth, StringRef Namespace,
const EncodingIDsVec &EncodingIDs) const;
void emitInstrLenTable(formatted_raw_ostream &OS,
ArrayRef<unsigned> InstrLen) const;
void emitPredicateFunction(formatted_raw_ostream &OS,
Expand Down Expand Up @@ -826,11 +827,12 @@ unsigned Filter::usefulness() const {
// //
//////////////////////////////////

// Emit the decoder state machine table.
void DecoderEmitter::emitTable(formatted_raw_ostream &OS, DecoderTable &Table,
indent Indent, unsigned BitWidth,
StringRef Namespace,
const EncodingIDsVec &EncodingIDs) const {
// Emit the decoder state machine table. Returns a mask of MCD decoder ops
// that were emitted.
unsigned DecoderEmitter::emitTable(formatted_raw_ostream &OS,
DecoderTable &Table, indent Indent,
unsigned BitWidth, StringRef Namespace,
const EncodingIDsVec &EncodingIDs) const {
// We'll need to be able to map from a decoded opcode into the corresponding
// EncodingID for this specific combination of BitWidth and Namespace. This
// is used below to index into NumberedEncodings.
Expand Down Expand Up @@ -884,6 +886,8 @@ void DecoderEmitter::emitTable(formatted_raw_ostream &OS, DecoderTable &Table,
OS << " (Fail)";
};

unsigned OpcodeMask = 0;

while (I != E) {
assert(I < E && "incomplete decode table entry!");

Expand All @@ -892,6 +896,7 @@ void DecoderEmitter::emitTable(formatted_raw_ostream &OS, DecoderTable &Table,
OS.PadToColumn(12);

const uint8_t DecoderOp = *I++;
OpcodeMask |= (1 << DecoderOp);
switch (DecoderOp) {
default:
PrintFatalError("Invalid decode table opcode: " + Twine((int)DecoderOp) +
Expand Down Expand Up @@ -1027,6 +1032,8 @@ void DecoderEmitter::emitTable(formatted_raw_ostream &OS, DecoderTable &Table,
Indent -= 2;

OS << Indent << "};\n\n";

return OpcodeMask;
}

void DecoderEmitter::emitInstrLenTable(formatted_raw_ostream &OS,
Expand All @@ -1045,19 +1052,13 @@ void DecoderEmitter::emitPredicateFunction(formatted_raw_ostream &OS,
OS << Indent << "static bool checkDecoderPredicate(unsigned Idx, "
<< "const FeatureBitset &Bits) {\n";
Indent += 2;
if (!Predicates.empty()) {
OS << Indent << "switch (Idx) {\n";
OS << Indent << "default: llvm_unreachable(\"Invalid index!\");\n";
unsigned Index = 0;
for (const auto &Predicate : Predicates) {
OS << Indent << "case " << Index++ << ":\n";
OS << Indent + 2 << "return (" << Predicate << ");\n";
}
OS << Indent << "}\n";
} else {
// No case statement to emit
OS << Indent << "llvm_unreachable(\"Invalid index!\");\n";
OS << Indent << "switch (Idx) {\n";
OS << Indent << "default: llvm_unreachable(\"Invalid index!\");\n";
for (const auto &[Index, Predicate] : enumerate(Predicates)) {
OS << Indent << "case " << Index << ":\n";
OS << Indent + 2 << "return (" << Predicate << ");\n";
}
OS << Indent << "}\n";
Indent -= 2;
OS << Indent << "}\n\n";
}
Expand Down Expand Up @@ -2217,8 +2218,15 @@ static void insertBits(InsnType &field, InsnType bits, unsigned startBit,

// emitDecodeInstruction - Emit the templated helper function
// decodeInstruction().
static void emitDecodeInstruction(formatted_raw_ostream &OS,
bool IsVarLenInst) {
static void emitDecodeInstruction(formatted_raw_ostream &OS, bool IsVarLenInst,
unsigned OpcodeMask) {
const bool HasTryDecode = OpcodeMask & ((1 << MCD::OPC_TryDecode) |
(1 << MCD::OPC_TryDecodeOrFail));
const bool HasCheckPredicate =
OpcodeMask &
((1 << MCD::OPC_CheckPredicate) | (1 << MCD::OPC_CheckPredicateOrFail));
const bool HasSoftFail = OpcodeMask & (1 << MCD::OPC_SoftFail);

OS << R"(
static unsigned decodeNumToSkip(const uint8_t *&Ptr) {
unsigned NumToSkip = *Ptr++;
Expand All @@ -2238,9 +2246,11 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
OS << ",\n "
"llvm::function_ref<void(APInt &, uint64_t)> makeUp";
}
OS << R"() {
const FeatureBitset &Bits = STI.getFeatureBits();
OS << ") {\n";
if (HasCheckPredicate)
OS << " const FeatureBitset &Bits = STI.getFeatureBits();\n";

OS << R"(
const uint8_t *Ptr = DecodeTable;
uint64_t CurFieldValue = 0;
DecodeStatus S = MCDisassembler::Success;
Expand Down Expand Up @@ -2321,7 +2331,9 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
Ptr += NumToSkip;
}
break;
}
})";
if (HasCheckPredicate) {
OS << R"(
case MCD::OPC_CheckPredicate:
case MCD::OPC_CheckPredicateOrFail: {
bool IsFail = DecoderOp == MCD::OPC_CheckPredicateOrFail;
Expand All @@ -2343,7 +2355,9 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
Ptr += NumToSkip;
}
break;
}
})";
}
OS << R"(
case MCD::OPC_Decode: {
// Decode the Opcode value.
unsigned Opc = decodeULEB128AndIncUnsafe(Ptr);
Expand All @@ -2364,7 +2378,9 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
<< ", using decoder " << DecodeIdx << ": "
<< (S != MCDisassembler::Fail ? "PASS\n" : "FAIL\n"));
return S;
}
})";
if (HasTryDecode) {
OS << R"(
case MCD::OPC_TryDecode:
case MCD::OPC_TryDecodeOrFail: {
bool IsFail = DecoderOp == MCD::OPC_TryDecodeOrFail;
Expand Down Expand Up @@ -2399,17 +2415,22 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
// set before the decode attempt.
S = MCDisassembler::Success;
break;
}
case MCD::OPC_SoftFail: {
// Decode the mask values.
uint64_t PositiveMask = decodeULEB128AndIncUnsafe(Ptr);
uint64_t NegativeMask = decodeULEB128AndIncUnsafe(Ptr);
bool Failed = (insn & PositiveMask) != 0 || (~insn & NegativeMask) != 0;
if (Failed)
S = MCDisassembler::SoftFail;
LLVM_DEBUG(dbgs() << Loc << ": OPC_SoftFail: " << (Failed ? "FAIL\n" : "PASS\n"));
break;
}
})";
}
if (HasSoftFail) {
OS << R"(
case MCD::OPC_SoftFail: {
// Decode the mask values.
uint64_t PositiveMask = decodeULEB128AndIncUnsafe(Ptr);
uint64_t NegativeMask = decodeULEB128AndIncUnsafe(Ptr);
bool Failed = (insn & PositiveMask) != 0 || (~insn & NegativeMask) != 0;
if (Failed)
S = MCDisassembler::SoftFail;
LLVM_DEBUG(dbgs() << Loc << ": OPC_SoftFail: " << (Failed ? "FAIL\n" : "PASS\n"));
break;
})";
}
OS << R"(
case MCD::OPC_Fail: {
LLVM_DEBUG(dbgs() << Loc << ": OPC_Fail\n");
return MCDisassembler::Fail;
Expand Down Expand Up @@ -2609,6 +2630,7 @@ namespace {
}

DecoderTableInfo TableInfo;
unsigned OpcodeMask = 0;
for (const auto &Opc : OpcMap) {
// Emit the decoder for this namespace+width combination.
ArrayRef<EncodingAndInst> NumberedEncodingsRef(NumberedEncodings.data(),
Expand All @@ -2634,23 +2656,29 @@ namespace {
TableInfo.Table.push_back(MCD::OPC_Fail);

// Print the table to the output stream.
emitTable(OS, TableInfo.Table, indent(0), FC.getBitWidth(), Opc.first.first,
Opc.second);
OpcodeMask |= emitTable(OS, TableInfo.Table, indent(0), FC.getBitWidth(),
Opc.first.first, Opc.second);
}

// For variable instruction, we emit a instruction length table
// to let the decoder know how long the instructions are.
// You can see example usage in M68k's disassembler.
if (IsVarLenInst)
emitInstrLenTable(OS, InstrLen);

const bool HasCheckPredicate =
OpcodeMask &
((1 << MCD::OPC_CheckPredicate) | (1 << MCD::OPC_CheckPredicateOrFail));

// Emit the predicate function.
emitPredicateFunction(OS, TableInfo.Predicates, indent(0));
if (HasCheckPredicate)
emitPredicateFunction(OS, TableInfo.Predicates, indent(0));

// Emit the decoder function.
emitDecoderFunction(OS, TableInfo.Decoders, indent(0));

// Emit the main entry point for the decoder, decodeInstruction().
emitDecodeInstruction(OS, IsVarLenInst);
emitDecodeInstruction(OS, IsVarLenInst, OpcodeMask);

OS << "\n} // namespace\n";
}
Expand Down