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

TryDecode/CheckPredicate/SoftFail MCD ops are not used by many targets.
Track the set of opcodes that were emitted and emit code for handling
TryDecode/CheckPredicate/SoftFail ops when decoding only if there were
emitted. This is purely eliminating dead code in the generated
`decodeInstruction` function.

This results in the following reduction in the size of the Disassembler
.so files with a release x86_64 release build on Linux:

```
Target                                                   Old Size        New Size  %  reduction
build/lib/libLLVMAArch64Disassembler.so.21.0git             256656          256656          0.00
build/lib/libLLVMAMDGPUDisassembler.so.21.0git              813000          808168          0.59
build/lib/libLLVMARCDisassembler.so.21.0git                  44816           43536          2.86
build/lib/libLLVMARMDisassembler.so.21.0git                 281744          278808          1.04
build/lib/libLLVMAVRDisassembler.so.21.0git                  36040           34496          4.28
build/lib/libLLVMBPFDisassembler.so.21.0git                  26248           23168         11.73
build/lib/libLLVMCSKYDisassembler.so.21.0git                 55960           53632          4.16
build/lib/libLLVMHexagonDisassembler.so.21.0git             115952          113416          2.19
build/lib/libLLVMLanaiDisassembler.so.21.0git                24360           21008         13.76
build/lib/libLLVMLoongArchDisassembler.so.21.0git            58584           56168          4.12
build/lib/libLLVMM68kDisassembler.so.21.0git                 57264           53880          5.91
build/lib/libLLVMMSP430Disassembler.so.21.0git               28896           28440          1.58
build/lib/libLLVMMipsDisassembler.so.21.0git                123128          120568          2.08
build/lib/libLLVMPowerPCDisassembler.so.21.0git              80656           78096          3.17
build/lib/libLLVMRISCVDisassembler.so.21.0git               154080          150200          2.52
build/lib/libLLVMSparcDisassembler.so.21.0git                42040           39568          5.88
build/lib/libLLVMSystemZDisassembler.so.21.0git              97056           94552          2.58
build/lib/libLLVMVEDisassembler.so.21.0git                   83944           81352          3.09
build/lib/libLLVMWebAssemblyDisassembler.so.21.0git          25280           25280          0.00
build/lib/libLLVMX86Disassembler.so.21.0git                2920624         2920624          0.00
build/lib/libLLVMXCoreDisassembler.so.21.0git                48320           44288          8.34
build/lib/libLLVMXtensaDisassembler.so.21.0git               42248           35840         15.17
```
This commit is contained in:
Rahul Joshi
2025-06-17 06:21:21 -07:00
committed by GitHub
parent 977d8a4bcd
commit 816ab1af0d

View File

@@ -222,10 +222,11 @@ public:
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,
@@ -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.
@@ -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!");
@@ -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) +
@@ -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,
@@ -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";
}
@@ -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++;
@@ -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;
@@ -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;
@@ -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);
@@ -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;
@@ -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;
@@ -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(),
@@ -2634,8 +2656,8 @@ 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
@@ -2643,14 +2665,20 @@ namespace {
// 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";
}