Index: llvm/utils/TableGen/DecoderEmitter/CMakeLists.txt =================================================================== --- llvm/utils/TableGen/DecoderEmitter/CMakeLists.txt +++ llvm/utils/TableGen/DecoderEmitter/CMakeLists.txt @@ -7,4 +7,6 @@ "Filter.cpp" "FilterChooser.cpp" "HelperFunctions.cpp" + "PrinterCapstone.cpp" + "PrinterLLVM.cpp" ) Index: llvm/utils/TableGen/DecoderEmitter/DecoderEmitter.h =================================================================== --- llvm/utils/TableGen/DecoderEmitter/DecoderEmitter.h +++ llvm/utils/TableGen/DecoderEmitter/DecoderEmitter.h @@ -9,130 +9,13 @@ #ifndef LLVM_UTILS_TABLEGEN_DECODEREMITTER_DECODEREMITTER_H #define LLVM_UTILS_TABLEGEN_DECODEREMITTER_DECODEREMITTER_H -#include "../CodeGenInstruction.h" -#include "../CodeGenTarget.h" -#include "../InfoByHwMode.h" -#include "../VarLenCodeEmitterGen.h" -#include "llvm/ADT/APInt.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/CachedHashString.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SetVector.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/MC/MCDecoderOps.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/FormattedStream.h" -#include "llvm/Support/LEB128.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/TableGen/Error.h" -#include "llvm/TableGen/Record.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "DecoderEmitterTypes.h" +#include "Printer.h" using namespace llvm; namespace tblgen_decoder_emitter { -////////////////////// -// Structs and Types -////////////////////// - -struct EncodingField { - unsigned Base, Width, Offset; - EncodingField(unsigned B, unsigned W, unsigned O) - : Base(B), Width(W), Offset(O) {} -}; - -struct OperandInfo { - std::vector Fields; - std::string Decoder; - bool HasCompleteDecoder; - uint64_t InitValue; - - OperandInfo(std::string D, bool HCD) - : Decoder(std::move(D)), HasCompleteDecoder(HCD), InitValue(0) {} - - void addField(unsigned Base, unsigned Width, unsigned Offset) { - Fields.push_back(EncodingField(Base, Width, Offset)); - } - - unsigned numFields() const { return Fields.size(); } - - typedef std::vector::const_iterator const_iterator; - - const_iterator begin() const { return Fields.begin(); } - const_iterator end() const { return Fields.end(); } -}; - -typedef std::vector DecoderTable; -typedef uint32_t DecoderFixup; -typedef std::vector FixupList; -typedef std::vector FixupScopeList; -typedef SmallSetVector PredicateSet; -typedef SmallSetVector DecoderSet; -struct DecoderTableInfo { - DecoderTable Table; - FixupScopeList FixupStack; - PredicateSet Predicates; - DecoderSet Decoders; -}; - -struct EncodingAndInst { - const Record *EncodingDef; - const CodeGenInstruction *Inst; - StringRef HwModeName; - - EncodingAndInst(const Record *EncodingDef, const CodeGenInstruction *Inst, - StringRef HwModeName = "") - : EncodingDef(EncodingDef), Inst(Inst), HwModeName(HwModeName) {} -}; - -struct EncodingIDAndOpcode { - unsigned EncodingID; - unsigned Opcode; - - EncodingIDAndOpcode() : EncodingID(0), Opcode(0) {} - EncodingIDAndOpcode(unsigned EncodingID, unsigned Opcode) - : EncodingID(EncodingID), Opcode(Opcode) {} -}; - -inline raw_ostream &operator<<(raw_ostream &OS, const EncodingAndInst &Value) { - if (Value.EncodingDef != Value.Inst->TheDef) - OS << Value.EncodingDef->getName() << ":"; - OS << Value.Inst->TheDef->getName(); - return OS; -} - -// The set (BIT_TRUE, BIT_FALSE, BIT_UNSET) represents a ternary logic system -// for a bit value. -// -// BIT_UNFILTERED is used as the init value for a filter position. It is used -// only for filter processings. -typedef enum { - BIT_TRUE, // '1' - BIT_FALSE, // '0' - BIT_UNSET, // '?' - BIT_UNFILTERED // unfiltered -} bit_value_t; - -// Representation of the instruction to work on. -typedef std::vector insn_t; - -static const uint64_t NoFixedSegmentsSentinel = -1ULL; - ////////////////////// // Functions ////////////////////// @@ -151,20 +34,6 @@ std::map> &Operands, bool IsVarLenInst); -// emitFieldFromInstruction - Emit the templated helper function -// fieldFromInstruction(). -// On Windows we make sure that this function is not inlined when -// using the VS compiler. It has a bug which causes the function -// to be optimized out in some circustances. See llvm.org/pr38292 -void emitFieldFromInstruction(formatted_raw_ostream &OS); - -// emitInsertBits - Emit the templated helper function insertBits(). -void emitInsertBits(formatted_raw_ostream &OS); - -// emitDecodeInstruction - Emit the templated helper function -// decodeInstruction(). -void emitDecodeInstruction(formatted_raw_ostream &OS, bool IsVarLenInst); - bool valueSet(bit_value_t V); bool valueNotSet(bit_value_t V); @@ -190,6 +59,7 @@ class DecoderEmitter { RecordKeeper &RK; + const PrinterInterface &PI; std::vector NumberedEncodings; ArrayRef NumberedInstructions; @@ -205,42 +75,16 @@ public: // Defaults preserved here for documentation, even though they aren't // strictly necessary given the way that this is currently being called. - DecoderEmitter(RecordKeeper &R, std::string PredicateNamespace, - std::string GPrefix = "if (", - std::string GPostfix = " == MCDisassembler::Fail)", - std::string ROK = "MCDisassembler::Success", - std::string RFail = "MCDisassembler::Fail", std::string L = "") - : RK(R), NumberedInstructions(nullptr), Target(R), - PredicateNamespace(std::move(PredicateNamespace)), GuardPrefix(std::move(GPrefix)), - GuardPostfix(std::move(GPostfix)), ReturnOK(std::move(ROK)), - ReturnFail(std::move(RFail)), Locals(std::move(L)) {} - - // Emit the decoder state machine table. - void emitTable(formatted_raw_ostream &O, DecoderTable &Table, - unsigned Indentation, unsigned BitWidth, - StringRef Namespace) const; - void emitInstrLenTable(formatted_raw_ostream &OS, - std::vector &InstrLen) const; - void emitPredicateFunction(formatted_raw_ostream &OS, - PredicateSet &Predicates, - unsigned Indentation) const; - void emitDecoderFunction(formatted_raw_ostream &OS, DecoderSet &Decoders, - unsigned Indentation) const; + DecoderEmitter(RecordKeeper &R, const PrinterInterface &PI) + : RK(R), PI(PI), NumberedInstructions(nullptr), Target(R) {} void retrieveHwModeEncodings(); - unsigned - fillOpcMap(bool const IsVarLenInst); + unsigned fillOpcMap(bool const IsVarLenInst); // run - Output the code emitter - void run(raw_ostream &O); + void run(); private: CodeGenTarget Target; - -public: - std::string PredicateNamespace; - std::string GuardPrefix, GuardPostfix; - std::string ReturnOK, ReturnFail; - std::string Locals; }; /// Filter - Filter works with FilterChooser to produce the decoding tree for @@ -290,10 +134,10 @@ bool Mixed; // a mixed region contains both set and unset bits // Map of well-known segment value to the set of uid's with that value. - std::map> FilteredInstructions; + std::map> FilteredInstrSubsets; // Set of uid's with non-constant segment values. - std::vector VariableInstructions; + std::vector VariableInstrSubset; // Map of well-known segment value to its delegate. std::map> FilterChooserMap; @@ -342,16 +186,6 @@ unsigned usefulness() const; }; // end class Filter -// These are states of our finite state machines used in FilterChooser's -// filterProcessor() which produces the filter candidates to use. -typedef enum { - ATTR_NONE, - ATTR_FILTERED, - ATTR_ALL_SET, - ATTR_ALL_UNSET, - ATTR_MIXED -} bitAttr_t; - /// FilterChooser - FilterChooser chooses the best filter among a set of /// Filters in order to perform the decoding of instructions at the current /// level. @@ -372,6 +206,9 @@ protected: friend class Filter; + // The PrinterInterface to emit source code from. + const PrinterInterface &PI; + // Vector of codegen instructions to choose our filter. ArrayRef AllInstructions; @@ -399,28 +236,25 @@ // Width of instructions unsigned BitWidth; - // Parent emitter - const DecoderEmitter *Emitter; - public: - FilterChooser(ArrayRef Insts, + FilterChooser(const PrinterInterface &PI, ArrayRef Insts, const std::vector &IDs, const std::map> &Ops, - unsigned BW, const DecoderEmitter *E) - : AllInstructions(Insts), Opcodes(IDs), Operands(Ops), + unsigned BW) + : PI(PI), AllInstructions(Insts), Opcodes(IDs), Operands(Ops), FilterBitValues(BW, BIT_UNFILTERED), Parent(nullptr), BestIndex(-1), - BitWidth(BW), Emitter(E) { + BitWidth(BW) { doFilter(); } - FilterChooser(ArrayRef Insts, + FilterChooser(const PrinterInterface &PI, ArrayRef Insts, const std::vector &IDs, const std::map> &Ops, const std::vector &ParentFilterBitValues, const FilterChooser &Parent) - : AllInstructions(Insts), Opcodes(IDs), Operands(Ops), + : PI(Parent.PI), AllInstructions(Insts), Opcodes(IDs), Operands(Ops), FilterBitValues(ParentFilterBitValues), Parent(&Parent), BestIndex(-1), - BitWidth(Parent.BitWidth), Emitter(Parent.Emitter) { + BitWidth(Parent.BitWidth) { doFilter(); } @@ -471,13 +305,6 @@ std::vector &FieldVals, const insn_t &Insn) const; - // Emits code to check the Predicates member of an instruction are true. - // Returns true if predicate matches were emitted, false otherwise. - bool emitPredicateMatch(raw_ostream &O, unsigned &Indentation, - unsigned Opc) const; - bool emitPredicateMatchAux(const Init &Val, bool ParenIfBinOp, - raw_ostream &OS) const; - bool doesOpcodeNeedPredicate(unsigned Opc) const; unsigned getPredicateIndex(DecoderTableInfo &TableInfo, StringRef P) const; void emitPredicateTableEntry(DecoderTableInfo &TableInfo, unsigned Opc) const; @@ -492,11 +319,7 @@ void emitSingletonTableEntry(DecoderTableInfo &TableInfo, const Filter &Best) const; - void emitBinaryParser(raw_ostream &O, unsigned &Indentation, - const OperandInfo &OpInfo, - bool &OpHasCompleteDecoder) const; - - void emitDecoder(raw_ostream &OS, unsigned Indentation, unsigned Opc, + void emitDecoder(raw_ostream &DecoderOS, unsigned Opc, bool &HasCompleteDecoder) const; unsigned getDecoderIndex(DecoderSet &Decoders, unsigned Opc, bool &HasCompleteDecoder) const; Index: llvm/utils/TableGen/DecoderEmitter/DecoderEmitter.cpp =================================================================== --- llvm/utils/TableGen/DecoderEmitter/DecoderEmitter.cpp +++ llvm/utils/TableGen/DecoderEmitter/DecoderEmitter.cpp @@ -12,274 +12,21 @@ //===----------------------------------------------------------------------===// #include "DecoderEmitter.h" +#include "../TableGenBackends.h" using namespace llvm; namespace tblgen_decoder_emitter { #define DEBUG_TYPE "decoder-emitter-DecoderEmitter" -STATISTIC(NumEncodings, "Number of encodings considered"); -STATISTIC(NumEncodingsLackingDisasm, "Number of encodings without disassembler info"); -STATISTIC(NumInstructions, "Number of instructions considered"); -STATISTIC(NumEncodingsOmitted, "Number of encodings omitted"); +STATISTIC(StatsNumEncodings, "Number of encodings considered"); +STATISTIC(StatsNumEncodingsLackingDisasm, + "Number of encodings without disassembler info"); +STATISTIC(StatsNumInstructions, "Number of instructions considered"); +STATISTIC(StatsNumEncodingsOmitted, "Number of encodings omitted"); -// Emit the decoder state machine table. -void DecoderEmitter::emitTable(formatted_raw_ostream &OS, DecoderTable &Table, - unsigned Indentation, unsigned BitWidth, - StringRef Namespace) const { - OS.indent(Indentation) << "static const uint8_t DecoderTable" << Namespace - << BitWidth << "[] = {\n"; - - Indentation += 2; - - // FIXME: We may be able to use the NumToSkip values to recover - // appropriate indentation levels. - DecoderTable::const_iterator I = Table.begin(); - DecoderTable::const_iterator const E = Table.end(); - while (I != E) { - assert (I < E && "incomplete decode table entry!"); - - uint64_t const Pos = I - Table.begin(); - OS << "/* " << Pos << " */"; - OS.PadToColumn(12); - - switch (*I) { - default: - PrintFatalError("invalid decode table opcode"); - case MCD::OPC_ExtractField: { - ++I; - unsigned const Start = *I++; - unsigned const Len = *I++; - OS.indent(Indentation) << "MCD::OPC_ExtractField, " << Start << ", " - << Len << ", // Inst{"; - if (Len > 1) - OS << (Start + Len - 1) << "-"; - OS << Start << "} ...\n"; - break; - } - case MCD::OPC_FilterValue: { - ++I; - OS.indent(Indentation) << "MCD::OPC_FilterValue, "; - // The filter value is ULEB128 encoded. - while (*I >= 128) - OS << (unsigned)*I++ << ", "; - OS << (unsigned)*I++ << ", "; - - // 24-bit numtoskip value. - uint8_t Byte = *I++; - uint32_t NumToSkip = Byte; - OS << (unsigned)Byte << ", "; - Byte = *I++; - OS << (unsigned)Byte << ", "; - NumToSkip |= Byte << 8; - Byte = *I++; - OS << utostr(Byte) << ", "; - NumToSkip |= Byte << 16; - OS << "// Skip to: " << ((I - Table.begin()) + NumToSkip) << "\n"; - break; - } - case MCD::OPC_CheckField: { - ++I; - unsigned const Start = *I++; - unsigned const Len = *I++; - OS.indent(Indentation) << "MCD::OPC_CheckField, " << Start << ", " - << Len << ", ";// << Val << ", " << NumToSkip << ",\n"; - // ULEB128 encoded field value. - for (; *I >= 128; ++I) - OS << (unsigned)*I << ", "; - OS << (unsigned)*I++ << ", "; - // 24-bit numtoskip value. - uint8_t Byte = *I++; - uint32_t NumToSkip = Byte; - OS << (unsigned)Byte << ", "; - Byte = *I++; - OS << (unsigned)Byte << ", "; - NumToSkip |= Byte << 8; - Byte = *I++; - OS << utostr(Byte) << ", "; - NumToSkip |= Byte << 16; - OS << "// Skip to: " << ((I - Table.begin()) + NumToSkip) << "\n"; - break; - } - case MCD::OPC_CheckPredicate: { - ++I; - OS.indent(Indentation) << "MCD::OPC_CheckPredicate, "; - for (; *I >= 128; ++I) - OS << (unsigned)*I << ", "; - OS << (unsigned)*I++ << ", "; - - // 24-bit numtoskip value. - uint8_t Byte = *I++; - uint32_t NumToSkip = Byte; - OS << (unsigned)Byte << ", "; - Byte = *I++; - OS << (unsigned)Byte << ", "; - NumToSkip |= Byte << 8; - Byte = *I++; - OS << utostr(Byte) << ", "; - NumToSkip |= Byte << 16; - OS << "// Skip to: " << ((I - Table.begin()) + NumToSkip) << "\n"; - break; - } - case MCD::OPC_Decode: - case MCD::OPC_TryDecode: { - bool const IsTry = *I == MCD::OPC_TryDecode; - ++I; - // Extract the ULEB128 encoded Opcode to a buffer. - uint8_t Buffer[16], *P = Buffer; - while ((*P++ = *I++) >= 128) - assert((P - Buffer) <= (ptrdiff_t)sizeof(Buffer) - && "ULEB128 value too large!"); - // Decode the Opcode value. - unsigned const Opc = decodeULEB128(Buffer); - OS.indent(Indentation) << "MCD::OPC_" << (IsTry ? "Try" : "") - << "Decode, "; - for (P = Buffer; *P >= 128; ++P) - OS << (unsigned)*P << ", "; - OS << (unsigned)*P << ", "; - - // Decoder index. - for (; *I >= 128; ++I) - OS << (unsigned)*I << ", "; - OS << (unsigned)*I++ << ", "; - - if (!IsTry) { - OS << "// Opcode: " << NumberedEncodings[Opc] << "\n"; - break; - } - - // Fallthrough for OPC_TryDecode. - - // 24-bit numtoskip value. - uint8_t Byte = *I++; - uint32_t NumToSkip = Byte; - OS << (unsigned)Byte << ", "; - Byte = *I++; - OS << (unsigned)Byte << ", "; - NumToSkip |= Byte << 8; - Byte = *I++; - OS << utostr(Byte) << ", "; - NumToSkip |= Byte << 16; - - OS << "// Opcode: " << NumberedEncodings[Opc] - << ", skip to: " << ((I - Table.begin()) + NumToSkip) << "\n"; - break; - } - case MCD::OPC_SoftFail: { - ++I; - OS.indent(Indentation) << "MCD::OPC_SoftFail"; - // Positive mask - uint64_t Value = 0; - unsigned Shift = 0; - do { - OS << ", " << (unsigned)*I; - Value += (*I & 0x7f) << Shift; - Shift += 7; - } while (*I++ >= 128); - if (Value > 127) { - OS << " /* 0x"; - OS.write_hex(Value); - OS << " */"; - } - // Negative mask - Value = 0; - Shift = 0; - do { - OS << ", " << (unsigned)*I; - Value += (*I & 0x7f) << Shift; - Shift += 7; - } while (*I++ >= 128); - if (Value > 127) { - OS << " /* 0x"; - OS.write_hex(Value); - OS << " */"; - } - OS << ",\n"; - break; - } - case MCD::OPC_Fail: { - ++I; - OS.indent(Indentation) << "MCD::OPC_Fail,\n"; - break; - } - } - } - OS.indent(Indentation) << "0\n"; - - Indentation -= 2; - - OS.indent(Indentation) << "};\n\n"; -} - -void DecoderEmitter::emitInstrLenTable(formatted_raw_ostream &OS, - std::vector &InstrLen) const { - OS << "static const uint8_t InstrLenTable[] = {\n"; - for (unsigned const&Len : InstrLen) { - OS << Len << ",\n"; - } - OS << "};\n\n"; -} - -void DecoderEmitter::emitPredicateFunction(formatted_raw_ostream &OS, - PredicateSet &Predicates, - unsigned Indentation) const { - // The predicate function is just a big switch statement based on the - // input predicate index. - OS.indent(Indentation) << "static bool checkDecoderPredicate(unsigned Idx, " - << "const FeatureBitset &Bits) {\n"; - Indentation += 2; - if (!Predicates.empty()) { - OS.indent(Indentation) << "switch (Idx) {\n"; - OS.indent(Indentation) << "default: llvm_unreachable(\"Invalid index!\");\n"; - unsigned Index = 0; - for (const auto &Predicate : Predicates) { - OS.indent(Indentation) << "case " << Index++ << ":\n"; - OS.indent(Indentation+2) << "return (" << Predicate << ");\n"; - } - OS.indent(Indentation) << "}\n"; - } else { - // No case statement to emit - OS.indent(Indentation) << "llvm_unreachable(\"Invalid index!\");\n"; - } - Indentation -= 2; - OS.indent(Indentation) << "}\n\n"; -} - -void DecoderEmitter::emitDecoderFunction(formatted_raw_ostream &OS, - DecoderSet &Decoders, - unsigned Indentation) const { - // The decoder function is just a big switch statement based on the - // input decoder index. - OS.indent(Indentation) << "template \n"; - OS.indent(Indentation) << "static DecodeStatus decodeToMCInst(DecodeStatus S," - << " unsigned Idx, InsnType insn, MCInst &MI,\n"; - OS.indent(Indentation) - << " uint64_t " - << "Address, const MCDisassembler *Decoder, bool &DecodeComplete) {\n"; - Indentation += 2; - OS.indent(Indentation) << "DecodeComplete = true;\n"; - // TODO: When InsnType is large, using uint64_t limits all fields to 64 bits - // It would be better for emitBinaryParser to use a 64-bit tmp whenever - // possible but fall back to an InsnType-sized tmp for truly large fields. - OS.indent(Indentation) << "using TmpType = " - "std::conditional_t::" - "value, InsnType, uint64_t>;\n"; - OS.indent(Indentation) << "TmpType tmp;\n"; - OS.indent(Indentation) << "switch (Idx) {\n"; - OS.indent(Indentation) << "default: llvm_unreachable(\"Invalid index!\");\n"; - unsigned Index = 0; - for (const auto &Decoder : Decoders) { - OS.indent(Indentation) << "case " << Index++ << ":\n"; - OS << Decoder; - OS.indent(Indentation+2) << "return S;\n"; - } - OS.indent(Indentation) << "}\n"; - Indentation -= 2; - OS.indent(Indentation) << "}\n\n"; -} - -/// Encodings of instructions might differ if the Hardware Mode is different as well. -/// Here we add all possible encodings. +/// Encodings of instructions might differ if the Hardware Mode is different as +/// well. Here we add all possible encodings. void DecoderEmitter::retrieveHwModeEncodings() { std::set HwModeNames; @@ -340,13 +87,13 @@ Def->getValueAsBit("isPseudo") || Def->getValueAsBit("isAsmParserOnly") || Def->getValueAsBit("isCodeGenOnly")) { - NumEncodingsLackingDisasm++; + StatsNumEncodingsLackingDisasm++; continue; } if (I < NumberedInstructions.size()) - NumInstructions++; - NumEncodings++; + StatsNumInstructions++; + StatsNumEncodings++; if (!Size && !IsVarLenInst) continue; @@ -355,7 +102,7 @@ InstrLen.resize(NumberedInstructions.size(), 0); if (unsigned const Len = populateInstruction(Target, *EncodingDef, *Inst, I, - Operands, IsVarLenInst)) { + Operands, IsVarLenInst)) { if (IsVarLenInst) { MaxInstLen = std::max(MaxInstLen, Len); InstrLen[I] = Len; @@ -368,28 +115,19 @@ OpcMap[std::make_pair(DecoderNamespace, Size)].emplace_back( I, IndexOfInstruction.find(Def)->second); } else { - NumEncodingsOmitted++; + StatsNumEncodingsOmitted++; } } return MaxInstLen; } // Emits disassembler code for instruction decoding. -void DecoderEmitter::run(raw_ostream &O) { - formatted_raw_ostream OS(O); - OS << "#include \"llvm/MC/MCInst.h\"\n"; - OS << "#include \"llvm/MC/MCSubtargetInfo.h\"\n"; - OS << "#include \"llvm/MC/SubtargetFeature.h\"\n"; - OS << "#include \"llvm/Support/DataTypes.h\"\n"; - OS << "#include \"llvm/Support/Debug.h\"\n"; - OS << "#include \"llvm/Support/LEB128.h\"\n"; - OS << "#include \"llvm/Support/raw_ostream.h\"\n"; - OS << "#include \n"; - OS << '\n'; - OS << "namespace llvm {\n\n"; - - emitFieldFromInstruction(OS); - emitInsertBits(OS); +void DecoderEmitter::run() { + PI.emitSourceFileHeader(); + PI.emitIncludes(); + PI.emitNamespaceBegin("llvm"); + PI.emitFieldFromInstruction(); + PI.emitInsertBits(); Target.reverseBitsForLittleEndianEncoding(); @@ -399,7 +137,8 @@ retrieveHwModeEncodings(); - for (const auto &NumberedAlias : RK.getAllDerivedDefinitions("AdditionalEncoding")) + for (const auto &NumberedAlias : + RK.getAllDerivedDefinitions("AdditionalEncoding")) NumberedEncodings.emplace_back( NumberedAlias, &Target.getInstruction(NumberedAlias->getValueAsDef("AliasOf"))); @@ -418,8 +157,8 @@ // Emit the decoder for this namespace+width combination. ArrayRef const NumberedEncodingsRef( NumberedEncodings.data(), NumberedEncodings.size()); - FilterChooser const FC(NumberedEncodingsRef, Opc.second, Operands, - IsVarLenInst ? MaxInstLen : 8 * Opc.first.second, this); + FilterChooser const FC(PI, NumberedEncodingsRef, Opc.second, Operands, + IsVarLenInst ? MaxInstLen : 8 * Opc.first.second); // The decode table is cleared for each top level decoder function. The // predicates and decoders themselves, however, are shared across all @@ -440,38 +179,102 @@ TableInfo.Table.push_back(MCD::OPC_Fail); // Print the table to the output stream. - emitTable(OS, TableInfo.Table, 0, FC.getBitWidth(), Opc.first.first); - OS.flush(); + PI.emitTable(TableInfo.Table, FC.getBitWidth(), Opc.first.first, + NumberedEncodings); + PI.flushOS(); } // 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); + PI.emitInstrLenTable(InstrLen); // Emit the predicate function. - emitPredicateFunction(OS, TableInfo.Predicates, 0); + PI.emitPredicateFunction(TableInfo.Predicates, 0); // Emit the decoder function. - emitDecoderFunction(OS, TableInfo.Decoders, 0); + PI.emitDecoderFunction(TableInfo.Decoders, 0); // Emit the main entry point for the decoder, decodeInstruction(). - emitDecodeInstruction(OS, IsVarLenInst); - - OS << "\n} // end namespace llvm\n"; + PI.emitDecodeInstruction(IsVarLenInst); + PI.emitNamespaceEnd("llvm"); } } // end namespace tblgen_decoder_emitter +namespace { +static void setPrinterParameters(CodeGenTarget &Target, ActionType Action, + std::string &PredicateNamespace, + std::string &GPrefix, std::string &GPostfix, + std::string &ROK, std::string &RFail, + std::string &L) { + // ARM and Thumb have a CHECK() macro to deal with DecodeStatuses. + if (Target.getName() == "ARM" || Target.getName() == "Thumb" || + Target.getName() == "AArch64" || Target.getName() == "ARM64") { + PredicateNamespace = std::string(Target.getName()); + + if (PredicateNamespace == "Thumb") + PredicateNamespace = "ARM"; + + switch (Action) { + default: + GPrefix = "if (!Check(S, "; + L = " MCDisassembler::DecodeStatus S = " + "MCDisassembler::Success;\n(void)S;"; + break; + case GenCapstone: + GPrefix = "if (!Check(&S, "; + L = " MCDisassembler_DecodeStatus S = MCDisassembler_Success;\n(void)S;"; + break; + } + GPostfix = "))"; + } else { + PredicateNamespace = Target.getName().str(); + GPrefix = "if ("; + GPostfix = " == MCDisassembler::Fail)"; + L = ""; + } + + ROK = "S"; + + switch (Action) { + default: + RFail = "MCDisassembler::Fail"; + break; + case GenCapstone: + RFail = "MCDisassembler_Fail"; + break; + } +} +} // namespace + namespace llvm { -void EmitDecoder(RecordKeeper &RK, raw_ostream &OS, - const std::string &PredicateNamespace, - const std::string &GPrefix, const std::string &GPostfix, - const std::string &ROK, const std::string &RFail, - const std::string &L) { - tblgen_decoder_emitter::DecoderEmitter(RK, PredicateNamespace, GPrefix, GPostfix, ROK, RFail, L) - .run(OS); +void EmitDecoder(RecordKeeper &RK, raw_ostream &OS, CodeGenTarget &Target, + ActionType Action) { + formatted_raw_ostream FOS(OS); + tblgen_decoder_emitter::PrinterInterface *PI; + std::string PredicateNamespace; + std::string GPrefix; + std::string GPostfix; + std::string ROK; + std::string RFail; + std::string L; + + setPrinterParameters(Target, Action, PredicateNamespace, GPrefix, GPostfix, + ROK, RFail, L); + + if (Action == GenCapstone) { + PI = new tblgen_decoder_emitter::PrinterCapstone( + FOS, PredicateNamespace, GPrefix, GPostfix, ROK, RFail, L, + Target.getName().str()); + } else { + PI = new tblgen_decoder_emitter::PrinterLLVM(FOS, PredicateNamespace, + GPrefix, GPostfix, ROK, RFail, + L, Target.getName().str()); + } + tblgen_decoder_emitter::DecoderEmitter(RK, *PI).run(); + + delete PI; } } // end namespace llvm - Index: llvm/utils/TableGen/DecoderEmitter/DecoderEmitterTypes.h =================================================================== --- /dev/null +++ llvm/utils/TableGen/DecoderEmitter/DecoderEmitterTypes.h @@ -0,0 +1,148 @@ +//===------- DecoderEmitterTypes.h - Decoder Generator ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_UTILS_TABLEGEN_DECODEREMITTER_DECODEREMITTERTYPES_H +#define LLVM_UTILS_TABLEGEN_DECODEREMITTER_DECODEREMITTERTYPES_H + +#include "../CodeGenInstruction.h" +#include "../CodeGenTarget.h" +#include "../InfoByHwMode.h" +#include "../VarLenCodeEmitterGen.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/CachedHashString.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/MC/MCDecoderOps.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FormattedStream.h" +#include "llvm/Support/LEB128.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace llvm; + +namespace tblgen_decoder_emitter { + +////////////////////// +// Structs and Types +////////////////////// + +struct EncodingField { + unsigned Base, Width, Offset; + EncodingField(unsigned B, unsigned W, unsigned O) + : Base(B), Width(W), Offset(O) {} +}; + +struct OperandInfo { + std::vector Fields; + std::string Decoder; + bool HasCompleteDecoder; + uint64_t InitValue; + + OperandInfo(std::string D, bool HCD) + : Decoder(std::move(D)), HasCompleteDecoder(HCD), InitValue(0) {} + + void addField(unsigned Base, unsigned Width, unsigned Offset) { + Fields.push_back(EncodingField(Base, Width, Offset)); + } + + unsigned numFields() const { return Fields.size(); } + + typedef std::vector::const_iterator const_iterator; + + const_iterator begin() const { return Fields.begin(); } + const_iterator end() const { return Fields.end(); } +}; + +typedef std::vector DecoderTable; +typedef uint32_t DecoderFixup; +typedef std::vector FixupList; +typedef std::vector FixupScopeList; +typedef SmallSetVector PredicateSet; +typedef SmallSetVector DecoderSet; +struct DecoderTableInfo { + DecoderTable Table; + FixupScopeList FixupStack; + PredicateSet Predicates; + DecoderSet Decoders; +}; + +struct EncodingAndInst { + const Record *EncodingDef; + const CodeGenInstruction *Inst; + StringRef HwModeName; + + EncodingAndInst(const Record *EncodingDef, const CodeGenInstruction *Inst, + StringRef HwModeName = "") + : EncodingDef(EncodingDef), Inst(Inst), HwModeName(HwModeName) {} +}; + +struct EncodingIDAndOpcode { + unsigned EncodingID; + unsigned Opcode; + + EncodingIDAndOpcode() : EncodingID(0), Opcode(0) {} + EncodingIDAndOpcode(unsigned EncodingID, unsigned Opcode) + : EncodingID(EncodingID), Opcode(Opcode) {} +}; + +inline raw_ostream &operator<<(raw_ostream &OS, const EncodingAndInst &Value) { + if (Value.EncodingDef != Value.Inst->TheDef) + OS << Value.EncodingDef->getName() << ":"; + OS << Value.Inst->TheDef->getName(); + return OS; +} + +// The set (BIT_TRUE, BIT_FALSE, BIT_UNSET) represents a ternary logic system +// for a bit value. +// +// BIT_UNFILTERED is used as the init value for a filter position. It is used +// only for filter processings. +typedef enum { + BIT_TRUE, // '1' + BIT_FALSE, // '0' + BIT_UNSET, // '?' + BIT_UNFILTERED // unfiltered +} bit_value_t; + +// Representation of the instruction to work on. +typedef std::vector insn_t; + +// These are states of our finite state machines used in FilterChooser's +// filterProcessor() which produces the filter candidates to use. +typedef enum { + ATTR_NONE, + ATTR_FILTERED, + ATTR_ALL_SET, + ATTR_ALL_UNSET, + ATTR_MIXED +} bitAttr_t; + +static const uint64_t NoFixedSegmentsSentinel = -1ULL; + +} // end namespace tblgen_decoder_emitter + +#endif // LLVM_UTILS_TABLEGEN_DECODEREMITTER_DECODEREMITTERTYPES_H Index: llvm/utils/TableGen/DecoderEmitter/Filter.cpp =================================================================== --- llvm/utils/TableGen/DecoderEmitter/Filter.cpp +++ llvm/utils/TableGen/DecoderEmitter/Filter.cpp @@ -19,8 +19,8 @@ Filter::Filter(Filter &&F) : Owner(F.Owner), StartBit(F.StartBit), NumBits(F.NumBits), Mixed(F.Mixed), - FilteredInstructions(std::move(F.FilteredInstructions)), - VariableInstructions(std::move(F.VariableInstructions)), + FilteredInstrSubsets(std::move(F.FilteredInstrSubsets)), + VariableInstrSubset(std::move(F.VariableInstrSubset)), FilterChooserMap(std::move(F.FilterChooserMap)), NumFiltered(F.NumFiltered), LastOpcFiltered(F.LastOpcFiltered) {} @@ -46,17 +46,17 @@ // The encoding bits are well-known. Lets add the uid of the // instruction into the bucket keyed off the constant field value. LastOpcFiltered = Owner.Opcodes[I]; - FilteredInstructions[Field].push_back(LastOpcFiltered); + FilteredInstrSubsets[Field].push_back(LastOpcFiltered); ++NumFiltered; } else { // Some of the encoding bit(s) are unspecified. This contributes to // one additional member of "Variable" instructions. - VariableInstructions.push_back(Owner.Opcodes[I]); + VariableInstrSubset.push_back(Owner.Opcodes[I]); } } - assert((FilteredInstructions.size() + VariableInstructions.size() > 0) && - "Filter returns no instruction categories"); + assert((FilteredInstrSubsets.size() + VariableInstrSubset.size() > 0) && + "Filter returns no instruction subsets."); } // Divides the decoding task into sub tasks and delegates them to the @@ -69,7 +69,7 @@ // Starts by inheriting our parent filter chooser's filter bit values. std::vector BitValueArray(Owner->FilterBitValues); - if (!VariableInstructions.empty()) { + if (!VariableInstrSubset.empty()) { // Conservatively marks each segment position as BIT_UNSET. for (unsigned BitIndex = 0; BitIndex < NumBits; ++BitIndex) BitValueArray[StartBit + BitIndex] = BIT_UNSET; @@ -78,8 +78,8 @@ // group of instructions whose segment values are variable. FilterChooserMap.insert(std::make_pair( NoFixedSegmentsSentinel, - std::make_unique(Owner->AllInstructions, - VariableInstructions, Owner->Operands, + std::make_unique(Owner->PI, Owner->AllInstructions, + VariableInstrSubset, Owner->Operands, BitValueArray, *Owner))); } @@ -91,21 +91,21 @@ } // Otherwise, create sub choosers. - for (const auto &Inst : FilteredInstructions) { + for (const auto &Subset : FilteredInstrSubsets) { // Marks all the segment positions with either BIT_TRUE or BIT_FALSE. for (unsigned BitIndex = 0; BitIndex < NumBits; ++BitIndex) { - if (Inst.first & (1ULL << BitIndex)) + if (Subset.first & (1ULL << BitIndex)) BitValueArray[StartBit + BitIndex] = BIT_TRUE; else BitValueArray[StartBit + BitIndex] = BIT_FALSE; } // Delegates to an inferior filter chooser for further processing on this - // category of instructions. + // subset of instructions. FilterChooserMap.insert(std::make_pair( - Inst.first, std::make_unique( - Owner->AllInstructions, Inst.second, Owner->Operands, - BitValueArray, *Owner))); + Subset.first, std::make_unique( + Owner->PI, Owner->AllInstructions, Subset.second, + Owner->Operands, BitValueArray, *Owner))); } } @@ -184,11 +184,11 @@ } // Returns the number of fanout produced by the filter. More fanout implies -// the filter distinguishes more categories of instructions. +// the filter distinguishes more subsets of instructions. unsigned Filter::usefulness() const { - if (!VariableInstructions.empty()) - return FilteredInstructions.size(); - return FilteredInstructions.size() + 1; + if (!VariableInstrSubset.empty()) + return FilteredInstrSubsets.size(); + return FilteredInstrSubsets.size() + 1; } } // end namespace tblgen_decoder_emitter Index: llvm/utils/TableGen/DecoderEmitter/FilterChooser.cpp =================================================================== --- llvm/utils/TableGen/DecoderEmitter/FilterChooser.cpp +++ llvm/utils/TableGen/DecoderEmitter/FilterChooser.cpp @@ -19,7 +19,7 @@ namespace tblgen_decoder_emitter { #define DEBUG_TYPE "decoder-emitter-FilterChooser" -STATISTIC(NumEncodingsSupported, "Number of encodings supported"); +STATISTIC(StatsNumEncodingsSupported, "Number of encodings supported"); // Populates the insn given the uid. void FilterChooser::insnWithID(insn_t &Insn, unsigned Opcode) const { @@ -168,67 +168,22 @@ return Num; } -void FilterChooser::emitBinaryParser(raw_ostream &O, unsigned &Indentation, - const OperandInfo &OpInfo, - bool &OpHasCompleteDecoder) const { - const std::string &Decoder = OpInfo.Decoder; - - bool const UseInsertBits = OpInfo.numFields() != 1 || OpInfo.InitValue != 0; - - if (UseInsertBits) { - O.indent(Indentation) << "tmp = 0x"; - O.write_hex(OpInfo.InitValue); - O << ";\n"; - } - - for (const EncodingField &EF : OpInfo) { - O.indent(Indentation); - if (UseInsertBits) - O << "insertBits(tmp, "; - else - O << "tmp = "; - O << "fieldFromInstruction(insn, " << EF.Base << ", " << EF.Width << ')'; - if (UseInsertBits) - O << ", " << EF.Offset << ", " << EF.Width << ')'; - else if (EF.Offset != 0) - O << " << " << EF.Offset; - O << ";\n"; - } - - if (Decoder != "") { - OpHasCompleteDecoder = OpInfo.HasCompleteDecoder; - O.indent(Indentation) << Emitter->GuardPrefix << Decoder - << "(MI, tmp, Address, Decoder)" - << Emitter->GuardPostfix << " { " - << (OpHasCompleteDecoder ? "" - : "DecodeComplete = false; ") - << "return MCDisassembler::Fail; }\n"; - } else { - OpHasCompleteDecoder = true; - O.indent(Indentation) << "MI.addOperand(MCOperand::createImm(tmp));\n"; - } -} - -void FilterChooser::emitDecoder(raw_ostream &OS, unsigned Indentation, - unsigned Opc, bool &HasCompleteDecoder) const { +void FilterChooser::emitDecoder(raw_ostream &DecoderOS, unsigned Opc, + bool &HasCompleteDecoder) const { HasCompleteDecoder = true; for (const auto &Op : Operands.find(Opc)->second) { // If a custom instruction decoder was specified, use that. if (Op.numFields() == 0 && !Op.Decoder.empty()) { HasCompleteDecoder = Op.HasCompleteDecoder; - OS.indent(Indentation) - << Emitter->GuardPrefix << Op.Decoder - << "(MI, insn, Address, Decoder)" << Emitter->GuardPostfix << " { " - << (HasCompleteDecoder ? "" : "DecodeComplete = false; ") - << "return MCDisassembler::Fail; }\n"; + PI.emitOpDecoder(DecoderOS, Op); break; } - bool OpHasCompleteDecoder; - emitBinaryParser(OS, Indentation, Op, OpHasCompleteDecoder); - if (!OpHasCompleteDecoder) - HasCompleteDecoder = false; + PI.emitOpBinaryParser(DecoderOS, Op); + + // If a custom decoder was set the flag decides otherwise its true. + HasCompleteDecoder = Op.Decoder != "" ? Op.HasCompleteDecoder : true; } } @@ -239,8 +194,7 @@ // FIXME: emitDecoder() function can take a buffer directly rather than // a stream. raw_svector_ostream S(Decoder); - unsigned const I = 4; - emitDecoder(S, I, Opc, HasCompleteDecoder); + emitDecoder(S, Opc, HasCompleteDecoder); // Using the full decoder string as the key value here is a bit // heavyweight, but is effective. If the string comparisons become a @@ -255,64 +209,6 @@ return (unsigned)(P - Decoders.begin()); } -// If ParenIfBinOp is true, print a surrounding () if Val uses && or ||. -bool FilterChooser::emitPredicateMatchAux(const Init &Val, bool ParenIfBinOp, - raw_ostream &OS) const { - if (auto *D = dyn_cast(&Val)) { - if (!D->getDef()->isSubClassOf("SubtargetFeature")) - return true; - OS << "Bits[" << Emitter->PredicateNamespace << "::" << D->getAsString() - << "]"; - return false; - } - if (auto *D = dyn_cast(&Val)) { - std::string const Op = D->getOperator()->getAsString(); - if (Op == "not" && D->getNumArgs() == 1) { - OS << '!'; - return emitPredicateMatchAux(*D->getArg(0), true, OS); - } - if ((Op == "any_of" || Op == "all_of") && D->getNumArgs() > 0) { - bool const Paren = - D->getNumArgs() > 1 && std::exchange(ParenIfBinOp, true); - if (Paren) - OS << '('; - ListSeparator LS(Op == "any_of" ? " || " : " && "); - for (auto *Arg : D->getArgs()) { - OS << LS; - if (emitPredicateMatchAux(*Arg, ParenIfBinOp, OS)) - return true; - } - if (Paren) - OS << ')'; - return false; - } - } - return true; -} - -bool FilterChooser::emitPredicateMatch(raw_ostream &O, unsigned &Indentation, - unsigned Opc) const { - ListInit *Predicates = - AllInstructions[Opc].EncodingDef->getValueAsListInit("Predicates"); - bool IsFirstEmission = true; - for (unsigned I = 0; I < Predicates->size(); ++I) { - Record *Pred = Predicates->getElementAsRecord(I); - if (!Pred->getValue("AssemblerMatcherPredicate")) - continue; - - if (!isa(Pred->getValue("AssemblerCondDag")->getValue())) - continue; - - if (!IsFirstEmission) - O << " && "; - if (emitPredicateMatchAux(*Pred->getValueAsDag("AssemblerCondDag"), - Predicates->size() > 1, O)) - PrintFatalError(Pred->getLoc(), "Invalid AssemblerCondDag!"); - IsFirstEmission = false; - } - return !Predicates->empty(); -} - bool FilterChooser::doesOpcodeNeedPredicate(unsigned Opc) const { ListInit *Predicates = AllInstructions[Opc].EncodingDef->getValueAsListInit("Predicates"); @@ -349,11 +245,10 @@ // Build up the predicate string. SmallString<256> Predicate; - // FIXME: emitPredicateMatch() functions can take a buffer directly rather - // than a stream. raw_svector_ostream PS(Predicate); - unsigned I = 0; - emitPredicateMatch(PS, I, Opc); + const ListInit *Predicates = + AllInstructions[Opc].EncodingDef->getValueAsListInit("Predicates"); + PI.emitPredicateMatch(PS, Predicates, Opc); // Figure out the index into the predicate table for the predicate just // computed. @@ -493,7 +388,7 @@ // can decode it. TableInfo.Table.push_back(HasCompleteDecoder ? MCD::OPC_Decode : MCD::OPC_TryDecode); - NumEncodingsSupported++; + StatsNumEncodingsSupported++; uint8_t Buffer[16], *P; encodeULEB128(Opc.Opcode, Buffer); for (P = Buffer; *P >= 128; ++P) Index: llvm/utils/TableGen/DecoderEmitter/HelperFunctions.cpp =================================================================== --- llvm/utils/TableGen/DecoderEmitter/HelperFunctions.cpp +++ llvm/utils/TableGen/DecoderEmitter/HelperFunctions.cpp @@ -525,274 +525,4 @@ return Bits.getNumBits(); } - -// emitFieldFromInstruction - Emit the templated helper function -// fieldFromInstruction(). -// On Windows we make sure that this function is not inlined when -// using the VS compiler. It has a bug which causes the function -// to be optimized out in some circustances. See llvm.org/pr38292 -void emitFieldFromInstruction(formatted_raw_ostream &OS) { - OS << "// Helper functions for extracting fields from encoded instructions.\n" - << "// InsnType must either be integral or an APInt-like object that " - "must:\n" - << "// * be default-constructible and copy-constructible\n" - << "// * be constructible from an APInt (this can be private)\n" - << "// * Support insertBits(bits, startBit, numBits)\n" - << "// * Support extractBitsAsZExtValue(numBits, startBit)\n" - << "// * Support the ~, &, ==, and != operators with other objects of " - "the same type\n" - << "// * Support the != and bitwise & with uint64_t\n" - << "// * Support put (<<) to raw_ostream&\n" - << "template \n" - << "#if defined(_MSC_VER) && !defined(__clang__)\n" - << "__declspec(noinline)\n" - << "#endif\n" - << "static std::enable_if_t::value, InsnType>\n" - << "fieldFromInstruction(const InsnType &insn, unsigned startBit,\n" - << " unsigned numBits) {\n" - << " assert(startBit + numBits <= 64 && \"Cannot support >64-bit " - "extractions!\");\n" - << " assert(startBit + numBits <= (sizeof(InsnType) * 8) &&\n" - << " \"Instruction field out of bounds!\");\n" - << " InsnType fieldMask;\n" - << " if (numBits == sizeof(InsnType) * 8)\n" - << " fieldMask = (InsnType)(-1LL);\n" - << " else\n" - << " fieldMask = (((InsnType)1 << numBits) - 1) << startBit;\n" - << " return (insn & fieldMask) >> startBit;\n" - << "}\n" - << "\n" - << "template \n" - << "static std::enable_if_t::value, " - "uint64_t>\n" - << "fieldFromInstruction(const InsnType &insn, unsigned startBit,\n" - << " unsigned numBits) {\n" - << " return insn.extractBitsAsZExtValue(numBits, startBit);\n" - << "}\n\n"; -} - -// emitInsertBits - Emit the templated helper function insertBits(). -void emitInsertBits(formatted_raw_ostream &OS) { - OS << "// Helper function for inserting bits extracted from an encoded " - "instruction into\n" - << "// a field.\n" - << "template \n" - << "static std::enable_if_t::value>\n" - << "insertBits(InsnType &field, InsnType bits, unsigned startBit, " - "unsigned numBits) {\n" - << " assert(startBit + numBits <= sizeof field * 8);\n" - << " field |= (InsnType)bits << startBit;\n" - << "}\n" - << "\n" - << "template \n" - << "static std::enable_if_t::value>\n" - << "insertBits(InsnType &field, uint64_t bits, unsigned startBit, " - "unsigned numBits) {\n" - << " field.insertBits(bits, startBit, numBits);\n" - << "}\n\n"; -} - -// emitDecodeInstruction - Emit the templated helper function -// decodeInstruction(). -void emitDecodeInstruction(formatted_raw_ostream &OS, bool IsVarLenInst) { - OS << "template \n" - << "static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], " - "MCInst &MI,\n" - << " InsnType insn, uint64_t " - "Address,\n" - << " const MCDisassembler *DisAsm,\n" - << " const MCSubtargetInfo &STI"; - if (IsVarLenInst) { - OS << ",\n" - << " llvm::function_ref makeUp"; - } - OS << ") {\n" - << " const FeatureBitset &Bits = STI.getFeatureBits();\n" - << "\n" - << " const uint8_t *Ptr = DecodeTable;\n" - << " uint64_t CurFieldValue = 0;\n" - << " DecodeStatus S = MCDisassembler::Success;\n" - << " while (true) {\n" - << " ptrdiff_t Loc = Ptr - DecodeTable;\n" - << " switch (*Ptr) {\n" - << " default:\n" - << " errs() << Loc << \": Unexpected decode table opcode!\\n\";\n" - << " return MCDisassembler::Fail;\n" - << " case MCD::OPC_ExtractField: {\n" - << " unsigned Start = *++Ptr;\n" - << " unsigned Len = *++Ptr;\n" - << " ++Ptr;\n"; - if (IsVarLenInst) - OS << " makeUp(insn, Start + Len);\n"; - OS << " CurFieldValue = fieldFromInstruction(insn, Start, Len);\n" - << " LLVM_DEBUG(dbgs() << Loc << \": OPC_ExtractField(\" << Start << " - "\", \"\n" - << " << Len << \"): \" << CurFieldValue << \"\\n\");\n" - << " break;\n" - << " }\n" - << " case MCD::OPC_FilterValue: {\n" - << " // Decode the field value.\n" - << " unsigned Len;\n" - << " uint64_t Val = decodeULEB128(++Ptr, &Len);\n" - << " Ptr += Len;\n" - << " // NumToSkip is a plain 24-bit integer.\n" - << " unsigned NumToSkip = *Ptr++;\n" - << " NumToSkip |= (*Ptr++) << 8;\n" - << " NumToSkip |= (*Ptr++) << 16;\n" - << "\n" - << " // Perform the filter operation.\n" - << " if (Val != CurFieldValue)\n" - << " Ptr += NumToSkip;\n" - << " LLVM_DEBUG(dbgs() << Loc << \": OPC_FilterValue(\" << Val << " - "\", \" << NumToSkip\n" - << " << \"): \" << ((Val != CurFieldValue) ? \"FAIL:\" " - ": \"PASS:\")\n" - << " << \" continuing at \" << (Ptr - DecodeTable) << " - "\"\\n\");\n" - << "\n" - << " break;\n" - << " }\n" - << " case MCD::OPC_CheckField: {\n" - << " unsigned Start = *++Ptr;\n" - << " unsigned Len = *++Ptr;\n"; - if (IsVarLenInst) - OS << " makeUp(insn, Start + Len);\n"; - OS << " uint64_t FieldValue = fieldFromInstruction(insn, Start, Len);\n" - << " // Decode the field value.\n" - << " unsigned PtrLen = 0;\n" - << " uint64_t ExpectedValue = decodeULEB128(++Ptr, &PtrLen);\n" - << " Ptr += PtrLen;\n" - << " // NumToSkip is a plain 24-bit integer.\n" - << " unsigned NumToSkip = *Ptr++;\n" - << " NumToSkip |= (*Ptr++) << 8;\n" - << " NumToSkip |= (*Ptr++) << 16;\n" - << "\n" - << " // If the actual and expected values don't match, skip.\n" - << " if (ExpectedValue != FieldValue)\n" - << " Ptr += NumToSkip;\n" - << " LLVM_DEBUG(dbgs() << Loc << \": OPC_CheckField(\" << Start << " - "\", \"\n" - << " << Len << \", \" << ExpectedValue << \", \" << " - "NumToSkip\n" - << " << \"): FieldValue = \" << FieldValue << \", " - "ExpectedValue = \"\n" - << " << ExpectedValue << \": \"\n" - << " << ((ExpectedValue == FieldValue) ? \"PASS\\n\" : " - "\"FAIL\\n\"));\n" - << " break;\n" - << " }\n" - << " case MCD::OPC_CheckPredicate: {\n" - << " unsigned Len;\n" - << " // Decode the Predicate Index value.\n" - << " unsigned PIdx = decodeULEB128(++Ptr, &Len);\n" - << " Ptr += Len;\n" - << " // NumToSkip is a plain 24-bit integer.\n" - << " unsigned NumToSkip = *Ptr++;\n" - << " NumToSkip |= (*Ptr++) << 8;\n" - << " NumToSkip |= (*Ptr++) << 16;\n" - << " // Check the predicate.\n" - << " bool Pred;\n" - << " if (!(Pred = checkDecoderPredicate(PIdx, Bits)))\n" - << " Ptr += NumToSkip;\n" - << " (void)Pred;\n" - << " LLVM_DEBUG(dbgs() << Loc << \": OPC_CheckPredicate(\" << PIdx " - "<< \"): \"\n" - << " << (Pred ? \"PASS\\n\" : \"FAIL\\n\"));\n" - << "\n" - << " break;\n" - << " }\n" - << " case MCD::OPC_Decode: {\n" - << " unsigned Len;\n" - << " // Decode the Opcode value.\n" - << " unsigned Opc = decodeULEB128(++Ptr, &Len);\n" - << " Ptr += Len;\n" - << " unsigned DecodeIdx = decodeULEB128(Ptr, &Len);\n" - << " Ptr += Len;\n" - << "\n" - << " MI.clear();\n" - << " MI.setOpcode(Opc);\n" - << " bool DecodeComplete;\n"; - if (IsVarLenInst) { - OS << " Len = InstrLenTable[Opc];\n" - << " makeUp(insn, Len);\n"; - } - OS << " S = decodeToMCInst(S, DecodeIdx, insn, MI, Address, DisAsm, " - "DecodeComplete);\n" - << " assert(DecodeComplete);\n" - << "\n" - << " LLVM_DEBUG(dbgs() << Loc << \": OPC_Decode: opcode \" << Opc\n" - << " << \", using decoder \" << DecodeIdx << \": \"\n" - << " << (S != MCDisassembler::Fail ? \"PASS\" : " - "\"FAIL\") << \"\\n\");\n" - << " return S;\n" - << " }\n" - << " case MCD::OPC_TryDecode: {\n" - << " unsigned Len;\n" - << " // Decode the Opcode value.\n" - << " unsigned Opc = decodeULEB128(++Ptr, &Len);\n" - << " Ptr += Len;\n" - << " unsigned DecodeIdx = decodeULEB128(Ptr, &Len);\n" - << " Ptr += Len;\n" - << " // NumToSkip is a plain 24-bit integer.\n" - << " unsigned NumToSkip = *Ptr++;\n" - << " NumToSkip |= (*Ptr++) << 8;\n" - << " NumToSkip |= (*Ptr++) << 16;\n" - << "\n" - << " // Perform the decode operation.\n" - << " MCInst TmpMI;\n" - << " TmpMI.setOpcode(Opc);\n" - << " bool DecodeComplete;\n" - << " S = decodeToMCInst(S, DecodeIdx, insn, TmpMI, Address, DisAsm, " - "DecodeComplete);\n" - << " LLVM_DEBUG(dbgs() << Loc << \": OPC_TryDecode: opcode \" << " - "Opc\n" - << " << \", using decoder \" << DecodeIdx << \": \");\n" - << "\n" - << " if (DecodeComplete) {\n" - << " // Decoding complete.\n" - << " LLVM_DEBUG(dbgs() << (S != MCDisassembler::Fail ? \"PASS\" : " - "\"FAIL\") << \"\\n\");\n" - << " MI = TmpMI;\n" - << " return S;\n" - << " } else {\n" - << " assert(S == MCDisassembler::Fail);\n" - << " // If the decoding was incomplete, skip.\n" - << " Ptr += NumToSkip;\n" - << " LLVM_DEBUG(dbgs() << \"FAIL: continuing at \" << (Ptr - " - "DecodeTable) << \"\\n\");\n" - << " // Reset decode status. This also drops a SoftFail status " - "that could be\n" - << " // set before the decode attempt.\n" - << " S = MCDisassembler::Success;\n" - << " }\n" - << " break;\n" - << " }\n" - << " case MCD::OPC_SoftFail: {\n" - << " // Decode the mask values.\n" - << " unsigned Len;\n" - << " uint64_t PositiveMask = decodeULEB128(++Ptr, &Len);\n" - << " Ptr += Len;\n" - << " uint64_t NegativeMask = decodeULEB128(Ptr, &Len);\n" - << " Ptr += Len;\n" - << " bool Fail = (insn & PositiveMask) != 0 || (~insn & " - "NegativeMask) != 0;\n" - << " if (Fail)\n" - << " S = MCDisassembler::SoftFail;\n" - << " LLVM_DEBUG(dbgs() << Loc << \": OPC_SoftFail: \" << (Fail ? " - "\"FAIL\\n\" : \"PASS\\n\"));\n" - << " break;\n" - << " }\n" - << " case MCD::OPC_Fail: {\n" - << " LLVM_DEBUG(dbgs() << Loc << \": OPC_Fail\\n\");\n" - << " return MCDisassembler::Fail;\n" - << " }\n" - << " }\n" - << " }\n" - << " llvm_unreachable(\"bogosity detected in disassembler state " - "machine!\");\n" - << "}\n\n"; -} - } // end namespace tblgen_decoder_emitter Index: llvm/utils/TableGen/DecoderEmitter/Printer.h =================================================================== --- /dev/null +++ llvm/utils/TableGen/DecoderEmitter/Printer.h @@ -0,0 +1,155 @@ +//===----------- PrinterInterface.h - Decoder Generator ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_UTILS_TABLEGEN_DECODEREMITTER_PRINTERINTERFACE_H +#define LLVM_UTILS_TABLEGEN_DECODEREMITTER_PRINTERINTERFACE_H + +#include "DecoderEmitterTypes.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace llvm; +namespace tblgen_decoder_emitter { + +/// Interface for printing the generated decoder. +/// Every string which will be in the generated code originates from here. +/// This class has methods for the FilterChooser class and the DecoderEmitter +/// class. +/// +/// The methods meant for the FilterChooser are used to generate the decoder +/// source code. The strings for these decoders are directly written to the +/// final out stream but assembled by the FilterChooser. +/// +/// The methods for the DecoderEmitter exclusively write to the final output +/// stream. +class PrinterInterface { + + friend class PrinterLLVM; + friend class PrinterCapstone; + +private: + formatted_raw_ostream &OS; + std::string TargetName; + std::string PredicateNamespace; + std::string GuardPrefix, GuardPostfix; + std::string ReturnOK, ReturnFail; + std::string Locals; + +public: + PrinterInterface(formatted_raw_ostream &OS, std::string PredicateNamespace, + std::string GPrefix, std::string GPostfix, std::string ROK, + std::string RFail, std::string L, std::string Target); + + virtual ~PrinterInterface(); + + virtual void flushOS() const; + + // + // FilterChooser printing + // + + virtual void emitOpDecoder(raw_ostream &DecoderOS, + const OperandInfo &Op) const = 0; + virtual void emitOpBinaryParser(raw_ostream &DecoderOS, + const OperandInfo &OpInfo) const = 0; + virtual bool emitPredicateMatchAux(const Init &Val, bool ParenIfBinOp, + raw_ostream &PredOS) const = 0; + // Emits code to check the Predicates member of an instruction are true. + // Returns true if predicate matches were emitted, false otherwise. + virtual bool emitPredicateMatch(raw_ostream &PredOS, + const ListInit *Predicates, + unsigned Opc) const = 0; + + // + // DecoderEmitter printing + // + virtual void emitFieldFromInstruction() const = 0; + virtual void emitInsertBits() const = 0; + virtual void emitDecodeInstruction(bool IsVarLenInst) const = 0; + // Emit the decoder state machine table. + virtual void + emitTable(DecoderTable &Table, unsigned BitWidth, StringRef Namespace, + std::vector NumberedEncodings) const = 0; + virtual void emitInstrLenTable(std::vector &InstrLen) const = 0; + virtual void emitPredicateFunction(PredicateSet &Predicates, + unsigned Indentation) const = 0; + virtual void emitDecoderFunction(DecoderSet &Decoders, + unsigned Indentation) const = 0; + virtual void emitIncludes() const = 0; + virtual void emitNamespaceBegin(std::string const &Namespace) const = 0; + virtual void emitNamespaceEnd(std::string const &Namespace) const = 0; + virtual void emitSourceFileHeader() const = 0; +}; + +// +// Printer Implementation classes +// + +class PrinterLLVM : public PrinterInterface { +public: + using PrinterInterface::PrinterInterface; + + virtual void emitOpDecoder(raw_ostream &DecoderOS, + const OperandInfo &Op) const override; + virtual void emitOpBinaryParser(raw_ostream &DecoderOS, + const OperandInfo &OpInfo) const override; + virtual bool emitPredicateMatchAux(const Init &Val, bool ParenIfBinOp, + raw_ostream &OS) const override; + virtual bool emitPredicateMatch(raw_ostream &PredOS, + const ListInit *Predicates, + unsigned Opc) const override; + virtual void emitFieldFromInstruction() const override; + virtual void emitInsertBits() const override; + virtual void emitDecodeInstruction(bool IsVarLenInst) const override; + virtual void + emitTable(DecoderTable &Table, unsigned BitWidth, StringRef Namespace, + std::vector NumberedEncodings) const override; + virtual void + emitInstrLenTable(std::vector &InstrLen) const override; + virtual void emitPredicateFunction(PredicateSet &Predicates, + unsigned Indentation) const override; + virtual void emitDecoderFunction(DecoderSet &Decoders, + unsigned Indentation) const override; + virtual void emitIncludes() const override; + virtual void emitNamespaceBegin(std::string const &Namespace) const override; + virtual void emitNamespaceEnd(std::string const &Namespace) const override; + virtual void emitSourceFileHeader() const override; +}; + +class PrinterCapstone : public PrinterInterface { +public: + using PrinterInterface::PrinterInterface; + + virtual void emitOpDecoder(raw_ostream &DecoderOS, + const OperandInfo &Op) const override; + virtual void emitOpBinaryParser(raw_ostream &DecoderOS, + const OperandInfo &OpInfo) const override; + virtual bool emitPredicateMatchAux(const Init &Val, bool ParenIfBinOp, + raw_ostream &OS) const override; + virtual bool emitPredicateMatch(raw_ostream &PredOS, + const ListInit *Predicates, + unsigned Opc) const override; + virtual void emitFieldFromInstruction() const override; + virtual void emitInsertBits() const override; + virtual void emitDecodeInstruction(bool IsVarLenInst) const override; + virtual void + emitTable(DecoderTable &Table, unsigned BitWidth, StringRef Namespace, + std::vector NumberedEncodings) const override; + virtual void + emitInstrLenTable(std::vector &InstrLen) const override; + virtual void emitPredicateFunction(PredicateSet &Predicates, + unsigned Indentation) const override; + virtual void emitDecoderFunction(DecoderSet &Decoders, + unsigned Indentation) const override; + virtual void emitIncludes() const override; + virtual void emitNamespaceBegin(std::string const &Namespace) const override; + virtual void emitNamespaceEnd(std::string const &Namespace) const override; + virtual void emitSourceFileHeader() const override; +}; + +} // end namespace tblgen_decoder_emitter +#endif // LLVM_UTILS_TABLEGEN_DECODEREMITTER_PRINTERINTERFACE_H Index: llvm/utils/TableGen/DecoderEmitter/PrinterCapstone.cpp =================================================================== --- /dev/null +++ llvm/utils/TableGen/DecoderEmitter/PrinterCapstone.cpp @@ -0,0 +1,564 @@ +//===------------- PrinterCapstone.cpp - Printer Capstone -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Emits the generated decoder C++ code for the LLVM disassembler. +// +//===----------------------------------------------------------------------===// + +#include "Printer.h" + +using namespace llvm; +namespace tblgen_decoder_emitter { + +void PrinterCapstone::emitOpDecoder(raw_ostream &DecoderOS, + const OperandInfo &Op) const { + unsigned const Indent = 4; + DecoderOS.indent(Indent) << GuardPrefix << Op.Decoder + << "(MI, insn, Address, Decoder)" << GuardPostfix + << " { " + << (Op.HasCompleteDecoder + ? "" + : "DecodeComplete = false; ") + << "return " << ReturnFail << "; } \\\n"; +} + +void PrinterCapstone::emitOpBinaryParser(raw_ostream &DecOS, + const OperandInfo &OpInfo) const { + unsigned const Indent = 4; + const std::string &Decoder = OpInfo.Decoder; + + bool const UseInsertBits = OpInfo.numFields() != 1 || OpInfo.InitValue != 0; + + if (UseInsertBits) { + DecOS.indent(Indent) << "tmp = "; + DecOS.write_hex(OpInfo.InitValue); + DecOS << "; \\\n"; + } + + for (const EncodingField &EF : OpInfo) { + DecOS.indent(Indent); + if (UseInsertBits) + DecOS << "tmp |= "; + else + DecOS << "tmp = "; + DecOS << "fieldname(insn, " << EF.Base << ", " << EF.Width << ')'; + if (UseInsertBits) + DecOS << " << " << EF.Offset; + else if (EF.Offset != 0) + DecOS << " << " << EF.Offset; + DecOS << "; \\\n"; + } + + if (Decoder != "") { + DecOS.indent(Indent) << GuardPrefix << Decoder + << "(MI, tmp, Address, Decoder)" << GuardPostfix + << " { " + << (OpInfo.HasCompleteDecoder + ? "" + : "DecodeComplete = false; ") + << "return " << ReturnFail << "; } \\\n"; + } else { + DecOS.indent(Indent) << "MCOperand_CreateImm0(MI, tmp); \\\n"; + } +} + +bool PrinterCapstone::emitPredicateMatchAux(const Init &Val, bool ParenIfBinOp, + raw_ostream &PredOS) const { + if (auto *D = dyn_cast(&Val)) { + if (!D->getDef()->isSubClassOf("SubtargetFeature")) + return true; + PredOS << PredicateNamespace << "_getFeatureBits(MI->csh->mode, " + << PredicateNamespace << "_" << D->getAsString() << ")"; + return false; + } + if (auto *D = dyn_cast(&Val)) { + std::string const Op = D->getOperator()->getAsString(); + if (Op == "not" && D->getNumArgs() == 1) { + PredOS << '!'; + return emitPredicateMatchAux(*D->getArg(0), true, PredOS); + } + if ((Op == "any_of" || Op == "all_of") && D->getNumArgs() > 0) { + bool const Paren = + D->getNumArgs() > 1 && std::exchange(ParenIfBinOp, true); + if (Paren) + PredOS << '('; + ListSeparator LS(Op == "any_of" ? " || " : " && "); + for (auto *Arg : D->getArgs()) { + PredOS << LS; + if (emitPredicateMatchAux(*Arg, ParenIfBinOp, PredOS)) + return true; + } + if (Paren) + PredOS << ')'; + return false; + } + } + return true; +} + +bool PrinterCapstone::emitPredicateMatch(raw_ostream &PredOS, + const ListInit *Predicates, + unsigned Opc) const { + bool IsFirstEmission = true; + for (unsigned I = 0; I < Predicates->size(); ++I) { + Record *Pred = Predicates->getElementAsRecord(I); + if (!Pred->getValue("AssemblerMatcherPredicate")) + continue; + + if (!isa(Pred->getValue("AssemblerCondDag")->getValue())) + continue; + + if (!IsFirstEmission) + PredOS << " && "; + if (emitPredicateMatchAux(*Pred->getValueAsDag("AssemblerCondDag"), + Predicates->size() > 1, PredOS)) + PrintFatalError(Pred->getLoc(), "Invalid AssemblerCondDag!"); + IsFirstEmission = false; + } + return !Predicates->empty(); +} + +void PrinterCapstone::emitFieldFromInstruction() const { + OS << "// Helper function for extracting fields from encoded instructions.\n" + << "#define FieldFromInstruction(fname, InsnType) \\\n" + << "static InsnType fname(InsnType insn, unsigned startBit, unsigned " + "numBits) \\\n" + << "{ \\\n" + << " InsnType fieldMask; \\\n" + << " if (numBits == sizeof(InsnType) * 8) \\\n" + << " fieldMask = (InsnType)(-1LL); \\\n" + << " else \\\n" + << " fieldMask = (((InsnType)1 << numBits) - 1) << startBit; \\\n" + << " return (insn & fieldMask) >> startBit; \\\n" + << "}\n\n"; +} + +void PrinterCapstone::emitInsertBits() const { return; } + +void PrinterCapstone::emitDecodeInstruction(bool IsVarLenInst) const { + OS << "#define DecodeInstruction(fname, fieldname, decoder, InsnType) \\\n" + << "static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], " + "MCInst &MI, \\\n" + << " InsnType insn, uint64_t " + "Address) { \\\n" + << " const uint8_t *Ptr = DecodeTable; \\\n" + << " uint64_t CurFieldValue = 0; \\\n" + << " DecodeStatus S = MCDisassembler_Success; \\\n" + << " while (true) { \\\n" + << " ptrdiff_t Loc = Ptr - DecodeTable; \\\n" + << " switch (*Ptr) { \\\n" + << " default: \\\n" + << " errs() << Loc << \": Unexpected decode table opcode!\\n\"; \\\n" + << " return MCDisassembler_Fail; \\\n" + << " case MCD_OPC_ExtractField: { \\\n" + << " unsigned Start = *++Ptr; \\\n" + << " unsigned Len = *++Ptr; \\\n" + << " ++Ptr; \\\n"; + if (IsVarLenInst) { + OS << " makeUp(insn, Start + Len); \\\n"; + } + OS << " CurFieldValue = fieldname(insn, Start, Len); \\\n" + << " break; \\\n" + << " } \\\n" + << " case MCD_OPC_FilterValue: { \\\n" + << " /* Decode the field value. */ \\\n" + << " unsigned Len; \\\n" + << " uint64_t Val = decodeULEB128(++Ptr, &Len); \\\n" + << " Ptr += Len; \\\n" + << " /* NumToSkip is a plain 24-bit integer. */ \\\n" + << " unsigned NumToSkip = *Ptr++; \\\n" + << " NumToSkip |= (*Ptr++) << 8; \\\n" + << " NumToSkip |= (*Ptr++) << 16; \\\n" + << " /* Perform the filter operation. */ \\\n" + << " if (Val != CurFieldValue) \\\n" + << " Ptr += NumToSkip; \\\n" + << " break; \\\n" + << " } \\\n" + << " case MCD_OPC_CheckField: { \\\n" + << " unsigned Start = *++Ptr; \\\n" + << " unsigned Len = *++Ptr; \\\n"; + if (IsVarLenInst) { + OS << " makeUp(insn, Start + Len); \\\n"; + } + OS << " uint64_t FieldValue = fieldname(insn, Start, Len); " + "\\\n" + << " /* Decode the field value. */ \\\n" + << " unsigned PtrLen = 0; \\\n" + << " uint64_t ExpectedValue = decodeULEB128(++Ptr, &PtrLen); \\\n" + << " Ptr += PtrLen; \\\n" + << " /* NumToSkip is a plain 24-bit integer. */ \\\n" + << " unsigned NumToSkip = *Ptr++; \\\n" + << " NumToSkip |= (*Ptr++) << 8; \\\n" + << " NumToSkip |= (*Ptr++) << 16; \\\n" + << " /* If the actual and expected values don't match, skip. */ \\\n" + << " if (ExpectedValue != FieldValue) \\\n" + << " Ptr += NumToSkip; \\\n" + << " break; \\\n" + << " } \\\n" + << " case MCD_OPC_CheckPredicate: { \\\n" + << " unsigned Len; \\\n" + << " /* Decode the Predicate Index value. */ \\\n" + << " unsigned PIdx = decodeULEB128(++Ptr, &Len); \\\n" + << " Ptr += Len; \\\n" + << " /* NumToSkip is a plain 24-bit integer. */ \\\n" + << " unsigned NumToSkip = *Ptr++; \\\n" + << " NumToSkip |= (*Ptr++) << 8; \\\n" + << " NumToSkip |= (*Ptr++) << 16; \\\n" + << " /* Check the predicate. */ \\\n" + << " bool Pred; \\\n" + << " if (!(Pred = checkDecoderPredicate(PIdx, Bits))) \\\n" + << " Ptr += NumToSkip; \\\n" + << " (void)Pred; \\\n" + << " break; \\\n" + << " } \\\n" + << " case MCD_OPC_Decode: { \\\n" + << " unsigned Len; \\\n" + << " /* Decode the Opcode value. */ \\\n" + << " unsigned Opc = decodeULEB128(++Ptr, &Len); \\\n" + << " Ptr += Len; \\\n" + << " unsigned DecodeIdx = decodeULEB128(Ptr, &Len); \\\n" + << " Ptr += Len; \\\n" + << " MCInst_clear(MI); \\\n" + << " MCInst_setOpcode(MI, Opc); \\\n" + << " bool DecodeComplete; \\\n"; + if (IsVarLenInst) { + OS << " Len = InstrLenTable[Opc]; \\\n" + << " makeUp(insn, Len); \\\n"; + } + OS << " S = decoder(S, DecodeIdx, insn, MI, Address, " + "&DecodeComplete); \\\n" + << " return S; \\\n" + << " } \\\n" + << " case MCD_OPC_TryDecode: { \\\n" + << " unsigned Len; \\\n" + << " /* Decode the Opcode value. */ \\\n" + << " unsigned Opc = decodeULEB128(++Ptr, &Len); \\\n" + << " Ptr += Len; \\\n" + << " unsigned DecodeIdx = decodeULEB128(Ptr, &Len); \\\n" + << " Ptr += Len; \\\n" + << " /* NumToSkip is a plain 24-bit integer. */ \\\n" + << " unsigned NumToSkip = *Ptr++; \\\n" + << " NumToSkip |= (*Ptr++) << 8; \\\n" + << " NumToSkip |= (*Ptr++) << 16; \\\n" + << " /* Perform the decode operation. */ \\\n" + << " MCInst_setOpcode(MI, Opc); \\\n" + << " bool DecodeComplete; \\\n" + << " S = decoder(S, DecodeIdx, insn, MI, Address, " + << "&DecodeComplete); \\\n" + << " if (DecodeComplete) { \\\n" + << " /* Decoding complete. */ \\\n" + << " return S; \\\n" + << " } else { \\\n" + << " /* If the decoding was incomplete, skip. */ \\\n" + << " Ptr += NumToSkip; \\\n" + << " /* Reset decode status. This also drops a SoftFail status " + "that could be */ \\\n" + << " /* set before the decode attempt. */ \\\n" + << " S = MCDisassembler_Success; \\\n" + << " } \\\n" + << " break; \\\n" + << " } \\\n" + << " case MCD_OPC_SoftFail: { \\\n" + << " /* Decode the mask values. */ \\\n" + << " unsigned Len; \\\n" + << " uint64_t PositiveMask = decodeULEB128(++Ptr, &Len); \\\n" + << " Ptr += Len; \\\n" + << " uint64_t NegativeMask = decodeULEB128(Ptr, &Len); \\\n" + << " Ptr += Len; \\\n" + << " bool Fail = (insn & PositiveMask) != 0 || (~insn & " + "NegativeMask) != 0; \\\n" + << " if (Fail) \\\n" + << " S = MCDisassembler_SoftFail; \\\n" + << " break; \\\n" + << " } \\\n" + << " case MCD_OPC_Fail: { \\\n" + << " return MCDisassembler_Fail; \\\n" + << " } \\\n" + << " } \\\n" + << " } \\\n" + << " /* Bogisity detected in disassembler state machine! */ \\\n" + << "}\n\n"; + OS << "FieldFromInstruction(fieldFromInstruction_2, uint16_t)\n" + << "DecodeToMCInst(decodeToMCInst_2, fieldFromInstruction_2, uint16_t)\n" + << "DecodeInstruction(decodeInstruction_2, fieldFromInstruction_2, " + "decodeToMCInst_2, uint16_t)\n" + << "\n" + << "FieldFromInstruction(fieldFromInstruction_4, uint32_t)\n" + << "DecodeToMCInst(decodeToMCInst_4, fieldFromInstruction_4, uint32_t)\n" + << "DecodeInstruction(decodeInstruction_4, fieldFromInstruction_4, " + "decodeToMCInst_4, uint32_t)\n"; +} + +void PrinterCapstone::emitTable( + DecoderTable &Table, unsigned BitWidth, StringRef Namespace, + std::vector NumberedEncodings) const { + unsigned Indent = 0; + OS.indent(Indent) << "static const uint8_t DecoderTable" << Namespace + << BitWidth << "[] = {\n"; + + Indent += 2; + + // FIXME: We may be able to use the NumToSkip values to recover + // appropriate indentation levels. + DecoderTable::const_iterator I = Table.begin(); + DecoderTable::const_iterator const E = Table.end(); + while (I != E) { + assert(I < E && "incomplete decode table entry!"); + + uint64_t const Pos = I - Table.begin(); + OS << "/* " << Pos << " */"; + OS.PadToColumn(12); + + switch (*I) { + default: + PrintFatalError("invalid decode table opcode"); + case MCD::OPC_ExtractField: { + ++I; + unsigned const Start = *I++; + unsigned const Len = *I++; + OS.indent(Indent) << "MCD_OPC_ExtractField, " << Start << ", " << Len + << ", // Inst{"; + if (Len > 1) + OS << (Start + Len - 1) << "-"; + OS << Start << "} ...\n"; + break; + } + case MCD::OPC_FilterValue: { + ++I; + OS.indent(Indent) << "MCD_OPC_FilterValue, "; + // The filter value is ULEB128 encoded. + while (*I >= 128) + OS << (unsigned)*I++ << ", "; + OS << (unsigned)*I++ << ", "; + + // 24-bit numtoskip value. + uint8_t Byte = *I++; + uint32_t NumToSkip = Byte; + OS << (unsigned)Byte << ", "; + Byte = *I++; + OS << (unsigned)Byte << ", "; + NumToSkip |= Byte << 8; + Byte = *I++; + OS << utostr(Byte) << ", "; + NumToSkip |= Byte << 16; + OS << "// Skip to: " << ((I - Table.begin()) + NumToSkip) << "\n"; + break; + } + case MCD::OPC_CheckField: { + ++I; + unsigned const Start = *I++; + unsigned const Len = *I++; + OS.indent(Indent) << "MCD_OPC_CheckField, " << Start << ", " << Len + << ", "; // << Val << ", " << NumToSkip << ",\n"; + // ULEB128 encoded field value. + for (; *I >= 128; ++I) + OS << (unsigned)*I << ", "; + OS << (unsigned)*I++ << ", "; + // 24-bit numtoskip value. + uint8_t Byte = *I++; + uint32_t NumToSkip = Byte; + OS << (unsigned)Byte << ", "; + Byte = *I++; + OS << (unsigned)Byte << ", "; + NumToSkip |= Byte << 8; + Byte = *I++; + OS << utostr(Byte) << ", "; + NumToSkip |= Byte << 16; + OS << "// Skip to: " << ((I - Table.begin()) + NumToSkip) << "\n"; + break; + } + case MCD::OPC_CheckPredicate: { + ++I; + OS.indent(Indent) << "MCD_OPC_CheckPredicate, "; + for (; *I >= 128; ++I) + OS << (unsigned)*I << ", "; + OS << (unsigned)*I++ << ", "; + + // 24-bit numtoskip value. + uint8_t Byte = *I++; + uint32_t NumToSkip = Byte; + OS << (unsigned)Byte << ", "; + Byte = *I++; + OS << (unsigned)Byte << ", "; + NumToSkip |= Byte << 8; + Byte = *I++; + OS << utostr(Byte) << ", "; + NumToSkip |= Byte << 16; + OS << "// Skip to: " << ((I - Table.begin()) + NumToSkip) << "\n"; + break; + } + case MCD::OPC_Decode: + case MCD::OPC_TryDecode: { + bool const IsTry = *I == MCD::OPC_TryDecode; + ++I; + // Extract the ULEB128 encoded Opcode to a buffer. + uint8_t Buffer[16], *P = Buffer; + while ((*P++ = *I++) >= 128) + assert((P - Buffer) <= (ptrdiff_t)sizeof(Buffer) && + "ULEB128 value too large!"); + // Decode the Opcode value. + unsigned const Opc = decodeULEB128(Buffer); + OS.indent(Indent) << "MCD_OPC_" << (IsTry ? "Try" : "") << "Decode, "; + for (P = Buffer; *P >= 128; ++P) + OS << (unsigned)*P << ", "; + OS << (unsigned)*P << ", "; + + // Decoder index. + for (; *I >= 128; ++I) + OS << (unsigned)*I << ", "; + OS << (unsigned)*I++ << ", "; + + if (!IsTry) { + OS << "// Opcode: " << NumberedEncodings[Opc] << "\n"; + break; + } + + // Fallthrough for OPC_TryDecode. + + // 24-bit numtoskip value. + uint8_t Byte = *I++; + uint32_t NumToSkip = Byte; + OS << (unsigned)Byte << ", "; + Byte = *I++; + OS << (unsigned)Byte << ", "; + NumToSkip |= Byte << 8; + Byte = *I++; + OS << utostr(Byte) << ", "; + NumToSkip |= Byte << 16; + + OS << "// Opcode: " << NumberedEncodings[Opc] + << ", skip to: " << ((I - Table.begin()) + NumToSkip) << "\n"; + break; + } + case MCD::OPC_SoftFail: { + ++I; + OS.indent(Indent) << "MCD_OPC_SoftFail"; + // Positive mask + uint64_t Value = 0; + unsigned Shift = 0; + do { + OS << ", " << (unsigned)*I; + Value += (*I & 0x7f) << Shift; + Shift += 7; + } while (*I++ >= 128); + if (Value > 127) { + OS << " /* 0x"; + OS.write_hex(Value); + OS << " */"; + } + // Negative mask + Value = 0; + Shift = 0; + do { + OS << ", " << (unsigned)*I; + Value += (*I & 0x7f) << Shift; + Shift += 7; + } while (*I++ >= 128); + if (Value > 127) { + OS << " /* 0x"; + OS.write_hex(Value); + OS << " */"; + } + OS << ",\n"; + break; + } + case MCD::OPC_Fail: { + ++I; + OS.indent(Indent) << "MCD_OPC_Fail,\n"; + break; + } + } + } + OS.indent(Indent) << "0\n"; + + Indent -= 2; + + OS.indent(Indent) << "};\n\n"; +} + +void PrinterCapstone::emitInstrLenTable(std::vector &InstrLen) const { + OS << "static const uint8_t InstrLenTable[] = {\n"; + for (unsigned const &Len : InstrLen) { + OS << Len << ",\n"; + } + OS << "};\n\n"; +} + +void PrinterCapstone::emitPredicateFunction(PredicateSet &Predicates, + unsigned Indentation) const { + // The predicate function is just a big switch statement based on the + // input predicate index. + OS.indent(Indentation) << "static bool checkDecoderPredicate(unsigned Idx, " + << "const FeatureBitset &Bits) {\n"; + Indentation += 2; + if (!Predicates.empty()) { + OS.indent(Indentation) << "switch (Idx) {\n"; + OS.indent(Indentation) + << "default: /* llvm_unreachable(\"Invalid index!\"); */\n"; + unsigned Index = 0; + for (const auto &Predicate : Predicates) { + OS.indent(Indentation) << "case " << Index++ << ":\n"; + OS.indent(Indentation + 2) << "return (" << Predicate << ");\n"; + } + OS.indent(Indentation) << "}\n"; + } else { + // No case statement to emit + OS.indent(Indentation) << "/* llvm_unreachable(\"Invalid index!\"); */\n"; + } + Indentation -= 2; + OS.indent(Indentation) << "}\n\n"; +} + +void PrinterCapstone::emitDecoderFunction(DecoderSet &Decoders, + unsigned Indentation) const { + // The decoder function is just a big switch statement based on the + // input decoder index. + OS.indent(Indentation) + << "#define DecodeToMCInst(fname, fieldname, InsnType) \\\n" + << "static DecodeStatus fname(DecodeStatus S, unsigned Idx, InsnType " + "insn, MCInst *MI, \\\n" + << " uint64_t Address, bool *Decoder) \\\n" + << "{ \\\n"; + Indentation += 2; + OS.indent(Indentation) << "InsnType tmp; \\\n"; + OS.indent(Indentation) << "switch (Idx) { \\\n"; + OS.indent(Indentation) + << "default: /* llvm_unreachable(\"Invalid index!\"); */ \\\n"; + unsigned Index = 0; + for (const auto &Decoder : Decoders) { + OS.indent(Indentation) << "case " << Index++ << ": \\\n"; + OS << Decoder; + OS.indent(Indentation + 2) << "return S; \\\n"; + } + OS.indent(Indentation) << "} \\\n"; + Indentation -= 2; + OS.indent(Indentation) << "}\n\n"; +} + +void PrinterCapstone::emitIncludes() const { + OS << "#include \"../../MCInst.h\"\n" + << "#include \"../../LEB128.h\"\n\n"; +} + +void PrinterCapstone::emitNamespaceBegin(std::string const &Namespace) const { + return; +} +void PrinterCapstone::emitNamespaceEnd(std::string const &Namespace) const { + return; +} + +void PrinterCapstone::emitSourceFileHeader() const { + OS << "/* Capstone Disassembly Engine, http://www.capstone-engine.org */\n"; + OS << "/* By Nguyen Anh Quynh , 2013-2022, */\n"; + OS << "/* Rot127 2022 */\n"; + OS << "/* Automatically generated file by the LLVM TableGen Disassembler " + "Backend. */\n"; + OS << "/* Do not edit. */\n\n"; +} + +} // end namespace tblgen_decoder_emitter Index: llvm/utils/TableGen/DecoderEmitter/PrinterLLVM.cpp =================================================================== --- /dev/null +++ llvm/utils/TableGen/DecoderEmitter/PrinterLLVM.cpp @@ -0,0 +1,690 @@ +//===----------------- PrinterLLVM.cpp - Printer LLVM -----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Emits the generated decoder C++ code for the LLVM disassembler. +// +//===----------------------------------------------------------------------===// + +#include "Printer.h" +#include "llvm/TableGen/TableGenBackend.h" + +using namespace llvm; +namespace tblgen_decoder_emitter { + +PrinterInterface::PrinterInterface(formatted_raw_ostream &OS, + std::string PredicateNamespace, + std::string GPrefix, std::string GPostfix, + std::string ROK, std::string RFail, + std::string L, std::string Target) + : OS(OS), TargetName(std::move(Target)), + PredicateNamespace(std::move(PredicateNamespace)), + GuardPrefix(std::move(GPrefix)), GuardPostfix(std::move(GPostfix)), + ReturnOK(std::move(ROK)), ReturnFail(std::move(RFail)), + Locals(std::move(L)) {} + +PrinterInterface::~PrinterInterface() {} + +void PrinterInterface::flushOS() const { OS.flush(); } + +void PrinterLLVM::emitOpDecoder(raw_ostream &DecoderOS, + const OperandInfo &Op) const { + unsigned const Indent = 4; + DecoderOS.indent(Indent) << GuardPrefix << Op.Decoder + << "(MI, insn, Address, Decoder)" << GuardPostfix + << " { " + << (Op.HasCompleteDecoder + ? "" + : "DecodeComplete = false; ") + << "return MCDisassembler::Fail; }\n"; +} + +void PrinterLLVM::emitOpBinaryParser(raw_ostream &DecOS, + const OperandInfo &OpInfo) const { + unsigned const Indent = 4; + const std::string &Decoder = OpInfo.Decoder; + + bool const UseInsertBits = OpInfo.numFields() != 1 || OpInfo.InitValue != 0; + + if (UseInsertBits) { + DecOS.indent(Indent) << "tmp = 0x"; + DecOS.write_hex(OpInfo.InitValue); + DecOS << ";\n"; + } + + for (const EncodingField &EF : OpInfo) { + DecOS.indent(Indent); + if (UseInsertBits) + DecOS << "insertBits(tmp, "; + else + DecOS << "tmp = "; + DecOS << "fieldFromInstruction(insn, " << EF.Base << ", " << EF.Width + << ')'; + if (UseInsertBits) + DecOS << ", " << EF.Offset << ", " << EF.Width << ')'; + else if (EF.Offset != 0) + DecOS << " << " << EF.Offset; + DecOS << ";\n"; + } + + if (Decoder != "") { + DecOS.indent(Indent) << GuardPrefix << Decoder + << "(MI, tmp, Address, Decoder)" << GuardPostfix + << " { " + << (OpInfo.HasCompleteDecoder + ? "" + : "DecodeComplete = false; ") + << "return MCDisassembler::Fail; }\n"; + } else { + DecOS.indent(Indent) << "MI.addOperand(MCOperand::createImm(tmp));\n"; + } +} + +// If ParenIfBinOp is true, print a surrounding () if Val uses && or ||. +bool PrinterLLVM::emitPredicateMatchAux(const Init &Val, bool ParenIfBinOp, + raw_ostream &PredOS) const { + if (auto *D = dyn_cast(&Val)) { + if (!D->getDef()->isSubClassOf("SubtargetFeature")) + return true; + PredOS << "Bits[" << PredicateNamespace << "::" << D->getAsString() << "]"; + return false; + } + if (auto *D = dyn_cast(&Val)) { + std::string const Op = D->getOperator()->getAsString(); + if (Op == "not" && D->getNumArgs() == 1) { + PredOS << '!'; + return emitPredicateMatchAux(*D->getArg(0), true, PredOS); + } + if ((Op == "any_of" || Op == "all_of") && D->getNumArgs() > 0) { + bool const Paren = + D->getNumArgs() > 1 && std::exchange(ParenIfBinOp, true); + if (Paren) + PredOS << '('; + ListSeparator LS(Op == "any_of" ? " || " : " && "); + for (auto *Arg : D->getArgs()) { + PredOS << LS; + if (emitPredicateMatchAux(*Arg, ParenIfBinOp, PredOS)) + return true; + } + if (Paren) + PredOS << ')'; + return false; + } + } + return true; +} + +bool PrinterLLVM::emitPredicateMatch(raw_ostream &PredOS, + const ListInit *Predicates, + unsigned Opc) const { + bool IsFirstEmission = true; + for (unsigned I = 0; I < Predicates->size(); ++I) { + Record *Pred = Predicates->getElementAsRecord(I); + if (!Pred->getValue("AssemblerMatcherPredicate")) + continue; + + if (!isa(Pred->getValue("AssemblerCondDag")->getValue())) + continue; + + if (!IsFirstEmission) + PredOS << " && "; + if (emitPredicateMatchAux(*Pred->getValueAsDag("AssemblerCondDag"), + Predicates->size() > 1, PredOS)) + PrintFatalError(Pred->getLoc(), "Invalid AssemblerCondDag!"); + IsFirstEmission = false; + } + return !Predicates->empty(); +} + +// emitFieldFromInstruction - Emit the templated helper function +// fieldFromInstruction(). +// On Windows we make sure that this function is not inlined when +// using the VS compiler. It has a bug which causes the function +// to be optimized out in some circustances. See llvm.org/pr38292 +void PrinterLLVM::emitFieldFromInstruction() const { + OS << "// Helper functions for extracting fields from encoded instructions.\n" + << "// InsnType must either be integral or an APInt-like object that " + "must:\n" + << "// * be default-constructible and copy-constructible\n" + << "// * be constructible from an APInt (this can be private)\n" + << "// * Support insertBits(bits, startBit, numBits)\n" + << "// * Support extractBitsAsZExtValue(numBits, startBit)\n" + << "// * Support the ~, &, ==, and != operators with other objects of " + "the same type\n" + << "// * Support the != and bitwise & with uint64_t\n" + << "// * Support put (<<) to raw_ostream&\n" + << "template \n" + << "#if defined(_MSC_VER) && !defined(__clang__)\n" + << "__declspec(noinline)\n" + << "#endif\n" + << "static std::enable_if_t::value, InsnType>\n" + << "fieldFromInstruction(const InsnType &insn, unsigned startBit,\n" + << " unsigned numBits) {\n" + << " assert(startBit + numBits <= 64 && \"Cannot support >64-bit " + "extractions!\");\n" + << " assert(startBit + numBits <= (sizeof(InsnType) * 8) &&\n" + << " \"Instruction field out of bounds!\");\n" + << " InsnType fieldMask;\n" + << " if (numBits == sizeof(InsnType) * 8)\n" + << " fieldMask = (InsnType)(-1LL);\n" + << " else\n" + << " fieldMask = (((InsnType)1 << numBits) - 1) << startBit;\n" + << " return (insn & fieldMask) >> startBit;\n" + << "}\n" + << "\n" + << "template \n" + << "static std::enable_if_t::value, " + "uint64_t>\n" + << "fieldFromInstruction(const InsnType &insn, unsigned startBit,\n" + << " unsigned numBits) {\n" + << " return insn.extractBitsAsZExtValue(numBits, startBit);\n" + << "}\n\n"; +} + +// emitInsertBits - Emit the templated helper function insertBits(). +void PrinterLLVM::emitInsertBits() const { + OS << "// Helper function for inserting bits extracted from an encoded " + "instruction into\n" + << "// a field.\n" + << "template \n" + << "static std::enable_if_t::value>\n" + << "insertBits(InsnType &field, InsnType bits, unsigned startBit, " + "unsigned numBits) {\n" + << " assert(startBit + numBits <= sizeof field * 8);\n" + << " field |= (InsnType)bits << startBit;\n" + << "}\n" + << "\n" + << "template \n" + << "static std::enable_if_t::value>\n" + << "insertBits(InsnType &field, uint64_t bits, unsigned startBit, " + "unsigned numBits) {\n" + << " field.insertBits(bits, startBit, numBits);\n" + << "}\n\n"; +} + +// emitDecodeInstruction - Emit the templated helper function +// decodeInstruction(). +void PrinterLLVM::emitDecodeInstruction(bool IsVarLenInst) const { + OS << "template \n" + << "static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], " + "MCInst &MI,\n" + << " InsnType insn, uint64_t " + "Address,\n" + << " const MCDisassembler *DisAsm,\n" + << " const MCSubtargetInfo &STI"; + if (IsVarLenInst) { + OS << ",\n" + << " llvm::function_ref makeUp"; + } + OS << ") {\n" + << " const FeatureBitset &Bits = STI.getFeatureBits();\n" + << "\n" + << " const uint8_t *Ptr = DecodeTable;\n" + << " uint64_t CurFieldValue = 0;\n" + << " DecodeStatus S = MCDisassembler::Success;\n" + << " while (true) {\n" + << " ptrdiff_t Loc = Ptr - DecodeTable;\n" + << " switch (*Ptr) {\n" + << " default:\n" + << " errs() << Loc << \": Unexpected decode table opcode!\\n\";\n" + << " return MCDisassembler::Fail;\n" + << " case MCD::OPC_ExtractField: {\n" + << " unsigned Start = *++Ptr;\n" + << " unsigned Len = *++Ptr;\n" + << " ++Ptr;\n"; + if (IsVarLenInst) { + OS << " makeUp(insn, Start + Len);\n"; + } + OS << " CurFieldValue = fieldFromInstruction(insn, Start, Len);\n" + << " LLVM_DEBUG(dbgs() << Loc << \": OPC_ExtractField(\" << Start << " + "\", \"\n" + << " << Len << \"): \" << CurFieldValue << \"\\n\");\n" + << " break;\n" + << " }\n" + << " case MCD::OPC_FilterValue: {\n" + << " // Decode the field value.\n" + << " unsigned Len;\n" + << " uint64_t Val = decodeULEB128(++Ptr, &Len);\n" + << " Ptr += Len;\n" + << " // NumToSkip is a plain 24-bit integer.\n" + << " unsigned NumToSkip = *Ptr++;\n" + << " NumToSkip |= (*Ptr++) << 8;\n" + << " NumToSkip |= (*Ptr++) << 16;\n" + << "\n" + << " // Perform the filter operation.\n" + << " if (Val != CurFieldValue)\n" + << " Ptr += NumToSkip;\n" + << " LLVM_DEBUG(dbgs() << Loc << \": OPC_FilterValue(\" << Val << " + "\", \" << NumToSkip\n" + << " << \"): \" << ((Val != CurFieldValue) ? \"FAIL:\" " + ": \"PASS:\")\n" + << " << \" continuing at \" << (Ptr - DecodeTable) << " + "\"\\n\");\n" + << "\n" + << " break;\n" + << " }\n" + << " case MCD::OPC_CheckField: {\n" + << " unsigned Start = *++Ptr;\n" + << " unsigned Len = *++Ptr;\n"; + if (IsVarLenInst) { + OS << " makeUp(insn, Start + Len);\n"; + } + OS << " uint64_t FieldValue = fieldFromInstruction(insn, Start, Len);\n" + << " // Decode the field value.\n" + << " unsigned PtrLen = 0;\n" + << " uint64_t ExpectedValue = decodeULEB128(++Ptr, &PtrLen);\n" + << " Ptr += PtrLen;\n" + << " // NumToSkip is a plain 24-bit integer.\n" + << " unsigned NumToSkip = *Ptr++;\n" + << " NumToSkip |= (*Ptr++) << 8;\n" + << " NumToSkip |= (*Ptr++) << 16;\n" + << "\n" + << " // If the actual and expected values don't match, skip.\n" + << " if (ExpectedValue != FieldValue)\n" + << " Ptr += NumToSkip;\n" + << " LLVM_DEBUG(dbgs() << Loc << \": OPC_CheckField(\" << Start << " + "\", \"\n" + << " << Len << \", \" << ExpectedValue << \", \" << " + "NumToSkip\n" + << " << \"): FieldValue = \" << FieldValue << \", " + "ExpectedValue = \"\n" + << " << ExpectedValue << \": \"\n" + << " << ((ExpectedValue == FieldValue) ? \"PASS\\n\" : " + "\"FAIL\\n\"));\n" + << " break;\n" + << " }\n" + << " case MCD::OPC_CheckPredicate: {\n" + << " unsigned Len;\n" + << " // Decode the Predicate Index value.\n" + << " unsigned PIdx = decodeULEB128(++Ptr, &Len);\n" + << " Ptr += Len;\n" + << " // NumToSkip is a plain 24-bit integer.\n" + << " unsigned NumToSkip = *Ptr++;\n" + << " NumToSkip |= (*Ptr++) << 8;\n" + << " NumToSkip |= (*Ptr++) << 16;\n" + << " // Check the predicate.\n" + << " bool Pred;\n" + << " if (!(Pred = checkDecoderPredicate(PIdx, Bits)))\n" + << " Ptr += NumToSkip;\n" + << " (void)Pred;\n" + << " LLVM_DEBUG(dbgs() << Loc << \": OPC_CheckPredicate(\" << PIdx " + "<< \"): \"\n" + << " << (Pred ? \"PASS\\n\" : \"FAIL\\n\"));\n" + << "\n" + << " break;\n" + << " }\n" + << " case MCD::OPC_Decode: {\n" + << " unsigned Len;\n" + << " // Decode the Opcode value.\n" + << " unsigned Opc = decodeULEB128(++Ptr, &Len);\n" + << " Ptr += Len;\n" + << " unsigned DecodeIdx = decodeULEB128(Ptr, &Len);\n" + << " Ptr += Len;\n" + << "\n" + << " MI.clear();\n" + << " MI.setOpcode(Opc);\n" + << " bool DecodeComplete;\n"; + if (IsVarLenInst) { + OS << " Len = InstrLenTable[Opc];\n" + << " makeUp(insn, Len);\n"; + } + OS << " S = decodeToMCInst(S, DecodeIdx, insn, MI, Address, DisAsm, " + "DecodeComplete);\n" + << " assert(DecodeComplete);\n" + << "\n" + << " LLVM_DEBUG(dbgs() << Loc << \": OPC_Decode: opcode \" << Opc\n" + << " << \", using decoder \" << DecodeIdx << \": \"\n" + << " << (S != MCDisassembler::Fail ? \"PASS\" : " + "\"FAIL\") << \"\\n\");\n" + << " return S;\n" + << " }\n" + << " case MCD::OPC_TryDecode: {\n" + << " unsigned Len;\n" + << " // Decode the Opcode value.\n" + << " unsigned Opc = decodeULEB128(++Ptr, &Len);\n" + << " Ptr += Len;\n" + << " unsigned DecodeIdx = decodeULEB128(Ptr, &Len);\n" + << " Ptr += Len;\n" + << " // NumToSkip is a plain 24-bit integer.\n" + << " unsigned NumToSkip = *Ptr++;\n" + << " NumToSkip |= (*Ptr++) << 8;\n" + << " NumToSkip |= (*Ptr++) << 16;\n" + << "\n" + << " // Perform the decode operation.\n" + << " MCInst TmpMI;\n" + << " TmpMI.setOpcode(Opc);\n" + << " bool DecodeComplete;\n" + << " S = decodeToMCInst(S, DecodeIdx, insn, TmpMI, Address, DisAsm, " + "DecodeComplete);\n" + << " LLVM_DEBUG(dbgs() << Loc << \": OPC_TryDecode: opcode \" << " + "Opc\n" + << " << \", using decoder \" << DecodeIdx << \": \");\n" + << "\n" + << " if (DecodeComplete) {\n" + << " // Decoding complete.\n" + << " LLVM_DEBUG(dbgs() << (S != MCDisassembler::Fail ? \"PASS\" : " + "\"FAIL\") << \"\\n\");\n" + << " MI = TmpMI;\n" + << " return S;\n" + << " } else {\n" + << " assert(S == MCDisassembler::Fail);\n" + << " // If the decoding was incomplete, skip.\n" + << " Ptr += NumToSkip;\n" + << " LLVM_DEBUG(dbgs() << \"FAIL: continuing at \" << (Ptr - " + "DecodeTable) << \"\\n\");\n" + << " // Reset decode status. This also drops a SoftFail status " + "that could be\n" + << " // set before the decode attempt.\n" + << " S = MCDisassembler::Success;\n" + << " }\n" + << " break;\n" + << " }\n" + << " case MCD::OPC_SoftFail: {\n" + << " // Decode the mask values.\n" + << " unsigned Len;\n" + << " uint64_t PositiveMask = decodeULEB128(++Ptr, &Len);\n" + << " Ptr += Len;\n" + << " uint64_t NegativeMask = decodeULEB128(Ptr, &Len);\n" + << " Ptr += Len;\n" + << " bool Fail = (insn & PositiveMask) != 0 || (~insn & " + "NegativeMask) != 0;\n" + << " if (Fail)\n" + << " S = MCDisassembler::SoftFail;\n" + << " LLVM_DEBUG(dbgs() << Loc << \": OPC_SoftFail: \" << (Fail ? " + "\"FAIL\\n\" : \"PASS\\n\"));\n" + << " break;\n" + << " }\n" + << " case MCD::OPC_Fail: {\n" + << " LLVM_DEBUG(dbgs() << Loc << \": OPC_Fail\\n\");\n" + << " return MCDisassembler::Fail;\n" + << " }\n" + << " }\n" + << " }\n" + << " llvm_unreachable(\"bogosity detected in disassembler state " + "machine!\");\n" + << "}\n\n"; +} + +// Emit the decoder state machine table. +void PrinterLLVM::emitTable( + DecoderTable &Table, unsigned BitWidth, StringRef Namespace, + std::vector NumberedEncodings) const { + unsigned Indent = 0; + OS.indent(Indent) << "static const uint8_t DecoderTable" << Namespace + << BitWidth << "[] = {\n"; + + Indent += 2; + + // FIXME: We may be able to use the NumToSkip values to recover + // appropriate indentation levels. + DecoderTable::const_iterator I = Table.begin(); + DecoderTable::const_iterator const E = Table.end(); + while (I != E) { + assert(I < E && "incomplete decode table entry!"); + + uint64_t const Pos = I - Table.begin(); + OS << "/* " << Pos << " */"; + OS.PadToColumn(12); + + switch (*I) { + default: + PrintFatalError("invalid decode table opcode"); + case MCD::OPC_ExtractField: { + ++I; + unsigned const Start = *I++; + unsigned const Len = *I++; + OS.indent(Indent) << "MCD::OPC_ExtractField, " << Start << ", " << Len + << ", // Inst{"; + if (Len > 1) + OS << (Start + Len - 1) << "-"; + OS << Start << "} ...\n"; + break; + } + case MCD::OPC_FilterValue: { + ++I; + OS.indent(Indent) << "MCD::OPC_FilterValue, "; + // The filter value is ULEB128 encoded. + while (*I >= 128) + OS << (unsigned)*I++ << ", "; + OS << (unsigned)*I++ << ", "; + + // 24-bit numtoskip value. + uint8_t Byte = *I++; + uint32_t NumToSkip = Byte; + OS << (unsigned)Byte << ", "; + Byte = *I++; + OS << (unsigned)Byte << ", "; + NumToSkip |= Byte << 8; + Byte = *I++; + OS << utostr(Byte) << ", "; + NumToSkip |= Byte << 16; + OS << "// Skip to: " << ((I - Table.begin()) + NumToSkip) << "\n"; + break; + } + case MCD::OPC_CheckField: { + ++I; + unsigned const Start = *I++; + unsigned const Len = *I++; + OS.indent(Indent) << "MCD::OPC_CheckField, " << Start << ", " << Len + << ", "; // << Val << ", " << NumToSkip << ",\n"; + // ULEB128 encoded field value. + for (; *I >= 128; ++I) + OS << (unsigned)*I << ", "; + OS << (unsigned)*I++ << ", "; + // 24-bit numtoskip value. + uint8_t Byte = *I++; + uint32_t NumToSkip = Byte; + OS << (unsigned)Byte << ", "; + Byte = *I++; + OS << (unsigned)Byte << ", "; + NumToSkip |= Byte << 8; + Byte = *I++; + OS << utostr(Byte) << ", "; + NumToSkip |= Byte << 16; + OS << "// Skip to: " << ((I - Table.begin()) + NumToSkip) << "\n"; + break; + } + case MCD::OPC_CheckPredicate: { + ++I; + OS.indent(Indent) << "MCD::OPC_CheckPredicate, "; + for (; *I >= 128; ++I) + OS << (unsigned)*I << ", "; + OS << (unsigned)*I++ << ", "; + + // 24-bit numtoskip value. + uint8_t Byte = *I++; + uint32_t NumToSkip = Byte; + OS << (unsigned)Byte << ", "; + Byte = *I++; + OS << (unsigned)Byte << ", "; + NumToSkip |= Byte << 8; + Byte = *I++; + OS << utostr(Byte) << ", "; + NumToSkip |= Byte << 16; + OS << "// Skip to: " << ((I - Table.begin()) + NumToSkip) << "\n"; + break; + } + case MCD::OPC_Decode: + case MCD::OPC_TryDecode: { + bool const IsTry = *I == MCD::OPC_TryDecode; + ++I; + // Extract the ULEB128 encoded Opcode to a buffer. + uint8_t Buffer[16], *P = Buffer; + while ((*P++ = *I++) >= 128) + assert((P - Buffer) <= (ptrdiff_t)sizeof(Buffer) && + "ULEB128 value too large!"); + // Decode the Opcode value. + unsigned const Opc = decodeULEB128(Buffer); + OS.indent(Indent) << "MCD::OPC_" << (IsTry ? "Try" : "") << "Decode, "; + for (P = Buffer; *P >= 128; ++P) + OS << (unsigned)*P << ", "; + OS << (unsigned)*P << ", "; + + // Decoder index. + for (; *I >= 128; ++I) + OS << (unsigned)*I << ", "; + OS << (unsigned)*I++ << ", "; + + if (!IsTry) { + OS << "// Opcode: " << NumberedEncodings[Opc] << "\n"; + break; + } + + // Fallthrough for OPC_TryDecode. + + // 24-bit numtoskip value. + uint8_t Byte = *I++; + uint32_t NumToSkip = Byte; + OS << (unsigned)Byte << ", "; + Byte = *I++; + OS << (unsigned)Byte << ", "; + NumToSkip |= Byte << 8; + Byte = *I++; + OS << utostr(Byte) << ", "; + NumToSkip |= Byte << 16; + + OS << "// Opcode: " << NumberedEncodings[Opc] + << ", skip to: " << ((I - Table.begin()) + NumToSkip) << "\n"; + break; + } + case MCD::OPC_SoftFail: { + ++I; + OS.indent(Indent) << "MCD::OPC_SoftFail"; + // Positive mask + uint64_t Value = 0; + unsigned Shift = 0; + do { + OS << ", " << (unsigned)*I; + Value += (*I & 0x7f) << Shift; + Shift += 7; + } while (*I++ >= 128); + if (Value > 127) { + OS << " /* 0x"; + OS.write_hex(Value); + OS << " */"; + } + // Negative mask + Value = 0; + Shift = 0; + do { + OS << ", " << (unsigned)*I; + Value += (*I & 0x7f) << Shift; + Shift += 7; + } while (*I++ >= 128); + if (Value > 127) { + OS << " /* 0x"; + OS.write_hex(Value); + OS << " */"; + } + OS << ",\n"; + break; + } + case MCD::OPC_Fail: { + ++I; + OS.indent(Indent) << "MCD::OPC_Fail,\n"; + break; + } + } + } + OS.indent(Indent) << "0\n"; + + Indent -= 2; + + OS.indent(Indent) << "};\n\n"; +} + +void PrinterLLVM::emitInstrLenTable(std::vector &InstrLen) const { + OS << "static const uint8_t InstrLenTable[] = {\n"; + for (unsigned const &Len : InstrLen) { + OS << Len << ",\n"; + } + OS << "};\n\n"; +} + +void PrinterLLVM::emitPredicateFunction(PredicateSet &Predicates, + unsigned Indentation) const { + // The predicate function is just a big switch statement based on the + // input predicate index. + OS.indent(Indentation) << "static bool checkDecoderPredicate(unsigned Idx, " + << "const FeatureBitset &Bits) {\n"; + Indentation += 2; + if (!Predicates.empty()) { + OS.indent(Indentation) << "switch (Idx) {\n"; + OS.indent(Indentation) + << "default: llvm_unreachable(\"Invalid index!\");\n"; + unsigned Index = 0; + for (const auto &Predicate : Predicates) { + OS.indent(Indentation) << "case " << Index++ << ":\n"; + OS.indent(Indentation + 2) << "return (" << Predicate << ");\n"; + } + OS.indent(Indentation) << "}\n"; + } else { + // No case statement to emit + OS.indent(Indentation) << "llvm_unreachable(\"Invalid index!\");\n"; + } + Indentation -= 2; + OS.indent(Indentation) << "}\n\n"; +} + +void PrinterLLVM::emitDecoderFunction(DecoderSet &Decoders, + unsigned Indentation) const { + // The decoder function is just a big switch statement based on the + // input decoder index. + OS.indent(Indentation) << "template \n"; + OS.indent(Indentation) << "static DecodeStatus decodeToMCInst(DecodeStatus S," + << " unsigned Idx, InsnType insn, MCInst &MI,\n"; + OS.indent(Indentation) + << " uint64_t " + << "Address, const MCDisassembler *Decoder, bool &DecodeComplete) {\n"; + Indentation += 2; + OS.indent(Indentation) << "DecodeComplete = true;\n"; + // TODO: When InsnType is large, using uint64_t limits all fields to 64 bits + // It would be better for emitBinaryParser to use a 64-bit tmp whenever + // possible but fall back to an InsnType-sized tmp for truly large fields. + OS.indent(Indentation) << "using TmpType = " + "std::conditional_t::" + "value, InsnType, uint64_t>;\n"; + OS.indent(Indentation) << "TmpType tmp;\n"; + OS.indent(Indentation) << "switch (Idx) {\n"; + OS.indent(Indentation) << "default: llvm_unreachable(\"Invalid index!\");\n"; + unsigned Index = 0; + for (const auto &Decoder : Decoders) { + OS.indent(Indentation) << "case " << Index++ << ":\n"; + OS << Decoder; + OS.indent(Indentation + 2) << "return S;\n"; + } + OS.indent(Indentation) << "}\n"; + Indentation -= 2; + OS.indent(Indentation) << "}\n\n"; +} + +void PrinterLLVM::emitIncludes() const { + OS << "#include \"llvm/MC/MCInst.h\"\n"; + OS << "#include \"llvm/MC/MCSubtargetInfo.h\"\n"; + OS << "#include \"llvm/MC/SubtargetFeature.h\"\n"; + OS << "#include \"llvm/Support/DataTypes.h\"\n"; + OS << "#include \"llvm/Support/Debug.h\"\n"; + OS << "#include \"llvm/Support/LEB128.h\"\n"; + OS << "#include \"llvm/Support/raw_ostream.h\"\n"; + OS << "#include \n"; + OS << '\n'; +} + +void PrinterLLVM::emitNamespaceBegin(std::string const &Namespace) const { + OS << "namespace " << Namespace << " {\n\n"; +} +void PrinterLLVM::emitNamespaceEnd(std::string const &Namespace) const { + OS << "\n} // end namespace " << Namespace << "\n"; +} + +void PrinterLLVM::emitSourceFileHeader() const { + llvm::emitSourceFileHeader(" * " + TargetName + " Disassembler", OS); +} + +} // end namespace tblgen_decoder_emitter Index: llvm/utils/TableGen/DecoderEmitter/README.md =================================================================== --- /dev/null +++ llvm/utils/TableGen/DecoderEmitter/README.md @@ -0,0 +1,61 @@ +# Decoder emitter + +The decoder emitter generates the code for the disassembler of several architectures. + +The general design is split into four classes. + +- `DecoderEmitter`: Controls code generation and pre-processes `Records`. +- `FilterChooser`: Builds the decoding state machine. +- `Filter`: Represents a state in the decoding state machine. +- `Printer`: Provides the actual code strings. + +The rough process of the code generation is described in the following diagram. +The details about the state machine creation (the `recurse` step) checkout [InstructionDecoding.md](InstructionDecoding.md) + +``` +DecoderEmitter FilterChooser Filter Printer Output Stream + + ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ + │ ├────────┐ │ │ │ │ │ │ │ │ + │ │ │Separate instr. │ │ │ │ │ │ │ │ + │ │ │into groups │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ + │ │◄───────┘ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ + │ │ Start separation process │ │ Separate │ │ │ │ │ │ + │ │ of instr. groups │ │ into │ │ │ │ │ │ + │ ├──────────────────────────►│ │ subsets │ │ │ │ │ │ + │ │ │ ├───────────┐ │ │ │ │ │ │ + │ │ │ │ │ Add Filter to │ │ │ │ │ │ + │ │ │ │ │ Filterlist │ │ │ │ │ │ + │ │ │ │ R ├──────────────────►│ │ │ │ │ │ + │ │ │ │ E │ │ │ │ │ │ │ + │ │ │ │ C │ │ │ │ │ │ │ + │ │ │ │ U │ └───┘ │ │ │ │ + │ │ │ │ R │ │ │ │ │ + │ │ │ │ S │ Request Filter decoder string │ │ │ │ + │ │ │ │ E ├───────────────────────────────────────►│ │ │ │ + │ │ │ │ │ │ │ │ │ + │ │ │ │ │◄───────────────────────────────────────┤ │ │ │ + │ │ │ │ │ Return decoder string │ │ │ │ + │ │ │ │◄──────────┘ │ │ │ │ + │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ + │ │◄──────────────────────────┤ │ │ │ │ │ + │ │ Return list of decoder │ │ │ │ │ │ + │ │ strings └───┘ │ │ │ │ + │ │ │ │ │ │ + │ │ │ │ │ │ + │ │ │ │ │ │ + │ │ │ │ │ │ + │ │ Request print decoders into file │ │ Print │ │ + │ ├───────────────────────────────────────────────────────────────────────────────────►│ │ decoders │ │ + │ │ │ ├────────────────►│ │ + │ │ │ │ │ │ + │ │ Request to print helper functions into file │ │ Print │ │ + │ ├───────────────────────────────────────────────────────────────────────────────────►│ │ functions │ │ + │ │ │ ├────────────────►│ │ + │ │ │ │ │ │ + └───┘ │ │ │ │ + └───┘ └───┘ +``` Index: llvm/utils/TableGen/DisassemblerEmitter.cpp =================================================================== --- llvm/utils/TableGen/DisassemblerEmitter.cpp +++ llvm/utils/TableGen/DisassemblerEmitter.cpp @@ -6,7 +6,9 @@ // //===----------------------------------------------------------------------===// +#include "./DecoderEmitter/Printer.h" #include "CodeGenTarget.h" +#include "TableGenBackends.h" #include "WebAssemblyDisassemblerEmitter.h" #include "X86DisassemblerTables.h" #include "X86RecognizableInstr.h" @@ -95,22 +97,18 @@ namespace llvm { -extern void EmitDecoder(RecordKeeper &RK, raw_ostream &OS, - const std::string &PredicateNamespace, - const std::string &GPrefix, const std::string &GPostfix, - const std::string &ROK, const std::string &RFail, - const std::string &L); +void EmitDecoder(RecordKeeper &RK, raw_ostream &OS, CodeGenTarget &Target, ActionType Action); -void EmitDisassembler(RecordKeeper &Records, raw_ostream &OS) { +void EmitDisassembler(RecordKeeper &Records, raw_ostream &OS, ActionType Action=GenDisassembler) { CodeGenTarget Target(Records); - emitSourceFileHeader(" * " + Target.getName().str() + " Disassembler", OS); // X86 uses a custom disassembler. if (Target.getName() == "X86") { + emitSourceFileHeader(" * " + Target.getName().str() + " Disassembler", OS); DisassemblerTables Tables; - ArrayRef numberedInstructions = - Target.getInstructionsByEnumValue(); + ArrayRef numberedInstructions = + Target.getInstructionsByEnumValue(); for (unsigned i = 0, e = numberedInstructions.size(); i != e; ++i) RecognizableInstr::processInstr(Tables, *numberedInstructions[i], i); @@ -128,27 +126,11 @@ // below (which depends on a Size table-gen Record), and also uses a custom // disassembler. if (Target.getName() == "WebAssembly") { + emitSourceFileHeader(" * " + Target.getName().str() + " Disassembler", OS); emitWebAssemblyDisassemblerTables(OS, Target.getInstructionsByEnumValue()); return; } - - // ARM and Thumb have a CHECK() macro to deal with DecodeStatuses. - if (Target.getName() == "ARM" || Target.getName() == "Thumb" || - Target.getName() == "AArch64" || Target.getName() == "ARM64") { - std::string PredicateNamespace = std::string(Target.getName()); - if (PredicateNamespace == "Thumb") - PredicateNamespace = "ARM"; - - EmitDecoder(Records, OS, PredicateNamespace, "if (!Check(S, ", "))", "S", - "MCDisassembler::Fail", - " MCDisassembler::DecodeStatus S = " - "MCDisassembler::Success;\n(void)S;"); - return; - } - - EmitDecoder(Records, OS, std::string(Target.getName()), "if (", - " == MCDisassembler::Fail)", "MCDisassembler::Success", - "MCDisassembler::Fail", ""); + EmitDecoder(Records, OS, Target, Action); } } // end namespace llvm Index: llvm/utils/TableGen/TableGen.cpp =================================================================== --- llvm/utils/TableGen/TableGen.cpp +++ llvm/utils/TableGen/TableGen.cpp @@ -19,47 +19,6 @@ using namespace llvm; -enum ActionType { - PrintRecords, - PrintDetailedRecords, - NullBackend, - DumpJSON, - GenEmitter, - GenRegisterInfo, - GenInstrInfo, - GenInstrDocs, - GenAsmWriter, - GenAsmMatcher, - GenDisassembler, - GenPseudoLowering, - GenCompressInst, - GenCallingConv, - GenDAGISel, - GenDFAPacketizer, - GenFastISel, - GenSubtarget, - GenIntrinsicEnums, - GenIntrinsicImpl, - PrintEnums, - PrintSets, - GenOptParserDefs, - GenOptRST, - GenCTags, - GenAttributes, - GenSearchableTables, - GenGlobalISel, - GenGICombiner, - GenX86EVEX2VEXTables, - GenX86FoldTables, - GenX86MnemonicTables, - GenRegisterBank, - GenExegesis, - GenAutomata, - GenDirectivesEnumDecl, - GenDirectivesEnumImpl, - GenDXILOperation, -}; - namespace llvm { cl::opt EmitLongStrLiterals( "long-string-literals", @@ -93,6 +52,8 @@ clEnumValN(GenAsmWriter, "gen-asm-writer", "Generate assembly writer"), clEnumValN(GenDisassembler, "gen-disassembler", "Generate disassembler"), + clEnumValN(GenCapstone, "gen-capstone", + "Generate disassembler for Capstone"), clEnumValN(GenPseudoLowering, "gen-pseudo-lowering", "Generate pseudo instruction lowering"), clEnumValN(GenCompressInst, "gen-compress-inst-emitter", @@ -151,12 +112,12 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) { switch (Action) { case PrintRecords: - OS << Records; // No argument, dump all contents + OS << Records; // No argument, dump all contents break; case PrintDetailedRecords: EmitDetailedRecords(Records, OS); break; - case NullBackend: // No backend at all. + case NullBackend: // No backend at all. break; case DumpJSON: EmitJSON(Records, OS); @@ -182,8 +143,9 @@ case GenAsmMatcher: EmitAsmMatcher(Records, OS); break; + case GenCapstone: case GenDisassembler: - EmitDisassembler(Records, OS); + EmitDisassembler(Records, OS, Action); break; case GenPseudoLowering: EmitPseudoLowering(Records, OS); @@ -215,20 +177,18 @@ case GenOptRST: EmitOptRST(Records, OS); break; - case PrintEnums: - { + case PrintEnums: { for (Record *Rec : Records.getAllDerivedDefinitions(Class)) OS << Rec->getName() << ", "; OS << "\n"; break; } - case PrintSets: - { + case PrintSets: { SetTheory Sets; Sets.addFieldExpander("Set", "Elements"); for (Record *Rec : Records.getAllDerivedDefinitions("Set")) { OS << Rec->getName() << " = ["; - const std::vector *Elts = Sets.expand(Rec); + const std::vector *Elts = Sets.expand(Rec); assert(Elts && "Couldn't expand Set instance"); for (Record *Elt : *Elts) OS << ' ' << Elt->getName(); @@ -282,7 +242,7 @@ return false; } -} +} // namespace int main(int argc, char **argv) { InitLLVM X(argc, argv); Index: llvm/utils/TableGen/TableGenBackends.h =================================================================== --- llvm/utils/TableGen/TableGenBackends.h +++ llvm/utils/TableGen/TableGenBackends.h @@ -55,6 +55,47 @@ // TableGen binary with as few dependencies as possible on the rest of // LLVM. +enum ActionType { + PrintRecords, + PrintDetailedRecords, + NullBackend, + DumpJSON, + GenEmitter, + GenRegisterInfo, + GenInstrInfo, + GenInstrDocs, + GenAsmWriter, + GenAsmMatcher, + GenDisassembler, + GenPseudoLowering, + GenCompressInst, + GenCallingConv, + GenDAGISel, + GenDFAPacketizer, + GenFastISel, + GenSubtarget, + GenIntrinsicEnums, + GenIntrinsicImpl, + PrintEnums, + PrintSets, + GenOptParserDefs, + GenOptRST, + GenCTags, + GenAttributes, + GenSearchableTables, + GenGlobalISel, + GenGICombiner, + GenX86EVEX2VEXTables, + GenX86FoldTables, + GenX86MnemonicTables, + GenRegisterBank, + GenExegesis, + GenAutomata, + GenDirectivesEnumDecl, + GenDirectivesEnumImpl, + GenDXILOperation, + GenCapstone, +}; namespace llvm { @@ -69,7 +110,7 @@ void EmitCodeEmitter(RecordKeeper &RK, raw_ostream &OS); void EmitDAGISel(RecordKeeper &RK, raw_ostream &OS); void EmitDFAPacketizer(RecordKeeper &RK, raw_ostream &OS); -void EmitDisassembler(RecordKeeper &RK, raw_ostream &OS); +void EmitDisassembler(RecordKeeper &RK, raw_ostream &OS, ActionType AT); void EmitFastISel(RecordKeeper &RK, raw_ostream &OS); void EmitInstrInfo(RecordKeeper &RK, raw_ostream &OS); void EmitInstrDocs(RecordKeeper &RK, raw_ostream &OS);