//===------------- 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 Capstone. // //===----------------------------------------------------------------------===// #include "Printer.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/CodeGen/ValueTypes.h" #include "llvm/MC/MCInst.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/Regex.h" #include "llvm/Support/ToolOutputFile.h" #include "llvm/TableGen/TableGenBackend.h" #include #include #include static void emitDefaultSourceFileHeader(raw_ostream &OS) { OS << "/* Capstone Disassembly Engine, https://www.capstone-engine.org */\n" << "/* By Nguyen Anh Quynh , 2013-2022, */\n" << "/* Rot127 2022-2024 */\n" << "/* Automatically generated file by Capstone's LLVM TableGen " "Disassembler " "Backend. */\n\n" << "/* LLVM-commit: */\n" << "/* LLVM-tag: */\n\n" << "/* Do not edit. */\n\n" << "/* Capstone's LLVM TableGen Backends: */\n" << "/* https://github.com/capstone-engine/llvm-capstone */\n\n"; } namespace llvm { /// Prints `namespace {` and `} // end namespace ` to the output /// stream. If Name == "" it emits an anonymous namespace. void PrinterCapstone::emitNamespace(std::string const &Name, bool Begin, std::string const &Comment, bool Newline) const { return; } /// Prints /// ``` /// #if /// ``` /// and /// `#endif // ` /// Used to control inclusion of a code block via a macro definition. void PrinterCapstone::emitPPIf(std::string const &Arg, bool Begin, bool Newline) const { if (Begin) { OS << "#if " << Arg << "\n"; } else { OS << "#endif // " << Arg << (Newline ? "\n\n" : "\n"); } } /// Prints /// ``` /// #ifdef /// #undef /// ``` /// and /// `#endif // ` /// Used to control inclusion of a code block via a macro definition. void PrinterCapstone::emitIncludeToggle(std::string const &Name, bool Begin, bool Newline, bool UndefAtEnd) const { std::set Ignore = {"GET_REGINFO_TARGET_DESC", "GET_REGINFO_HEADER", "GET_MNEMONIC_CHECKER", "GET_MNEMONIC_SPELL_CHECKER", "GET_MATCHER_IMPLEMENTATION", "GET_SUBTARGET_FEATURE_NAME", "GET_REGISTER_MATCHER", "GET_OPERAND_DIAGNOSTIC_TYPES", "GET_ASSEMBLER_HEADER", "GET_INSTRINFO_HEADER", "GET_INSTRINFO_HELPER_DECLS", "GET_INSTRINFO_HELPERS", "GET_INSTRINFO_CTOR_DTOR", "GET_INSTRINFO_OPERAND_ENUM", "GET_INSTRINFO_NAMED_OPS", "GET_INSTRINFO_OPERAND_TYPES_ENUM", "GET_INSTRINFO_OPERAND_TYPE", "GET_INSTRINFO_MEM_OPERAND_SIZE", "GET_INSTRINFO_LOGICAL_OPERAND_SIZE_MAP", "GET_INSTRINFO_LOGICAL_OPERAND_TYPE_MAP", "GET_INSTRINFO_MC_HELPER_DECLS", "GET_INSTRINFO_MC_HELPERS", "ENABLE_INSTR_PREDICATE_VERIFIER", "GET_GENISTRINFO_MC_HELPERS", "GET_SUBTARGETINFO_MC_DESC", "GET_SUBTARGETINFO_TARGET_DESC", "GET_SUBTARGETINFO_HEADER", "GET_SUBTARGETINFO_CTOR", "GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS", "GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS", "GET_SUBTARGETINFO_MACRO"}; if (Ignore.find(Name) != Ignore.end()) return; if (Begin) { OS << "#ifdef " << Name << "\n"; if (!UndefAtEnd) OS << "#undef " << Name << "\n\n"; } else { if (UndefAtEnd) OS << "#undef " << Name << "\n"; OS << "#endif // " << Name << (Newline ? "\n\n" : "\n"); } } void PrinterCapstone::emitIfNotDef(std::string const &Name, bool Begin) const { if (Name == "NDEBUG") return; if (Begin) { OS << "#ifndef " << Name << "\n"; } else { OS << "#endif // " << Name << "\n\n"; } } void PrinterCapstone::regInfoEmitSourceFileHeader( std::string const &Desc) const { static unsigned Count = 0; if (Count > 0) { // Only emit it once at the beginning. return; } emitDefaultSourceFileHeader(OS); ++Count; } void writeFile(std::string Filename, std::string const &Str) { std::error_code EC; ToolOutputFile InsnMapFile(Filename, EC, sys::fs::OF_Text); if (EC) PrintFatalNote("Could no write \"" + Filename + "\" Error:\n" + EC.message()); InsnMapFile.os() << Str; InsnMapFile.keep(); } // runEnums - Print out enum values for all of the registers. void PrinterCapstone::regInfoEmitEnums(CodeGenTarget const &Target, CodeGenRegBank const &Bank) const { std::string CSRegEnumStr; raw_string_ostream CSRegEnum(CSRegEnumStr); emitDefaultSourceFileHeader(CSRegEnum); const auto &Registers = Bank.getRegisters(); // Register enums are stored as uint16_t in the tables. Make sure we'll fit. assert(Registers.size() <= 0xffff && "Too many regs to fit in tables"); emitIncludeToggle("GET_REGINFO_ENUM", true); StringRef TargetName = Target.getName(); OS << "enum {\n " << TargetName << "_NoRegister,\n"; CSRegEnum << "\t" << TargetName.upper() << "_REG_INVALID = 0,\n"; for (const auto &Reg : Registers) { OS << " " << TargetName << "_" << Reg.getName() << " = " << Reg.EnumValue << ",\n"; CSRegEnum << "\t" << TargetName.upper() << "_REG_" << Reg.getName().upper() << " = " << Reg.EnumValue << ",\n"; } assert(Registers.size() == Registers.back().EnumValue && "Register enum value mismatch!"); OS << " NUM_TARGET_REGS // " << Registers.size() + 1 << "\n"; OS << "};\n"; CSRegEnum << "\t" << TargetName.upper() << "_REG_ENDING, // " << Registers.size() + 1 << "\n"; writeFile(TargetName.str() + "GenCSRegEnum.inc", CSRegEnumStr); const auto &RegisterClasses = Bank.getRegClasses(); if (!RegisterClasses.empty()) { // RegisterClass enums are stored as uint16_t in the tables. assert(RegisterClasses.size() <= 0xffff && "Too many register classes to fit in tables"); OS << "\n// Register classes\n\n"; OS << "enum {\n"; for (const auto &RC : RegisterClasses) OS << " " << TargetName << "_" << RC.getName() << "RegClassID" << " = " << RC.EnumValue << ",\n"; OS << "\n};\n"; } const std::vector &RegAltNameIndices = Target.getRegAltNameIndices(); // If the only definition is the default NoRegAltName, we don't need to // emit anything. if (RegAltNameIndices.size() > 1) { OS << "\n// Register alternate name indices\n\n"; OS << "enum {\n"; for (unsigned I = 0, E = RegAltNameIndices.size(); I != E; ++I) OS << " " << TargetName << "_" << RegAltNameIndices[I]->getName() << ",\t// " << I << "\n"; OS << " NUM_TARGET_REG_ALT_NAMES = " << RegAltNameIndices.size() << "\n"; OS << "};\n"; } auto &SubRegIndices = Bank.getSubRegIndices(); if (!SubRegIndices.empty()) { OS << "\n// Subregister indices\n\n"; std::string const Namespace = SubRegIndices.front().getNamespace(); OS << "enum {\n " << TargetName << "_NoSubRegister,\n"; unsigned I = 0; for (const auto &Idx : SubRegIndices) OS << " " << TargetName << "_" << Idx.getName() << ",\t// " << ++I << "\n"; OS << " " << TargetName << "_NUM_TARGET_SUBREGS\n};\n"; } emitIncludeToggle("GET_REGINFO_ENUM", false); } static void printDiff16(raw_ostream &OS, int16_t Val) { OS << Val; } void PrinterCapstone::regInfoEmitRegDiffLists( std::string const TargetName, SequenceToOffsetTable const &DiffSeqs) const { OS << "static const MCPhysReg " << TargetName << "RegDiffLists[] = {\n"; DiffSeqs.emit(OS, printDiff16); OS << "};\n\n"; } void PrinterCapstone::regInfoEmitLaneMaskLists( std::string const TargetName, SequenceToOffsetTable const &LaneMaskSeqs) const { return; } void PrinterCapstone::regInfoEmitSubRegIdxLists( std::string const TargetName, SequenceToOffsetTable>> const &SubRegIdxSeqs) const { OS << "static const uint16_t " << TargetName << "SubRegIdxLists[] = {\n"; SubRegIdxSeqs.emit(OS, [](raw_ostream &OS, const CodeGenSubRegIndex *Idx) { OS << Idx->EnumValue; }); OS << "};\n\n"; } void PrinterCapstone::regInfoEmitSubRegIdxSizes( std::string const TargetName, std::deque const &SubRegIndices) const { return; } void PrinterCapstone::regInfoEmitSubRegStrTable( std::string const TargetName, SequenceToOffsetTable const &RegStrings) const { OS << "static const MCRegisterDesc " << TargetName << "RegDesc[] = { // Descriptors\n"; OS << " { " << RegStrings.get("") << ", 0, 0, 0, 0, 0 },\n"; } void PrinterCapstone::regInfoEmitRegDesc( SequenceToOffsetTable const &LaneMaskSeqs, std::deque const &Regs, SequenceToOffsetTable>> const &SubRegIdxSeqs, SequenceToOffsetTable const &DiffSeqs, SmallVector const &SubRegIdxLists, SmallVector const &SubRegLists, SmallVector const &SuperRegLists, SmallVector const &RegUnitLists, SmallVector const &RegUnitLaneMasks, SequenceToOffsetTable const &RegStrings) const { unsigned i = 0; for (const auto &Reg : Regs) { unsigned FirstRU = Reg.getNativeRegUnits().find_first(); unsigned Offset = DiffSeqs.get(RegUnitLists[i]); // The value must be kept in sync with MCRegisterInfo.h. constexpr unsigned RegUnitBits = 12; assert(isUInt(FirstRU) && "Too many regunits"); assert(isUInt<32 - RegUnitBits>(Offset) && "Offset is too big"); OS << " { " << RegStrings.get(std::string(Reg.getName())) << ", " << DiffSeqs.get(SubRegLists[i]) << ", " << DiffSeqs.get(SuperRegLists[i]) << ", " << SubRegIdxSeqs.get(SubRegIdxLists[i]) << ", " << (Offset << RegUnitBits | FirstRU) << ", " << LaneMaskSeqs.get(RegUnitLaneMasks[i]) << " },\n"; ++i; } OS << "};\n\n"; } void PrinterCapstone::regInfoEmitRegUnitRoots( std::string const TargetName, CodeGenRegBank const &RegBank) const { return; } static std::string getQualifiedNameCCS(const Record *R) { std::string Namespace; if (R->getValue("Namespace")) Namespace = std::string(R->getValueAsString("Namespace")); if (Namespace.empty()) return std::string(R->getName()); return StringRef(Namespace).str() + "_" + R->getName().str(); } void PrinterCapstone::regInfoEmitRegClasses( std::list const &RegClasses, SequenceToOffsetTable &RegClassStrings, CodeGenTarget const &Target) const { for (const auto &RC : RegClasses) { ArrayRef const Order = RC.getOrder(); // Give the register class a legal C name if it's anonymous. const std::string &Name = RC.getName(); RegClassStrings.add(Name); // Emit the register list now (unless it would be a zero-length array). if (!Order.empty()) { OS << " // " << Name << " Register Class...\n" << " static const MCPhysReg " << Name << "[] = {\n "; for (Record *Reg : Order) { OS << getQualifiedNameCCS(Reg) << ", "; } OS << "\n };\n\n"; OS << " // " << Name << " Bit set.\n" << " static const uint8_t " << Name << "Bits[] = {\n "; PrinterBitVectorEmitter BVE; for (Record *Reg : Order) { BVE.add(Target.getRegBank().getReg(Reg)->EnumValue); } BVE.print(OS); OS << "\n };\n\n"; } } } void PrinterCapstone::regInfoEmitStrLiteralRegClasses( std::string const TargetName, SequenceToOffsetTable const &RegClassStrings) const { return; } void PrinterCapstone::regInfoEmitMCRegClassesTable( std::string const TargetName, std::list const &RegClasses, SequenceToOffsetTable &RegClassStrings) const { OS << "static const MCRegisterClass " << TargetName << "MCRegisterClasses[] = {\n"; for (const auto &RC : RegClasses) { ArrayRef const Order = RC.getOrder(); std::string const RCName = Order.empty() ? "nullptr" : RC.getName(); std::string const RCBitsName = Order.empty() ? "nullptr" : RC.getName() + "Bits"; std::string const RCBitsSize = Order.empty() ? "0" : "sizeof(" + RCBitsName + ")"; assert(isInt<8>(RC.CopyCost) && "Copy cost too large."); // For Capstone we are only interested in: // RegClass Name, Size group and bit size OS << " { " << RCName << ", " << RCBitsName << ", " << RCBitsSize << " },\n"; } OS << "};\n\n"; } void PrinterCapstone::regInfoEmitRegEncodingTable( std::string const TargetName, std::deque const &Regs) const { OS << "static const uint16_t " << TargetName; OS << "RegEncodingTable[] = {\n"; // Add entry for NoRegister OS << " 0,\n"; for (const auto &RE : Regs) { Record *Reg = RE.TheDef; BitsInit *BI = Reg->getValueAsBitsInit("HWEncoding"); uint64_t Value = 0; for (unsigned I = 0, Ie = BI->getNumBits(); I != Ie; ++I) { if (BitInit *B = dyn_cast(BI->getBit(I))) Value |= (uint64_t)B->getValue() << I; } OS << " " << Value << ",\n"; } OS << "};\n"; // End of HW encoding table return; } void PrinterCapstone::regInfoEmitMCRegInfoInit( std::string const TargetName, CodeGenRegBank const &RegBank, std::deque const &Regs, std::list const &RegClasses, std::deque const &SubRegIndices) const { return; } void PrinterCapstone::regInfoEmitInfoDwarfRegsRev( StringRef const &Namespace, DwarfRegNumsVecTy &DwarfRegNums, unsigned MaxLength, bool IsCtor) const { return; } void PrinterCapstone::regInfoEmitInfoDwarfRegs(StringRef const &Namespace, DwarfRegNumsVecTy &DwarfRegNums, unsigned MaxLength, bool IsCtor) const { return; } void PrinterCapstone::regInfoEmitInfoRegMapping(StringRef const &Namespace, unsigned MaxLength, bool IsCtor) const { return; } void PrinterCapstone::regInfoEmitHeaderIncludes() const { return; } void PrinterCapstone::regInfoEmitHeaderExternRegClasses( std::list const &RegClasses) const { return; } void PrinterCapstone::regInfoEmitHeaderDecl( std::string const &TargetName, std::string const &ClassName, bool SubRegsPresent, bool DeclareGetPhysRegBaseClass) const { return; } void PrinterCapstone::regInfoEmitExternRegClassesArr( std::string const &TargetName) const { return; } void PrinterCapstone::regInfoEmitVTSeqs( SequenceToOffsetTable> const &VTSeqs) const { return; } void PrinterCapstone::regInfoEmitSubRegIdxTable( std::deque const &SubRegIndices) const { return; } void PrinterCapstone::regInfoEmitRegClassInfoTable( std::list const &RegClasses, SequenceToOffsetTable> const &VTSeqs, CodeGenHwModes const &CGH, unsigned NumModes) const { return; } void PrinterCapstone::regInfoEmitSubClassMaskTable( std::list const &RegClasses, SmallVector &SuperRegIdxLists, SequenceToOffsetTable>> &SuperRegIdxSeqs, std::deque const &SubRegIndices, BitVector &MaskBV) const { return; } void PrinterCapstone::regInfoEmitSuperRegIdxSeqsTable( SequenceToOffsetTable>> const &SuperRegIdxSeqs) const { return; } void PrinterCapstone::regInfoEmitSuperClassesTable( std::list const &RegClasses) const { return; } void PrinterCapstone::regInfoEmitRegClassMethods( std::list const &RegClasses, std::string const &TargetName) const { return; } void PrinterCapstone::regInfomitRegClassInstances( std::list const &RegClasses, SequenceToOffsetTable>> const &SuperRegIdxSeqs, SmallVector const &SuperRegIdxLists, std::string const &TargetName) const { return; } void PrinterCapstone::regInfoEmitRegClassTable( std::list const &RegClasses) const { return; } void PrinterCapstone::regInfoEmitCostPerUseTable( std::vector const &AllRegCostPerUse, unsigned NumRegCosts) const { return; } void PrinterCapstone::regInfoEmitInAllocatableClassTable( llvm::BitVector const &InAllocClass) const { return; } void PrinterCapstone::regInfoEmitRegExtraDesc(std::string const &TargetName, unsigned NumRegCosts) const { return; } void PrinterCapstone::regInfoEmitSubClassSubRegGetter( std::string const &ClassName, unsigned SubRegIndicesSize, std::deque const &SubRegIndices, std::list const &RegClasses, CodeGenRegBank &RegBank) const { return; } void PrinterCapstone::regInfoEmitRegClassWeight( CodeGenRegBank const &RegBank, std::string const &ClassName) const { return; } void PrinterCapstone::regInfoEmitRegUnitWeight( CodeGenRegBank const &RegBank, std::string const &ClassName, bool RegUnitsHaveUnitWeight) const { return; } void PrinterCapstone::regInfoEmitGetNumRegPressureSets( std::string const &ClassName, unsigned NumSets) const { return; } void PrinterCapstone::regInfoEmitGetRegPressureTables( CodeGenRegBank const &RegBank, std::string const &ClassName, unsigned NumSets) const { return; } void PrinterCapstone::regInfoEmitRCSetsTable( std::string const &ClassName, unsigned NumRCs, SequenceToOffsetTable> const &PSetsSeqs, std::vector> const &PSets) const { return; } void PrinterCapstone::regInfoEmitGetRegUnitPressureSets( SequenceToOffsetTable> const &PSetsSeqs, CodeGenRegBank const &RegBank, std::string const &ClassName, std::vector> const &PSets) const { return; } void PrinterCapstone::regInfoEmitExternTableDecl( std::string const &TargetName) const { return; } void PrinterCapstone::regInfoEmitRegClassInit( std::string const &TargetName, std::string const &ClassName, CodeGenRegBank const &RegBank, std::list const &RegClasses, std::deque const &Regs, unsigned SubRegIndicesSize) const { return; } void PrinterCapstone::regInfoEmitSaveListTable( Record const *CSRSet, SetTheory::RecVec const *Regs) const { return; } void PrinterCapstone::regInfoEmitRegMaskTable(std::string const &CSRSetName, BitVector &Covered) const { return; } void PrinterCapstone::regInfoEmitGetRegMasks( std::vector const &CSRSets, std::string const &ClassName) const { return; } void PrinterCapstone::regInfoEmitGPRCheck( std::string const &ClassName, std::list const &RegCategories) const { return; } void PrinterCapstone::regInfoEmitFixedRegCheck( std::string const &ClassName, std::list const &RegCategories) const { return; } void PrinterCapstone::regInfoEmitArgRegCheck( std::string const &ClassName, std::list const &RegCategories) const { return; } void PrinterCapstone::regInfoEmitGetRegMaskNames( std::vector const &CSRSets, std::string const &ClassName) const { return; } void PrinterCapstone::regInfoEmitGetFrameLowering( std::string const &TargetName) const { return; } void PrinterCapstone::regInfoEmitComposeSubRegIndicesImplHead( std::string const &ClName) const { return; } void PrinterCapstone::regInfoEmitComposeSubRegIndicesImplBody( SmallVector, 4> const &Rows, unsigned SubRegIndicesSize, SmallVector const &RowMap) const { return; } void PrinterCapstone::regInfoEmitLaneMaskComposeSeq( SmallVector, 4> const &Sequences, SmallVector const &SubReg2SequenceIndexMap, std::deque const &SubRegIndices) const { return; } void PrinterCapstone::regInfoEmitComposeSubRegIdxLaneMask( std::string const &ClName, std::deque const &SubRegIndices) const { return; } void PrinterCapstone::regInfoEmitComposeSubRegIdxLaneMaskRev( std::string const &ClName, std::deque const &SubRegIndices) const { return; } void PrinterCapstone::regInfoEmitIsConstantPhysReg( std::deque const &Regs, std::string const &ClassName) const {} void patchQualifier(std::string &Code) { while (Code.find("::") != std::string::npos) Code = Regex("::").sub("_", Code); } void patchNullptr(std::string &Code) { while (Code.find("nullptr") != std::string::npos) Code = Regex("nullptr").sub("NULL", Code); } void patchIsGetImmReg(std::string &Code) { Regex Pattern = Regex("[a-zA-Z0-9_]+\\.(get|is)(Imm|Reg)\\(\\)"); SmallVector Matches; while (Pattern.match(Code, &Matches)) { StringRef Match = Matches[0]; StringRef Op = Match.split(".").first; StringRef Func = Match.split(".").second.trim(")"); Code = Code.replace(Code.find(Match), Match.size(), "MCOperand_" + Func.str() + Op.str() + ")"); } } static std::string handleDefaultArg(const std::string &TargetName, std::string &Code) { // Default values of the template function arguments. // Tuple is (function name, default argument, number of arguments) static SmallVector Default0 = {"0"}; static SmallVector Default1 = {"1"}; static SmallVector Default01 = {"0", "1"}; static SmallVector &, int>> AArch64TemplFuncWithDefaults = {// Default is 1 {"printVectorIndex", Default1, 1}, // Default is false == 0 {"printPrefetchOp", Default0, 1}, // Default is 0 {"printSVERegOp", Default0, 1}, {"printMatrixIndex", Default1, 1}}; static SmallVector &, int>> LoongArchTemplFuncWithDefaults = { // Default is 0 {"decodeSImmOperand", Default0, 2}, {"decodeUImmOperand", Default0, 2}, }; static SmallVector &, int>> MipsTemplFuncWithDefaults = { {"DecodeSImmWithOffsetAndScale", Default01, 3}, {"printUImm", Default0, 2}, }; SmallVector &, int>> *TemplFuncWithDefaults; if (StringRef(TargetName).upper() == "AARCH64") TemplFuncWithDefaults = &AArch64TemplFuncWithDefaults; else if (StringRef(TargetName).upper() == "LOONGARCH") TemplFuncWithDefaults = &LoongArchTemplFuncWithDefaults; else if (StringRef(TargetName).upper() == "MIPS") TemplFuncWithDefaults = &MipsTemplFuncWithDefaults; else return Code; for (std::tuple Func : *TemplFuncWithDefaults) { // Search for function where default argument is not passed // e.g. printVectorIndex -> printVectorIndex_1 // e.g. decodeSImmOperand<1> -> decodeSImmOperand_1_0 auto Name = std::get<0>(Func); auto DefaultArg = std::get<1>(Func); auto ExpectedArgCount = std::get<2>(Func); SmallVector Matches; while (Regex(Name + "(<[0-9a-zA-Z,]*>)?($|\\()").match(Code, &Matches)) { StringRef Arg = Matches[1]; // Count the number of passed arguments int ActualArgCount = 0; unsigned DefIdx = 0; if (!Arg.empty() && Arg != "<>") { ActualArgCount = Arg.count(',') + 1; if (ActualArgCount == ExpectedArgCount) { break; } } std::string NewArg; NewArg = Regex("<").sub("", Arg); NewArg = Regex(">").sub("", NewArg); NewArg = Regex(",").sub("_", NewArg); while (ActualArgCount < ExpectedArgCount) { assert(DefIdx < DefaultArg.size() && "Out of bounds for predefined template arguments"); // Add default argument if (NewArg.empty()) { // e.g. printVectorIndex -> printVectorIndex_1 NewArg += DefaultArg[DefIdx++]; ActualArgCount++; } else { // e.g. decodeSImmOperand<1> -> decodeSimmOperand_1_0 NewArg += "_"; NewArg += DefaultArg[DefIdx++]; ActualArgCount++; } } assert(ActualArgCount == ExpectedArgCount && "Inconsistent template arg patching."); StringRef Match = Matches[0]; if (Match.ends_with("(")) { Code = Regex(Name + "(<[0-9a-zA-Z,]*>)?\\(") .sub(Name + "_" + NewArg + "(", Code); } else { Code = Regex(Name + "(<[0-9a-zA-Z,]*>)?$").sub(Name + "_" + NewArg, Code); } } } return Code; } /// @brief Replaces template arguments of the form and similar. /// It also handles default arguments for certain hard-coded function names. /// /// @param TargetName The current target name /// @param Code The C++ code. static void patchTemplateArgs(const std::string &TargetName, std::string &Code) { Code = handleDefaultArg(TargetName, Code); size_t B = Code.find_first_of("<"); size_t E = Code.find(">"); while (B != std::string::npos && E != std::string::npos) { std::string const &DecName = Code.substr(0, B); std::string Args = Code.substr(B + 1, E - B - 1); std::string Rest = Code.substr(E + 1); if (Args.empty()) { return; } while ((Args.find("true") != std::string::npos) || (Args.find("false") != std::string::npos) || (Args.find(",") != std::string::npos) || (Args.find("'") != std::string::npos) || (Args.find("-") != std::string::npos)) { Args = Regex("true").sub("1", Args); Args = Regex("false").sub("0", Args); Args = Regex(" *, *").sub("_", Args); Args = Regex("'").sub("", Args); Args = Regex("-").sub("minus", Args); } Code = DecName + "_" + Args + Rest; E = Code.find(">"); B = Code.find_first_of("<"); } } static void patchPrintOperandAddr(std::string &Decoder) { bool ContainsAddress = Decoder.find("Address") != std::string::npos; bool PrintOperand = Decoder.find("printOperand(") != std::string::npos; bool PrintAdrLabelOperand = Decoder.find("printAdrLabelOperand") != std::string::npos; if (!ContainsAddress) { return; } StringRef Find; StringRef Replace; if (PrintOperand) { Find = "printOperand\\(([^\n]+Address.+)"; Replace = "printOperandAddr(\\1"; } else if (PrintAdrLabelOperand) { Find = "printAdrLabelOperand([^\n]+Address.+)"; Replace = "printAdrLabelOperandAddr\\1"; } else { llvm_unreachable("Unhandled printOperand function."); } Decoder = Regex(Find).sub(Replace, Decoder); } std::string PrinterCapstone::translateToC(std::string const &TargetName, std::string const &Code) { std::string PatchedCode(Code); patchQualifier(PatchedCode); patchNullptr(PatchedCode); patchIsGetImmReg(PatchedCode); patchTemplateArgs(TargetName, PatchedCode); if (TargetName == "ARM" || TargetName == "Alpha") { patchPrintOperandAddr(PatchedCode); } return PatchedCode; } void PrinterCapstone::decoderEmitterEmitOpDecoder(raw_ostream &DecoderOS, const OperandInfo &Op) const { unsigned const Indent = 4; DecoderOS.indent(Indent) << GuardPrefix; DecoderOS << translateToC(TargetName, Op.Decoder); DecoderOS << "(MI, insn, Address, Decoder)" << GuardPostfix << " { " << (Op.HasCompleteDecoder ? "" : "*DecodeComplete = false; ") << "return " << ReturnFail << "; } \\\n"; } void PrinterCapstone::decoderEmitterEmitOpBinaryParser( raw_ostream &DecOS, const OperandInfo &OpInfo) const { unsigned const Indent = 4; const std::string &Decoder = translateToC(TargetName, 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 << "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::decoderEmitterEmitPredicateMatchAux( const Init &Val, bool ParenIfBinOp, raw_ostream &PredOS) const { if (auto *D = dyn_cast(&Val)) { if (!D->getDef()->isSubClassOf("SubtargetFeature")) return true; std::string Subtarget = StringRef(PredicateNamespace).str() + "_" + D->getAsString(); PredOS << PredicateNamespace << "_getFeatureBits(Inst->csh->mode, " << Subtarget << ")"; return false; } if (auto *D = dyn_cast(&Val)) { std::string const Op = D->getOperator()->getAsString(); if (Op == "not" && D->getNumArgs() == 1) { PredOS << '!'; return decoderEmitterEmitPredicateMatchAux(*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 (decoderEmitterEmitPredicateMatchAux(*Arg, ParenIfBinOp, PredOS)) return true; } if (Paren) PredOS << ')'; return false; } } return true; } bool PrinterCapstone::decoderEmitterEmitPredicateMatch( 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 (decoderEmitterEmitPredicateMatchAux( *Pred->getValueAsDag("AssemblerCondDag"), Predicates->size() > 1, PredOS)) PrintFatalError(Pred->getLoc(), "Invalid AssemblerCondDag!"); IsFirstEmission = false; } return !Predicates->empty(); } void PrinterCapstone::decoderEmitterEmitFieldFromInstruction() 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::decoderEmitterEmitInsertBits() const { return; } // Helper to propagate SoftFail status. Returns false if the status is Fail; // callers are expected to early-exit in that condition. (Note, the '&' operator // is correct to propagate the values of this enum; see comment on 'enum // DecodeStatus'.) void PrinterCapstone::decoderEmitterEmitCheck() const { OS << "static bool Check(DecodeStatus *Out, const DecodeStatus In) {\n" << " *Out = (DecodeStatus) (*Out & In);\n" << " return *Out != MCDisassembler_Fail;\n" << "}\n\n"; } void PrinterCapstone::decoderEmitterEmitDecodeInstruction( bool IsVarLenInst) const { OS << "#define DecodeInstruction(fname, fieldname, decoder, InsnType) \\\n" << "static DecodeStatus fname(const uint8_t DecodeTable[], " "MCInst *MI, \\\n" << " InsnType insn, uint64_t " "Address, const void *Decoder) { \\\n" << " const uint8_t *Ptr = DecodeTable; \\\n" << " uint64_t CurFieldValue = 0; \\\n" << " DecodeStatus S = MCDisassembler_Success; \\\n" << " while (true) { \\\n" << " switch (*Ptr) { \\\n" << " default: \\\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 = checkDecoderPredicate(MI, PIdx); \\\n" << " if (!Pred) \\\n" << " Ptr += NumToSkip; \\\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, " "Decoder, &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, " << "Decoder, &DecodeComplete); \\\n" << " if (DecodeComplete) { \\\n" << " /* Decoding complete. */ \\\n" << " return S; \\\n" << " } else { \\\n" << " /* LLVM uses a MCInst on the stack, but for our use case, */ " "\\\n" << " /* it is enough for now to reset the op counter. */ \\\n" << " MCInst_clear(MI); \\\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"; std::set InsnBytesAsUint16 = {"ARM", "TriCore", "ARC"}; std::set InsnBytesAsUint24 = {"Xtensa"}; std::set InsnBytesAsUint32 = {"ARM", "AArch64", "LoongArch", "Alpha", "Mips", "TriCore", "ARC"}; std::set InsnBytesAsUint64 = {"SystemZ", "ARC"}; bool MacroDefined = false; if (InsnBytesAsUint16.find(TargetName) != InsnBytesAsUint16.end()) { 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"; MacroDefined = true; } if (InsnBytesAsUint24.find(TargetName) != InsnBytesAsUint24.end()) { OS << "FieldFromInstruction(fieldFromInstruction_3, uint32_t)\n" << "DecodeToMCInst(decodeToMCInst_3, fieldFromInstruction_3, uint32_t)\n" << "DecodeInstruction(decodeInstruction_3, fieldFromInstruction_3, " "decodeToMCInst_3, uint32_t)\n\n"; MacroDefined = true; } if (InsnBytesAsUint32.find(TargetName) != InsnBytesAsUint32.end()) { OS << "FieldFromInstruction(fieldFromInstruction_4, uint32_t)\n" << "DecodeToMCInst(decodeToMCInst_4, fieldFromInstruction_4, uint32_t)\n" << "DecodeInstruction(decodeInstruction_4, fieldFromInstruction_4, " "decodeToMCInst_4, uint32_t)\n"; MacroDefined = true; } if (InsnBytesAsUint64.find(TargetName) != InsnBytesAsUint64.end()) { OS << "FieldFromInstruction(fieldFromInstruction_8, uint64_t)\n" << "DecodeToMCInst(decodeToMCInst_8, fieldFromInstruction_8, uint64_t)\n" << "DecodeInstruction(decodeInstruction_8, fieldFromInstruction_8, " "decodeToMCInst_8, uint64_t)\n"; MacroDefined = true; } // Special case: The LLVM disassembler uses uint64_t values for decoding. // Although PPC instructions are 4 bytes wide. if (TargetName == "PPC") { OS << "FieldFromInstruction(fieldFromInstruction_4, uint64_t)\n" << "DecodeToMCInst(decodeToMCInst_4, fieldFromInstruction_4, uint64_t)\n" << "DecodeInstruction(decodeInstruction_4, fieldFromInstruction_4, " "decodeToMCInst_4, uint64_t)\n"; MacroDefined = true; } if (!MacroDefined) { llvm_unreachable( "No decoder macro was defined. Please add the missing arch.\n\n"); } } void PrinterCapstone::decoderEmitterEmitTable( 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::decoderEmitterEmitInstrLenTable( std::vector &InstrLen) const { OS << "static const uint8_t InstrLenTable[] = {\n"; for (unsigned const &Len : InstrLen) { OS << Len << ",\n"; } OS << "};\n\n"; } void PrinterCapstone::decoderEmitterEmitPredicateFunction( 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(MCInst *Inst, unsigned Idx" << ") {\n"; Indentation += 2; if (!Predicates.empty()) { OS.indent(Indentation) << "switch (Idx) {\n"; OS.indent(Indentation) << "default: CS_ASSERT_RET_VAL(0 && \"Invalid index!\", false);\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) << "CS_ASSERT_RET_VAL(0 && \"Invalid index!\", false);\n"; } Indentation -= 2; OS.indent(Indentation) << "}\n\n"; } void PrinterCapstone::decoderEmitterEmitDecoderFunction( 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, const void *Decoder, bool " "*DecodeComplete) \\\n" << "{ \\\n"; Indentation += 2; OS.indent(Indentation) << "*DecodeComplete = true; \\\n"; if (TargetName != "TriCore") { OS.indent(Indentation) << "InsnType tmp; \\\n"; } OS.indent(Indentation) << "switch (Idx) { \\\n"; OS.indent(Indentation) << "default: CS_ASSERT_RET_VAL(0 && \"Invalid " "index!\", MCDisassembler_Fail); \\\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::decoderEmitterEmitIncludes() const { OS << "#include \"../../MCInst.h\"\n" << "#include \"../../cs_priv.h\"\n" << "#include \"../../LEB128.h\"\n\n"; } void PrinterCapstone::decoderEmitterEmitSourceFileHeader() const { emitDefaultSourceFileHeader(OS); } //------------------------- // Backend: AsmWriter //------------------------- void PrinterCapstone::asmWriterEmitSourceFileHeader( RecordKeeper &Records) const { emitDefaultSourceFileHeader(OS); OS << "#include \n" << "#include \"../../cs_priv.h\"\n\n"; } void PrinterCapstone::asmWriterEmitGetMnemonic( std::string const &TargetName, StringRef const &ClassName) const { OS << "/// getMnemonic - This method is automatically generated by " "tablegen\n" "/// from the instruction set description.\n" "static MnemonicBitsInfo getMnemonic(MCInst *MI, SStream *O) {\n"; } void PrinterCapstone::asmWriterEmitAsmStrs( SequenceToOffsetTable const &StrTable) const { StrTable.emitStringLiteralDef(OS, " static const char AsmStrs[]"); } void PrinterCapstone::asmWriterEmitMnemonicDecodeTable( unsigned const OpcodeInfoBits, unsigned BitsLeft, unsigned const &AsmStrBits, ArrayRef const &NumberedInstructions, std::vector const &OpcodeInfo) const { // Emit the lookup tables in pieces to minimize wasted bytes. unsigned BytesNeeded = ((OpcodeInfoBits - BitsLeft) + 7) / 8; unsigned Table = 0, Shift = 0; SmallString<128> BitsString; raw_svector_ostream BitsOS(BitsString); // If the total bits is more than 32-bits we need to use a 64-bit type. BitsOS << " uint" << ((BitsLeft < (OpcodeInfoBits - 32)) ? 64 : 32) << "_t Bits = 0;\n"; while (BytesNeeded != 0) { // Figure out how big this table section needs to be, but no bigger than 4. unsigned TableSize = std::min(1 << Log2_32(BytesNeeded), 4); BytesNeeded -= TableSize; TableSize *= 8; // Convert to bits; uint64_t const Mask = (1ULL << TableSize) - 1; OS << " static const uint" << TableSize << "_t OpInfo" << Table << "[] = {\n"; for (unsigned I = 0, E = NumberedInstructions.size(); I != E; ++I) { OS << " " << ((OpcodeInfo[I] >> Shift) & Mask) << "U,\t// " << NumberedInstructions[I]->TheDef->getName() << "\n"; } OS << " };\n\n"; // Emit string to combine the individual table lookups. BitsOS << " Bits |= "; // If the total bits is more than 32-bits we need to use a 64-bit type. if (BitsLeft < (OpcodeInfoBits - 32)) BitsOS << "(uint64_t)"; BitsOS << "OpInfo" << Table << "[MCInst_getOpcode(MI)] << " << Shift << ";\n"; // Prepare the shift for the next iteration and increment the table count. Shift += TableSize; ++Table; } OS << " // Emit the opcode for the instruction.\n"; OS << BitsString; // Return mnemonic string and bits. OS << " MnemonicBitsInfo MBI = {\n" << "#ifndef CAPSTONE_DIET\n" << " AsmStrs+(Bits & " << (1 << AsmStrBits) - 1 << ")-1,\n" << "#else\n" << " NULL,\n" << "#endif // CAPSTONE_DIET\n" << " Bits\n" << " };\n"; OS << " return MBI;\n"; OS << "}\n\n"; } void PrinterCapstone::asmWriterEmitPrintInstruction( std::string const &TargetName, std::vector> &TableDrivenOperandPrinters, unsigned &BitsLeft, unsigned &AsmStrBits, StringRef const &ClassName, bool PassSubtarget) const { const unsigned OpcodeInfoBits = 64; // This function has some huge switch statements that causing excessive // compile time in LLVM profile instrumenation build. This print function // usually is not frequently called in compilation. Here we disable the // profile instrumenation for this function. OS << "/// printInstruction - This method is automatically generated by " "tablegen\n" "/// from the instruction set description.\n" "static void " << "printInstruction(MCInst *MI, uint64_t Address, " << "SStream *O) {\n"; // Emit the initial tab character. OS << " SStream_concat0(O, \"\");\n"; // Emit the starting string. OS << " MnemonicBitsInfo MnemonicInfo = getMnemonic(MI, O);\n\n"; OS << " SStream_concat0(O, MnemonicInfo.first);\n\n"; OS << " uint" << ((BitsLeft < (OpcodeInfoBits - 32)) ? 64 : 32) << "_t Bits = MnemonicInfo.second;\n" << " CS_ASSERT_RET(Bits != 0 && \"Cannot print this instruction.\");\n"; // Output the table driven operand information. BitsLeft = OpcodeInfoBits - AsmStrBits; for (unsigned I = 0, E = TableDrivenOperandPrinters.size(); I != E; ++I) { std::vector &Commands = TableDrivenOperandPrinters[I]; // Compute the number of bits we need to represent these cases, this is // ceil(log2(numentries)). unsigned const NumBits = Log2_32_Ceil(Commands.size()); assert(NumBits <= BitsLeft && "consistency error"); // Emit code to extract this field from Bits. OS << "\n // Fragment " << I << " encoded into " << NumBits << " bits for " << Commands.size() << " unique commands.\n"; if (Commands.size() == 2) { // Emit two possibilitys with if/else. OS << " if ((Bits >> " << (OpcodeInfoBits - BitsLeft) << ") & " << ((1 << NumBits) - 1) << ") {\n" << translateToC(TargetName, Commands[1]) << " } else {\n" << translateToC(TargetName, Commands[0]) << " }\n\n"; } else if (Commands.size() == 1) { // Emit a single possibility. OS << translateToC(TargetName, Commands[0]) << "\n\n"; } else { OS << " switch ((Bits >> " << (OpcodeInfoBits - BitsLeft) << ") & " << ((1 << NumBits) - 1) << ") {\n" << " default: CS_ASSERT_RET(0 && \"Invalid command number.\");\n"; // Print out all the cases. for (unsigned J = 0, F = Commands.size(); J != F; ++J) { OS << " case " << J << ":\n"; OS << translateToC(TargetName, Commands[J]); OS << " break;\n"; } OS << " }\n\n"; } BitsLeft -= NumBits; } } void PrinterCapstone::asmWriterEmitOpCases( std::vector> &OpsToPrint, bool PassSubtarget) const { OS << " case " << OpsToPrint.back().first << ":"; AsmWriterOperand const TheOp = OpsToPrint.back().second; OpsToPrint.pop_back(); // Check to see if any other operands are identical in this list, and if so, // emit a case label for them. for (unsigned I = OpsToPrint.size(); I != 0; --I) if (OpsToPrint[I - 1].second == TheOp) { OS << "\n case " << OpsToPrint[I - 1].first << ":"; OpsToPrint.erase(OpsToPrint.begin() + I - 1); } // Finally, emit the code. OS << "\n " << translateToC(TargetName, TheOp.getCode(PassSubtarget)); OS << "\n break;\n"; } void PrinterCapstone::asmWriterEmitInstrSwitch() const { OS << " switch (MCInst_getOpcode(MI)) {\n"; OS << " default: CS_ASSERT_RET(0 && \"Unexpected opcode.\");\n"; } void PrinterCapstone::asmWriterEmitCompoundClosure(unsigned Indent, bool Newline, bool Semicolon) const { for (; Indent > 0; --Indent) { OS << " "; } OS << "}"; if (Semicolon) OS << ";"; if (Newline) OS << "\n"; } void PrinterCapstone::asmWriterEmitInstruction( AsmWriterInst const &FirstInst, std::vector const &SimilarInsts, unsigned DifferingOperand, bool PassSubtarget) const { OS << " case " << FirstInst.CGI->Namespace << "_" << FirstInst.CGI->TheDef->getName() << ":\n"; for (const AsmWriterInst &AWI : SimilarInsts) OS << " case " << AWI.CGI->Namespace << "_" << AWI.CGI->TheDef->getName() << ":\n"; for (unsigned I = 0, E = FirstInst.Operands.size(); I != E; ++I) { if (I != DifferingOperand) { // If the operand is the same for all instructions, just print it. OS << " " << translateToC(TargetName, FirstInst.Operands[I].getCode(PassSubtarget)); } else { // If this is the operand that varies between all of the instructions, // emit a switch for just this operand now. OS << " switch (MCInst_getOpcode(MI)) {\n"; OS << " default: CS_ASSERT_RET(0 && \"Unexpected opcode.\");\n"; std::vector> OpsToPrint; OpsToPrint.push_back( std::make_pair(FirstInst.CGI->Namespace.str() + "_" + FirstInst.CGI->TheDef->getName().str(), FirstInst.Operands[I])); for (const AsmWriterInst &AWI : SimilarInsts) { OpsToPrint.push_back(std::make_pair( AWI.CGI->Namespace.str() + "_" + AWI.CGI->TheDef->getName().str(), AWI.Operands[I])); } std::reverse(OpsToPrint.begin(), OpsToPrint.end()); while (!OpsToPrint.empty()) asmWriterEmitOpCases(OpsToPrint, PassSubtarget); OS << " }"; } OS << "\n"; } OS << " break;\n"; } void PrinterCapstone::asmWriterEmitGetRegNameAssert( std::string const &TargetName, StringRef const &ClassName, bool HasAltNames, unsigned RegSize) const { OS << "\n\n/// getRegisterName - This method is automatically generated by " "tblgen\n" "/// from the register set description. This returns the assembler " "name\n" "/// for the specified register.\n" "static const char *"; if (HasAltNames) OS << "\ngetRegisterName(unsigned RegNo, unsigned AltIdx) {\n"; else OS << "getRegisterName(unsigned RegNo) {\n"; OS << "#ifndef CAPSTONE_DIET\n"; OS << " CS_ASSERT_RET_VAL(RegNo && RegNo < " << (RegSize + 1) << " && \"Invalid register number!\", NULL);\n" << "\n"; } void PrinterCapstone::asmWriterEmitStringLiteralDef( SequenceToOffsetTable const &StringTable, StringRef const &AltName) const { StringTable.emitStringLiteralDef(OS, Twine(" static const char AsmStrs") + AltName + "[]"); } void PrinterCapstone::asmWriterEmitRegAsmOffsets( unsigned RegSizes, SmallVector const &AsmNames, SequenceToOffsetTable const &StringTable, StringRef const &AltName) const { OS << " static const " << getMinimalTypeForRange(StringTable.size() - 1, 32) << " RegAsmOffset" << AltName << "[] = {"; for (unsigned I = 0, E = RegSizes; I != E; ++I) { if ((I % 14) == 0) OS << "\n "; OS << StringTable.get(AsmNames[I]) << ", "; } OS << "\n };\n" << "\n"; } void PrinterCapstone::asmWriterEmitAltIdxSwitch( bool HasAltNames, std::vector const &AltNameIndices, StringRef const &Namespace) const { if (HasAltNames) { OS << " switch(AltIdx) {\n" << " default: CS_ASSERT_RET_VAL(0 && \"Invalid register alt name " "index!\", NULL);\n"; for (const Record *R : AltNameIndices) { StringRef const AltName = R->getName(); OS << " case "; if (!Namespace.empty()) OS << Namespace << "_"; OS << AltName << ":\n"; if (R->isValueUnset("FallbackRegAltNameIndex")) OS << " CS_ASSERT_RET_VAL(*(AsmStrs" << AltName << "+RegAsmOffset" << AltName << "[RegNo-1]) &&\n" << " \"Invalid alt name index for register!\", NULL);\n"; else { OS << " if (!*(AsmStrs" << AltName << "+RegAsmOffset" << AltName << "[RegNo-1]))\n" << " return getRegisterName(RegNo, "; if (!Namespace.empty()) OS << Namespace << "_"; OS << R->getValueAsDef("FallbackRegAltNameIndex")->getName() << ");\n"; } OS << " return AsmStrs" << AltName << "+RegAsmOffset" << AltName << "[RegNo-1];\n"; } OS << " }\n"; } else { OS << " CS_ASSERT_RET_VAL(*(AsmStrs+RegAsmOffset[RegNo-1]) &&\n" << " \"Invalid alt name index for register!\", NULL);\n" << " return AsmStrs+RegAsmOffset[RegNo-1];\n"; } OS << "#else\n" << " return NULL;\n" << "#endif // CAPSTONE_DIET\n"; OS << "}\n"; } char const *PrinterCapstone::asmWriterGetPatCondKIgnore() const { return "AliasPatternCond_K_Ignore, 0"; } char const *PrinterCapstone::asmWriterGetPatCondKRegClass() const { return "AliasPatternCond_K_RegClass, {0}_{1}RegClassID"; } char const *PrinterCapstone::asmWriterGetPatCondKTiedReg() const { return "AliasPatternCond_K_TiedReg, {0}"; } char const *PrinterCapstone::asmWriterGetPatCondKCustom() const { return "AliasPatternCond_K_Custom, {0}"; } char const *PrinterCapstone::asmWriterGetPatCondKImm() const { return "AliasPatternCond_K_Imm, (uint32_t){0}"; } char const *PrinterCapstone::asmWriterGetPatCondKNoReg() const { return "AliasPatternCond_K_Reg, {0}_NoRegister"; } char const *PrinterCapstone::asmWriterGetPatCondKReg() const { return "AliasPatternCond_K_Reg, {0}_{1}"; } char const *PrinterCapstone::asmWriterGetPatCondKFeature() const { return "AliasPatternCond_K_{0}{1}Feature, {2}_{3}"; } char const *PrinterCapstone::asmWriterGetPatCondKEndOrFeature() const { return "AliasPatternCond_K_EndOrFeatures, 0"; } char const *PrinterCapstone::asmWriterGetPatOpcStart() const { return " // {0} - {1}\n"; } char const *PrinterCapstone::asmWriterGetCondPatStart() const { return " // {0} - {1}\n"; } std::string PrinterCapstone::asmWriterGetCond(std::string const &Cond) const { return formatv(" {{{0}},\n", Cond); } char const *PrinterCapstone::asmWriterGetPatternFormat() const { return " {{{0}, {1}, {2}, {3} },\n"; } char const *PrinterCapstone::asmWriterGetOpcodeFormat() const { return " {{{0}, {1}, {2} },\n"; } void PrinterCapstone::asmWriterEmitPrintAliasInstrHeader( std::string const &TargetName, StringRef const &ClassName, bool PassSubtarget) const { OS << "static bool printAliasInstr(MCInst" << " *MI, uint64_t Address, " << "SStream *OS) {\n" << "#ifndef CAPSTONE_DIET\n"; } void PrinterCapstone::asmWriterEmitPrintAliasInstrBodyRetFalse() const { OS << " return false;\n"; OS << "#endif // CAPSTONE_DIET\n"; OS << "}\n\n"; } void PrinterCapstone::asmWriterEmitDeclValid(std::string const &TargetName, StringRef const &ClassName) const { OS << "static bool " << TargetName << ClassName << "ValidateMCOperand(const MCOperand *MCOp,\n" << " unsigned PredicateIndex);\n"; } void PrinterCapstone::asmWriterEmitPrintAliasInstrBody( raw_string_ostream &OpcodeO, raw_string_ostream &PatternO, raw_string_ostream &CondO, std::vector> const &AsmStrings, std::vector const &MCOpPredicates, std::string const &TargetName, StringRef const &ClassName, bool PassSubtarget) const { OS.indent(2) << "static const PatternsForOpcode OpToPatterns[] = {\n"; OS << OpcodeO.str(); OS.indent(2) << "{0},"; // Null terminated to ease binary search. OS.indent(2) << "};\n\n"; OS.indent(2) << "static const AliasPattern Patterns[] = {\n"; OS << PatternO.str(); OS.indent(2) << "{0},"; OS.indent(2) << "};\n\n"; OS.indent(2) << "static const AliasPatternCond Conds[] = {\n"; OS << CondO.str(); OS.indent(2) << "{0},"; OS.indent(2) << "};\n\n"; OS.indent(2) << "static const char AsmStrings[] =\n"; for (const auto &P : AsmStrings) { OS.indent(4) << "/* " << P.first << " */ \"" << P.second << "\\0\"\n"; } OS.indent(2) << ";\n\n"; // Assert that the opcode table is sorted. Use a static local constructor to // ensure that the check only happens once on first run. OS << "#ifndef NDEBUG\n"; OS.indent(2) << "//static struct SortCheck {\n"; OS.indent(2) << "// SortCheck(ArrayRef OpToPatterns) {\n"; OS.indent(2) << "// assert(std::is_sorted(\n"; OS.indent(2) << "// OpToPatterns.begin(), OpToPatterns.end(),\n"; OS.indent(2) << "// [](const PatternsForOpcode &L, const " "//PatternsForOpcode &R) {\n"; OS.indent(2) << "// return L.Opcode < R.Opcode;\n"; OS.indent(2) << "// }) &&\n"; OS.indent(2) << "// \"tablegen failed to sort opcode patterns\");\n"; OS.indent(2) << "// }\n"; OS.indent(2) << "//} sortCheckVar(OpToPatterns);\n"; OS << "#endif\n\n"; OS.indent(2) << "AliasMatchingData M = {\n"; OS.indent(2) << " OpToPatterns,\n"; OS.indent(2) << " Patterns,\n"; OS.indent(2) << " Conds,\n"; OS.indent(2) << " AsmStrings,\n"; if (!MCOpPredicates.empty()) OS.indent(2) << " " << TargetName << ClassName << "ValidateMCOperand,\n"; else OS.indent(2) << " NULL,\n"; OS.indent(2) << "};\n"; OS.indent(2) << "const char *AsmString = matchAliasPatterns(MI, &M);\n"; OS.indent(2) << "if (!AsmString) return false;\n\n"; // Code that prints the alias, replacing the operands with the ones from the // MCInst. OS << " unsigned I = 0;\n"; OS << " while (AsmString[I] != ' ' && AsmString[I] != '\\t' &&\n"; OS << " AsmString[I] != '$' && AsmString[I] != '\\0')\n"; OS << " ++I;\n"; OS << " SStream_concat1(OS, '\\t');\n" << " char *substr = malloc(I+1);\n" << " memcpy(substr, AsmString, I);\n" << " substr[I] = '\\0';\n" << " SStream_concat0(OS, substr);\n" << " free(substr);\n"; OS << " if (AsmString[I] != '\\0') {\n"; OS << " if (AsmString[I] == ' ' || AsmString[I] == '\\t') {\n"; OS << " SStream_concat1(OS, '\\t');\n"; OS << " ++I;\n"; OS << " }\n"; OS << " do {\n"; OS << " if (AsmString[I] == '$') {\n"; OS << " ++I;\n"; OS << " if (AsmString[I] == (char)0xff) {\n"; OS << " ++I;\n"; OS << " int OpIdx = AsmString[I++] - 1;\n"; OS << " int PrintMethodIdx = AsmString[I++] - 1;\n"; OS << " printCustomAliasOperand(MI, Address, OpIdx, " "PrintMethodIdx, "; OS << "OS);\n"; OS << " } else\n"; OS << " printOperand(MI, ((unsigned)AsmString[I++]) - 1, "; OS << "OS);\n"; OS << " } else {\n"; OS << " SStream_concat1(OS, AsmString[I++]);\n"; OS << " }\n"; OS << " } while (AsmString[I] != '\\0');\n"; OS << " }\n\n"; OS << " return true;\n"; OS << "#else\n" << " return false;\n"; OS << "#endif // CAPSTONE_DIET\n"; OS << "}\n\n"; } void PrinterCapstone::asmWriterEmitPrintAliasOp( std::string const &TargetName, StringRef const &ClassName, std::vector> const &PrintMethods, bool PassSubtarget) const { OS << "static void printCustomAliasOperand(\n" << " MCInst *MI, uint64_t Address, unsigned OpIdx,\n" << " unsigned PrintMethodIdx,\n" << " SStream *OS) {\n" << "#ifndef CAPSTONE_DIET\n"; if (PrintMethods.empty()) OS << " CS_ASSERT_RET(0 && \"Unknown PrintMethod kind\");\n"; else { OS << " switch (PrintMethodIdx) {\n" << " default:\n" << " CS_ASSERT_RET(0 && \"Unknown PrintMethod kind\");\n" << " break;\n"; for (unsigned I = 0; I < PrintMethods.size(); ++I) { OS << " case " << I << ":\n"; std::string PrintMethod = PrinterCapstone::translateToC(TargetName, PrintMethods[I].first); OS << " " << PrintMethod << "(MI, " << (PrintMethods[I].second ? "Address, " : "") << "OpIdx, " << "OS);\n" << " break;\n"; } OS << " }\n"; } OS << "#endif // CAPSTONE_DIET\n"; OS << "}\n\n"; } void PrinterCapstone::asmWriterEmitPrintMC( std::string const &TargetName, StringRef const &ClassName, std::vector const &MCOpPredicates) const { if (!MCOpPredicates.empty()) { OS << "static bool " << TargetName << ClassName << "ValidateMCOperand(const MCOperand *MCOp,\n" << " unsigned PredicateIndex) {\n" << " switch (PredicateIndex) {\n" << " default:\n" << " CS_ASSERT_RET_VAL(0 && \"Unknown MCOperandPredicate kind\", " "false);\n" << " return false;\n"; for (unsigned I = 0; I < MCOpPredicates.size(); ++I) { StringRef const MCOpPred = MCOpPredicates[I]->getValueAsString("MCOperandPredicate"); OS << " case " << I + 1 << ": {\n"; std::string PrintMethod = PrinterCapstone::translateToC(TargetName, MCOpPred.data()); OS << PrintMethod << "\n" << " }\n"; } OS << " }\n" << "}\n\n"; } } //------------------------- // Backend: Subtarget //------------------------- void PrinterCapstone::subtargetEmitGetMacroFusions( CodeGenTarget &TGT, std::string Target, const std::string &ClassName) const { return; } void PrinterCapstone::subtargetEmitSourceFileHeader() const { emitDefaultSourceFileHeader(OS); } void PrinterCapstone::subtargetEmitFeatureEnum( DenseMap &FeatureMap, std::vector const &DefList, unsigned N) const { StringRef TN = StringRef(TargetName); // Open enumeration. OS << "enum {\n"; // For each record for (unsigned I = 0; I < N; ++I) { // Next record Record *Def = DefList[I]; // Get and emit name OS << " " << TN << "_" << Def->getName() << " = " << I << ",\n"; // Save the index for this feature. FeatureMap[Def] = I; } OS << " " << TN << "_" << "NumSubtargetFeatures = " << N << "\n"; // Close enumeration and namespace OS << "};\n"; } void PrinterCapstone::subtargetEmitGetSTIMacro( StringRef const &Value, StringRef const &Attribute) const {} void PrinterCapstone::subtargetEmitHwModes(CodeGenHwModes const &CGH, std::string const &ClassName) const { } void PrinterCapstone::subtargetEmitFeatureKVHeader( std::string const &Target) const { // Begin feature table } void PrinterCapstone::subtargetEmitFeatureKVPartI( std::string const &Target, StringRef const &CommandLineName, StringRef const &Name, StringRef const &Desc) const {} void PrinterCapstone::subtargetEmitFeatureKVPartII() const {} void PrinterCapstone::subtargetEmitPrintFeatureMask( std::array const &Mask) const {} void PrinterCapstone::subtargetEmitFeatureKVEnd() const {} void PrinterCapstone::subtargetEmitCPUKVHeader( std::string const &Target) const {} void PrinterCapstone::subtargetEmitCPUKVEnd() const {} void PrinterCapstone::subtargetEmitCPUKVPartI(StringRef const &Name) const {} void PrinterCapstone::subtargetEmitCPUKVPartII() const {} void PrinterCapstone::subtargetEmitCPUKVPartIII( std::string const &ProcModelName) const {} void PrinterCapstone::subtargetEmitDBGMacrosBegin() const {} void PrinterCapstone::subtargetEmitDBGMacrosEnd() const {} void PrinterCapstone::subtargetEmitFunctionalItinaryUnits( CodeGenSchedModels const &SchedModels) const {} std::string const PrinterCapstone::subtargetGetBeginStageTable( std::string const &TargetName) const { return ""; } std::string const PrinterCapstone::subtargetGetBeginOperandCycleTable( std::string const &TargetName) const { return ""; } std::string const PrinterCapstone::subtargetGetBeginBypassTable( std::string const &TargetName) const { return ""; } std::string const PrinterCapstone::subtargetGetEndStageTable() const { return ""; } std::string const PrinterCapstone::subtargetGetEndOperandCycleTable() const { return ""; } std::string const PrinterCapstone::subtargetGetEndBypassTable() const { return ""; } // subtargetFormItineraryStageString - Compose a string containing the stage // data initialization for the specified itinerary. N is the number // of stages. void PrinterCapstone::subtargetFormItineraryStageString( std::string const &Name, Record *ItinData, std::string &ItinString, unsigned &NStages) const {} // FormItineraryOperandCycleString - Compose a string containing the // operand cycle initialization for the specified itinerary. N is the // number of operands that has cycles specified. void PrinterCapstone::subtargetFormItineraryOperandCycleString( Record *ItinData, std::string &ItinString, unsigned &NOperandCycles) const { } void PrinterCapstone::subtargetFormItineraryBypassString( const std::string &Name, Record *ItinData, std::string &ItinString, unsigned NOperandCycles) const {} std::string PrinterCapstone::subtargetGetStageEntryPartI(std::string const &ItinStageString, unsigned StageCount) const { return ""; } std::string PrinterCapstone::subtargetGetStageEntryPartII(unsigned StageCount, unsigned NStages) const { return ""; } std::string PrinterCapstone::subtargetGetStageEntryPartIII() const { return ""; } std::string PrinterCapstone::subtargetGetOperandCycleEntryPartI( std::string const &ItinOperandCycleString) const { return ""; } std::string PrinterCapstone::subtargetGetOperandCycleEntryPartII( unsigned OperandCycleCount, unsigned NOperandCycles) const { return ""; } std::string PrinterCapstone::subtargetGetOperandCycleEntryPartIII( std::string const &OperandIdxComment) const { return ""; } std::string PrinterCapstone::subtargetGetOperandCycleEntryPartIV( std::string const &ItinBypassString, std::string const &OperandIdxComment) const { return ""; } void PrinterCapstone::subtargetEmitProcessorItineraryTable( std::string const &ItinsDefName, std::vector &ItinList, CodeGenSchedModels const &SchedModels) const {} void PrinterCapstone::subtargetEmitPreOperandTableComment() const {} // Emit SchedClass tables for all processors and associated global tables. void PrinterCapstone::subtargetEmitSchedClassTables( SchedClassTablesT &SchedTables, std::string const &TargetName, CodeGenSchedModels const &SchedModels) const {} unsigned PrinterCapstone::subtargetEmitRegisterFileTables( CodeGenProcModel const &ProcModel) const { return 0; } void PrinterCapstone::subtargetEmitMCExtraProcInfoTableHeader( std::string const &ProcModelName) const {} void PrinterCapstone::subtargetEmitMCExtraProcInfoTableEnd() const {} void PrinterCapstone::subtargetEmitReorderBufferSize( int64_t ReorderBufferSize) const {} void PrinterCapstone::subtargetEmitMaxRetirePerCycle( int64_t MaxRetirePerCycle) const {} void PrinterCapstone::subtargetEmitRegisterFileInfo( CodeGenProcModel const &ProcModel, unsigned NumRegisterFiles, unsigned NumCostEntries) const {} void PrinterCapstone::subtargetEmitResourceDescriptorLoadQueue( unsigned QueueID) const {} void PrinterCapstone::subtargetEmitResourceDescriptorStoreQueue( unsigned QueueID) const {} void PrinterCapstone::subtargetEmitProcessorResourceSubUnits( const CodeGenProcModel &ProcModel, CodeGenSchedModels const &SchedModels) const {} void PrinterCapstone::subtargetEmitMCProcResourceDescHeader( std::string const &ProcModelName) const {} void PrinterCapstone::subtargetEmitMCProcResourceDescEnd() const {} void PrinterCapstone::subtargetEmitMCProcResourceDesc( Record const *PRDef, Record const *SuperDef, std::string const &ProcModelName, unsigned SubUnitsOffset, unsigned SuperIdx, unsigned NumUnits, int BufferSize, unsigned I, unsigned const SubUnitsBeginOffset) const {} // Emit either the value defined in the TableGen Record, or the default // value defined in the C++ header. The Record is null if the processor does not // define a model. void PrinterCapstone::subtargetEmitProcessorProp(Record const *R, StringRef const Name, char Separator) const {} void PrinterCapstone::subtargetEmitProcModelHeader( std::string const &ModelName) const {} void PrinterCapstone::subtargetEmitProcModel( CodeGenProcModel const &PM, CodeGenSchedModels const &SchedModels) const {} void PrinterCapstone::subtargetEmitResolveVariantSchedClassImplHdr() const {} void PrinterCapstone::subtargetEmitResolveVariantSchedClassImplEnd() const {} void PrinterCapstone::subtargetEmitSchedClassSwitch() const {} void PrinterCapstone::subtargetEmitSchedClassCase( unsigned VC, std::string const &SCName) const {} void PrinterCapstone::subtargetEmitSchedClassProcGuard( unsigned Pi, bool OnlyExpandMCInstPredicates, std::string const &ModelName) const {} // Indent <= -1 (default = -1) means previous PE indent level. void PrinterCapstone::subtargetEmitPredicates( CodeGenSchedTransition const &T, CodeGenSchedClass const &SC, bool (*IsTruePredicate)(Record const *Rec), int Indent) const {} void PrinterCapstone::subtargetEmitProcTransitionEnd() const {} void PrinterCapstone::subtargetEmitSchedClassCaseEnd( CodeGenSchedClass const &SC) const {} void PrinterCapstone::subtargetEmitSchedClassSwitchEnd() const {} // Used by method `SubtargetEmitter::emitSchedModelHelpersImpl()` to generate // epilogue code for the auto-generated helper. void PrinterCapstone::subtargetEmitSchedModelHelperEpilogue( bool ShouldReturnZero) const {} void PrinterCapstone::subtargetEmitGenMCSubtargetInfoClass( std::string const &TargetName, bool OverrideGetHwMode) const {} void PrinterCapstone::subtargetEmitMCSubtargetInfoImpl( std::string const &TargetName, unsigned NumFeatures, unsigned NumProcs, bool SchedModelHasItin) const {} void PrinterCapstone::subtargetEmitIncludeSTIDesc() const {} void PrinterCapstone::subtargetEmitDFAPacketizerClass( CodeGenTarget &TGT, std::string const &TargetName, std::string const &ClassName) const {} void PrinterCapstone::subtargetEmitDFAPacketizerClassEnd() const {} void PrinterCapstone::subtargetEmitSTICtor() const {} void PrinterCapstone::subtargetEmitExternKVArrays( std::string const &TargetName, bool SchedModelsHasItin) const {} void PrinterCapstone::subtargetEmitClassDefs(std::string const &TargetName, std::string const &ClassName, unsigned NumFeatures, unsigned NumProcs, bool SchedModelsHasItin) const {} void PrinterCapstone::subtargetEmitResolveSchedClassHdr( std::string const &ClassName) const {} void PrinterCapstone::subtargetEmitResolveSchedClassEnd( std::string const &ClassName) const {} void PrinterCapstone::subtargetEmitResolveVariantSchedClass( std::string const &TargetName, std::string const &ClassName) const {} void PrinterCapstone::subtargetEmitPredicateProlog( const RecordKeeper &Records) const {} void PrinterCapstone::subtargetEmitParseFeaturesFunction( std::string const &TargetName, std::vector const &Features) const {} void PrinterCapstone::subtargetEmitExpandedSTIPreds( StringRef const &TargetName, std::string const &ClassName, CodeGenSchedModels const &SchedModels) {} void PrinterCapstone::subtargetPrepareSchedClassPreds( StringRef const &TargetName, bool OnlyExpandMCInstPredicates) {} void PrinterCapstone::subtargetEmitExpandedSTIPredsMCAnaDecl( StringRef const &TargetName, CodeGenSchedModels const &SchedModels) {} void PrinterCapstone::subtargetEmitExpandedSTIPredsMCAnaDefs( StringRef const &TargetName, std::string const &ClassPrefix, CodeGenSchedModels const &SchedModels) const {} void PrinterCapstone::subtargetEmitExpandedSTIPredsHeader( StringRef const &TargetName, CodeGenSchedModels const &SchedModels) {} void PrinterCapstone::subtargetEmitStageAndSycleTables( std::string const &StageTable, std::string const &OperandCycleTable, std::string const &BypassTable) const {} //--------------------------- // Backend: InstrInfoEmitter //--------------------------- void PrinterCapstone::instrInfoEmitSourceFileHeader() const { emitDefaultSourceFileHeader(OS); } void PrinterCapstone::instrInfoEmitSetGetComputeFeatureMacro() const {} void PrinterCapstone::instrInfoSetOperandInfoStr( std::string &Res, Record const *OpR, CGIOperandList::OperandInfo const &Op, CGIOperandList::ConstraintInfo const &Constraint) const { if (OpR->isSubClassOf("RegisterOperand")) OpR = OpR->getValueAsDef("RegClass"); if (OpR->isSubClassOf("RegisterClass")) Res += OpR->getValueAsString("Namespace").str() + "_" + OpR->getName().str() + "RegClassID, "; else if (OpR->isSubClassOf("PointerLikeRegClass")) Res += utostr(OpR->getValueAsInt("RegClassKind")) + ", "; else // -1 means the operand does not have a fixed register class. Res += "-1, "; // Fill in applicable flags. Res += "0"; // Ptr value whose register class is resolved via callback. if (OpR->isSubClassOf("PointerLikeRegClass")) Res += "|(1<isSubClassOf("PredicateOp")) Res += "|(1<isSubClassOf("OptionalDefOperand")) Res += "|(1<isSubClassOf("BranchTargetOperand")) Res += "|(1<> ImplicitLists, std::map, unsigned> &EmittedLists) const { for (auto &List : ImplicitLists) { OS << " /* " << EmittedLists[List] << " */"; for (auto &Reg : List) OS << ' ' << getQualifiedName(Reg) << ','; OS << '\n'; } } void PrinterCapstone::instrInfoEmitRecord(CodeGenSchedModels const &SchedModels, CodeGenInstruction const &Inst, unsigned Num, int MinOperands) const { OS << " { " << MinOperands << ", "; } void PrinterCapstone::instrInfoEmitTargetIndepFlags( CodeGenInstruction const &Inst, bool GetAllowRegisterRenaming) const {} void PrinterCapstone::instrInfoEmitTSFFlags(uint64_t Value) const {} void PrinterCapstone::instrInfoEmitUseDefsLists( StringRef TargetName, const CodeGenInstruction &Inst, std::map, unsigned> &EmittedLists, std::vector const &ImplicitOps) const {} void PrinterCapstone::instrInfoEmitOperandInfo( OperandInfoListTy &OperandInfoList) const { unsigned Offset = 0; for (auto &OperandInfo : OperandInfoList) { OS << " /* " << Offset << " */"; for (auto &Info : OperandInfo) OS << " { " << Info << " },"; OS << '\n'; Offset += OperandInfo.size(); } } void PrinterCapstone::instrInfoEmitOperandInfoOffset( StringRef TargetName, std::vector const &OperandInfo, OperandInfoMapTy const &OperandInfoMap) const { // We emit the pointer to the MCOperandInfo entry within this array. OS << "&" << TargetName << "Descs.OperandInfo[" << OperandInfoMap.find(OperandInfo)->second << "]"; } void PrinterCapstone::instrInfoEmitRecordEnd( unsigned InstNum, std::string const &InstName) const { OS << " }, // Inst #" << InstNum << " = " << InstName << "\n"; } void PrinterCapstone::instrInfoEmitMCInstrDescDecl( std::string const &TargetName, unsigned NumberedInstructionsSize, unsigned OperandInfoSize, unsigned ImplicitListSize) const { OS << "typedef struct " << TargetName << "InstrTable {\n"; OS << " MCInstrDesc Insts[" << NumberedInstructionsSize << "];\n"; OS << " MCOperandInfo OperandInfo[" << OperandInfoSize << "];\n"; OS << " MCPhysReg ImplicitOps[" << ImplicitListSize << "];\n"; OS << "} " << TargetName << "InstrTable;\n\n"; } void PrinterCapstone::instrInfoEmitStringLiteralDef( std::string const &TargetName, SequenceToOffsetTable InstrNames) const {} void PrinterCapstone::instrInfoEmitInstrNameIndices( std::string const &TargetName, ArrayRef const &NumberedInstructions, SequenceToOffsetTable const &InstrNames) const {} void PrinterCapstone::instrInfoEmitInstrDeprFeatures( std::string const &TargetName, std::string const &TargetNamespace, ArrayRef const &NumberedInstructions, SequenceToOffsetTable const &InstrNames) const {} void PrinterCapstone::instrInfoEmitInstrComplexDeprInfos( std::string const &TargetName, ArrayRef const &NumberedInstructions) const {} void PrinterCapstone::instrInfoEmitMCInstrInfoInitRoutine( std::string const &TargetName, unsigned NumberedInstrSize, bool HasDeprecationFeatures, bool HasComplexDeprecationInfos) const {} void PrinterCapstone::instrInfoEmitHeader(std::string const &TargetName) const { } void PrinterCapstone::instrInfoEmitClassStruct( std::string const &ClassName) const {} void PrinterCapstone::instrInfoEmitTIIHelperMethod( StringRef const &TargetName, Record const *Rec, bool ExpandDefinition) const {} void PrinterCapstone::instrInfoEmitExternArrays( std::string const &TargetName, bool HasDeprecationFeatures, bool HasComplexDeprecationInfos) const {} void PrinterCapstone::instrInfoEmitMCInstrInfoInit( std::string const &TargetName, unsigned NumberedInstrSize, bool HasDeprecationFeatures, bool HasComplexDeprecationInfos) const {} void PrinterCapstone::instrInfoEmitOperandEnum( std::map const &Operands) const {} void PrinterCapstone::instrInfoEmitGetNamedOperandIdx( std::map const &Operands, OpNameMapTy const &OperandMap) const {} void PrinterCapstone::instrInfoEmitOpTypeEnumPartI() const {} void PrinterCapstone::instrInfoEmitOpTypeEnumPartII(StringRef const &OpName, unsigned EnumVal) const {} void PrinterCapstone::instrInfoEmitOpTypeEnumPartIII() const {} void PrinterCapstone::instrInfoEmitOpTypeOffsetTable( std::vector OperandOffsets, unsigned OpRecSize, ArrayRef const &NumberedInstructions) const {} void PrinterCapstone::instrInfoEmitOpcodeOpTypesTable( unsigned EnumVal, std::vector const &OperandRecords, std::vector OperandOffsets, ArrayRef const &NumberedInstructions) const {} void PrinterCapstone::instrInfoEmitGetOpTypeHdr() const {} void PrinterCapstone::instrInfoEmitGetOpTypeReturn() const {} void PrinterCapstone::instrInfoEmitGetOpTypeUnreachable() const {} void PrinterCapstone::instrInfoEmitGetOpTypeEnd() const {} void PrinterCapstone::instrInfoEmitGetMemOpSizeHdr() const {} void PrinterCapstone::instrInfoEmitGetOpMemSizeTbl( std::map> &SizeToOperandName) const {} std::string PrinterCapstone::instrInfoGetInstMapEntry(StringRef const &Namespace, StringRef const &InstrName) const { return Namespace.str() + "_" + InstrName.str(); } void PrinterCapstone::instrInfoEmitGetLogicalOpSizeHdr() const {} void PrinterCapstone::instrInfoEmitGetLogicalOpSizeTable( size_t LogicalOpListSize, std::vector *> const &LogicalOpSizeList) const { } void PrinterCapstone::instrInfoEmitGetLogicalOpSizeSwitch( std::map> InstMap) const {} void PrinterCapstone::instrInfoEmitGetLogicalOpSizeReturn() const {} void PrinterCapstone::instrInfoEmitGetLogicalOpSizeEnd() const {} void PrinterCapstone::instrInfoEmitGetLogicalOpIdx() const {} std::string PrinterCapstone::instrInfoGetOpTypeListEntry(StringRef const &Namespace, StringRef const &OpName) const { return Namespace.str() + "_OpTypes_" + OpName.str(); } void PrinterCapstone::instrInfoEmitGetLogicalOpTypeHdr() const {} void PrinterCapstone::instrInfoEmitGetLogicalOpTypeTable( size_t OpTypeListSize, std::vector *> const &LogicalOpTypeList) const {} void PrinterCapstone::instrInfoEmitGetLogicalOpTypeSwitch( std::map> InstMap) const {} void PrinterCapstone::instrInfoEmitGetLogicalOpTypeReturn() const {} void PrinterCapstone::instrInfoEmitGetLogicalOpTypeEnd() const {} void PrinterCapstone::instrInfoEmitDeclareMCInstFeatureClasses() const {} void PrinterCapstone::instrInfoEmitPredFcnDecl( RecVec const &TIIPredicates) const {} void PrinterCapstone::instrInfoEmitPredFcnImpl(StringRef const &TargetName, RecVec const &TIIPredicates) {} void PrinterCapstone::instrInfoEmitInstrPredVerifierIncludes() const {} void PrinterCapstone::instrInfoEmitMacroDefineCheck() const {} void PrinterCapstone::instrInfoEmitSubtargetFeatureBitEnumeration( std::map &SubtargetFeatures) const {} void PrinterCapstone::instrInfoEmitEmitSTFNameTable( std::map &SubtargetFeatures) const {} void PrinterCapstone::instrInfoEmitFeatureBitsEnum( std::vector> const &FeatureBitsets) const {} void PrinterCapstone::instrInfoEmitFeatureBitsArray( std::vector> const &FeatureBitsets, std::map const &SubtargetFeatures) const {} void PrinterCapstone::instrInfoEmitRequiredFeatureRefs( std::vector> const &FeatureBitsets, std::map const &SubtargetFeatures, CodeGenTarget const &Target) const {} void PrinterCapstone::instrInfoEmitOpcodeChecker() const {} void PrinterCapstone::instrInfoEmitPredicateVerifier( StringRef const &TargetName) const {} void PrinterCapstone::instrInfoEmitEnums( CodeGenTarget const &Target, StringRef const &Namespace, CodeGenSchedModels const &SchedModels) const { emitIncludeToggle("GET_INSTRINFO_ENUM", true); unsigned Num = 0; OS << " enum {\n"; for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) OS << " " << Namespace << "_" << Inst->TheDef->getName() << "\t= " << Num++ << ",\n"; OS << " INSTRUCTION_LIST_END = " << Num << "\n"; OS << " };\n\n"; emitIncludeToggle("GET_INSTRINFO_ENUM", false); } void PrinterCapstone::instrInfoEmitTIIPredicates(StringRef const &TargetName, RecVec const &TIIPredicates, bool ExpandDefinition) {} void PrinterCapstone::instrInfoEmitComputeAssemblerAvailableFeatures( StringRef const &TargetName, std::map &SubtargetFeatures) const {} //-------------------------- // Backend: AsmMatcher //-------------------------- namespace { std::string getImplicitUses(StringRef const &TargetName, CodeGenInstruction const *Inst) { std::string Flags = "{ "; for (Record const *U : Inst->ImplicitUses) { assert(U->isSubClassOf("Register")); Flags += TargetName.upper() + "_REG_" + U->getName().upper() + ", "; } Flags += "0 }"; return Flags; } std::string getImplicitDefs(StringRef const &TargetName, CodeGenInstruction const *Inst) { std::string Flags = "{ "; for (Record const *U : Inst->ImplicitDefs) { assert(U->isSubClassOf("Register")); Flags += TargetName.upper() + "_REG_" + U->getName().upper() + ", "; } Flags += "0 }"; return Flags; } static inline std::string normalizedMnemonic(StringRef const &Mn, const bool Upper = true, const bool ReplaceDot = true, const StringRef RemovePattern = "") { // Each tuple is: Regex Pattern : Replacement char static SmallVector> Replacements = { {"[.]", "_"}, {"[|]", "_"}, {"[+]", "p"}, {"[-]", "m"}, {"[/]", "s"}, {"[{}]", "_"}, {"[#]", "h"}, }; auto Mnemonic = Upper ? Mn.upper() : Mn.str(); if (RemovePattern != "") { while (Regex(RemovePattern).match(Mnemonic)) { Mnemonic = Regex(RemovePattern).sub("", Mnemonic); } } for (std::tuple Repl : Replacements) { auto SearchPat = std::get<0>(Repl); auto ReplaceStr = std::get<1>(Repl); if (!ReplaceDot && SearchPat == "[.]") { continue; } while (Regex(SearchPat).match(Mnemonic)) { Mnemonic = Regex(SearchPat).sub(ReplaceStr, Mnemonic); } } return Mnemonic; } static inline std::string getNormalMnemonic(StringRef TargetName, StringRef Mnemonic, const bool Upper = true, const bool ReplaceDot = true) { StringRef RemovePattern = ""; if (TargetName.equals_insensitive("ARM") || TargetName.equals_insensitive("AArch64")) { RemovePattern = "[{}]"; } else if (TargetName.equals_insensitive("ARC")) { RemovePattern = "[.]$"; } return normalizedMnemonic(Mnemonic, Upper, ReplaceDot, RemovePattern); } std::string getReqFeatures(StringRef const &TargetName, AsmMatcherInfo &AMI, std::unique_ptr const &MI, bool UseMI, CodeGenInstruction const *CGI) { std::string Flags = "{ "; // The debug if if ((CGI->isBranch || CGI->isReturn) && !CGI->isCall) { Flags += TargetName.str() + "_GRP_JUMP, "; } if (CGI->isReturn) { Flags += TargetName.str() + "_GRP_RET, "; } if (CGI->isCall) { Flags += TargetName.str() + "_GRP_CALL, "; } for (const auto &OpInfo : CGI->Operands.OperandList) { if (OpInfo.OperandType == "MCOI::OPERAND_PCREL" && (CGI->isBranch || CGI->isReturn || CGI->isIndirectBranch || CGI->isCall)) { Flags += TargetName.str() + "_GRP_BRANCH_RELATIVE, "; } } // The group flags _GRP_PRIVILEGE and _GRP_INT (interrupt) are not // handled here. LLVM does not provide this info. for (Record *Predicate : CGI->TheDef->getValueAsListOfDefs("Predicates")) { if (const SubtargetFeatureInfo *Feature = AMI.getSubtargetFeature(Predicate)) Flags += TargetName.str() + "_FEATURE_" + Feature->TheDef->getName().upper() + ", "; } Flags += "0 }"; return Flags; } std::string getLLVMInstEnumName(StringRef const &TargetName, CodeGenInstruction const *CGI) { std::string UniqueName = CGI->TheDef->getName().str(); std::string Enum = TargetName.str() + "_" + UniqueName; std::replace(Enum.begin(), Enum.end(), '/', 's'); return Enum; } std::string getArchSupplInfoAArch64(CodeGenInstruction const *CGI) { // Compute memory access type std::string MemoryAccess; if (CGI->mayLoad && CGI->mayStore) { MemoryAccess = "CS_AC_READ_WRITE"; } else if (CGI->mayLoad && !CGI->mayStore) { MemoryAccess = "CS_AC_READ"; } else if (!CGI->mayLoad && CGI->mayStore) { MemoryAccess = "CS_AC_WRITE"; } else { MemoryAccess = "CS_AC_INVALID"; } return "{ .aarch64 = { .mem_acc = " + MemoryAccess + " }}"; } std::string getArchSupplInfoARM(CodeGenInstruction const *CGI) { // Compute memory access type std::string MemoryAccess; if (CGI->mayLoad && CGI->mayStore) { MemoryAccess = "CS_AC_READ_WRITE"; } else if (CGI->mayLoad && !CGI->mayStore) { MemoryAccess = "CS_AC_READ"; } else if (!CGI->mayLoad && CGI->mayStore) { MemoryAccess = "CS_AC_WRITE"; } else { MemoryAccess = "CS_AC_INVALID"; } return "{ .aarch64 = { .mem_acc = " + MemoryAccess + " }}"; } std::string getArchSupplInfoPPC(StringRef const &TargetName, CodeGenInstruction const *CGI, raw_string_ostream &PPCFormatEnum) { static std::set Formats; // Get instruction format ArrayRef> SCs = CGI->TheDef->getSuperClasses(); if (SCs.empty()) { llvm_unreachable("A CGI without superclass should not exist."); } // Get base instruction format class "I" const Record *PrevSC = nullptr; // Superclasses are in post-order. So we go through them backwards. // The class before the "I" class is the format class. for (int I = SCs.size() - 1; I >= 0; --I) { const Record *SC = SCs[I].first; if (SC->getName() == "I") { if (!PrevSC) llvm_unreachable("I class has no predecessor."); std::string Format = "PPC_INSN_FORM_" + PrevSC->getName().upper(); if (Formats.find(Format) == Formats.end()) { PPCFormatEnum << Format + ",\n"; } Formats.emplace(Format); return "{ .ppc = { " + Format + " }}"; } PrevSC = SC; } // Pseudo instructions return "{{ 0 }}"; } std::string getArchSupplInfoSystemZ(StringRef const &TargetName, CodeGenInstruction const *CGI, raw_string_ostream &PPCFormatEnum) { static std::set Formats; // Get instruction format ArrayRef> SCs = CGI->TheDef->getSuperClasses(); if (SCs.empty()) { llvm_unreachable("A CGI without superclass should not exist."); } // Get base instruction format class "I" const Record *PrevSC = nullptr; // Superclasses are in post-order. So we go through them backwards. // The class before the "I" class is the format class. for (int I = SCs.size() - 1; I >= 0; --I) { const Record *SC = SCs[I].first; if (SC->getName() == "InstSystemZ") { if (!PrevSC) llvm_unreachable("InstSystemZ class has no predecessor."); std::string Format = "SYSTEMZ_INSN_FORM_" + PrevSC->getName().upper(); if (Formats.find(Format) == Formats.end()) { PPCFormatEnum << Format + ",\n"; } Formats.emplace(Format); return "{ .systemz = { " + Format + " }}"; } PrevSC = SC; } // Pseudo instructions return "{{ 0 }}"; } std::string getArchSupplInfoLoongArch(StringRef const &TargetName, CodeGenInstruction const *CGI, raw_string_ostream &LoongArchFormatEnum) { static std::set Formats; // Get instruction format ArrayRef> SCs = CGI->TheDef->getSuperClasses(); if (SCs.empty()) { llvm_unreachable("A CGI without superclass should not exist."); } // Compute memory access type std::string MemoryAccess; if (CGI->mayLoad && CGI->mayStore) { MemoryAccess = "CS_AC_READ_WRITE"; } else if (CGI->mayLoad && !CGI->mayStore) { MemoryAccess = "CS_AC_READ"; } else if (!CGI->mayLoad && CGI->mayStore) { MemoryAccess = "CS_AC_WRITE"; } else { MemoryAccess = "CS_AC_INVALID"; } // Get base instruction format class "LAInst" const Record *PrevSC = nullptr; // Superclasses are in post-order. So we go through them backwards. // The class before the "LAInst" class is the format class. for (int I = SCs.size() - 1; I >= 0; --I) { const Record *SC = SCs[I].first; if (SC->getName() == "LAInst") { if (!PrevSC) llvm_unreachable("I class has no predecessor."); std::string Format = "LOONGARCH_INSN_FORM_" + PrevSC->getName().upper(); if (Formats.find(Format) == Formats.end()) { LoongArchFormatEnum << Format + ",\n"; } Formats.emplace(Format); return "{ .loongarch = { " + Format + ", " + MemoryAccess + " }}"; } PrevSC = SC; } // Pseudo instructions return "{ .loongarch = { 0, " + MemoryAccess + " }}"; } std::string getArchSupplInfoXtensa(StringRef const &TargetName, CodeGenInstruction const *CGI, raw_string_ostream &OS) { static std::set Formats; // Get instruction format ArrayRef> SCs = CGI->TheDef->getSuperClasses(); if (SCs.empty()) { llvm_unreachable("A CGI without superclass should not exist."); } const Record *PrevSC = nullptr; for (int I = SCs.size() - 1; I >= 0; --I) { const Record *SC = SCs[I].first; if (Regex("XtensaInst[0-9]+").match(SC->getName())) { if (!PrevSC) llvm_unreachable("I class has no predecessor."); if (PrevSC->getName() == "Requires") { break; } StringRef form = PrevSC->getName(); form.consume_front("Xtensa"); form.consume_back("_Inst"); std::string Format = "XTENSA_INSN_FORM_" + form.upper(); if (Formats.find(Format) == Formats.end()) { OS << Format + ",\n"; } Formats.emplace(Format); return "{ .xtensa = { " + Format + " }}"; } PrevSC = SC; } // Pseudo instructions return "{{ 0 }}"; } std::string getArchSupplInfo(StringRef const &TargetName, CodeGenInstruction const *CGI, raw_string_ostream &FormatEnum) { if (TargetName == "PPC") { return getArchSupplInfoPPC(TargetName, CGI, FormatEnum); } else if (StringRef(TargetName).upper() == "AARCH64") { return getArchSupplInfoAArch64(CGI); } else if (StringRef(TargetName).upper() == "ARM") { return getArchSupplInfoARM(CGI); } else if (StringRef(TargetName).upper() == "LOONGARCH") { return getArchSupplInfoLoongArch(TargetName, CGI, FormatEnum); } else if (StringRef(TargetName).upper() == "SYSTEMZ") { return getArchSupplInfoSystemZ(TargetName, CGI, FormatEnum); } else if (StringRef(TargetName).upper() == "XTENSA") { return getArchSupplInfoXtensa(TargetName, CGI, FormatEnum); } return "{{ 0 }}"; } Record *argInitOpToRecord(Init *ArgInit) { DagInit *SubArgDag = dyn_cast(ArgInit); if (SubArgDag) ArgInit = SubArgDag->getOperator(); DefInit *Arg = dyn_cast(ArgInit); Record *Rec = Arg->getDef(); return Rec; } std::string getPrimaryCSOperandType(Record const *OpRec) { std::string OperandType; if (OpRec->isSubClassOf("PredicateOperand")) return "CS_OP_PRED"; if (OpRec->isSubClassOf("RegisterClass") || OpRec->isSubClassOf("PointerLikeRegClass")) OperandType = "OPERAND_REGISTER"; else if (OpRec->isSubClassOf("Operand") || OpRec->isSubClassOf("RegisterOperand")) OperandType = std::string(OpRec->getValueAsString("OperandType")); else return "CS_OP_INVALID"; if (OperandType == "OPERAND_UNKNOWN") { if (OpRec->getValueAsDef("Type")->getValueAsInt("Size") == 0) // Pseudo type return "CS_OP_INVALID"; OperandType = "OPERAND_IMMEDIATE"; } if (OperandType == "OPERAND_PCREL" || OperandType == "OPERAND_IMMEDIATE") OperandType = "CS_OP_IMM"; else if (OperandType == "OPERAND_MEMORY") OperandType = "CS_OP_MEM"; else if (OperandType == "OPERAND_REGISTER") OperandType = "CS_OP_REG"; // Arch dependent special Op types else if (OperandType == "OPERAND_VPRED_N" || OperandType == "OPERAND_VPRED_R") return "CS_OP_INVALID"; else if (OperandType == "OPERAND_IMPLICIT_IMM_0") return "CS_OP_IMM"; // Mips else if (OperandType == "OPERAND_MEM_SIMM9") return "CS_OP_IMM"; // nanoMips else if (OperandType == "OPERAND_NM_SPREL7") return "CS_OP_REG"; else if (OperandType == "OPERAND_NM_GPREL9") return "CS_OP_REG"; else if (OperandType == "OPERAND_NM_GPREL18") return "CS_OP_REG"; else if (OperandType == "OPERAND_NM_GPREL21") return "CS_OP_REG"; else if (OperandType == "OPERAND_NM_SAVE_REGLIST") return "CS_OP_INVALID"; else PrintFatalNote("Unhandled OperandType: " + OperandType); return OperandType; } /// Compares both lists of super classes for any matches. /// It ignores very common (Architecture independent) /// super classes (DAGOperand, RegisterOperand, PatFrags /// etc.). Because those will certainly lead to false positives. bool compareTypeSuperClasses(ArrayRef> OpTypeSC, ArrayRef> PatTypeSC) { std::vector IgnoredSC = { "DAGOperand", "Operand", "PatFrag", "PatFrags", "RegisterClass", "RegisterOperand", "SDPatternOperator", "ValueType"}; std::vector OpSCToTest; std::vector PatSCToTest; // Go backwards over super clases (backwards over the inheritance tree) until // we find a SC to ignore. for (auto SCPair : reverse(OpTypeSC)) { if (find(IgnoredSC, SCPair.first->getName()) != IgnoredSC.end()) break; OpSCToTest.emplace_back(SCPair.first); } for (auto SCPair : reverse(PatTypeSC)) { if (find(IgnoredSC, SCPair.first->getName()) != IgnoredSC.end()) break; PatSCToTest.emplace_back(SCPair.first); } return any_of(OpSCToTest, [&](Record *OpSCRec) { return find(PatSCToTest, OpSCRec) != PatSCToTest.end(); }); } /// @brief Checks if the given operand is part of a pattern of type iPTR. /// @param OpRec The operand Record. /// @param OpName The operand name (Rn, imm, offset etc.) /// @param PatternDag The pattern DAG to search in. /// @param PartOfPTRPattern True, if the given pattern is of type iPTR. False /// otherwise. /// @param MatchByTypeSuperClasses If true, a valid match is also if any type /// super classes are the same. /// @return True, if the pattern contains a node with the same name (and /// optionally the same type name or same super class type) as the given /// operand. False otherwise. bool opIsPartOfiPTRPattern(Record const *OpRec, StringRef const &OpName, DagInit *PatternDag, bool PartOfPTRPattern, bool MatchByTypeSuperClasses = false) { for (unsigned I = 0; I < PatternDag->getNumArgs(); ++I) { DagInit *DagArg = dyn_cast(PatternDag->getArg(I)); if (DagArg) { // Another pattern. Search in it. Record *DagRec = dyn_cast(DagArg->getOperator())->getDef(); // Check if DAG operator is of type iPTR. if (DagRec->getValue("Value") && getValueType(DagRec) == MVT::SimpleValueType::iPTR) PartOfPTRPattern = true; // Complex patterns define their type in "Ty" if (DagRec->getValue("Ty") && getValueType(DagRec->getValueAsDef("Ty")) == MVT::SimpleValueType::iPTR) PartOfPTRPattern = true; if (opIsPartOfiPTRPattern(OpRec, OpName, DagArg, PartOfPTRPattern, MatchByTypeSuperClasses)) return true; continue; } DefInit *LeaveDef = dyn_cast(PatternDag->getArg(I)); if (!LeaveDef) return false; bool Matches; StringRef const &PatOpName = PatternDag->getArgNameStr(I); Matches = OpName.equals(PatOpName); if (MatchByTypeSuperClasses) { std::string OpInitType = OpRec->getNameInitAsString(); std::string PatOpType = PatternDag->getArg(I)->getAsString(); RecordKeeper &RK = OpRec->getRecords(); ArrayRef> OpTypeSC = RK.getDef(OpInitType)->getSuperClasses(); ArrayRef> PatTypeSC = RK.getDef(PatOpType)->getSuperClasses(); Matches |= compareTypeSuperClasses(OpTypeSC, PatTypeSC); } if (Matches) { if (PartOfPTRPattern) return true; return false; } } return false; } std::string getCSOperandType( StringRef const &TargetName, CodeGenInstruction const *CGI, Record const *OpRec, StringRef const &OpName, std::map> const InsnPatternMap) { std::string OperandType = getPrimaryCSOperandType(OpRec); if ((StringRef(TargetName).upper() == "AARCH64") && OperandType != "CS_OP_MEM") { // The definitions of AArch64 are so flawed, when it comes to memory // operands (they are not labeled as such), that we just search for the op // name enclosed in []. if (Regex("\\[[^]]*\\$" + OpName.str() + "[^[]*]").match(CGI->AsmString)) { // Memory operands are always preceded by a ' '. // Angle brackets not preceded by a ' ' mark offset operands // of SME/SVE matrix operands. They are bound to the previous operand, so // to say. if (Regex("[\t ]\\[[^]]*\\$" + OpName.str() + "[^[]*]") .match(CGI->AsmString)) { return OperandType += " | CS_OP_MEM"; } return OperandType += " | CS_OP_BOUND"; } } DagInit *PatternDag = nullptr; if (OperandType == "CS_OP_MEM") // It is only marked as mem, we treat it as immediate. OperandType += " | CS_OP_IMM"; else if (OpRec->getValue("Type") && getValueType(OpRec->getValueAsDef("Type")) == MVT::SimpleValueType::iPTR) OperandType += " | CS_OP_MEM"; else if (!CGI->TheDef->isValueUnset("Pattern") && !CGI->TheDef->getValueAsListInit("Pattern")->empty()) { // Check if operand is part of a pattern with a memory type (iPTR) ListInit *PatternList = CGI->TheDef->getValueAsListInit("Pattern"); PatternDag = dyn_cast(PatternList->getValues()[0]); } else if (!InsnPatternMap.empty()) { // Pattern field is not set in the CGI. // But there might be (multiple) patterns in the record keeper // for this CGI std::string CGIName = CGI->TheDef->getName().str(); if (InsnPatternMap.find(CGIName) == InsnPatternMap.end()) return OperandType; bool OpTypeIsPartOfAnyPattern = any_of(InsnPatternMap.at(CGIName), [&](Record *PatternDag) { return opIsPartOfiPTRPattern( OpRec, OpName, PatternDag->getValueAsDag("PatternToMatch"), false); }); if (OpTypeIsPartOfAnyPattern) OperandType += " | CS_OP_MEM"; return OperandType; } if (PatternDag && opIsPartOfiPTRPattern(OpRec, OpName, PatternDag, false)) OperandType += " | CS_OP_MEM"; return OperandType; } void printInsnMapEntry(StringRef const &TargetName, AsmMatcherInfo &AMI, std::unique_ptr const &MI, bool UseMI, CodeGenInstruction const *CGI, raw_string_ostream &InsnMap, unsigned InsnNum, raw_string_ostream &FormatEnum) { InsnMap << "{\n"; InsnMap.indent(2) << "/* " << (CGI->AsmString != "" ? CGI->AsmString : "") << " */\n"; // adds id InsnMap.indent(2) << getLLVMInstEnumName(TargetName, CGI) << " /* " << InsnNum << " */"; InsnMap << ", " << TargetName.upper() << "_INS_" << (UseMI ? getNormalMnemonic(TargetName, MI->Mnemonic) : "INVALID") << ",\n"; // no diet only InsnMap.indent(2) << "#ifndef CAPSTONE_DIET\n"; if (UseMI) { InsnMap.indent(4) << getImplicitUses(TargetName.upper(), CGI) << ", "; InsnMap << getImplicitDefs(TargetName.upper(), CGI) << ", "; InsnMap << getReqFeatures(TargetName.upper(), AMI, MI, UseMI, CGI) << ", "; InsnMap << ((CGI->isBranch || CGI->isReturn) ? "1" : "0") << ", "; InsnMap << (CGI->isIndirectBranch ? "1" : "0") << ", "; InsnMap << getArchSupplInfo(TargetName.upper(), CGI, FormatEnum) << "\n"; } else { InsnMap.indent(4) << "{ 0 }, { 0 }, { 0 }, 0, 0, {{ 0 }}"; } InsnMap << '\n'; InsnMap.indent(2) << "#endif\n"; InsnMap << "},\n"; } static std::string getCSAccess(short Access) { if (Access == 1) return "CS_AC_READ"; else if (Access == 2) return "CS_AC_WRITE"; else if (Access == 3) return "CS_AC_READ | CS_AC_WRITE"; else if (Access == 0) return "CS_AC_INVALID"; else PrintFatalNote("Invalid access flags set."); } /// @brief Returns the operand data type. If it is a float it updates /// OperandType as well. /// @param Op The operand. /// @param OperandType The operand type. /// @return The strig of data types. std::string getOperandDataTypes(Record const *Op, std::string &OperandType) { MVT::SimpleValueType VT; std::vector OpDataTypes; if (!Op->getValue("RegTypes") && Op->getValue("RegClass") && OperandType.find("CS_OP_REG") != std::string::npos) Op = Op->getValueAsDef("RegClass"); if (!(Op->getValue("Type") || Op->getValue("RegTypes"))) return "{ CS_DATA_TYPE_LAST }"; if (OperandType.find("CS_OP_REG") != std::string::npos && Op->getValue("RegTypes")) { OpDataTypes = Op->getValueAsListOfDefs("RegTypes"); } else { Record *OpType = Op->getValueAsDef("Type"); VT = getValueType(OpType); bool IsFloat = false; for (uint8_t V = MVT::SimpleValueType::FIRST_FP_VALUETYPE; V <= MVT::SimpleValueType::LAST_FP_VALUETYPE; V++) IsFloat |= (VT == V); if (IsFloat) OperandType = (OperandType.find("MEM") != std::string::npos) ? "CS_OP_MEM | CS_OP_FP" : "CS_OP_FP"; StringRef EnumVT = getEnumName(VT); return "{ CS_DATA_TYPE_" + EnumVT.substr(5).str() + ", CS_DATA_TYPE_LAST }"; } std::string DataTypes = "{ "; for (Record *Type : OpDataTypes) { StringRef EnumVT = getEnumName(getValueType(Type)); DataTypes += "CS_DATA_TYPE_" + EnumVT.substr(5).str() + ", "; } DataTypes += "CS_DATA_TYPE_LAST }"; return DataTypes; } typedef struct OpData { Record *Rec; std::string OpAsm; std::string OpType; std::string DataTypes; unsigned Access; ///< 0b00 = unkown, 0b01 = In, 0b10 = Out, 0b11 = In and Out std::string str() const { return "Asm: " + OpAsm + " Type: " + OpType + " Access: " + std::to_string(Access); } } OpData; uint8_t getOpAccess(CodeGenInstruction const *CGI, std::string OperandType, bool IsOutOp) { if (OperandType.find("CS_OP_MEM") != std::string::npos) { if (CGI->mayLoad_Unset && CGI->mayStore_Unset) { return 0; } else if (CGI->mayLoad && CGI->mayStore) return 3; else if (CGI->mayLoad) return 1; else if (CGI->mayStore) return 2; } return IsOutOp ? 2 : 1; } void addComplexOperand( StringRef const &TargetName, CodeGenInstruction const *CGI, Record const *ComplexOp, StringRef const &ArgName, bool IsOutOp, std::vector &InsOps, std::map> const InsnPatternMap) { DagInit *SubOps = ComplexOp->getValueAsDag("MIOperandInfo"); unsigned E = SubOps->getNumArgs(); for (unsigned I = 0; I != E; ++I) { Init *ArgInit = SubOps->getArg(I); Record *SubOp = argInitOpToRecord(ArgInit); // Determine Operand type std::string OperandType; std::string SubOperandType = getCSOperandType( TargetName, CGI, SubOp, SubOp->getName().str(), InsnPatternMap); std::string ComplOperandType = getCSOperandType(TargetName, CGI, ComplexOp, ArgName, InsnPatternMap); if (ComplOperandType.find("CS_OP_MEM") != std::string::npos) OperandType = "CS_OP_MEM | " + SubOperandType; else if (!CGI->TheDef->isValueUnset("Pattern") && !CGI->TheDef->getValueAsListInit("Pattern")->empty()) { OperandType = SubOperandType; ListInit *PatternList = CGI->TheDef->getValueAsListInit("Pattern"); DagInit *PatternDag = dyn_cast(PatternList->getValues()[0]); if (PatternDag && opIsPartOfiPTRPattern(SubOp, SubOps->getArgNameStr(I), PatternDag, false)) OperandType += " | CS_OP_MEM"; } else OperandType = SubOperandType; unsigned AccessFlag = getOpAccess(CGI, OperandType, IsOutOp); std::string OpDataTypes = getOperandDataTypes(SubOp, SubOperandType); // Check if Operand was already seen before (as In or Out operand). // If so update its access flags. std::string OpName = ArgName.str() + " - " + SubOp->getName().str(); InsOps.push_back(OpData{SubOp, std::move(OpName), std::move(OperandType), std::move(OpDataTypes), AccessFlag}); } } void printInsnOpMapEntry( CodeGenTarget const &Target, std::unique_ptr const &MI, bool UseMI, CodeGenInstruction const *CGI, raw_string_ostream &InsnOpMap, unsigned InsnNum, std::map> const InsnPatternMap) { std::string TargetName = Target.getName().upper(); // Instruction without mnemonic. if (!UseMI) { std::string LLVMEnum = getLLVMInstEnumName(TargetName, CGI); // Write the C struct of the Instruction operands. // The many braces are necessary because of this bug from // medieval times: // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119 InsnOpMap << "{{{ /* " + LLVMEnum + " (" << InsnNum << ") - " + TargetName + "_INS_" + (UseMI ? getNormalMnemonic(TargetName, MI->Mnemonic) : "INVALID") + " - " + CGI->AsmString + " */\n"; InsnOpMap << " 0\n"; InsnOpMap << "}}},\n"; return; } DagInit *InDI = CGI->TheDef->getValueAsDag("InOperandList"); DagInit *OutDI = CGI->TheDef->getValueAsDag("OutOperandList"); unsigned NumDefs = OutDI->getNumArgs(); unsigned E = OutDI->getNumArgs() + InDI->getNumArgs(); bool IsOutOp; std::vector InsOps; // Iterate over every In and Out operand and get its Def. for (unsigned I = 0; I != E; ++I) { Init *ArgInit; StringRef ArgName; IsOutOp = I < NumDefs; if (IsOutOp) { ArgInit = OutDI->getArg(I); ArgName = OutDI->getArgNameStr(I); } else { ArgInit = InDI->getArg(I - NumDefs); ArgName = InDI->getArgNameStr(I - NumDefs); } Record *Rec = argInitOpToRecord(ArgInit); // Add complex operands. // Operands which effectively consists of two or more operands. if (Rec->getValue("MIOperandInfo")) { if (Rec->getValueAsDag("MIOperandInfo")->getNumArgs() > 0) { addComplexOperand(TargetName, CGI, Rec, ArgName, IsOutOp, InsOps, InsnPatternMap); continue; } } // Determine Operand type std::string OperandType = getCSOperandType(TargetName, CGI, Rec, ArgName, InsnPatternMap); if (OperandType == "") continue; std::string OpDataTypes = getOperandDataTypes(Rec, OperandType); // Check if Operand was already seen before (as In or Out operand). // If so update its access flags. unsigned AccessFlag = getOpAccess(CGI, OperandType, IsOutOp); InsOps.push_back(OpData{Rec, ArgName.str(), std::move(OperandType), std::move(OpDataTypes), AccessFlag}); } if (InsOps.size() > 15) { for (OpData const &OD : InsOps) { PrintNote(OD.str()); OD.Rec->dump(); } PrintFatalNote("Inst has more then 15 operands: " + CGI->AsmString); } std::string LLVMEnum = getLLVMInstEnumName(TargetName, CGI); // Write the C struct of the Instruction operands. InsnOpMap << "{ /* " + LLVMEnum + " (" << InsnNum << ") - " + TargetName + "_INS_" + (UseMI ? getNormalMnemonic(TargetName, MI->Mnemonic) : "INVALID") + " - " + CGI->AsmString + " */\n"; InsnOpMap << "{\n"; for (OpData const &OD : InsOps) { InsnOpMap.indent(2) << "{ " << OD.OpType << ", " << getCSAccess(OD.Access) << ", " << OD.DataTypes << " }, /* " << OD.OpAsm << " */\n"; } InsnOpMap.indent(2) << "{ 0 }\n"; InsnOpMap << "}},\n"; } void printInsnNameMapEnumEntry(StringRef const &TargetName, std::unique_ptr const &MI, raw_string_ostream &InsnNameMap, raw_string_ostream &InsnEnum) { static std::set MnemonicsSeen; static std::set EnumsSeen; const bool ReplaceDot = !TargetName.equals_insensitive("TriCore"); std::string Mnemonic = getNormalMnemonic(TargetName, MI->Mnemonic, false, ReplaceDot); if (MnemonicsSeen.find(Mnemonic) != MnemonicsSeen.end()) return; std::string EnumName = TargetName.str() + "_INS_" + getNormalMnemonic(TargetName, MI->Mnemonic); InsnNameMap.indent(2) << "\"" + Mnemonic + "\", // " + EnumName + "\n"; if (EnumsSeen.find(EnumName) == EnumsSeen.end()) InsnEnum.indent(2) << EnumName + ",\n"; MnemonicsSeen.emplace(Mnemonic); EnumsSeen.emplace(EnumName); } void printFeatureEnumEntry(StringRef const &TargetName, AsmMatcherInfo &AMI, CodeGenInstruction const *CGI, raw_string_ostream &FeatureEnum, raw_string_ostream &FeatureNameArray) { static std::set Features; std::string EnumName; for (std::pair ST : AMI.SubtargetFeatures) { const SubtargetFeatureInfo &STF = ST.second; std::string Feature = STF.TheDef->getName().upper(); if (Features.find(Feature) != Features.end()) continue; Features.emplace(Feature); // Enum EnumName = TargetName.str() + "_FEATURE_" + STF.TheDef->getName().upper(); FeatureEnum << EnumName; if (Features.size() == 1) FeatureEnum << " = 128"; FeatureEnum << ",\n"; // Enum name map FeatureNameArray << "{ " + EnumName + ", \"" + STF.TheDef->getName().str() + "\" },\n"; } } /// Emits enum entries for each operand group. /// The operand group name is equal printer method of the operand. /// printSORegRegOperand -> SORegRegOperand void printOpPrintGroupEnum(StringRef const &TargetName, CodeGenInstruction const *CGI, raw_string_ostream &OpGroupEnum) { static std::set OpGroups; // Some operand groups, which exists, are never passed here. // So we add them manually. static const std::set ARMExceptions = { "RegImmShift", "LdStmModeOperand", "MandatoryInvertedPredicateOperand", }; /// Some groups are hard to generate. Like standard template arguments. /// Those are added here. static const std::set AArch64Exceptions = { "VectorIndex_8", "PrefetchOp_1", "LogicalImm_int8_t", "LogicalImm_int16_t", "InverseCondCode", "AMNoIndex", "PSBHintOp", "BTIHintOp", "ImplicitlyTypedVectorList", "SVERegOp_0", "SVELogicalImm_int16_t", "SVELogicalImm_int32_t", "SVELogicalImm_int64_t", "MatrixIndex_8", "MatrixIndex_0", "MatrixIndex_1", "AdrLabel", "AdrpLabel", "ZPRasFPR_128"}; static const std::set PPCExceptions = { "S12ImmOperand", // PS S12 immediates. Used as memory disponent. }; bool NoExceptions = false; const std::set *Exc; if (TargetName == "ARM") Exc = &ARMExceptions; else if (TargetName == "AArch64") Exc = &AArch64Exceptions; else if (TargetName == "PPC") Exc = &PPCExceptions; else NoExceptions = true; if (OpGroups.empty() && !NoExceptions) { for (const std::string &OpGroup : *Exc) { OpGroupEnum.indent(2) << TargetName + "_OP_GROUP_" + OpGroup + " = " << OpGroups.size() << ",\n"; OpGroups.emplace(OpGroup); } } for (const CGIOperandList::OperandInfo &Op : CGI->Operands) { std::string OpGroup = PrinterCapstone::translateToC(TargetName.str(), Op.PrinterMethodName) .substr(5); if (OpGroups.find(OpGroup) != OpGroups.end()) continue; OpGroupEnum.indent(2) << TargetName + "_OP_GROUP_" + OpGroup + " = " << OpGroups.size() << ",\n"; OpGroups.emplace(OpGroup); } } void printInsnAliasEnum(CodeGenTarget const &Target, raw_string_ostream &AliasEnum, raw_string_ostream &AliasMnemMap) { RecordKeeper &Records = Target.getTargetRecord()->getRecords(); std::vector AllInstAliases = Records.getAllDerivedDefinitions("InstAlias"); std::set AliasMnemonicsSeen; for (Record *AliasRec : AllInstAliases) { int Priority = AliasRec->getValueAsInt("EmitPriority"); if (Priority < 1) continue; // Aliases with priority 0 are never emitted. const DagInit *AliasDag = AliasRec->getValueAsDag("ResultInst"); DefInit *DI = dyn_cast(AliasDag->getOperator()); CodeGenInstruction *RealInst = &Target.getInstruction(DI->getDef()); StringRef AliasAsm = AliasRec->getValueAsString("AsmString"); SmallVector Matches; // Some Alias only differ by operands. Get only the mnemonic part. Regex("^[a-zA-Z0-9+-.]+").match(AliasAsm, &Matches); if (Matches.empty()) { continue; } StringRef &AliasMnemonic = Matches[0]; std::string NormAliasMnem = Target.getName().upper() + "_INS_ALIAS_" + getNormalMnemonic(Target.getName(), AliasMnemonic); if (AliasMnemonicsSeen.find(NormAliasMnem) != AliasMnemonicsSeen.end()) continue; AliasMnemonicsSeen.emplace(NormAliasMnem); AliasEnum << "\t" + NormAliasMnem + ", // Real instr.: " + getLLVMInstEnumName(Target.getName().upper(), RealInst) + "\n"; bool ReplaceDotInMnemonic = Target.getName().equals_insensitive("PPC") ? false : true; AliasMnemMap << "\t{ " + NormAliasMnem + ", \"" + getNormalMnemonic(Target.getName(), AliasMnemonic, false, ReplaceDotInMnemonic) + "\" },\n"; } } void addInsnsToPatternMap(Record *Pattern, std::map> &Map, ArrayRef ResInsns) { for (Init *RI : ResInsns) { Record *RIRec = dyn_cast(dyn_cast(RI)->getOperator())->getDef(); if (!RIRec->getValue("isPseudo")) continue; // No instruction if (RIRec->getValueAsBit("isPseudo")) { if (!RIRec->getValue("ResultInst")) continue; // Add the resulting instruction of this pseudo instruction as well. addInsnsToPatternMap( Pattern, Map, ArrayRef(RIRec->getValueAsDag("ResultInst"))); } std::string RIName = dyn_cast(RI)->getOperator()->getAsString(); if (Map.find(RIName) == Map.end()) { std::vector PatVec; PatVec.emplace_back(Pattern); Map.emplace(RIName, std::move(PatVec)); } else { std::vector &PatternVec = Map.at(RIName); PatternVec.emplace_back(Pattern); } } } /// Returns a map with instruction name and its pattern. /// Only needed by archs which, very annoyingly, /// do not set the Pattern field in CGIs (like AArch64). void getInsnPatternMap(CodeGenTarget const &Target, std::map> &Map) { for (Record *P : Target.getTargetRecord()->getRecords().getAllDerivedDefinitions("Pat")) { ListInit *ResInsns = P->getValueAsListInit("ResultInstrs"); addInsnsToPatternMap(P, Map, ResInsns->getValues()); } } } // namespace /// This function emits all the mapping files and /// Instruction enum for the current architecture. void PrinterCapstone::asmMatcherEmitMatchTable(CodeGenTarget const &Target, AsmMatcherInfo &Info, StringToOffsetTable &StringTable, unsigned VariantCount) const { std::string InsnMapStr; std::string InsnOpMapStr; std::string InsnNameMapStr; std::string InsnEnumStr; std::string FeatureEnumStr; std::string FeatureNameArrayStr; std::string OpGroupStr; std::string FormatEnumStr; std::string AliasEnumStr; std::string AliasMnemMapStr; raw_string_ostream InsnMap(InsnMapStr); raw_string_ostream InsnOpMap(InsnOpMapStr); raw_string_ostream InsnNameMap(InsnNameMapStr); raw_string_ostream InsnEnum(InsnEnumStr); raw_string_ostream FeatureEnum(FeatureEnumStr); raw_string_ostream FeatureNameArray(FeatureNameArrayStr); raw_string_ostream OpGroups(OpGroupStr); raw_string_ostream FormatEnum(FormatEnumStr); raw_string_ostream AliasEnum(AliasEnumStr); raw_string_ostream AliasMnemMap(AliasMnemMapStr); emitDefaultSourceFileHeader(InsnMap); emitDefaultSourceFileHeader(InsnOpMap); emitDefaultSourceFileHeader(InsnNameMap); emitDefaultSourceFileHeader(InsnEnum); emitDefaultSourceFileHeader(FeatureEnum); emitDefaultSourceFileHeader(FeatureNameArray); emitDefaultSourceFileHeader(OpGroups); emitDefaultSourceFileHeader(FormatEnum); emitDefaultSourceFileHeader(AliasEnum); emitDefaultSourceFileHeader(AliasMnemMap); // Currently we ignore any other Asm variant then the primary. Record *AsmVariant = Target.getAsmParserVariant(0); AsmVariantInfo Variant; Variant.RegisterPrefix = AsmVariant->getValueAsString("RegisterPrefix"); Variant.TokenizingCharacters = AsmVariant->getValueAsString("TokenizingCharacters"); Variant.SeparatorCharacters = AsmVariant->getValueAsString("SeparatorCharacters"); Variant.BreakCharacters = AsmVariant->getValueAsString("BreakCharacters"); Variant.Name = AsmVariant->getValueAsString("Name"); Variant.AsmVariantNo = AsmVariant->getValueAsInt("Variant"); SmallPtrSet SingletonRegisters; // Map instructino name to DefInit of pattern. // This is noly necessary for AArch64 currently. // Because CGI->pattern is not set in the td files. // So we search all patterns save them under the name // of the instruciton they belong to. std::map> InsnPatternMap; getInsnPatternMap(Target, InsnPatternMap); std::string TargetNameUpper = Target.getName().upper(); // The CS mapping tables, for instructions and their operands, // need an entry for every CodeGenInstruction. unsigned InsnNum = 0; for (const CodeGenInstruction *CGI : Target.getInstructionsByEnumValue()) { auto MI = std::make_unique(*CGI); bool UseMI = true; MI->tokenizeAsmString(Info, Variant); // Ignore "codegen only" instructions. if (CGI->TheDef->getValueAsBit("isCodeGenOnly") || MI->AsmOperands.empty()) { UseMI = false; MI->Mnemonic = "invalid"; } else MI->Mnemonic = MI->AsmOperands[0].Token; printInsnNameMapEnumEntry(TargetNameUpper, MI, InsnNameMap, InsnEnum); printFeatureEnumEntry(TargetNameUpper, Info, CGI, FeatureEnum, FeatureNameArray); printOpPrintGroupEnum(Target.getName(), CGI, OpGroups); printInsnOpMapEntry(Target, MI, UseMI, CGI, InsnOpMap, InsnNum, InsnPatternMap); printInsnMapEntry(Target.getName(), Info, MI, UseMI, CGI, InsnMap, InsnNum, FormatEnum); ++InsnNum; } printInsnAliasEnum(Target, AliasEnum, AliasMnemMap); std::string TName = Target.getName().str(); std::string InsnMapFilename = TName + "GenCSMappingInsn.inc"; writeFile(InsnMapFilename, InsnMapStr); InsnMapFilename = TName + "GenCSMappingInsnOp.inc"; writeFile(InsnMapFilename, InsnOpMapStr); InsnMapFilename = TName + "GenCSMappingInsnName.inc"; writeFile(InsnMapFilename, InsnNameMapStr); InsnMapFilename = TName + "GenCSInsnEnum.inc"; writeFile(InsnMapFilename, InsnEnumStr); InsnMapFilename = TName + "GenCSFeatureEnum.inc"; writeFile(InsnMapFilename, FeatureEnumStr); InsnMapFilename = TName + "GenCSFeatureName.inc"; writeFile(InsnMapFilename, FeatureNameArrayStr); InsnMapFilename = TName + "GenCSOpGroup.inc"; writeFile(InsnMapFilename, OpGroupStr); InsnMapFilename = TName + "GenCSAliasEnum.inc"; writeFile(InsnMapFilename, AliasEnumStr); InsnMapFilename = TName + "GenCSAliasMnemMap.inc"; writeFile(InsnMapFilename, AliasMnemMapStr); if (TName == "PPC" || TName == "LoongArch" || TName == "SystemZ" || TName == "Xtensa") { InsnMapFilename = TName + "GenCSInsnFormatsEnum.inc"; writeFile(InsnMapFilename, FormatEnumStr); } } void PrinterCapstone::asmMatcherEmitSourceFileHeader( std::string const &Desc) const {} void PrinterCapstone::asmMatcherEmitDeclarations(bool HasOptionalOperands, bool ReportMultipleNearMisses, bool HasOperandInfos) const {} void PrinterCapstone::asmMatcherEmitOperandDiagTypes( std::set const Types) const {} void PrinterCapstone::asmMatcherEmitGetSubtargetFeatureName( std::map const SubtargetFeatures) const {} void PrinterCapstone::asmMatcherEmitConversionFunctionI( StringRef const &TargetName, StringRef const &ClassName, std::string const &TargetOperandClass, bool HasOptionalOperands, size_t MaxNumOperands) const {} void PrinterCapstone::asmMatcherEmitConversionFunctionII( std::string const &EnumName, StringRef const &AsmMatchConverter) const {} void PrinterCapstone::asmMatcherEmitConversionFunctionIII( std::string const &EnumName, std::string const TargetOperandClass, bool HasOptionalOperands, MatchableInfo::AsmOperand const &Op, MatchableInfo::ResOperand const &OpInfo) const {} void PrinterCapstone::asmMatcherEmitConversionFunctionIV( std::string const &EnumName, int64_t Val) const {} void PrinterCapstone::asmMatcherEmitConversionFunctionV( std::string const &EnumName, std::string const &Reg) const {} void PrinterCapstone::asmMatcherEmitConversionFunctionVI() const {} void PrinterCapstone::asmMatcherWriteCvtOSToOS() const {} void PrinterCapstone::asmMatcherEmitOperandFunctionI( StringRef const &TargetName, StringRef const &ClassName) const {} void PrinterCapstone::asmMatcherEmitOperandFunctionII( std::string const &EnumName, MatchableInfo::AsmOperand const &Op, MatchableInfo::ResOperand const &OpInfo) const {} void PrinterCapstone::asmMatcherEmitOperandFunctionIII( std::string const &EnumName) const {} void PrinterCapstone::asmMatcherEmitOperandFunctionIV( std::string const &EnumName) const {} void PrinterCapstone::asmMatcherEmitOperandFunctionV() const {} void PrinterCapstone::asmMatcherEmitTiedOperandEnum( std::map, std::string> TiedOperandsEnumMap) const {} void PrinterCapstone::asmMatcherWriteOpOSToOS() const {} void PrinterCapstone::asmMatcherEmitTiedOpTable( std::map, std::string> TiedOperandsEnumMap) const {} void PrinterCapstone::asmMatcherEmitTiedOpEmptyTable() const {} void PrinterCapstone::asmMatcherEmitOperandConvKindEnum( SmallSetVector OperandConversionKinds) const {} void PrinterCapstone::asmMatcherEmitInstrConvKindEnum( SmallSetVector InstructionConversionKinds) const {} void PrinterCapstone::asmMatcherEmitConversionTable( size_t MaxRowLength, std::vector> const ConversionTable, SmallSetVector InstructionConversionKinds, SmallSetVector OperandConversionKinds, std::map, std::string> TiedOperandsEnumMap) const {} void PrinterCapstone::asmMatcherEmitMatchClassKindEnum( std::forward_list const &Infos) const {} void PrinterCapstone::asmMatcherEmitMatchClassDiagStrings( AsmMatcherInfo const &Info) const {} void PrinterCapstone::asmMatcherEmitRegisterMatchErrorFunc( AsmMatcherInfo &Info) const {} void PrinterCapstone::asmMatcherEmitIsSubclassI() const {} bool PrinterCapstone::asmMatcherEmitIsSubclassII( bool EmittedSwitch, std::string const &Name) const { return true; } void PrinterCapstone::asmMatcherEmitIsSubclassIII(StringRef const &Name) const { } void PrinterCapstone::asmMatcherEmitIsSubclassIV( std::vector const &SuperClasses) const {} void PrinterCapstone::asmMatcherEmitIsSubclassV(bool EmittedSwitch) const {} void PrinterCapstone::asmMatcherEmitValidateOperandClass( AsmMatcherInfo &Info) const {} void PrinterCapstone::asmMatcherEmitMatchClassKindNames( std::forward_list &Infos) const {} void PrinterCapstone::asmMatcherEmitAsmTiedOperandConstraints( CodeGenTarget &Target, AsmMatcherInfo &Info) const {} std::string PrinterCapstone::getNameForFeatureBitset( const std::vector &FeatureBitset) const { return ""; } void PrinterCapstone::asmMatcherEmitFeatureBitsetEnum( std::vector> const FeatureBitsets) const {} void PrinterCapstone::asmMatcherEmitFeatureBitsets( std::vector> const FeatureBitsets, AsmMatcherInfo const &Info) const {} void PrinterCapstone::asmMatcherEmitMatchEntryStruct( unsigned MaxMnemonicIndex, unsigned NumConverters, size_t MaxNumOperands, std::vector> const FeatureBitsets, AsmMatcherInfo const &Info) const {} void PrinterCapstone::asmMatcherEmitMatchFunction( CodeGenTarget const &Target, Record const *AsmParser, StringRef const &ClassName, bool HasMnemonicFirst, bool HasOptionalOperands, bool ReportMultipleNearMisses, bool HasMnemonicAliases, size_t MaxNumOperands, bool HasDeprecation, unsigned int VariantCount) const {} void PrinterCapstone::asmMatcherEmitMnemonicSpellChecker( CodeGenTarget const &Target, unsigned VariantCount) const {} void PrinterCapstone::asmMatcherEmitMnemonicChecker( CodeGenTarget const &Target, unsigned VariantCount, bool HasMnemonicFirst, bool HasMnemonicAliases) const {} void PrinterCapstone::asmMatcherEmitCustomOperandParsing( unsigned MaxMask, CodeGenTarget &Target, AsmMatcherInfo const &Info, StringRef ClassName, StringToOffsetTable &StringTable, unsigned MaxMnemonicIndex, unsigned MaxFeaturesIndex, bool HasMnemonicFirst, Record const &AsmParser) const {} void PrinterCapstone::asmMatcherEmitIncludes() const {} void PrinterCapstone::asmMatcherEmitMnemonicTable( StringToOffsetTable &StringTable) const {} void PrinterCapstone::asmMatcherEmitMatchRegisterName( Record const *AsmParser, std::vector const Matches) const {} void PrinterCapstone::asmMatcherEmitMatchTokenString( std::vector const Matches) const {} void PrinterCapstone::asmMatcherEmitMatchRegisterAltName( Record const *AsmParser, std::vector const Matches) const {} void PrinterCapstone::asmMatcherEmitMnemonicAliasVariant( std::vector const &Cases, unsigned Indent) const {} void PrinterCapstone::asmMatcherAppendMnemonicAlias( Record const *R, std::string const &FeatureMask, std::string &MatchCode) const {} void PrinterCapstone::asmMatcherAppendMnemonic(Record const *R, std::string &MatchCode) const {} void PrinterCapstone::asmMatcherAppendMnemonicAliasEnd( std::string &MatchCode) const {} void PrinterCapstone::asmMatcherEmitApplyMnemonicAliasesI() const {} void PrinterCapstone::asmMatcherEmitApplyMnemonicAliasesII( int AsmParserVariantNo) const {} void PrinterCapstone::asmMatcherEmitApplyMnemonicAliasesIII() const {} void PrinterCapstone::asmMatcherEmitApplyMnemonicAliasesIV() const {} void PrinterCapstone::asmMatcherEmitApplyMnemonicAliasesV() const {} void PrinterCapstone::asmMatcherEmitSTFBitEnum(AsmMatcherInfo &Info) const {} void PrinterCapstone::asmMatcherEmitComputeAssemblerAvailableFeatures( AsmMatcherInfo &Info, StringRef const &ClassName) const {} void PrinterCapstone::searchableTablesWriteFiles() const { std::string Filename = TargetName + "GenSystemRegister.inc"; std::string HeaderStr; raw_string_ostream Header(HeaderStr); emitDefaultSourceFileHeader(Header); raw_string_ostream &Decl = searchableTablesGetOS(ST_DECL_OS); raw_string_ostream &Impl = searchableTablesGetOS(ST_IMPL_OS); writeFile(Filename, Header.str() + Decl.str() + Impl.str()); raw_string_ostream &SysOpsEnum = searchableTablesGetOS(ST_ENUM_SYSOPS_OS); if (!SysOpsEnum.str().empty()) { Filename = TargetName + "GenCSSystemOperandsEnum.inc"; writeFile(Filename, Header.str() + SysOpsEnum.str()); } } raw_string_ostream &PrinterCapstone::searchableTablesGetOS(StreamType G) const { // Very bad design here. But we only use it for our dirty generation // for Capstone so it is not meant to be reliable. static bool Init = false; static std::string SysRegDecl; static raw_string_ostream *SysRegDeclOS; static std::string SysRegEnum; static raw_string_ostream *SysOpsEnumOS; static std::string SysRegImpl; static raw_string_ostream *SysRegImplOS; if (!Init) { SysRegDeclOS = new raw_string_ostream(SysRegDecl); SysRegImplOS = new raw_string_ostream(SysRegImpl); SysOpsEnumOS = new raw_string_ostream(SysRegEnum); Init = true; } switch (G) { default: assert(0 && "No stream specified."); case ST_DECL_OS: return *SysRegDeclOS; case ST_IMPL_OS: return *SysRegImplOS; case ST_ENUM_SYSOPS_OS: return *SysOpsEnumOS; } } void PrinterCapstone::searchableTablesEmitGenericEnum( const GenericEnum &Enum) const { // We do not emit enums here, but generate them when we print the mapping // tables Because the table has the type information for its fields, we have a // chance to distinguish between Sys regs, imms and other alias. The generated // enums are written to GenCSSystemOperandsEnum.inc } void PrinterCapstone::searchableTablesEmitGenericTable( const GenericTable &Enum) const {} void PrinterCapstone::searchableTablesEmitIfdef(const std::string Guard, StreamType ST) { raw_string_ostream &OutS = searchableTablesGetOS(ST); OutS << "#ifdef " << Guard << "\n"; PreprocessorGuards.insert(Guard); } void PrinterCapstone::searchableTablesEmitEndif(StreamType ST) const { raw_string_ostream &OutS = searchableTablesGetOS(ST); OutS << "#endif\n\n"; } void PrinterCapstone::searchableTablesEmitUndef() const { raw_string_ostream &OutS = searchableTablesGetOS(ST_IMPL_OS); for (const auto &Guard : PreprocessorGuards) OutS << "#undef " << Guard << "\n"; } std::string PrinterCapstone::searchableTablesSearchableFieldType( const GenericTable &Table, const SearchIndex &Index, const GenericField &Field, TypeContext Ctx) const { if (isa(Field.RecType)) { if (Ctx == TypeInStaticStruct) return "const char *"; if (Ctx == TypeInTempStruct) return "const char *"; return "const char *"; } else if (BitsRecTy *BI = dyn_cast(Field.RecType)) { unsigned NumBits = BI->getNumBits(); if (NumBits <= 8) return "uint8_t"; if (NumBits <= 16) return "uint16_t"; if (NumBits <= 32) return "uint32_t"; if (NumBits <= 64) return "uint64_t"; PrintFatalError(Index.Loc, Twine("In table '") + Table.Name + "' lookup method '" + Index.Name + "', key field '" + Field.Name + "' of type bits is too large"); } else if (isa(Field.RecType)) { return "bool"; } else if (Field.Enum || Field.IsIntrinsic || Field.IsInstruction) return "unsigned"; PrintFatalError(Index.Loc, Twine("In table '") + Table.Name + "' lookup method '" + Index.Name + "', key field '" + Field.Name + "' has invalid type: " + Field.RecType->getAsString()); } std::string PrinterCapstone::searchableTablesPrimaryRepresentation( SMLoc Loc, const GenericField &Field, Init *I, StringRef const &InstrinsicEnumName) const { if (StringInit *SI = dyn_cast(I)) { if (Field.IsCode || SI->hasCodeFormat()) { std::string Code = Regex("::").sub("_", std::string(SI->getValue())); while (Code.find("::") != std::string::npos) Code = Regex("::").sub("_", Code); return Code; } else return Regex("::").sub("_", SI->getAsString()); } else if (BitsInit *BI = dyn_cast(I)) return "0x" + utohexstr(getAsInt(BI)); else if (BitInit *BI = dyn_cast(I)) return BI->getValue() ? "true" : "false"; else if (Field.IsIntrinsic) return "Intrinsic_" + InstrinsicEnumName.str(); else if (Field.IsInstruction) return Regex("::").sub("_", I->getAsString()); else if (Field.Enum) { auto *Entry = Field.Enum->EntryMap[cast(I)->getDef()]; if (!Entry) PrintFatalError(Loc, Twine("Entry for field '") + Field.Name + "' is null"); return Regex("::").sub("_", std::string(Entry->first)); } PrintFatalError(Loc, Twine("invalid field type for field '") + Field.Name + "'; expected: bit, bits, string, or code"); } std::string getTableNamespacePrefix(const GenericTable &Table, std::string TargetName) { // Sometimes table type are wrapped into namespaces. // In Capstone we need to prepend the name to those types in this case. std::set> AArch64NSTypePairs = { {"AArch64SysReg", "SysReg"}, {"AArch64PState", "PStateImm0_15"}, {"AArch64PState", "PStateImm0_1"}, {"AArch64SVCR", "SVCR"}, {"AArch64AT", "AT"}, {"AArch64DB", "DB"}, {"AArch64DBnXS", "DBnXS"}, {"AArch64DC", "DC"}, {"AArch64IC", "IC"}, {"AArch64ISB", "ISB"}, {"AArch64TSB", "TSB"}, {"AArch64PRFM", "PRFM"}, {"AArch64SVEPRFM", "SVEPRFM"}, {"AArch64RPRFM", "RPRFM"}, {"AArch64SVCR", "SVCR"}, {"AArch64SVEPredPattern", "SVEPREDPAT"}, {"AArch64SVEVecLenSpecifier", "SVEVECLENSPECIFIER"}, {"AArch64ExactFPImm", "ExactFPImm"}, {"AArch64BTIHint", "BTI"}, {"AArch64TLBI", "TLBI"}, {"AArch64PRCTX", "PRCTX"}, {"AArch64BTIHint", "BTI"}, {"AArch64PSBHint", "PSB"}, }; std::set> ARMNSTypePairs = { {"ARMSysReg", "MClassSysReg"}, {"ARMBankedReg", "BankedReg"}, }; std::set> *NSTable; if (StringRef(TargetName).upper() != "AARCH64" && TargetName != "ARM") return Table.CppTypeName + "_"; if (StringRef(TargetName).upper() == "AARCH64") NSTable = &AArch64NSTypePairs; else if (TargetName == "ARM") NSTable = &ARMNSTypePairs; else PrintFatalNote("No Namespace Type table defined for target."); for (auto NSTPair : *NSTable) { if (NSTPair.second == Table.CppTypeName) return NSTPair.first + "_"; } PrintNote("No namespace defined for type: " + Table.CppTypeName); return ""; } void PrinterCapstone::searchableTablesEmitLookupDeclaration( const GenericTable &Table, const SearchIndex &Index, StreamType ST) { raw_string_ostream &OutS = (ST == ST_DECL_OS) ? searchableTablesGetOS(ST_DECL_OS) : searchableTablesGetOS(ST_IMPL_OS); std::string NamespacePre = getTableNamespacePrefix(Table, TargetName); OutS << "const " << NamespacePre << Table.CppTypeName << " *" << NamespacePre << Index.Name << "("; ListSeparator LS; for (const auto &Field : Index.Fields) OutS << LS << searchableTablesSearchableFieldType(Table, Index, Field, TypeInArgument) << " " << Field.Name; OutS << ")"; if (ST == ST_DECL_OS) { OutS << ";\n"; } else if (ST == ST_IMPL_OS) OutS << " {\n"; } void PrinterCapstone::searchableTablesEmitIndexTypeStruct( const GenericTable &Table, const SearchIndex &Index) { for (const auto &Field : Index.Fields) { if (isa(Field.RecType)) { EmittingNameLookup = isa(Field.RecType); } } } void PrinterCapstone::searchableTablesEmitIndexArrayI() const { raw_string_ostream &OutS = searchableTablesGetOS(ST_IMPL_OS); if (EmittingNameLookup) OutS << " static const struct IndexTypeStr Index[] = {\n"; else OutS << " static const struct IndexType Index[] = {\n"; } void PrinterCapstone::searchableTablesEmitIndexArrayII() const { raw_string_ostream &OutS = searchableTablesGetOS(ST_IMPL_OS); OutS << " { "; } void PrinterCapstone::searchableTablesEmitIndexArrayIII( ListSeparator &LS, std::string Repr) const { raw_string_ostream &OutS = searchableTablesGetOS(ST_IMPL_OS); OutS << LS << Repr; } void PrinterCapstone::searchableTablesEmitIndexArrayIV( std::pair const &Entry) const { raw_string_ostream &OutS = searchableTablesGetOS(ST_IMPL_OS); OutS << ", " << Entry.second << " },\n"; } void PrinterCapstone::searchableTablesEmitIndexArrayV() const { raw_string_ostream &OutS = searchableTablesGetOS(ST_IMPL_OS); OutS << " };\n\n"; } void PrinterCapstone::searchableTablesEmitIsContiguousCase( StringRef const &IndexName, const GenericTable &Table, const SearchIndex &Index, bool IsPrimary) { searchableTablesEmitReturns(Table, Index, IsPrimary); } void PrinterCapstone::searchableTablesEmitIfFieldCase( const GenericField &Field, std::string const &FirstRepr, std::string const &LastRepr) const {} void PrinterCapstone::searchableTablesEmitKeyTypeStruct( const GenericTable &Table, const SearchIndex &Index) const {} void PrinterCapstone::searchableTablesEmitKeyArray(const GenericTable &Table, const SearchIndex &Index, bool IsPrimary) const {} void PrinterCapstone::searchableTablesEmitIndexLamda( const SearchIndex &Index, StringRef const &IndexName, StringRef const &IndexTypeName) const {} void PrinterCapstone::searchableTablesEmitReturns(const GenericTable &Table, const SearchIndex &Index, bool IsPrimary) { raw_string_ostream &OutS = searchableTablesGetOS(ST_IMPL_OS); if (EmittingNameLookup) { OutS << " unsigned i = binsearch_IndexTypeStrEncoding(Index, " "ARR_SIZE(Index), "; EmittingNameLookup = false; } else OutS << " unsigned i = binsearch_IndexTypeEncoding(Index, " "ARR_SIZE(Index), "; for (const auto &Field : Index.Fields) OutS << Field.Name; OutS << ");\n" << " if (i == -1)\n" << " return NULL;\n" << " else\n" << " return &" << Table.Name << "[Index[i].index];\n"; OutS << "}\n\n"; } void PrinterCapstone::searchableTablesEmitMapI( const GenericTable &Table) const { raw_string_ostream &OutS = searchableTablesGetOS(ST_IMPL_OS); OutS << "static const " << getTableNamespacePrefix(Table, TargetName) << Table.CppTypeName << " " << Table.Name << "[] = {\n"; raw_string_ostream &EnumOS = searchableTablesGetOS(ST_ENUM_SYSOPS_OS); EnumOS << "#ifdef GET_ENUM_VALUES_" << Table.CppTypeName << "\n"; EnumOS << "#undef GET_ENUM_VALUES_" << Table.CppTypeName << "\n"; } void PrinterCapstone::searchableTablesEmitMapII() const { raw_string_ostream &OutS = searchableTablesGetOS(ST_IMPL_OS); OutS << " { "; } uint64_t BitsInitToUInt(const BitsInit *BI) { uint64_t Value = 0; for (unsigned I = 0, Ie = BI->getNumBits(); I != Ie; ++I) { if (BitInit *B = dyn_cast(BI->getBit(I))) Value |= (uint64_t)B->getValue() << I; } return Value; } unsigned getEnumValue(Record *Entry) { if (!Entry->getValue("EnumValueField") || Entry->isValueUnset("EnumValueField")) { // Guess field which has the encoding. if (Entry->getValue("Encoding")) { BitsInit *BI = Entry->getValueAsBitsInit("Encoding"); return BitsInitToUInt(BI); } Entry->dump(); PrintFatalNote("Which of those fields above are the encoding/enum value?"); } StringRef EnumValField = Entry->getValueAsString("EnumValueField"); return BitsInitToUInt(Entry->getValueAsBitsInit(EnumValField)); } void PrinterCapstone::searchableTablesEmitMapIII(const GenericTable &Table, ListSeparator &LS, GenericField const &Field, StringRef &IntrinsicEnum, Record *Entry) const { static std::set EnumNamesSeen; unsigned EnumVal = getEnumValue(Entry); raw_string_ostream &OutS = searchableTablesGetOS(ST_IMPL_OS); OutS << LS; std::string EnumName; std::string Repr = searchableTablesPrimaryRepresentation( Table.Locs[0], Field, Entry->getValueInit(Field.Name), IntrinsicEnum); // Emit table field if (Field.Name == "Name" || Field.Name == "AltName") { // Prepend the enum id to the name field std::string OpName = Repr; while (OpName.find("\"") != std::string::npos) OpName = Regex("\"").sub("", OpName); EnumName = StringRef(TargetName).upper() + "_" + StringRef(Table.CppTypeName).upper() + "_" + StringRef(OpName).upper(); Repr = "\"" + OpName + "\", { .raw_val = " + EnumName + " }"; OutS << Repr; // Emit enum name if (EnumNamesSeen.find(EnumName) != EnumNamesSeen.end()) return; EnumNamesSeen.emplace(EnumName); raw_string_ostream &EnumOS = searchableTablesGetOS(ST_ENUM_SYSOPS_OS); EnumOS << "\t" + EnumName + " = " << format("0x%x", EnumVal) << ",\n"; } else { OutS << Regex("{ *}").sub("{0}", Repr); } } void PrinterCapstone::searchableTablesEmitMapIV(unsigned i) const { raw_string_ostream &OutS = searchableTablesGetOS(ST_IMPL_OS); OutS << " }, // " << i << "\n"; } void PrinterCapstone::searchableTablesEmitMapV() { raw_string_ostream &OutS = searchableTablesGetOS(ST_IMPL_OS); OutS << " };\n\n"; raw_string_ostream &EnumOS = searchableTablesGetOS(ST_ENUM_SYSOPS_OS); EnumOS << "#endif\n\n"; } } // end namespace llvm