[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:
@@ -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";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user