diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2022-07-03 14:10:23 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2022-07-03 14:10:23 +0000 |
| commit | 145449b1e420787bb99721a429341fa6be3adfb6 (patch) | |
| tree | 1d56ae694a6de602e348dd80165cf881a36600ed /llvm/utils | |
| parent | ecbca9f5fb7d7613d2b94982c4825eb0d33d6842 (diff) | |
Diffstat (limited to 'llvm/utils')
56 files changed, 2508 insertions, 1196 deletions
diff --git a/llvm/utils/TableGen/AsmMatcherEmitter.cpp b/llvm/utils/TableGen/AsmMatcherEmitter.cpp index be17d5c718c2..1acc2a86d176 100644 --- a/llvm/utils/TableGen/AsmMatcherEmitter.cpp +++ b/llvm/utils/TableGen/AsmMatcherEmitter.cpp @@ -95,6 +95,7 @@ // //===----------------------------------------------------------------------===// +#include "CodeGenInstruction.h" #include "CodeGenTarget.h" #include "SubtargetFeatureInfo.h" #include "Types.h" @@ -3394,7 +3395,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { StringTable.GetOrAddStringOffset(LenMnemonic, false)); } - OS << "static const char *const MnemonicTable =\n"; + OS << "static const char MnemonicTable[] =\n"; StringTable.EmitString(OS); OS << ";\n\n"; diff --git a/llvm/utils/TableGen/AsmWriterEmitter.cpp b/llvm/utils/TableGen/AsmWriterEmitter.cpp index 9283ceeb31e0..1d738274c75a 100644 --- a/llvm/utils/TableGen/AsmWriterEmitter.cpp +++ b/llvm/utils/TableGen/AsmWriterEmitter.cpp @@ -19,15 +19,14 @@ #include "Types.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Debug.h" -#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/MathExtras.h" @@ -868,8 +867,6 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { IAPrinter IAP(CGA.Result->getAsString(), FlatAliasAsmString, NumMIOps); - bool CantHandle = false; - unsigned MIOpNum = 0; for (unsigned i = 0, e = LastOpNo; i != e; ++i) { // Skip over tied operands as they're not part of an alias declaration. @@ -969,10 +966,9 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { break; } case CodeGenInstAlias::ResultOperand::K_Reg: - // If this is zero_reg, something's playing tricks we're not - // equipped to handle. if (!CGA.ResultOperands[i].getRegister()) { - CantHandle = true; + IAP.addCond(std::string(formatv( + "AliasPatternCond::K_Reg, {0}::NoRegister", Namespace))); break; } @@ -985,8 +981,6 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { MIOpNum += RO.getMINumOperands(); } - if (CantHandle) continue; - std::vector<Record *> ReqFeatures; if (PassSubtarget) { // We only consider ReqFeatures predicates if PassSubtarget @@ -1005,6 +999,17 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { if (D->getNumArgs() == 0) PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!"); bool IsOr = CombineType == "any_of"; + // Change (any_of FeatureAll, (any_of ...)) to (any_of FeatureAll, ...). + if (IsOr && D->getNumArgs() == 2 && isa<DagInit>(D->getArg(1))) { + DagInit *RHS = dyn_cast<DagInit>(D->getArg(1)); + SmallVector<Init *> Args{D->getArg(0)}; + SmallVector<StringInit *> ArgNames{D->getArgName(0)}; + for (unsigned i = 0, e = RHS->getNumArgs(); i != e; ++i) { + Args.push_back(RHS->getArg(i)); + ArgNames.push_back(RHS->getArgName(i)); + } + D = DagInit::get(D->getOperator(), nullptr, Args, ArgNames); + } for (auto *Arg : D->getArgs()) { bool IsNeg = false; diff --git a/llvm/utils/TableGen/AsmWriterInst.cpp b/llvm/utils/TableGen/AsmWriterInst.cpp index 887abbac9d3b..4a78108d6f4a 100644 --- a/llvm/utils/TableGen/AsmWriterInst.cpp +++ b/llvm/utils/TableGen/AsmWriterInst.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "AsmWriterInst.h" +#include "CodeGenInstruction.h" #include "CodeGenTarget.h" #include "llvm/ADT/StringExtras.h" #include "llvm/TableGen/Error.h" diff --git a/llvm/utils/TableGen/Attributes.cpp b/llvm/utils/TableGen/Attributes.cpp index 5deac4b34bf2..1f975f52d6e7 100644 --- a/llvm/utils/TableGen/Attributes.cpp +++ b/llvm/utils/TableGen/Attributes.cpp @@ -6,10 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Support/MemoryBuffer.h" #include "llvm/TableGen/Record.h" -#include <algorithm> -#include <string> #include <vector> using namespace llvm; diff --git a/llvm/utils/TableGen/CallingConvEmitter.cpp b/llvm/utils/TableGen/CallingConvEmitter.cpp index 127ae6247bd9..8f080cd250ab 100644 --- a/llvm/utils/TableGen/CallingConvEmitter.cpp +++ b/llvm/utils/TableGen/CallingConvEmitter.cpp @@ -15,12 +15,19 @@ #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/TableGenBackend.h" -#include <cassert> using namespace llvm; namespace { class CallingConvEmitter { RecordKeeper &Records; + unsigned Counter; + std::string CurrentAction; + bool SwiftAction; + + std::map<std::string, std::set<std::string>> AssignedRegsMap; + std::map<std::string, std::set<std::string>> AssignedSwiftRegsMap; + std::map<std::string, std::set<std::string>> DelegateToMap; + public: explicit CallingConvEmitter(RecordKeeper &R) : Records(R) {} @@ -29,7 +36,7 @@ public: private: void EmitCallingConv(Record *CC, raw_ostream &O); void EmitAction(Record *Action, unsigned Indent, raw_ostream &O); - unsigned Counter; + void EmitArgRegisterLists(raw_ostream &O); }; } // End anonymous namespace @@ -39,6 +46,7 @@ void CallingConvEmitter::run(raw_ostream &O) { // Emit prototypes for all of the non-custom CC's so that they can forward ref // each other. Records.startTimer("Emit prototypes"); + O << "#ifndef GET_CC_REGISTER_LISTS\n\n"; for (Record *CC : CCs) { if (!CC->getValueAsBit("Custom")) { unsigned Pad = CC->getName().size(); @@ -59,18 +67,28 @@ void CallingConvEmitter::run(raw_ostream &O) { // Emit each non-custom calling convention description in full. Records.startTimer("Emit full descriptions"); for (Record *CC : CCs) { - if (!CC->getValueAsBit("Custom")) + if (!CC->getValueAsBit("Custom")) { EmitCallingConv(CC, O); + } } -} + EmitArgRegisterLists(O); + + O << "\n#endif // CC_REGISTER_LIST\n"; +} void CallingConvEmitter::EmitCallingConv(Record *CC, raw_ostream &O) { ListInit *CCActions = CC->getValueAsListInit("Actions"); Counter = 0; + CurrentAction = CC->getName().str(); + // Call upon the creation of a map entry from the void! + // We want an entry in AssignedRegsMap for every action, even if that + // entry is empty. + AssignedRegsMap[CurrentAction] = {}; + O << "\n\n"; - unsigned Pad = CC->getName().size(); + unsigned Pad = CurrentAction.size(); if (CC->getValueAsBit("Entry")) { O << "bool llvm::"; Pad += 12; @@ -78,13 +96,21 @@ void CallingConvEmitter::EmitCallingConv(Record *CC, raw_ostream &O) { O << "static bool "; Pad += 13; } - O << CC->getName() << "(unsigned ValNo, MVT ValVT,\n" + O << CurrentAction << "(unsigned ValNo, MVT ValVT,\n" << std::string(Pad, ' ') << "MVT LocVT, CCValAssign::LocInfo LocInfo,\n" << std::string(Pad, ' ') << "ISD::ArgFlagsTy ArgFlags, CCState &State) {\n"; // Emit all of the actions, in order. for (unsigned i = 0, e = CCActions->size(); i != e; ++i) { + Record *Action = CCActions->getElementAsRecord(i); + SwiftAction = llvm::any_of(Action->getSuperClasses(), + [](const std::pair<Record *, SMRange> &Class) { + std::string Name = + Class.first->getNameInitAsString(); + return StringRef(Name).startswith("CCIfSwift"); + }); + O << "\n"; - EmitAction(CCActions->getElementAsRecord(i), 2, O); + EmitAction(Action, 2, O); } O << "\n return true; // CC didn't match.\n"; @@ -94,7 +120,7 @@ void CallingConvEmitter::EmitCallingConv(Record *CC, raw_ostream &O) { void CallingConvEmitter::EmitAction(Record *Action, unsigned Indent, raw_ostream &O) { std::string IndentStr = std::string(Indent, ' '); - + if (Action->isSubClassOf("CCPredicateAction")) { O << IndentStr << "if ("; @@ -122,18 +148,30 @@ void CallingConvEmitter::EmitAction(Record *Action, O << IndentStr << "if (!" << CC->getName() << "(ValNo, ValVT, LocVT, LocInfo, ArgFlags, State))\n" << IndentStr << " return false;\n"; + DelegateToMap[CurrentAction].insert(CC->getName().str()); } else if (Action->isSubClassOf("CCAssignToReg")) { ListInit *RegList = Action->getValueAsListInit("RegList"); if (RegList->size() == 1) { - O << IndentStr << "if (unsigned Reg = State.AllocateReg("; - O << getQualifiedName(RegList->getElementAsRecord(0)) << ")) {\n"; + std::string Name = getQualifiedName(RegList->getElementAsRecord(0)); + O << IndentStr << "if (unsigned Reg = State.AllocateReg(" << Name + << ")) {\n"; + if (SwiftAction) + AssignedSwiftRegsMap[CurrentAction].insert(Name); + else + AssignedRegsMap[CurrentAction].insert(Name); } else { O << IndentStr << "static const MCPhysReg RegList" << ++Counter << "[] = {\n"; O << IndentStr << " "; ListSeparator LS; - for (unsigned i = 0, e = RegList->size(); i != e; ++i) - O << LS << getQualifiedName(RegList->getElementAsRecord(i)); + for (unsigned i = 0, e = RegList->size(); i != e; ++i) { + std::string Name = getQualifiedName(RegList->getElementAsRecord(i)); + if (SwiftAction) + AssignedSwiftRegsMap[CurrentAction].insert(Name); + else + AssignedRegsMap[CurrentAction].insert(Name); + O << LS << Name; + } O << "\n" << IndentStr << "};\n"; O << IndentStr << "if (unsigned Reg = State.AllocateReg(RegList" << Counter << ")) {\n"; @@ -288,6 +326,83 @@ void CallingConvEmitter::EmitAction(Record *Action, } } +void CallingConvEmitter::EmitArgRegisterLists(raw_ostream &O) { + // Transitively merge all delegated CCs into AssignedRegsMap. + using EntryTy = std::pair<std::string, std::set<std::string>>; + bool Redo; + do { + Redo = false; + std::deque<EntryTy> Worklist(DelegateToMap.begin(), DelegateToMap.end()); + + while (!Worklist.empty()) { + EntryTy Entry = Worklist.front(); + Worklist.pop_front(); + + const std::string &CCName = Entry.first; + std::set<std::string> &Registers = Entry.second; + if (!Registers.empty()) + continue; + + for (auto &InnerEntry : Worklist) { + const std::string &InnerCCName = InnerEntry.first; + std::set<std::string> &InnerRegisters = InnerEntry.second; + + if (InnerRegisters.find(CCName) != InnerRegisters.end()) { + AssignedRegsMap[InnerCCName].insert( + AssignedRegsMap[CCName].begin(), + AssignedRegsMap[CCName].end()); + InnerRegisters.erase(CCName); + } + } + + DelegateToMap.erase(CCName); + Redo = true; + } + } while (Redo); + + if (AssignedRegsMap.empty()) + return; + + O << "\n#else\n\n"; + + for (auto &Entry : AssignedRegsMap) { + const std::string &RegName = Entry.first; + std::set<std::string> &Registers = Entry.second; + + if (RegName.empty()) + continue; + + O << "const MCRegister " << Entry.first << "_ArgRegs[] = { "; + + if (Registers.empty()) { + O << "0"; + } else { + ListSeparator LS; + for (const std::string &Reg : Registers) + O << LS << Reg; + } + + O << " };\n"; + } + + if (AssignedSwiftRegsMap.empty()) + return; + + O << "\n// Registers used by Swift.\n"; + for (auto &Entry : AssignedSwiftRegsMap) { + const std::string &RegName = Entry.first; + std::set<std::string> &Registers = Entry.second; + + O << "const MCRegister " << RegName << "_Swift_ArgRegs[] = { "; + + ListSeparator LS; + for (const std::string &Reg : Registers) + O << LS << Reg; + + O << " };\n"; + } +} + namespace llvm { void EmitCallingConv(RecordKeeper &RK, raw_ostream &OS) { diff --git a/llvm/utils/TableGen/CodeBeadsGen.cpp b/llvm/utils/TableGen/CodeBeadsGen.cpp deleted file mode 100644 index 18a6d6d19eb2..000000000000 --- a/llvm/utils/TableGen/CodeBeadsGen.cpp +++ /dev/null @@ -1,137 +0,0 @@ -//===---------- CodeBeadsGen.cpp - Code Beads Generator -------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// CodeBeads are data fields carrying auxiliary information for instructions. -// -// Under the hood it's simply implemented by a `bits` field (with arbitrary -// length) in each TG instruction description, where this TG backend will -// generate a helper function to access it. -// -// This is especially useful for expressing variable length encoding -// instructions and complex addressing modes. Since in those cases each -// instruction is usually associated with large amount of information like -// addressing mode details used on a specific operand. Instead of retreating to -// ad-hoc methods to figure out these information when encoding an instruction, -// CodeBeads provide a clean table for the instruction encoder to lookup. -//===----------------------------------------------------------------------===// - -#include "CodeGenTarget.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Support/Debug.h" -#include "llvm/TableGen/Error.h" -#include "llvm/TableGen/Record.h" -#include "llvm/TableGen/TableGenBackend.h" -#include <map> -#include <string> -#include <vector> -using namespace llvm; - -namespace { - -class CodeBeadsGen { - RecordKeeper &Records; - -public: - CodeBeadsGen(RecordKeeper &R) : Records(R) {} - void run(raw_ostream &OS); -}; - -void CodeBeadsGen::run(raw_ostream &OS) { - CodeGenTarget Target(Records); - std::vector<Record *> Insts = Records.getAllDerivedDefinitions("Instruction"); - - // For little-endian instruction bit encodings, reverse the bit order - Target.reverseBitsForLittleEndianEncoding(); - - ArrayRef<const CodeGenInstruction *> NumberedInstructions = - Target.getInstructionsByEnumValue(); - - // Emit function declaration - OS << "const uint8_t *llvm::" << Target.getInstNamespace(); - OS << "::getMCInstrBeads(unsigned Opcode) {\n"; - - // First, get the maximum bit length among all beads. And do some - // simple validation - unsigned MaxBitLength = 0; - - for (const CodeGenInstruction *CGI : NumberedInstructions) { - Record *R = CGI->TheDef; - if (!R->getValue("Beads")) - continue; - - BitsInit *BI = R->getValueAsBitsInit("Beads"); - if (!BI->isComplete()) { - PrintFatalError(R->getLoc(), "Record `" + R->getName() + - "', bit field 'Beads' is not complete"); - } - - MaxBitLength = std::max(MaxBitLength, BI->getNumBits()); - } - - // Number of bytes - unsigned Parts = MaxBitLength / 8; - - // Emit instruction base values - OS << " static const uint8_t InstBits[][" << Parts << "] = {\n"; - for (const CodeGenInstruction *CGI : NumberedInstructions) { - Record *R = CGI->TheDef; - - if (R->getValueAsString("Namespace") == "TargetOpcode" || - !R->getValue("Beads")) { - OS << "\t{ 0x0 },\t// "; - if (R->getValueAsBit("isPseudo")) - OS << "(Pseudo) "; - OS << R->getName() << "\n"; - continue; - } - - BitsInit *BI = R->getValueAsBitsInit("Beads"); - - // Convert to byte array: - // [dcba] -> [a][b][c][d] - OS << "\t{"; - for (unsigned p = 0; p < Parts; ++p) { - unsigned Right = 8 * p; - unsigned Left = Right + 8; - - uint8_t Value = 0; - for (unsigned i = Right; i != Left; ++i) { - unsigned Shift = i % 8; - if (auto *B = dyn_cast<BitInit>(BI->getBit(i))) { - Value |= (static_cast<uint8_t>(B->getValue()) << Shift); - } else { - PrintFatalError(R->getLoc(), "Record `" + R->getName() + - "', bit 'Beads[" + Twine(i) + - "]' is not defined"); - } - } - - if (p) - OS << ','; - OS << " 0x"; - OS.write_hex(Value); - OS << ""; - } - OS << " }," << '\t' << "// " << R->getName() << "\n"; - } - OS << "\t{ 0x0 }\n };\n"; - - // Emit initial function code - OS << " return InstBits[Opcode];\n" - << "}\n\n"; -} - -} // End anonymous namespace - -namespace llvm { - -void EmitCodeBeads(RecordKeeper &RK, raw_ostream &OS) { - emitSourceFileHeader("Machine Code Beads", OS); - CodeBeadsGen(RK).run(OS); -} - -} // namespace llvm diff --git a/llvm/utils/TableGen/CodeEmitterGen.cpp b/llvm/utils/TableGen/CodeEmitterGen.cpp index fbac0d969917..2b9931b23c11 100644 --- a/llvm/utils/TableGen/CodeEmitterGen.cpp +++ b/llvm/utils/TableGen/CodeEmitterGen.cpp @@ -16,11 +16,13 @@ #include "CodeGenTarget.h" #include "SubtargetFeatureInfo.h" #include "Types.h" +#include "VarLenCodeEmitterGen.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/Casting.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/TableGenBackend.h" #include <cassert> @@ -117,16 +119,16 @@ AddCodeToMergeInOperand(Record *R, BitsInit *BI, const std::string &VarName, (!NamedOpIndices.empty() && NamedOpIndices.count( CGI.Operands.getSubOperandNumber(NumberedOp).first)))) { ++NumberedOp; + } - if (NumberedOp >= CGI.Operands.back().MIOperandNo + - CGI.Operands.back().MINumOperands) { - errs() << "Too few operands in record " << R->getName() << - " (no match for variable " << VarName << "):\n"; - errs() << *R; - errs() << '\n'; - - return; - } + if (NumberedOp >= + CGI.Operands.back().MIOperandNo + CGI.Operands.back().MINumOperands) { + std::string E; + raw_string_ostream S(E); + S << "Too few operands in record " << R->getName() + << " (no match for variable " << VarName << "):\n"; + S << *R; + PrintFatalError(R, E); } OpIdx = NumberedOp++; @@ -396,132 +398,138 @@ void CodeEmitterGen::run(raw_ostream &o) { ArrayRef<const CodeGenInstruction*> NumberedInstructions = Target.getInstructionsByEnumValue(); - const CodeGenHwModes &HWM = Target.getHwModes(); - // The set of HwModes used by instruction encodings. - std::set<unsigned> HwModes; - BitWidth = 0; - for (const CodeGenInstruction *CGI : NumberedInstructions) { - Record *R = CGI->TheDef; - if (R->getValueAsString("Namespace") == "TargetOpcode" || - R->getValueAsBit("isPseudo")) - continue; + if (any_of(NumberedInstructions, [](const CodeGenInstruction *CGI) { + Record *R = CGI->TheDef; + return R->getValue("Inst") && isa<DagInit>(R->getValueInit("Inst")); + })) { + emitVarLenCodeEmitter(Records, o); + } else { + const CodeGenHwModes &HWM = Target.getHwModes(); + // The set of HwModes used by instruction encodings. + std::set<unsigned> HwModes; + BitWidth = 0; + for (const CodeGenInstruction *CGI : NumberedInstructions) { + Record *R = CGI->TheDef; + if (R->getValueAsString("Namespace") == "TargetOpcode" || + R->getValueAsBit("isPseudo")) + continue; - if (const RecordVal *RV = R->getValue("EncodingInfos")) { - if (DefInit *DI = dyn_cast_or_null<DefInit>(RV->getValue())) { - EncodingInfoByHwMode EBM(DI->getDef(), HWM); - for (auto &KV : EBM) { - BitsInit *BI = KV.second->getValueAsBitsInit("Inst"); - BitWidth = std::max(BitWidth, BI->getNumBits()); - HwModes.insert(KV.first); + if (const RecordVal *RV = R->getValue("EncodingInfos")) { + if (DefInit *DI = dyn_cast_or_null<DefInit>(RV->getValue())) { + EncodingInfoByHwMode EBM(DI->getDef(), HWM); + for (auto &KV : EBM) { + BitsInit *BI = KV.second->getValueAsBitsInit("Inst"); + BitWidth = std::max(BitWidth, BI->getNumBits()); + HwModes.insert(KV.first); + } + continue; } - continue; } + BitsInit *BI = R->getValueAsBitsInit("Inst"); + BitWidth = std::max(BitWidth, BI->getNumBits()); + } + UseAPInt = BitWidth > 64; + + // Emit function declaration + if (UseAPInt) { + o << "void " << Target.getName() + << "MCCodeEmitter::getBinaryCodeForInstr(const MCInst &MI,\n" + << " SmallVectorImpl<MCFixup> &Fixups,\n" + << " APInt &Inst,\n" + << " APInt &Scratch,\n" + << " const MCSubtargetInfo &STI) const {\n"; + } else { + o << "uint64_t " << Target.getName(); + o << "MCCodeEmitter::getBinaryCodeForInstr(const MCInst &MI,\n" + << " SmallVectorImpl<MCFixup> &Fixups,\n" + << " const MCSubtargetInfo &STI) const {\n"; } - BitsInit *BI = R->getValueAsBitsInit("Inst"); - BitWidth = std::max(BitWidth, BI->getNumBits()); - } - UseAPInt = BitWidth > 64; - - // Emit function declaration - if (UseAPInt) { - o << "void " << Target.getName() - << "MCCodeEmitter::getBinaryCodeForInstr(const MCInst &MI,\n" - << " SmallVectorImpl<MCFixup> &Fixups,\n" - << " APInt &Inst,\n" - << " APInt &Scratch,\n" - << " const MCSubtargetInfo &STI) const {\n"; - } else { - o << "uint64_t " << Target.getName(); - o << "MCCodeEmitter::getBinaryCodeForInstr(const MCInst &MI,\n" - << " SmallVectorImpl<MCFixup> &Fixups,\n" - << " const MCSubtargetInfo &STI) const {\n"; - } - - // Emit instruction base values - if (HwModes.empty()) { - emitInstructionBaseValues(o, NumberedInstructions, Target, -1); - } else { - for (unsigned HwMode : HwModes) - emitInstructionBaseValues(o, NumberedInstructions, Target, (int)HwMode); - } - if (!HwModes.empty()) { - o << " const uint64_t *InstBits;\n"; - o << " unsigned HwMode = STI.getHwMode();\n"; - o << " switch (HwMode) {\n"; - o << " default: llvm_unreachable(\"Unknown hardware mode!\"); break;\n"; - for (unsigned I : HwModes) { - o << " case " << I << ": InstBits = InstBits_" << HWM.getMode(I).Name - << "; break;\n"; + // Emit instruction base values + if (HwModes.empty()) { + emitInstructionBaseValues(o, NumberedInstructions, Target, -1); + } else { + for (unsigned HwMode : HwModes) + emitInstructionBaseValues(o, NumberedInstructions, Target, (int)HwMode); } - o << " };\n"; - } - // Map to accumulate all the cases. - std::map<std::string, std::vector<std::string>> CaseMap; + if (!HwModes.empty()) { + o << " const uint64_t *InstBits;\n"; + o << " unsigned HwMode = STI.getHwMode();\n"; + o << " switch (HwMode) {\n"; + o << " default: llvm_unreachable(\"Unknown hardware mode!\"); break;\n"; + for (unsigned I : HwModes) { + o << " case " << I << ": InstBits = InstBits_" << HWM.getMode(I).Name + << "; break;\n"; + } + o << " };\n"; + } - // Construct all cases statement for each opcode - for (Record *R : Insts) { - if (R->getValueAsString("Namespace") == "TargetOpcode" || - R->getValueAsBit("isPseudo")) - continue; - std::string InstName = - (R->getValueAsString("Namespace") + "::" + R->getName()).str(); - std::string Case = getInstructionCase(R, Target); + // Map to accumulate all the cases. + std::map<std::string, std::vector<std::string>> CaseMap; - CaseMap[Case].push_back(std::move(InstName)); - } + // Construct all cases statement for each opcode + for (Record *R : Insts) { + if (R->getValueAsString("Namespace") == "TargetOpcode" || + R->getValueAsBit("isPseudo")) + continue; + std::string InstName = + (R->getValueAsString("Namespace") + "::" + R->getName()).str(); + std::string Case = getInstructionCase(R, Target); - // Emit initial function code - if (UseAPInt) { - int NumWords = APInt::getNumWords(BitWidth); - int NumBytes = (BitWidth + 7) / 8; - o << " const unsigned opcode = MI.getOpcode();\n" - << " if (Inst.getBitWidth() != " << BitWidth << ")\n" - << " Inst = Inst.zext(" << BitWidth << ");\n" - << " if (Scratch.getBitWidth() != " << BitWidth << ")\n" - << " Scratch = Scratch.zext(" << BitWidth << ");\n" - << " LoadIntFromMemory(Inst, (const uint8_t *)&InstBits[opcode * " - << NumWords << "], " << NumBytes << ");\n" - << " APInt &Value = Inst;\n" - << " APInt &op = Scratch;\n" - << " switch (opcode) {\n"; - } else { - o << " const unsigned opcode = MI.getOpcode();\n" - << " uint64_t Value = InstBits[opcode];\n" - << " uint64_t op = 0;\n" - << " (void)op; // suppress warning\n" - << " switch (opcode) {\n"; - } + CaseMap[Case].push_back(std::move(InstName)); + } + + // Emit initial function code + if (UseAPInt) { + int NumWords = APInt::getNumWords(BitWidth); + o << " const unsigned opcode = MI.getOpcode();\n" + << " if (Scratch.getBitWidth() != " << BitWidth << ")\n" + << " Scratch = Scratch.zext(" << BitWidth << ");\n" + << " Inst = APInt(" << BitWidth + << ", makeArrayRef(InstBits + opcode * " << NumWords << ", " << NumWords + << "));\n" + << " APInt &Value = Inst;\n" + << " APInt &op = Scratch;\n" + << " switch (opcode) {\n"; + } else { + o << " const unsigned opcode = MI.getOpcode();\n" + << " uint64_t Value = InstBits[opcode];\n" + << " uint64_t op = 0;\n" + << " (void)op; // suppress warning\n" + << " switch (opcode) {\n"; + } - // Emit each case statement - std::map<std::string, std::vector<std::string>>::iterator IE, EE; - for (IE = CaseMap.begin(), EE = CaseMap.end(); IE != EE; ++IE) { - const std::string &Case = IE->first; - std::vector<std::string> &InstList = IE->second; + // Emit each case statement + std::map<std::string, std::vector<std::string>>::iterator IE, EE; + for (IE = CaseMap.begin(), EE = CaseMap.end(); IE != EE; ++IE) { + const std::string &Case = IE->first; + std::vector<std::string> &InstList = IE->second; - for (int i = 0, N = InstList.size(); i < N; i++) { - if (i) o << "\n"; - o << " case " << InstList[i] << ":"; + for (int i = 0, N = InstList.size(); i < N; i++) { + if (i) + o << "\n"; + o << " case " << InstList[i] << ":"; + } + o << " {\n"; + o << Case; + o << " break;\n" + << " }\n"; } - o << " {\n"; - o << Case; - o << " break;\n" - << " }\n"; - } - // Default case: unhandled opcode - o << " default:\n" - << " std::string msg;\n" - << " raw_string_ostream Msg(msg);\n" - << " Msg << \"Not supported instr: \" << MI;\n" - << " report_fatal_error(msg.c_str());\n" - << " }\n"; - if (UseAPInt) - o << " Inst = Value;\n"; - else - o << " return Value;\n"; - o << "}\n\n"; + // Default case: unhandled opcode + o << " default:\n" + << " std::string msg;\n" + << " raw_string_ostream Msg(msg);\n" + << " Msg << \"Not supported instr: \" << MI;\n" + << " report_fatal_error(Msg.str().c_str());\n" + << " }\n"; + if (UseAPInt) + o << " Inst = Value;\n"; + else + o << " return Value;\n"; + o << "}\n\n"; + } const auto &All = SubtargetFeatureInfo::getAll(Records); std::map<Record *, SubtargetFeatureInfo, LessRecordByID> SubtargetFeatures; diff --git a/llvm/utils/TableGen/CodeGenDAGPatterns.cpp b/llvm/utils/TableGen/CodeGenDAGPatterns.cpp index a1f8f4809d5f..9d6adb6d2c37 100644 --- a/llvm/utils/TableGen/CodeGenDAGPatterns.cpp +++ b/llvm/utils/TableGen/CodeGenDAGPatterns.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "CodeGenDAGPatterns.h" +#include "CodeGenInstruction.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/STLExtras.h" @@ -2815,6 +2816,7 @@ void TreePattern::ComputeNamedNodes(TreePatternNode *N) { TreePatternNodePtr TreePattern::ParseTreePattern(Init *TheInit, StringRef OpName) { + RecordKeeper &RK = TheInit->getRecordKeeper(); if (DefInit *DI = dyn_cast<DefInit>(TheInit)) { Record *R = DI->getDef(); @@ -2853,13 +2855,13 @@ TreePatternNodePtr TreePattern::ParseTreePattern(Init *TheInit, if (!OpName.empty()) error("Constant int or bit argument should not have a name!"); if (isa<BitInit>(TheInit)) - TheInit = TheInit->convertInitializerTo(IntRecTy::get()); + TheInit = TheInit->convertInitializerTo(IntRecTy::get(RK)); return std::make_shared<TreePatternNode>(TheInit, 1); } if (BitsInit *BI = dyn_cast<BitsInit>(TheInit)) { // Turn this into an IntInit. - Init *II = BI->convertInitializerTo(IntRecTy::get()); + Init *II = BI->convertInitializerTo(IntRecTy::get(RK)); if (!II || !isa<IntInit>(II)) error("Bits value must be constants!"); return ParseTreePattern(II, OpName); @@ -2958,8 +2960,8 @@ TreePatternNodePtr TreePattern::ParseTreePattern(Init *TheInit, else // Otherwise, no chain. Operator = getDAGPatterns().get_intrinsic_wo_chain_sdnode(); - Children.insert(Children.begin(), - std::make_shared<TreePatternNode>(IntInit::get(IID), 1)); + Children.insert(Children.begin(), std::make_shared<TreePatternNode>( + IntInit::get(RK, IID), 1)); } if (Operator->isSubClassOf("ComplexPattern")) { @@ -4366,7 +4368,7 @@ void CodeGenDAGPatterns::ExpandHwModeBasedTypes() { PatternsToMatch.emplace_back(P.getSrcRecord(), P.getPredicates(), std::move(NewSrc), std::move(NewDst), P.getDstRegs(), P.getAddedComplexity(), - Record::getNewUID(), Mode, Check); + Record::getNewUID(Records), Mode, Check); }; for (PatternToMatch &P : Copy) { @@ -4742,7 +4744,7 @@ void CodeGenDAGPatterns::GenerateVariants() { PatternsToMatch[i].getSrcRecord(), PatternsToMatch[i].getPredicates(), Variant, PatternsToMatch[i].getDstPatternShared(), PatternsToMatch[i].getDstRegs(), - PatternsToMatch[i].getAddedComplexity(), Record::getNewUID(), + PatternsToMatch[i].getAddedComplexity(), Record::getNewUID(Records), PatternsToMatch[i].getForceMode(), PatternsToMatch[i].getHwModeFeatures()); } diff --git a/llvm/utils/TableGen/CodeGenDAGPatterns.h b/llvm/utils/TableGen/CodeGenDAGPatterns.h index 39d81230a4f2..94694a96eb90 100644 --- a/llvm/utils/TableGen/CodeGenDAGPatterns.h +++ b/llvm/utils/TableGen/CodeGenDAGPatterns.h @@ -28,7 +28,6 @@ #include <functional> #include <map> #include <numeric> -#include <set> #include <vector> namespace llvm { diff --git a/llvm/utils/TableGen/CodeGenInstruction.cpp b/llvm/utils/TableGen/CodeGenInstruction.cpp index 78b698c31b2b..ba12633ace8c 100644 --- a/llvm/utils/TableGen/CodeGenInstruction.cpp +++ b/llvm/utils/TableGen/CodeGenInstruction.cpp @@ -12,7 +12,6 @@ #include "CodeGenInstruction.h" #include "CodeGenTarget.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/TableGen/Error.h" @@ -416,6 +415,7 @@ CodeGenInstruction::CodeGenInstruction(Record *R) hasExtraDefRegAllocReq = R->getValueAsBit("hasExtraDefRegAllocReq"); isCodeGenOnly = R->getValueAsBit("isCodeGenOnly"); isPseudo = R->getValueAsBit("isPseudo"); + isMeta = R->getValueAsBit("isMeta"); ImplicitDefs = R->getValueAsListOfDefs("Defs"); ImplicitUses = R->getValueAsListOfDefs("Uses"); @@ -632,8 +632,8 @@ bool CodeGenInstAlias::tryAliasOpMatch(DagInit *Result, unsigned AliasOpNo, if (!BI->isComplete()) return false; // Convert the bits init to an integer and use that for the result. - IntInit *II = - dyn_cast_or_null<IntInit>(BI->convertInitializerTo(IntRecTy::get())); + IntInit *II = dyn_cast_or_null<IntInit>( + BI->convertInitializerTo(IntRecTy::get(BI->getRecordKeeper()))); if (!II) return false; ResOp = ResultOperand(II->getValue()); diff --git a/llvm/utils/TableGen/CodeGenInstruction.h b/llvm/utils/TableGen/CodeGenInstruction.h index e0ce5d433602..d3de6d95780c 100644 --- a/llvm/utils/TableGen/CodeGenInstruction.h +++ b/llvm/utils/TableGen/CodeGenInstruction.h @@ -16,13 +16,13 @@ #include "llvm/ADT/BitVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/MachineValueType.h" -#include "llvm/Support/SMLoc.h" #include <cassert> #include <string> #include <utility> #include <vector> namespace llvm { +class SMLoc; template <typename T> class ArrayRef; class Record; class DagInit; @@ -271,6 +271,7 @@ template <typename T> class ArrayRef; bool hasExtraDefRegAllocReq : 1; bool isCodeGenOnly : 1; bool isPseudo : 1; + bool isMeta : 1; bool isRegSequence : 1; bool isExtractSubreg : 1; bool isInsertSubreg : 1; diff --git a/llvm/utils/TableGen/CodeGenIntrinsics.h b/llvm/utils/TableGen/CodeGenIntrinsics.h index b005a5866f80..599795e3c065 100644 --- a/llvm/utils/TableGen/CodeGenIntrinsics.h +++ b/llvm/utils/TableGen/CodeGenIntrinsics.h @@ -26,7 +26,7 @@ struct CodeGenIntrinsic { Record *TheDef; // The actual record defining this intrinsic. std::string Name; // The name of the LLVM function "llvm.bswap.i32" std::string EnumName; // The name of the enum "bswap_i32" - std::string GCCBuiltinName; // Name of the corresponding GCC builtin, or "". + std::string ClangBuiltinName; // Name of the corresponding GCC builtin, or "". std::string MSBuiltinName; // Name of the corresponding MS builtin, or "". std::string TargetPrefix; // Target prefix, e.g. "ppc" for t-s intrinsics. @@ -125,6 +125,9 @@ struct CodeGenIntrinsic { /// True if the intrinsic is no-return. bool isNoReturn; + /// True if the intrinsic is no-callback. + bool isNoCallback; + /// True if the intrinsic is no-sync. bool isNoSync; diff --git a/llvm/utils/TableGen/CodeGenMapTable.cpp b/llvm/utils/TableGen/CodeGenMapTable.cpp index 38871eb8cf3c..02695942f5c1 100644 --- a/llvm/utils/TableGen/CodeGenMapTable.cpp +++ b/llvm/utils/TableGen/CodeGenMapTable.cpp @@ -75,8 +75,8 @@ // //===----------------------------------------------------------------------===// +#include "CodeGenInstruction.h" #include "CodeGenTarget.h" -#include "llvm/Support/Format.h" #include "llvm/TableGen/Error.h" using namespace llvm; typedef std::map<std::string, std::vector<Record*> > InstrRelMapTy; diff --git a/llvm/utils/TableGen/CodeGenRegisters.cpp b/llvm/utils/TableGen/CodeGenRegisters.cpp index afaeb73ffab1..2c61be713afc 100644 --- a/llvm/utils/TableGen/CodeGenRegisters.cpp +++ b/llvm/utils/TableGen/CodeGenRegisters.cpp @@ -12,21 +12,18 @@ //===----------------------------------------------------------------------===// #include "CodeGenRegisters.h" -#include "CodeGenTarget.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/IntEqClasses.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Debug.h" -#include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" @@ -204,12 +201,16 @@ namespace { class RegUnitIterator { CodeGenRegister::Vec::const_iterator RegI, RegE; CodeGenRegister::RegUnitList::iterator UnitI, UnitE; + static CodeGenRegister::RegUnitList Sentinel; public: RegUnitIterator(const CodeGenRegister::Vec &Regs): RegI(Regs.begin()), RegE(Regs.end()) { - if (RegI != RegE) { + if (RegI == RegE) { + UnitI = Sentinel.end(); + UnitE = Sentinel.end(); + } else { UnitI = (*RegI)->getRegUnits().begin(); UnitE = (*RegI)->getRegUnits().end(); advance(); @@ -240,6 +241,8 @@ protected: } }; +CodeGenRegister::RegUnitList RegUnitIterator::Sentinel; + } // end anonymous namespace // Return true of this unit appears in RegUnits. @@ -635,6 +638,7 @@ struct TupleExpander : SetTheory::Expander { Def->getValueAsListOfStrings("RegAsmNames"); // Zip them up. + RecordKeeper &RK = Def->getRecords(); for (unsigned n = 0; n != Length; ++n) { std::string Name; Record *Proto = Lists[0][n]; @@ -651,13 +655,13 @@ struct TupleExpander : SetTheory::Expander { SmallVector<Init *, 2> CostPerUse; CostPerUse.insert(CostPerUse.end(), CostList->begin(), CostList->end()); - StringInit *AsmName = StringInit::get(""); + StringInit *AsmName = StringInit::get(RK, ""); if (!RegNames.empty()) { if (RegNames.size() <= n) PrintFatalError(Def->getLoc(), "Register tuple definition missing name for '" + Name + "'."); - AsmName = StringInit::get(RegNames[n]); + AsmName = StringInit::get(RK, RegNames[n]); } // Create a new Record representing the synthesized register. This record @@ -696,7 +700,7 @@ struct TupleExpander : SetTheory::Expander { // Composite registers are always covered by sub-registers. if (Field == "CoveredBySubRegs") - RV.setValue(BitInit::get(true)); + RV.setValue(BitInit::get(RK, true)); // Copy fields from the RegisterTuples def. if (Field == "SubRegIndices" || @@ -1106,6 +1110,17 @@ void CodeGenRegisterClass::buildRegUnitSet(const CodeGenRegBank &RegBank, } //===----------------------------------------------------------------------===// +// CodeGenRegisterCategory +//===----------------------------------------------------------------------===// + +CodeGenRegisterCategory::CodeGenRegisterCategory(CodeGenRegBank &RegBank, + Record *R) + : TheDef(R), Name(std::string(R->getName())) { + for (Record *RegClass : R->getValueAsListOfDefs("Classes")) + Classes.push_back(RegBank.getRegClass(RegClass)); +} + +//===----------------------------------------------------------------------===// // CodeGenRegBank //===----------------------------------------------------------------------===// @@ -1222,6 +1237,12 @@ CodeGenRegBank::CodeGenRegBank(RecordKeeper &Records, for (auto &RC : RegClasses) RC.EnumValue = i++; CodeGenRegisterClass::computeSubClasses(*this); + + // Read in the register category definitions. + std::vector<Record *> RCats = + Records.getAllDerivedDefinitions("RegisterCategory"); + for (auto *R : RCats) + RegCategories.emplace_back(*this, R); } // Create a synthetic CodeGenSubRegIndex without a corresponding Record. @@ -1794,6 +1815,7 @@ void CodeGenRegBank::computeRegUnitWeights() { unsigned NumIters = 0; for (bool Changed = true; Changed; ++NumIters) { assert(NumIters <= NumNativeRegUnits && "Runaway register unit weights"); + (void) NumIters; Changed = false; for (auto &Reg : Registers) { CodeGenRegister::RegUnitList NormalUnits; diff --git a/llvm/utils/TableGen/CodeGenRegisters.h b/llvm/utils/TableGen/CodeGenRegisters.h index c9fcf83b0a8a..0fc8b3ef80dd 100644 --- a/llvm/utils/TableGen/CodeGenRegisters.h +++ b/llvm/utils/TableGen/CodeGenRegisters.h @@ -27,7 +27,6 @@ #include "llvm/ADT/StringRef.h" #include "llvm/MC/LaneBitmask.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/MachineValueType.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/SetTheory.h" #include <cassert> @@ -476,6 +475,26 @@ namespace llvm { static void computeSubClasses(CodeGenRegBank&); }; + // Register categories are used when we need to deterine the category a + // register falls into (GPR, vector, fixed, etc.) without having to know + // specific information about the target architecture. + class CodeGenRegisterCategory { + Record *TheDef; + std::string Name; + std::list<CodeGenRegisterClass *> Classes; + + public: + CodeGenRegisterCategory(CodeGenRegBank &, Record *R); + CodeGenRegisterCategory(CodeGenRegisterCategory &) = delete; + + // Return the Record that defined this class, or NULL if the class was + // created by TableGen. + Record *getDef() const { return TheDef; } + + std::string getName() const { return Name; } + std::list<CodeGenRegisterClass *> getClasses() const { return Classes; } + }; + // Register units are used to model interference and register pressure. // Every register is assigned one or more register units such that two // registers overlap if and only if they have a register unit in common. @@ -559,6 +578,13 @@ namespace llvm { typedef std::map<CodeGenRegisterClass::Key, CodeGenRegisterClass*> RCKeyMap; RCKeyMap Key2RC; + // Register categories. + std::list<CodeGenRegisterCategory> RegCategories; + DenseMap<Record *, CodeGenRegisterCategory *> Def2RCat; + using RCatKeyMap = + std::map<CodeGenRegisterClass::Key, CodeGenRegisterCategory *>; + RCatKeyMap Key2RCat; + // Remember each unique set of register units. Initially, this contains a // unique set for each register class. Simliar sets are coalesced with // pruneUnitSets and new supersets are inferred during computeRegUnitSets. @@ -719,6 +745,14 @@ namespace llvm { return RegClasses; } + std::list<CodeGenRegisterCategory> &getRegCategories() { + return RegCategories; + } + + const std::list<CodeGenRegisterCategory> &getRegCategories() const { + return RegCategories; + } + // Find a register class from its def. CodeGenRegisterClass *getRegClass(const Record *) const; diff --git a/llvm/utils/TableGen/CodeGenSchedule.cpp b/llvm/utils/TableGen/CodeGenSchedule.cpp index e47bda725a17..4933bfc476f4 100644 --- a/llvm/utils/TableGen/CodeGenSchedule.cpp +++ b/llvm/utils/TableGen/CodeGenSchedule.cpp @@ -17,7 +17,6 @@ #include "llvm/ADT/MapVector.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Debug.h" diff --git a/llvm/utils/TableGen/CodeGenSchedule.h b/llvm/utils/TableGen/CodeGenSchedule.h index a331a30b51a8..f7e35b0c808f 100644 --- a/llvm/utils/TableGen/CodeGenSchedule.h +++ b/llvm/utils/TableGen/CodeGenSchedule.h @@ -17,11 +17,8 @@ #include "llvm/ADT/APInt.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/Support/ErrorHandling.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/SetTheory.h" -#include <map> namespace llvm { diff --git a/llvm/utils/TableGen/CodeGenTarget.cpp b/llvm/utils/TableGen/CodeGenTarget.cpp index 2c1583f7979d..af2e8576af2e 100644 --- a/llvm/utils/TableGen/CodeGenTarget.cpp +++ b/llvm/utils/TableGen/CodeGenTarget.cpp @@ -14,16 +14,13 @@ //===----------------------------------------------------------------------===// #include "CodeGenTarget.h" -#include "CodeGenDAGPatterns.h" +#include "CodeGenInstruction.h" #include "CodeGenIntrinsics.h" #include "CodeGenSchedule.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringExtras.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/Timer.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" -#include "llvm/TableGen/TableGenBackend.h" #include <algorithm> using namespace llvm; @@ -56,9 +53,12 @@ StringRef llvm::getName(MVT::SimpleValueType T) { } StringRef llvm::getEnumName(MVT::SimpleValueType T) { + // clang-format off switch (T) { case MVT::Other: return "MVT::Other"; case MVT::i1: return "MVT::i1"; + case MVT::i2: return "MVT::i2"; + case MVT::i4: return "MVT::i4"; case MVT::i8: return "MVT::i8"; case MVT::i16: return "MVT::i16"; case MVT::i32: return "MVT::i32"; @@ -91,6 +91,8 @@ StringRef llvm::getEnumName(MVT::SimpleValueType T) { case MVT::v256i1: return "MVT::v256i1"; case MVT::v512i1: return "MVT::v512i1"; case MVT::v1024i1: return "MVT::v1024i1"; + case MVT::v128i2: return "MVT::v128i2"; + case MVT::v64i4: return "MVT::v64i4"; case MVT::v1i8: return "MVT::v1i8"; case MVT::v2i8: return "MVT::v2i8"; case MVT::v4i8: return "MVT::v4i8"; @@ -227,6 +229,8 @@ StringRef llvm::getEnumName(MVT::SimpleValueType T) { case MVT::nxv2bf16: return "MVT::nxv2bf16"; case MVT::nxv4bf16: return "MVT::nxv4bf16"; case MVT::nxv8bf16: return "MVT::nxv8bf16"; + case MVT::nxv16bf16: return "MVT::nxv16bf16"; + case MVT::nxv32bf16: return "MVT::nxv32bf16"; case MVT::nxv1f32: return "MVT::nxv1f32"; case MVT::nxv2f32: return "MVT::nxv2f32"; case MVT::nxv4f32: return "MVT::nxv4f32"; @@ -245,6 +249,7 @@ StringRef llvm::getEnumName(MVT::SimpleValueType T) { case MVT::externref: return "MVT::externref"; default: llvm_unreachable("ILLEGAL VALUE TYPE!"); } + // clang-format on } /// getQualifiedName - Return the name of the specified record, with a @@ -471,7 +476,7 @@ GetInstByName(const char *Name, return I->second.get(); } -static const char *const FixedInstrs[] = { +static const char *FixedInstrs[] = { #define HANDLE_TARGET_OPCODE(OPC) #OPC, #include "llvm/Support/TargetOpcodes.def" nullptr}; @@ -555,7 +560,7 @@ void CodeGenTarget::reverseBitsForLittleEndianEncoding() { NewBits[middle] = BI->getBit(middle); } - BitsInit *NewBI = BitsInit::get(NewBits); + BitsInit *NewBI = BitsInit::get(Records, NewBits); // Update the bits in reversed order so that emitInstrOpBits will get the // correct endianness. @@ -666,6 +671,7 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R, isCommutative = false; canThrow = false; isNoReturn = false; + isNoCallback = false; isNoSync = false; isNoFree = false; isWillReturn = false; @@ -682,8 +688,8 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R, EnumName = DefName.substr(4); - if (R->getValue("GCCBuiltinName")) // Ignore a missing GCCBuiltinName field. - GCCBuiltinName = std::string(R->getValueAsString("GCCBuiltinName")); + if (R->getValue("ClangBuiltinName")) // Ignore a missing ClangBuiltinName field. + ClangBuiltinName = std::string(R->getValueAsString("ClangBuiltinName")); if (R->getValue("MSBuiltinName")) // Ignore a missing MSBuiltinName field. MSBuiltinName = std::string(R->getValueAsString("MSBuiltinName")); @@ -864,6 +870,8 @@ void CodeGenIntrinsic::setProperty(Record *R) { isConvergent = true; else if (R->getName() == "IntrNoReturn") isNoReturn = true; + else if (R->getName() == "IntrNoCallback") + isNoCallback = true; else if (R->getName() == "IntrNoSync") isNoSync = true; else if (R->getName() == "IntrNoFree") diff --git a/llvm/utils/TableGen/CodeGenTarget.h b/llvm/utils/TableGen/CodeGenTarget.h index 5bd84c873f2f..f14828f2c347 100644 --- a/llvm/utils/TableGen/CodeGenTarget.h +++ b/llvm/utils/TableGen/CodeGenTarget.h @@ -17,16 +17,15 @@ #define LLVM_UTILS_TABLEGEN_CODEGENTARGET_H #include "CodeGenHwModes.h" -#include "CodeGenInstruction.h" #include "CodeGenRegisters.h" #include "InfoByHwMode.h" #include "SDNodeProperties.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/TableGen/Record.h" -#include <algorithm> namespace llvm { +class RecordKeeper; +class Record; +class CodeGenInstruction; struct CodeGenRegister; class CodeGenSchedModels; class CodeGenTarget; diff --git a/llvm/utils/TableGen/DAGISelEmitter.cpp b/llvm/utils/TableGen/DAGISelEmitter.cpp index 2f211e2958fa..d012a0172a8f 100644 --- a/llvm/utils/TableGen/DAGISelEmitter.cpp +++ b/llvm/utils/TableGen/DAGISelEmitter.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "CodeGenDAGPatterns.h" +#include "CodeGenInstruction.h" #include "DAGISelMatcher.h" #include "llvm/Support/Debug.h" #include "llvm/TableGen/Record.h" diff --git a/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp b/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp index 5b0d16a8f3c8..777e75dcd929 100644 --- a/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp +++ b/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp @@ -13,9 +13,7 @@ #include "CodeGenDAGPatterns.h" #include "DAGISelMatcher.h" #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/StringMap.h" #include "llvm/ADT/MapVector.h" -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/Support/CommandLine.h" diff --git a/llvm/utils/TableGen/DAGISelMatcherGen.cpp b/llvm/utils/TableGen/DAGISelMatcherGen.cpp index 2361ed8a7a95..44bff4c67ab3 100644 --- a/llvm/utils/TableGen/DAGISelMatcherGen.cpp +++ b/llvm/utils/TableGen/DAGISelMatcherGen.cpp @@ -6,9 +6,10 @@ // //===----------------------------------------------------------------------===// -#include "DAGISelMatcher.h" #include "CodeGenDAGPatterns.h" +#include "CodeGenInstruction.h" #include "CodeGenRegisters.h" +#include "DAGISelMatcher.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/TableGen/Error.h" diff --git a/llvm/utils/TableGen/DFAEmitter.cpp b/llvm/utils/TableGen/DFAEmitter.cpp index 27161d261e85..f2d9165c5c8c 100644 --- a/llvm/utils/TableGen/DFAEmitter.cpp +++ b/llvm/utils/TableGen/DFAEmitter.cpp @@ -21,7 +21,6 @@ //===----------------------------------------------------------------------===// #include "DFAEmitter.h" -#include "CodeGenTarget.h" #include "SequenceToOffsetTable.h" #include "TableGenBackends.h" #include "llvm/ADT/SmallVector.h" @@ -30,9 +29,9 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include "llvm/TableGen/Record.h" -#include "llvm/TableGen/TableGenBackend.h" #include <cassert> #include <cstdint> +#include <deque> #include <map> #include <set> #include <string> @@ -306,6 +305,7 @@ void Automaton::emit(raw_ostream &OS) { } LLVM_DEBUG(dbgs() << " NFA automaton has " << SeenStates.size() << " states with " << NumTransitions << " transitions.\n"); + (void) NumTransitions; const auto &ActionTypes = Transitions.back().getTypes(); OS << "// The type of an action in the " << Name << " automaton.\n"; diff --git a/llvm/utils/TableGen/DFAPacketizerEmitter.cpp b/llvm/utils/TableGen/DFAPacketizerEmitter.cpp index 9cbdbc19c206..6704d747f715 100644 --- a/llvm/utils/TableGen/DFAPacketizerEmitter.cpp +++ b/llvm/utils/TableGen/DFAPacketizerEmitter.cpp @@ -17,9 +17,7 @@ #include "CodeGenSchedule.h" #include "CodeGenTarget.h" #include "DFAEmitter.h" -#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringExtras.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include "llvm/TableGen/Record.h" diff --git a/llvm/utils/TableGen/DXILEmitter.cpp b/llvm/utils/TableGen/DXILEmitter.cpp new file mode 100644 index 000000000000..fd58e798b445 --- /dev/null +++ b/llvm/utils/TableGen/DXILEmitter.cpp @@ -0,0 +1,374 @@ +//===- DXILEmitter.cpp - DXIL operation Emitter ---------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// DXILEmitter uses the descriptions of DXIL operation to construct enum and +// helper functions for DXIL operation. +// +//===----------------------------------------------------------------------===// + +#include "SequenceToOffsetTable.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" + +using namespace llvm; + +namespace { + +struct DXILShaderModel { + int Major; + int Minor; +}; +struct DXILParam { + int Pos; // position in parameter list + StringRef Type; // llvm type name, $o for overload, $r for resource + // type, $cb for legacy cbuffer, $u4 for u4 struct + StringRef Name; // short, unique name + StringRef Doc; // the documentation description of this parameter + bool IsConst; // whether this argument requires a constant value in the IR + StringRef EnumName; // the name of the enum type if applicable + int MaxValue; // the maximum value for this parameter if applicable + DXILParam(const Record *R) { + Name = R->getValueAsString("name"); + Pos = R->getValueAsInt("pos"); + Type = R->getValueAsString("llvm_type"); + if (R->getValue("doc")) + Doc = R->getValueAsString("doc"); + IsConst = R->getValueAsBit("is_const"); + EnumName = R->getValueAsString("enum_name"); + MaxValue = R->getValueAsInt("max_value"); + } +}; + +struct DXILOperationData { + StringRef Name; // short, unique name + + StringRef DXILOp; // name of DXIL operation + int DXILOpID; // ID of DXIL operation + StringRef DXILClass; // name of the opcode class + StringRef Category; // classification for this instruction + StringRef Doc; // the documentation description of this instruction + + SmallVector<DXILParam> Params; // the operands that this instruction takes + StringRef OverloadTypes; // overload types if applicable + StringRef FnAttr; // attribute shorthands: rn=does not access + // memory,ro=only reads from memory + StringRef Intrinsic; // The llvm intrinsic map to DXILOp. Default is "" which + // means no map exist + bool IsDeriv; // whether this is some kind of derivative + bool IsGradient; // whether this requires a gradient calculation + bool IsFeedback; // whether this is a sampler feedback op + bool IsWave; // whether this requires in-wave, cross-lane functionality + bool RequiresUniformInputs; // whether this operation requires that all + // of its inputs are uniform across the wave + SmallVector<StringRef, 4> + ShaderStages; // shader stages to which this applies, empty for all. + DXILShaderModel ShaderModel; // minimum shader model required + DXILShaderModel ShaderModelTranslated; // minimum shader model required with + // translation by linker + SmallVector<StringRef, 4> counters; // counters for this inst. + DXILOperationData(const Record *R) { + Name = R->getValueAsString("name"); + DXILOp = R->getValueAsString("dxil_op"); + DXILOpID = R->getValueAsInt("dxil_opid"); + DXILClass = R->getValueAsDef("op_class")->getValueAsString("name"); + Category = R->getValueAsDef("category")->getValueAsString("name"); + + if (R->getValue("llvm_intrinsic")) { + auto *IntrinsicDef = R->getValueAsDef("llvm_intrinsic"); + auto DefName = IntrinsicDef->getName(); + assert(DefName.startswith("int_") && "invalid intrinsic name"); + // Remove the int_ from intrinsic name. + Intrinsic = DefName.substr(4); + } + + Doc = R->getValueAsString("doc"); + + ListInit *ParamList = R->getValueAsListInit("ops"); + for (unsigned i = 0; i < ParamList->size(); ++i) { + Record *Param = ParamList->getElementAsRecord(i); + Params.emplace_back(DXILParam(Param)); + } + OverloadTypes = R->getValueAsString("oload_types"); + FnAttr = R->getValueAsString("fn_attr"); + } +}; +} // end anonymous namespace + +static void emitDXILOpEnum(DXILOperationData &DXILOp, raw_ostream &OS) { + // Name = ID, // Doc + OS << DXILOp.Name << " = " << DXILOp.DXILOpID << ", // " << DXILOp.Doc + << "\n"; +} + +static std::string buildCategoryStr(StringSet<> &Cetegorys) { + std::string Str; + raw_string_ostream OS(Str); + for (auto &It : Cetegorys) { + OS << " " << It.getKey(); + } + return OS.str(); +} + +// Emit enum declaration for DXIL. +static void emitDXILEnums(std::vector<DXILOperationData> &DXILOps, + raw_ostream &OS) { + // Sort by Category + OpName. + std::sort(DXILOps.begin(), DXILOps.end(), + [](DXILOperationData &A, DXILOperationData &B) { + // Group by Category first. + if (A.Category == B.Category) + // Inside same Category, order by OpName. + return A.DXILOp < B.DXILOp; + else + return A.Category < B.Category; + }); + + OS << "// Enumeration for operations specified by DXIL\n"; + OS << "enum class OpCode : unsigned {\n"; + + StringMap<StringSet<>> ClassMap; + StringRef PrevCategory = ""; + for (auto &DXILOp : DXILOps) { + StringRef Category = DXILOp.Category; + if (Category != PrevCategory) { + OS << "\n// " << Category << "\n"; + PrevCategory = Category; + } + emitDXILOpEnum(DXILOp, OS); + auto It = ClassMap.find(DXILOp.DXILClass); + if (It != ClassMap.end()) { + It->second.insert(DXILOp.Category); + } else { + ClassMap[DXILOp.DXILClass].insert(DXILOp.Category); + } + } + + OS << "\n};\n\n"; + + std::vector<std::pair<std::string, std::string>> ClassVec; + for (auto &It : ClassMap) { + ClassVec.emplace_back( + std::make_pair(It.getKey().str(), buildCategoryStr(It.second))); + } + // Sort by Category + ClassName. + std::sort(ClassVec.begin(), ClassVec.end(), + [](std::pair<std::string, std::string> &A, + std::pair<std::string, std::string> &B) { + StringRef ClassA = A.first; + StringRef CategoryA = A.second; + StringRef ClassB = B.first; + StringRef CategoryB = B.second; + // Group by Category first. + if (CategoryA == CategoryB) + // Inside same Category, order by ClassName. + return ClassA < ClassB; + else + return CategoryA < CategoryB; + }); + + OS << "// Groups for DXIL operations with equivalent function templates\n"; + OS << "enum class OpCodeClass : unsigned {\n"; + PrevCategory = ""; + for (auto &It : ClassVec) { + + StringRef Category = It.second; + if (Category != PrevCategory) { + OS << "\n// " << Category << "\n"; + PrevCategory = Category; + } + StringRef Name = It.first; + OS << Name << ",\n"; + } + OS << "\n};\n\n"; +} + +// Emit map from llvm intrinsic to DXIL operation. +static void emitDXILIntrinsicMap(std::vector<DXILOperationData> &DXILOps, + raw_ostream &OS) { + OS << "\n"; + // FIXME: use array instead of SmallDenseMap. + OS << "static const SmallDenseMap<Intrinsic::ID, DXIL::OpCode> LowerMap = " + "{\n"; + for (auto &DXILOp : DXILOps) { + if (DXILOp.Intrinsic.empty()) + continue; + // {Intrinsic::sin, DXIL::OpCode::Sin}, + OS << " { Intrinsic::" << DXILOp.Intrinsic + << ", DXIL::OpCode::" << DXILOp.DXILOp << "},\n"; + } + OS << "};\n"; + OS << "\n"; +} + +static std::string emitDXILOperationFnAttr(StringRef FnAttr) { + return StringSwitch<std::string>(FnAttr) + .Case("rn", "Attribute::ReadNone") + .Case("ro", "Attribute::ReadOnly") + .Default("Attribute::None"); +} + +static std::string getOverloadKind(StringRef Overload) { + return StringSwitch<std::string>(Overload) + .Case("half", "OverloadKind::HALF") + .Case("float", "OverloadKind::FLOAT") + .Case("double", "OverloadKind::DOUBLE") + .Case("i1", "OverloadKind::I1") + .Case("i16", "OverloadKind::I16") + .Case("i32", "OverloadKind::I32") + .Case("i64", "OverloadKind::I64") + .Case("udt", "OverloadKind::UserDefineType") + .Case("obj", "OverloadKind::ObjectType") + .Default("OverloadKind::VOID"); +} + +static std::string getDXILOperationOverload(StringRef Overloads) { + SmallVector<StringRef> OverloadStrs; + Overloads.split(OverloadStrs, ';', /*MaxSplit*/ -1, /*KeepEmpty*/ false); + // Format is: OverloadKind::FLOAT | OverloadKind::HALF + assert(!OverloadStrs.empty() && "Invalid overloads"); + auto It = OverloadStrs.begin(); + std::string Result; + raw_string_ostream OS(Result); + OS << getOverloadKind(*It); + for (++It; It != OverloadStrs.end(); ++It) { + OS << " | " << getOverloadKind(*It); + } + return OS.str(); +} + +static std::string lowerFirstLetter(StringRef Name) { + if (Name.empty()) + return ""; + + std::string LowerName = Name.str(); + LowerName[0] = llvm::toLower(Name[0]); + return LowerName; +} + +static std::string getDXILOpClassName(StringRef DXILOpClass) { + // Lower first letter expect for special case. + return StringSwitch<std::string>(DXILOpClass) + .Case("CBufferLoad", "cbufferLoad") + .Case("CBufferLoadLegacy", "cbufferLoadLegacy") + .Case("GSInstanceID", "gsInstanceID") + .Default(lowerFirstLetter(DXILOpClass)); +} + +static void emitDXILOperationTable(std::vector<DXILOperationData> &DXILOps, + raw_ostream &OS) { + // Sort by DXILOpID. + std::sort(DXILOps.begin(), DXILOps.end(), + [](DXILOperationData &A, DXILOperationData &B) { + return A.DXILOpID < B.DXILOpID; + }); + + // Collect Names. + SequenceToOffsetTable<std::string> OpClassStrings; + SequenceToOffsetTable<std::string> OpStrings; + + StringSet<> ClassSet; + for (auto &DXILOp : DXILOps) { + OpStrings.add(DXILOp.DXILOp.str()); + + if (ClassSet.find(DXILOp.DXILClass) != ClassSet.end()) + continue; + ClassSet.insert(DXILOp.DXILClass); + OpClassStrings.add(getDXILOpClassName(DXILOp.DXILClass)); + } + + // Layout names. + OpStrings.layout(); + OpClassStrings.layout(); + + // Emit the DXIL operation table. + //{DXIL::OpCode::Sin, OpCodeNameIndex, OpCodeClass::Unary, + // OpCodeClassNameIndex, + // OverloadKind::FLOAT | OverloadKind::HALF, Attribute::AttrKind::ReadNone}, + OS << "static const OpCodeProperty *getOpCodeProperty(DXIL::OpCode DXILOp) " + "{\n"; + + OS << " static const OpCodeProperty OpCodeProps[] = {\n"; + for (auto &DXILOp : DXILOps) { + OS << " { DXIL::OpCode::" << DXILOp.DXILOp << ", " + << OpStrings.get(DXILOp.DXILOp.str()) + << ", OpCodeClass::" << DXILOp.DXILClass << ", " + << OpClassStrings.get(getDXILOpClassName(DXILOp.DXILClass)) << ", " + << getDXILOperationOverload(DXILOp.OverloadTypes) << ", " + << emitDXILOperationFnAttr(DXILOp.FnAttr) << " },\n"; + } + OS << " };\n"; + + OS << " // FIXME: change search to indexing with\n"; + OS << " // DXILOp once all DXIL op is added.\n"; + OS << " OpCodeProperty TmpProp;\n"; + OS << " TmpProp.OpCode = DXILOp;\n"; + OS << " const OpCodeProperty *Prop =\n"; + OS << " llvm::lower_bound(OpCodeProps, TmpProp,\n"; + OS << " [](const OpCodeProperty &A, const " + "OpCodeProperty &B) {\n"; + OS << " return A.OpCode < B.OpCode;\n"; + OS << " });\n"; + OS << " assert(Prop && \"fail to find OpCodeProperty\");\n"; + OS << " return Prop;\n"; + OS << "}\n\n"; + + // Emit the string tables. + OS << "static const char *getOpCodeName(DXIL::OpCode DXILOp) {\n\n"; + + OpStrings.emitStringLiteralDef(OS, + " static const char DXILOpCodeNameTable[]"); + + OS << " auto *Prop = getOpCodeProperty(DXILOp);\n"; + OS << " unsigned Index = Prop->OpCodeNameOffset;\n"; + OS << " return DXILOpCodeNameTable + Index;\n"; + OS << "}\n\n"; + + OS << "static const char *getOpCodeClassName(const OpCodeProperty &Prop) " + "{\n\n"; + + OpClassStrings.emitStringLiteralDef( + OS, " static const char DXILOpCodeClassNameTable[]"); + + OS << " unsigned Index = Prop.OpCodeClassNameOffset;\n"; + OS << " return DXILOpCodeClassNameTable + Index;\n"; + OS << "}\n "; +} + +namespace llvm { + +void EmitDXILOperation(RecordKeeper &Records, raw_ostream &OS) { + std::vector<Record *> Ops = Records.getAllDerivedDefinitions("dxil_op"); + OS << "// Generated code, do not edit.\n"; + OS << "\n"; + + std::vector<DXILOperationData> DXILOps; + DXILOps.reserve(Ops.size()); + for (auto *Record : Ops) { + DXILOps.emplace_back(DXILOperationData(Record)); + } + + OS << "#ifdef DXIL_OP_ENUM\n"; + emitDXILEnums(DXILOps, OS); + OS << "#endif\n\n"; + + OS << "#ifdef DXIL_OP_INTRINSIC_MAP\n"; + emitDXILIntrinsicMap(DXILOps, OS); + OS << "#endif\n\n"; + + OS << "#ifdef DXIL_OP_OPERATION_TABLE\n"; + emitDXILOperationTable(DXILOps, OS); + OS << "#endif\n\n"; + + OS << "\n"; +} + +} // namespace llvm diff --git a/llvm/utils/TableGen/FixedLenDecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp index c5dd1e626696..8477e0639f90 100644 --- a/llvm/utils/TableGen/FixedLenDecoderEmitter.cpp +++ b/llvm/utils/TableGen/DecoderEmitter.cpp @@ -1,4 +1,4 @@ -//===------------ FixedLenDecoderEmitter.cpp - Decoder Generator ----------===// +//===---------------- DecoderEmitter.cpp - Decoder Generator --------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -7,13 +7,14 @@ //===----------------------------------------------------------------------===// // // It contains the tablegen backend that emits the decoder functions for -// targets with fixed length instruction set. +// targets with fixed/variable length instruction set. // //===----------------------------------------------------------------------===// #include "CodeGenInstruction.h" #include "CodeGenTarget.h" #include "InfoByHwMode.h" +#include "VarLenCodeEmitterGen.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/CachedHashString.h" @@ -23,7 +24,7 @@ #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" -#include "llvm/MC/MCFixedLenDisassembler.h" +#include "llvm/MC/MCDecoderOps.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" @@ -121,19 +122,18 @@ raw_ostream &operator<<(raw_ostream &OS, const EncodingAndInst &Value) { return OS; } -class FixedLenDecoderEmitter { +class DecoderEmitter { RecordKeeper &RK; std::vector<EncodingAndInst> NumberedEncodings; public: // Defaults preserved here for documentation, even though they aren't // strictly necessary given the way that this is currently being called. - FixedLenDecoderEmitter(RecordKeeper &R, std::string PredicateNamespace, - std::string GPrefix = "if (", - std::string GPostfix = " == MCDisassembler::Fail)", - std::string ROK = "MCDisassembler::Success", - std::string RFail = "MCDisassembler::Fail", - std::string L = "") + DecoderEmitter(RecordKeeper &R, std::string PredicateNamespace, + std::string GPrefix = "if (", + std::string GPostfix = " == MCDisassembler::Fail)", + std::string ROK = "MCDisassembler::Success", + std::string RFail = "MCDisassembler::Fail", std::string L = "") : RK(R), Target(R), PredicateNamespace(std::move(PredicateNamespace)), GuardPrefix(std::move(GPrefix)), GuardPostfix(std::move(GPostfix)), ReturnOK(std::move(ROK)), ReturnFail(std::move(RFail)), @@ -143,6 +143,8 @@ public: void emitTable(formatted_raw_ostream &o, DecoderTable &Table, unsigned Indentation, unsigned BitWidth, StringRef Namespace) const; + void emitInstrLenTable(formatted_raw_ostream &OS, + std::vector<unsigned> &InstrLen) const; void emitPredicateFunction(formatted_raw_ostream &OS, PredicateSet &Predicates, unsigned Indentation) const; @@ -217,8 +219,28 @@ static void dumpBits(raw_ostream &o, const BitsInit &bits) { } static BitsInit &getBitsField(const Record &def, StringRef str) { - BitsInit *bits = def.getValueAsBitsInit(str); - return *bits; + const RecordVal *RV = def.getValue(str); + if (BitsInit *Bits = dyn_cast<BitsInit>(RV->getValue())) + return *Bits; + + // variable length instruction + VarLenInst VLI = VarLenInst(cast<DagInit>(RV->getValue()), RV); + SmallVector<Init *, 16> Bits; + + for (auto &SI : VLI) { + if (const BitsInit *BI = dyn_cast<BitsInit>(SI.Value)) { + for (unsigned Idx = 0U; Idx < BI->getNumBits(); ++Idx) { + Bits.push_back(BI->getBit(Idx)); + } + } else if (const BitInit *BI = dyn_cast<BitInit>(SI.Value)) { + Bits.push_back(const_cast<BitInit *>(BI)); + } else { + for (unsigned Idx = 0U; Idx < SI.BitWidth; ++Idx) + Bits.push_back(UnsetInit::get(def.getRecords())); + } + } + + return *BitsInit::get(def.getRecords(), Bits); } // Representation of the instruction to work on. @@ -388,13 +410,13 @@ protected: unsigned BitWidth; // Parent emitter - const FixedLenDecoderEmitter *Emitter; + const DecoderEmitter *Emitter; public: FilterChooser(ArrayRef<EncodingAndInst> Insts, const std::vector<EncodingIDAndOpcode> &IDs, const std::map<unsigned, std::vector<OperandInfo>> &Ops, - unsigned BW, const FixedLenDecoderEmitter *E) + unsigned BW, const DecoderEmitter *E) : AllInstructions(Insts), Opcodes(IDs), Operands(Ops), FilterBitValues(BW, BIT_UNFILTERED), Parent(nullptr), BestIndex(-1), BitWidth(BW), Emitter(E) { @@ -421,20 +443,21 @@ protected: // Populates the insn given the uid. void insnWithID(insn_t &Insn, unsigned Opcode) const { BitsInit &Bits = getBitsField(*AllInstructions[Opcode].EncodingDef, "Inst"); - + Insn.resize(BitWidth > Bits.getNumBits() ? BitWidth : Bits.getNumBits(), + BIT_UNSET); // We may have a SoftFail bitmask, which specifies a mask where an encoding // may differ from the value in "Inst" and yet still be valid, but the // disassembler should return SoftFail instead of Success. // // This is used for marking UNPREDICTABLE instructions in the ARM world. - BitsInit *SFBits = - AllInstructions[Opcode].EncodingDef->getValueAsBitsInit("SoftFail"); - - for (unsigned i = 0; i < BitWidth; ++i) { + const RecordVal *RV = + AllInstructions[Opcode].EncodingDef->getValue("SoftFail"); + const BitsInit *SFBits = RV ? dyn_cast<BitsInit>(RV->getValue()) : nullptr; + for (unsigned i = 0; i < Bits.getNumBits(); ++i) { if (SFBits && bitFromBits(*SFBits, i) == BIT_TRUE) - Insn.push_back(BIT_UNSET); + Insn[i] = BIT_UNSET; else - Insn.push_back(bitFromBits(Bits, i)); + Insn[i] = bitFromBits(Bits, i); } } @@ -486,6 +509,8 @@ protected: // Returns true if predicate matches were emitted, false otherwise. bool emitPredicateMatch(raw_ostream &o, unsigned &Indentation, unsigned Opc) const; + bool emitPredicateMatchAux(const Init &Val, bool ParenIfBinOp, + raw_ostream &OS) const; bool doesOpcodeNeedPredicate(unsigned Opc) const; unsigned getPredicateIndex(DecoderTableInfo &TableInfo, StringRef P) const; @@ -747,11 +772,9 @@ unsigned Filter::usefulness() const { ////////////////////////////////// // Emit the decoder state machine table. -void FixedLenDecoderEmitter::emitTable(formatted_raw_ostream &OS, - DecoderTable &Table, - unsigned Indentation, - unsigned BitWidth, - StringRef Namespace) const { +void DecoderEmitter::emitTable(formatted_raw_ostream &OS, DecoderTable &Table, + unsigned Indentation, unsigned BitWidth, + StringRef Namespace) const { OS.indent(Indentation) << "static const uint8_t DecoderTable" << Namespace << BitWidth << "[] = {\n"; @@ -936,9 +959,18 @@ void FixedLenDecoderEmitter::emitTable(formatted_raw_ostream &OS, OS.indent(Indentation) << "};\n\n"; } -void FixedLenDecoderEmitter:: -emitPredicateFunction(formatted_raw_ostream &OS, PredicateSet &Predicates, - unsigned Indentation) const { +void DecoderEmitter::emitInstrLenTable(formatted_raw_ostream &OS, + std::vector<unsigned> &InstrLen) const { + OS << "static const uint8_t InstrLenTable[] = {\n"; + for (unsigned &Len : InstrLen) { + OS << Len << ",\n"; + } + OS << "};\n\n"; +} + +void DecoderEmitter::emitPredicateFunction(formatted_raw_ostream &OS, + PredicateSet &Predicates, + unsigned Indentation) const { // The predicate function is just a big switch statement based on the // input predicate index. OS.indent(Indentation) << "static bool checkDecoderPredicate(unsigned Idx, " @@ -961,16 +993,17 @@ emitPredicateFunction(formatted_raw_ostream &OS, PredicateSet &Predicates, OS.indent(Indentation) << "}\n\n"; } -void FixedLenDecoderEmitter:: -emitDecoderFunction(formatted_raw_ostream &OS, DecoderSet &Decoders, - unsigned Indentation) const { +void DecoderEmitter::emitDecoderFunction(formatted_raw_ostream &OS, + DecoderSet &Decoders, + unsigned Indentation) const { // The decoder function is just a big switch statement based on the // input decoder index. OS.indent(Indentation) << "template <typename InsnType>\n"; OS.indent(Indentation) << "static DecodeStatus decodeToMCInst(DecodeStatus S," << " unsigned Idx, InsnType insn, MCInst &MI,\n"; - OS.indent(Indentation) << " uint64_t " - << "Address, const void *Decoder, bool &DecodeComplete) {\n"; + OS.indent(Indentation) + << " uint64_t " + << "Address, const MCDisassembler *Decoder, bool &DecodeComplete) {\n"; Indentation += 2; OS.indent(Indentation) << "DecodeComplete = true;\n"; // TODO: When InsnType is large, using uint64_t limits all fields to 64 bits @@ -1195,6 +1228,40 @@ unsigned FilterChooser::getDecoderIndex(DecoderSet &Decoders, return (unsigned)(P - Decoders.begin()); } +// If ParenIfBinOp is true, print a surrounding () if Val uses && or ||. +bool FilterChooser::emitPredicateMatchAux(const Init &Val, bool ParenIfBinOp, + raw_ostream &OS) const { + if (auto *D = dyn_cast<DefInit>(&Val)) { + if (!D->getDef()->isSubClassOf("SubtargetFeature")) + return true; + OS << "Bits[" << Emitter->PredicateNamespace << "::" << D->getAsString() + << "]"; + return false; + } + if (auto *D = dyn_cast<DagInit>(&Val)) { + std::string Op = D->getOperator()->getAsString(); + if (Op == "not" && D->getNumArgs() == 1) { + OS << '!'; + return emitPredicateMatchAux(*D->getArg(0), true, OS); + } + if ((Op == "any_of" || Op == "all_of") && D->getNumArgs() > 0) { + bool Paren = D->getNumArgs() > 1 && std::exchange(ParenIfBinOp, true); + if (Paren) + OS << '('; + ListSeparator LS(Op == "any_of" ? " || " : " && "); + for (auto *Arg : D->getArgs()) { + OS << LS; + if (emitPredicateMatchAux(*Arg, ParenIfBinOp, OS)) + return true; + } + if (Paren) + OS << ')'; + return false; + } + } + return true; +} + bool FilterChooser::emitPredicateMatch(raw_ostream &o, unsigned &Indentation, unsigned Opc) const { ListInit *Predicates = @@ -1208,40 +1275,11 @@ bool FilterChooser::emitPredicateMatch(raw_ostream &o, unsigned &Indentation, if (!isa<DagInit>(Pred->getValue("AssemblerCondDag")->getValue())) continue; - const DagInit *D = Pred->getValueAsDag("AssemblerCondDag"); - std::string CombineType = D->getOperator()->getAsString(); - if (CombineType != "any_of" && CombineType != "all_of") - PrintFatalError(Pred->getLoc(), "Invalid AssemblerCondDag!"); - if (D->getNumArgs() == 0) - PrintFatalError(Pred->getLoc(), "Invalid AssemblerCondDag!"); - bool IsOr = CombineType == "any_of"; - if (!IsFirstEmission) o << " && "; - - if (IsOr) - o << "("; - - ListSeparator LS(IsOr ? " || " : " && "); - for (auto *Arg : D->getArgs()) { - o << LS; - if (auto *NotArg = dyn_cast<DagInit>(Arg)) { - if (NotArg->getOperator()->getAsString() != "not" || - NotArg->getNumArgs() != 1) - PrintFatalError(Pred->getLoc(), "Invalid AssemblerCondDag!"); - Arg = NotArg->getArg(0); - o << "!"; - } - if (!isa<DefInit>(Arg) || - !cast<DefInit>(Arg)->getDef()->isSubClassOf("SubtargetFeature")) - PrintFatalError(Pred->getLoc(), "Invalid AssemblerCondDag!"); - o << "Bits[" << Emitter->PredicateNamespace << "::" << Arg->getAsString() - << "]"; - } - - if (IsOr) - o << ")"; - + if (emitPredicateMatchAux(*Pred->getValueAsDag("AssemblerCondDag"), + Predicates->size() > 1, o)) + PrintFatalError(Pred->getLoc(), "Invalid AssemblerCondDag!"); IsFirstEmission = false; } return !Predicates->empty(); @@ -1309,8 +1347,9 @@ void FilterChooser::emitPredicateTableEntry(DecoderTableInfo &TableInfo, void FilterChooser::emitSoftFailTableEntry(DecoderTableInfo &TableInfo, unsigned Opc) const { - BitsInit *SFBits = - AllInstructions[Opc].EncodingDef->getValueAsBitsInit("SoftFail"); + const RecordVal *RV = AllInstructions[Opc].EncodingDef->getValue("SoftFail"); + BitsInit *SFBits = RV ? dyn_cast<BitsInit>(RV->getValue()) : nullptr; + if (!SFBits) return; BitsInit *InstBits = AllInstructions[Opc].EncodingDef->getValueAsBitsInit("Inst"); @@ -1785,11 +1824,9 @@ void FilterChooser::emitTableEntries(DecoderTableInfo &TableInfo) const { } } -static std::string findOperandDecoderMethod(TypedInit *TI) { +static std::string findOperandDecoderMethod(Record *Record) { std::string Decoder; - Record *Record = cast<DefInit>(TI)->getDef(); - RecordVal *DecoderString = Record->getValue("DecoderMethod"); StringInit *String = DecoderString ? dyn_cast<StringInit>(DecoderString->getValue()) : nullptr; @@ -1812,17 +1849,88 @@ static std::string findOperandDecoderMethod(TypedInit *TI) { return Decoder; } -static bool +OperandInfo getOpInfo(Record *TypeRecord) { + std::string Decoder = findOperandDecoderMethod(TypeRecord); + + RecordVal *HasCompleteDecoderVal = TypeRecord->getValue("hasCompleteDecoder"); + BitInit *HasCompleteDecoderBit = + HasCompleteDecoderVal + ? dyn_cast<BitInit>(HasCompleteDecoderVal->getValue()) + : nullptr; + bool HasCompleteDecoder = + HasCompleteDecoderBit ? HasCompleteDecoderBit->getValue() : true; + + return OperandInfo(Decoder, HasCompleteDecoder); +} + +void parseVarLenInstOperand(const Record &Def, + std::vector<OperandInfo> &Operands, + const CodeGenInstruction &CGI) { + + const RecordVal *RV = Def.getValue("Inst"); + VarLenInst VLI(cast<DagInit>(RV->getValue()), RV); + SmallVector<int> TiedTo; + + for (unsigned Idx = 0; Idx < CGI.Operands.size(); ++Idx) { + auto &Op = CGI.Operands[Idx]; + if (Op.MIOperandInfo && Op.MIOperandInfo->getNumArgs() > 0) + for (auto *Arg : Op.MIOperandInfo->getArgs()) + Operands.push_back(getOpInfo(cast<DefInit>(Arg)->getDef())); + else + Operands.push_back(getOpInfo(Op.Rec)); + + int TiedReg = Op.getTiedRegister(); + TiedTo.push_back(-1); + if (TiedReg != -1) { + TiedTo[Idx] = TiedReg; + TiedTo[TiedReg] = Idx; + } + } + + unsigned CurrBitPos = 0; + for (auto &EncodingSegment : VLI) { + unsigned Offset = 0; + StringRef OpName; + + if (const StringInit *SI = dyn_cast<StringInit>(EncodingSegment.Value)) { + OpName = SI->getValue(); + } else if (const DagInit *DI = dyn_cast<DagInit>(EncodingSegment.Value)) { + OpName = cast<StringInit>(DI->getArg(0))->getValue(); + Offset = cast<IntInit>(DI->getArg(2))->getValue(); + } + + if (!OpName.empty()) { + auto OpSubOpPair = + const_cast<CodeGenInstruction &>(CGI).Operands.ParseOperandName( + OpName); + unsigned OpIdx = CGI.Operands.getFlattenedOperandNumber(OpSubOpPair); + Operands[OpIdx].addField(CurrBitPos, EncodingSegment.BitWidth, Offset); + + int TiedReg = TiedTo[OpSubOpPair.first]; + if (TiedReg != -1) { + unsigned OpIdx = CGI.Operands.getFlattenedOperandNumber( + std::make_pair(TiedReg, OpSubOpPair.second)); + Operands[OpIdx].addField(CurrBitPos, EncodingSegment.BitWidth, Offset); + } + } + + CurrBitPos += EncodingSegment.BitWidth; + } +} + +static unsigned populateInstruction(CodeGenTarget &Target, const Record &EncodingDef, const CodeGenInstruction &CGI, unsigned Opc, - std::map<unsigned, std::vector<OperandInfo>> &Operands) { + std::map<unsigned, std::vector<OperandInfo>> &Operands, + bool IsVarLenInst) { const Record &Def = *CGI.TheDef; // If all the bit positions are not specified; do not decode this instruction. // We are bound to fail! For proper disassembly, the well-known encoding bits // of the instruction must be fully specified. BitsInit &Bits = getBitsField(EncodingDef, "Inst"); - if (Bits.allInComplete()) return false; + if (Bits.allInComplete()) + return 0; std::vector<OperandInfo> InsnOperands; @@ -1834,7 +1942,7 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef, InsnOperands.push_back( OperandInfo(std::string(InstDecoder), HasCompleteInstDecoder)); Operands[Opc] = InsnOperands; - return true; + return Bits.getNumBits(); } // Generate a description of the operand of the instruction that we know @@ -1848,11 +1956,11 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef, DagInit *Out = Def.getValueAsDag("OutOperandList"); DagInit *In = Def.getValueAsDag("InOperandList"); for (unsigned i = 0; i < Out->getNumArgs(); ++i) - InOutOperands.push_back(std::make_pair(Out->getArg(i), - Out->getArgNameStr(i))); + InOutOperands.push_back( + std::make_pair(Out->getArg(i), Out->getArgNameStr(i))); for (unsigned i = 0; i < In->getNumArgs(); ++i) - InOutOperands.push_back(std::make_pair(In->getArg(i), - In->getArgNameStr(i))); + InOutOperands.push_back( + std::make_pair(In->getArg(i), In->getArgNameStr(i))); // Search for tied operands, so that we can correctly instantiate // operands that are not explicitly represented in the encoding. @@ -1869,257 +1977,254 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef, } } - std::map<std::string, std::vector<OperandInfo>> NumberedInsnOperands; - std::set<std::string> NumberedInsnOperandsNoTie; - if (Target.getInstructionSet()-> - getValueAsBit("decodePositionallyEncodedOperands")) { - const std::vector<RecordVal> &Vals = Def.getValues(); - unsigned NumberedOp = 0; + if (IsVarLenInst) { + parseVarLenInstOperand(EncodingDef, InsnOperands, CGI); + } else { + std::map<std::string, std::vector<OperandInfo>> NumberedInsnOperands; + std::set<std::string> NumberedInsnOperandsNoTie; + if (Target.getInstructionSet()->getValueAsBit( + "decodePositionallyEncodedOperands")) { + const std::vector<RecordVal> &Vals = Def.getValues(); + unsigned NumberedOp = 0; + + std::set<unsigned> NamedOpIndices; + if (Target.getInstructionSet()->getValueAsBit( + "noNamedPositionallyEncodedOperands")) + // Collect the set of operand indices that might correspond to named + // operand, and skip these when assigning operands based on position. + for (unsigned i = 0, e = Vals.size(); i != e; ++i) { + unsigned OpIdx; + if (!CGI.Operands.hasOperandNamed(Vals[i].getName(), OpIdx)) + continue; + + NamedOpIndices.insert(OpIdx); + } - std::set<unsigned> NamedOpIndices; - if (Target.getInstructionSet()-> - getValueAsBit("noNamedPositionallyEncodedOperands")) - // Collect the set of operand indices that might correspond to named - // operand, and skip these when assigning operands based on position. for (unsigned i = 0, e = Vals.size(); i != e; ++i) { - unsigned OpIdx; - if (!CGI.Operands.hasOperandNamed(Vals[i].getName(), OpIdx)) + // Ignore fixed fields in the record, we're looking for values like: + // bits<5> RST = { ?, ?, ?, ?, ? }; + if (Vals[i].isNonconcreteOK() || Vals[i].getValue()->isComplete()) continue; - NamedOpIndices.insert(OpIdx); - } - - for (unsigned i = 0, e = Vals.size(); i != e; ++i) { - // Ignore fixed fields in the record, we're looking for values like: - // bits<5> RST = { ?, ?, ?, ?, ? }; - if (Vals[i].isNonconcreteOK() || Vals[i].getValue()->isComplete()) - continue; - - // Determine if Vals[i] actually contributes to the Inst encoding. - unsigned bi = 0; - for (; bi < Bits.getNumBits(); ++bi) { - VarInit *Var = nullptr; - VarBitInit *BI = dyn_cast<VarBitInit>(Bits.getBit(bi)); - if (BI) - Var = dyn_cast<VarInit>(BI->getBitVar()); - else - Var = dyn_cast<VarInit>(Bits.getBit(bi)); + // Determine if Vals[i] actually contributes to the Inst encoding. + unsigned bi = 0; + for (; bi < Bits.getNumBits(); ++bi) { + VarInit *Var = nullptr; + VarBitInit *BI = dyn_cast<VarBitInit>(Bits.getBit(bi)); + if (BI) + Var = dyn_cast<VarInit>(BI->getBitVar()); + else + Var = dyn_cast<VarInit>(Bits.getBit(bi)); - if (Var && Var->getName() == Vals[i].getName()) - break; - } + if (Var && Var->getName() == Vals[i].getName()) + break; + } - if (bi == Bits.getNumBits()) - continue; + if (bi == Bits.getNumBits()) + continue; - // Skip variables that correspond to explicitly-named operands. - unsigned OpIdx; - if (CGI.Operands.hasOperandNamed(Vals[i].getName(), OpIdx)) - continue; + // Skip variables that correspond to explicitly-named operands. + unsigned OpIdx; + if (CGI.Operands.hasOperandNamed(Vals[i].getName(), OpIdx)) + continue; - // Get the bit range for this operand: - unsigned bitStart = bi++, bitWidth = 1; - for (; bi < Bits.getNumBits(); ++bi) { - VarInit *Var = nullptr; - VarBitInit *BI = dyn_cast<VarBitInit>(Bits.getBit(bi)); - if (BI) - Var = dyn_cast<VarInit>(BI->getBitVar()); - else - Var = dyn_cast<VarInit>(Bits.getBit(bi)); + // Get the bit range for this operand: + unsigned bitStart = bi++, bitWidth = 1; + for (; bi < Bits.getNumBits(); ++bi) { + VarInit *Var = nullptr; + VarBitInit *BI = dyn_cast<VarBitInit>(Bits.getBit(bi)); + if (BI) + Var = dyn_cast<VarInit>(BI->getBitVar()); + else + Var = dyn_cast<VarInit>(Bits.getBit(bi)); - if (!Var) - break; + if (!Var) + break; - if (Var->getName() != Vals[i].getName()) - break; + if (Var->getName() != Vals[i].getName()) + break; - ++bitWidth; - } + ++bitWidth; + } - unsigned NumberOps = CGI.Operands.size(); - while (NumberedOp < NumberOps && - (CGI.Operands.isFlatOperandNotEmitted(NumberedOp) || - (!NamedOpIndices.empty() && NamedOpIndices.count( - CGI.Operands.getSubOperandNumber(NumberedOp).first)))) - ++NumberedOp; + unsigned NumberOps = CGI.Operands.size(); + while (NumberedOp < NumberOps && + (CGI.Operands.isFlatOperandNotEmitted(NumberedOp) || + (!NamedOpIndices.empty() && + NamedOpIndices.count( + CGI.Operands.getSubOperandNumber(NumberedOp).first)))) + ++NumberedOp; - OpIdx = NumberedOp++; + OpIdx = NumberedOp++; - // OpIdx now holds the ordered operand number of Vals[i]. - std::pair<unsigned, unsigned> SO = - CGI.Operands.getSubOperandNumber(OpIdx); - const std::string &Name = CGI.Operands[SO.first].Name; + // OpIdx now holds the ordered operand number of Vals[i]. + std::pair<unsigned, unsigned> SO = + CGI.Operands.getSubOperandNumber(OpIdx); + const std::string &Name = CGI.Operands[SO.first].Name; - LLVM_DEBUG(dbgs() << "Numbered operand mapping for " << Def.getName() - << ": " << Name << "(" << SO.first << ", " << SO.second - << ") => " << Vals[i].getName() << "\n"); + LLVM_DEBUG(dbgs() << "Numbered operand mapping for " << Def.getName() + << ": " << Name << "(" << SO.first << ", " + << SO.second << ") => " << Vals[i].getName() << "\n"); - std::string Decoder; - Record *TypeRecord = CGI.Operands[SO.first].Rec; + std::string Decoder; + Record *TypeRecord = CGI.Operands[SO.first].Rec; - RecordVal *DecoderString = TypeRecord->getValue("DecoderMethod"); - StringInit *String = DecoderString ? - dyn_cast<StringInit>(DecoderString->getValue()) : nullptr; - if (String && String->getValue() != "") - Decoder = std::string(String->getValue()); + RecordVal *DecoderString = TypeRecord->getValue("DecoderMethod"); + StringInit *String = + DecoderString ? dyn_cast<StringInit>(DecoderString->getValue()) + : nullptr; + if (String && String->getValue() != "") + Decoder = std::string(String->getValue()); - if (Decoder == "" && - CGI.Operands[SO.first].MIOperandInfo && - CGI.Operands[SO.first].MIOperandInfo->getNumArgs()) { - Init *Arg = CGI.Operands[SO.first].MIOperandInfo-> - getArg(SO.second); - if (DefInit *DI = cast<DefInit>(Arg)) - TypeRecord = DI->getDef(); - } + if (Decoder == "" && CGI.Operands[SO.first].MIOperandInfo && + CGI.Operands[SO.first].MIOperandInfo->getNumArgs()) { + Init *Arg = CGI.Operands[SO.first].MIOperandInfo->getArg(SO.second); + if (DefInit *DI = cast<DefInit>(Arg)) + TypeRecord = DI->getDef(); + } - bool isReg = false; - if (TypeRecord->isSubClassOf("RegisterOperand")) - TypeRecord = TypeRecord->getValueAsDef("RegClass"); - if (TypeRecord->isSubClassOf("RegisterClass")) { - Decoder = "Decode" + TypeRecord->getName().str() + "RegisterClass"; - isReg = true; - } else if (TypeRecord->isSubClassOf("PointerLikeRegClass")) { - Decoder = "DecodePointerLikeRegClass" + - utostr(TypeRecord->getValueAsInt("RegClassKind")); - isReg = true; - } + bool isReg = false; + if (TypeRecord->isSubClassOf("RegisterOperand")) + TypeRecord = TypeRecord->getValueAsDef("RegClass"); + if (TypeRecord->isSubClassOf("RegisterClass")) { + Decoder = "Decode" + TypeRecord->getName().str() + "RegisterClass"; + isReg = true; + } else if (TypeRecord->isSubClassOf("PointerLikeRegClass")) { + Decoder = "DecodePointerLikeRegClass" + + utostr(TypeRecord->getValueAsInt("RegClassKind")); + isReg = true; + } - DecoderString = TypeRecord->getValue("DecoderMethod"); - String = DecoderString ? - dyn_cast<StringInit>(DecoderString->getValue()) : nullptr; - if (!isReg && String && String->getValue() != "") - Decoder = std::string(String->getValue()); + DecoderString = TypeRecord->getValue("DecoderMethod"); + String = DecoderString ? dyn_cast<StringInit>(DecoderString->getValue()) + : nullptr; + if (!isReg && String && String->getValue() != "") + Decoder = std::string(String->getValue()); - RecordVal *HasCompleteDecoderVal = - TypeRecord->getValue("hasCompleteDecoder"); - BitInit *HasCompleteDecoderBit = HasCompleteDecoderVal ? - dyn_cast<BitInit>(HasCompleteDecoderVal->getValue()) : nullptr; - bool HasCompleteDecoder = HasCompleteDecoderBit ? - HasCompleteDecoderBit->getValue() : true; + RecordVal *HasCompleteDecoderVal = + TypeRecord->getValue("hasCompleteDecoder"); + BitInit *HasCompleteDecoderBit = + HasCompleteDecoderVal + ? dyn_cast<BitInit>(HasCompleteDecoderVal->getValue()) + : nullptr; + bool HasCompleteDecoder = + HasCompleteDecoderBit ? HasCompleteDecoderBit->getValue() : true; - OperandInfo OpInfo(Decoder, HasCompleteDecoder); - OpInfo.addField(bitStart, bitWidth, 0); + OperandInfo OpInfo(Decoder, HasCompleteDecoder); + OpInfo.addField(bitStart, bitWidth, 0); - NumberedInsnOperands[Name].push_back(OpInfo); + NumberedInsnOperands[Name].push_back(OpInfo); - // FIXME: For complex operands with custom decoders we can't handle tied - // sub-operands automatically. Skip those here and assume that this is - // fixed up elsewhere. - if (CGI.Operands[SO.first].MIOperandInfo && - CGI.Operands[SO.first].MIOperandInfo->getNumArgs() > 1 && - String && String->getValue() != "") - NumberedInsnOperandsNoTie.insert(Name); + // FIXME: For complex operands with custom decoders we can't handle tied + // sub-operands automatically. Skip those here and assume that this is + // fixed up elsewhere. + if (CGI.Operands[SO.first].MIOperandInfo && + CGI.Operands[SO.first].MIOperandInfo->getNumArgs() > 1 && String && + String->getValue() != "") + NumberedInsnOperandsNoTie.insert(Name); + } } - } - // For each operand, see if we can figure out where it is encoded. - for (const auto &Op : InOutOperands) { - if (!NumberedInsnOperands[std::string(Op.second)].empty()) { - llvm::append_range(InsnOperands, - NumberedInsnOperands[std::string(Op.second)]); - continue; - } - if (!NumberedInsnOperands[TiedNames[std::string(Op.second)]].empty()) { - if (!NumberedInsnOperandsNoTie.count(TiedNames[std::string(Op.second)])) { - // Figure out to which (sub)operand we're tied. - unsigned i = - CGI.Operands.getOperandNamed(TiedNames[std::string(Op.second)]); - int tiedTo = CGI.Operands[i].getTiedRegister(); - if (tiedTo == -1) { - i = CGI.Operands.getOperandNamed(Op.second); - tiedTo = CGI.Operands[i].getTiedRegister(); - } + // For each operand, see if we can figure out where it is encoded. + for (const auto &Op : InOutOperands) { + if (!NumberedInsnOperands[std::string(Op.second)].empty()) { + llvm::append_range(InsnOperands, + NumberedInsnOperands[std::string(Op.second)]); + continue; + } + if (!NumberedInsnOperands[TiedNames[std::string(Op.second)]].empty()) { + if (!NumberedInsnOperandsNoTie.count( + TiedNames[std::string(Op.second)])) { + // Figure out to which (sub)operand we're tied. + unsigned i = + CGI.Operands.getOperandNamed(TiedNames[std::string(Op.second)]); + int tiedTo = CGI.Operands[i].getTiedRegister(); + if (tiedTo == -1) { + i = CGI.Operands.getOperandNamed(Op.second); + tiedTo = CGI.Operands[i].getTiedRegister(); + } - if (tiedTo != -1) { - std::pair<unsigned, unsigned> SO = - CGI.Operands.getSubOperandNumber(tiedTo); + if (tiedTo != -1) { + std::pair<unsigned, unsigned> SO = + CGI.Operands.getSubOperandNumber(tiedTo); - InsnOperands.push_back( - NumberedInsnOperands[TiedNames[std::string(Op.second)]] - [SO.second]); + InsnOperands.push_back( + NumberedInsnOperands[TiedNames[std::string(Op.second)]] + [SO.second]); + } } + continue; } - continue; - } - TypedInit *TI = cast<TypedInit>(Op.first); + // At this point, we can locate the decoder field, but we need to know how + // to interpret it. As a first step, require the target to provide + // callbacks for decoding register classes. - // At this point, we can locate the decoder field, but we need to know how - // to interpret it. As a first step, require the target to provide - // callbacks for decoding register classes. - std::string Decoder = findOperandDecoderMethod(TI); - Record *TypeRecord = cast<DefInit>(TI)->getDef(); + OperandInfo OpInfo = getOpInfo(cast<DefInit>(Op.first)->getDef()); - RecordVal *HasCompleteDecoderVal = - TypeRecord->getValue("hasCompleteDecoder"); - BitInit *HasCompleteDecoderBit = HasCompleteDecoderVal ? - dyn_cast<BitInit>(HasCompleteDecoderVal->getValue()) : nullptr; - bool HasCompleteDecoder = HasCompleteDecoderBit ? - HasCompleteDecoderBit->getValue() : true; + // Some bits of the operand may be required to be 1 depending on the + // instruction's encoding. Collect those bits. + if (const RecordVal *EncodedValue = EncodingDef.getValue(Op.second)) + if (const BitsInit *OpBits = + dyn_cast<BitsInit>(EncodedValue->getValue())) + for (unsigned I = 0; I < OpBits->getNumBits(); ++I) + if (const BitInit *OpBit = dyn_cast<BitInit>(OpBits->getBit(I))) + if (OpBit->getValue()) + OpInfo.InitValue |= 1ULL << I; - OperandInfo OpInfo(Decoder, HasCompleteDecoder); + unsigned Base = ~0U; + unsigned Width = 0; + unsigned Offset = 0; - // Some bits of the operand may be required to be 1 depending on the - // instruction's encoding. Collect those bits. - if (const RecordVal *EncodedValue = EncodingDef.getValue(Op.second)) - if (const BitsInit *OpBits = dyn_cast<BitsInit>(EncodedValue->getValue())) - for (unsigned I = 0; I < OpBits->getNumBits(); ++I) - if (const BitInit *OpBit = dyn_cast<BitInit>(OpBits->getBit(I))) - if (OpBit->getValue()) - OpInfo.InitValue |= 1ULL << I; - - unsigned Base = ~0U; - unsigned Width = 0; - unsigned Offset = 0; + for (unsigned bi = 0; bi < Bits.getNumBits(); ++bi) { + VarInit *Var = nullptr; + VarBitInit *BI = dyn_cast<VarBitInit>(Bits.getBit(bi)); + if (BI) + Var = dyn_cast<VarInit>(BI->getBitVar()); + else + Var = dyn_cast<VarInit>(Bits.getBit(bi)); - for (unsigned bi = 0; bi < Bits.getNumBits(); ++bi) { - VarInit *Var = nullptr; - VarBitInit *BI = dyn_cast<VarBitInit>(Bits.getBit(bi)); - if (BI) - Var = dyn_cast<VarInit>(BI->getBitVar()); - else - Var = dyn_cast<VarInit>(Bits.getBit(bi)); + if (!Var) { + if (Base != ~0U) { + OpInfo.addField(Base, Width, Offset); + Base = ~0U; + Width = 0; + Offset = 0; + } + continue; + } - if (!Var) { - if (Base != ~0U) { - OpInfo.addField(Base, Width, Offset); - Base = ~0U; - Width = 0; - Offset = 0; + if ((Var->getName() != Op.second && + Var->getName() != TiedNames[std::string(Op.second)])) { + if (Base != ~0U) { + OpInfo.addField(Base, Width, Offset); + Base = ~0U; + Width = 0; + Offset = 0; + } + continue; } - continue; - } - if (Var->getName() != Op.second && - Var->getName() != TiedNames[std::string(Op.second)]) { - if (Base != ~0U) { + if (Base == ~0U) { + Base = bi; + Width = 1; + Offset = BI ? BI->getBitNum() : 0; + } else if (BI && BI->getBitNum() != Offset + Width) { OpInfo.addField(Base, Width, Offset); - Base = ~0U; - Width = 0; - Offset = 0; + Base = bi; + Width = 1; + Offset = BI->getBitNum(); + } else { + ++Width; } - continue; } - if (Base == ~0U) { - Base = bi; - Width = 1; - Offset = BI ? BI->getBitNum() : 0; - } else if (BI && BI->getBitNum() != Offset + Width) { + if (Base != ~0U) OpInfo.addField(Base, Width, Offset); - Base = bi; - Width = 1; - Offset = BI->getBitNum(); - } else { - ++Width; - } - } - - if (Base != ~0U) - OpInfo.addField(Base, Width, Offset); - if (OpInfo.numFields() > 0) - InsnOperands.push_back(OpInfo); + if (OpInfo.numFields() > 0) + InsnOperands.push_back(OpInfo); + } } Operands[Opc] = InsnOperands; @@ -2142,7 +2247,7 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef, }); #endif - return true; + return Bits.getNumBits(); } // emitFieldFromInstruction - Emit the templated helper function @@ -2155,13 +2260,12 @@ static void emitFieldFromInstruction(formatted_raw_ostream &OS) { << "// InsnType must either be integral or an APInt-like object that " "must:\n" << "// * be default-constructible and copy-constructible\n" - << "// * be constructible from a uint64_t\n" << "// * be constructible from an APInt (this can be private)\n" << "// * Support insertBits(bits, startBit, numBits)\n" << "// * Support extractBitsAsZExtValue(numBits, startBit)\n" - << "// * be convertible to bool\n" << "// * Support the ~, &, ==, and != operators with other objects of " "the same type\n" + << "// * Support the != and bitwise & with uint64_t\n" << "// * Support put (<<) to raw_ostream&\n" << "template <typename InsnType>\n" << "#if defined(_MSC_VER) && !defined(__clang__)\n" @@ -2214,18 +2318,26 @@ static void emitInsertBits(formatted_raw_ostream &OS) { // emitDecodeInstruction - Emit the templated helper function // decodeInstruction(). -static void emitDecodeInstruction(formatted_raw_ostream &OS) { +static void emitDecodeInstruction(formatted_raw_ostream &OS, + bool IsVarLenInst) { OS << "template <typename InsnType>\n" << "static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], " "MCInst &MI,\n" << " InsnType insn, uint64_t " "Address,\n" - << " const void *DisAsm,\n" - << " const MCSubtargetInfo &STI) {\n" + << " const MCDisassembler *DisAsm,\n" + << " const MCSubtargetInfo &STI"; + if (IsVarLenInst) { + OS << ",\n" + << " llvm::function_ref<void(APInt " + "&," + << " uint64_t)> makeUp"; + } + OS << ") {\n" << " const FeatureBitset &Bits = STI.getFeatureBits();\n" << "\n" << " const uint8_t *Ptr = DecodeTable;\n" - << " InsnType CurFieldValue = 0;\n" + << " uint64_t CurFieldValue = 0;\n" << " DecodeStatus S = MCDisassembler::Success;\n" << " while (true) {\n" << " ptrdiff_t Loc = Ptr - DecodeTable;\n" @@ -2236,8 +2348,10 @@ static void emitDecodeInstruction(formatted_raw_ostream &OS) { << " case MCD::OPC_ExtractField: {\n" << " unsigned Start = *++Ptr;\n" << " unsigned Len = *++Ptr;\n" - << " ++Ptr;\n" - << " CurFieldValue = fieldFromInstruction(insn, Start, Len);\n" + << " ++Ptr;\n"; + if (IsVarLenInst) + OS << " makeUp(insn, Start + Len);\n"; + OS << " CurFieldValue = fieldFromInstruction(insn, Start, Len);\n" << " LLVM_DEBUG(dbgs() << Loc << \": OPC_ExtractField(\" << Start << " "\", \"\n" << " << Len << \"): \" << CurFieldValue << \"\\n\");\n" @@ -2246,7 +2360,7 @@ static void emitDecodeInstruction(formatted_raw_ostream &OS) { << " case MCD::OPC_FilterValue: {\n" << " // Decode the field value.\n" << " unsigned Len;\n" - << " InsnType Val = decodeULEB128(++Ptr, &Len);\n" + << " uint64_t Val = decodeULEB128(++Ptr, &Len);\n" << " Ptr += Len;\n" << " // NumToSkip is a plain 24-bit integer.\n" << " unsigned NumToSkip = *Ptr++;\n" @@ -2267,11 +2381,14 @@ static void emitDecodeInstruction(formatted_raw_ostream &OS) { << " }\n" << " case MCD::OPC_CheckField: {\n" << " unsigned Start = *++Ptr;\n" - << " unsigned Len = *++Ptr;\n" - << " InsnType FieldValue = fieldFromInstruction(insn, Start, Len);\n" + << " unsigned Len = *++Ptr;\n"; + if (IsVarLenInst) + OS << " makeUp(insn, Start + Len);\n"; + OS << " uint64_t FieldValue = fieldFromInstruction(insn, Start, Len);\n" << " // Decode the field value.\n" - << " InsnType ExpectedValue = decodeULEB128(++Ptr, &Len);\n" - << " Ptr += Len;\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" @@ -2321,8 +2438,12 @@ static void emitDecodeInstruction(formatted_raw_ostream &OS) { << "\n" << " MI.clear();\n" << " MI.setOpcode(Opc);\n" - << " bool DecodeComplete;\n" - << " S = decodeToMCInst(S, DecodeIdx, insn, MI, Address, DisAsm, " + << " bool DecodeComplete;\n"; + if (IsVarLenInst) { + OS << " Len = InstrLenTable[Opc];\n" + << " makeUp(insn, Len);\n"; + } + OS << " S = decodeToMCInst(S, DecodeIdx, insn, MI, Address, DisAsm, " "DecodeComplete);\n" << " assert(DecodeComplete);\n" << "\n" @@ -2376,11 +2497,12 @@ static void emitDecodeInstruction(formatted_raw_ostream &OS) { << " case MCD::OPC_SoftFail: {\n" << " // Decode the mask values.\n" << " unsigned Len;\n" - << " InsnType PositiveMask = decodeULEB128(++Ptr, &Len);\n" + << " uint64_t PositiveMask = decodeULEB128(++Ptr, &Len);\n" << " Ptr += Len;\n" - << " InsnType NegativeMask = decodeULEB128(Ptr, &Len);\n" + << " uint64_t NegativeMask = decodeULEB128(Ptr, &Len);\n" << " Ptr += Len;\n" - << " bool Fail = (insn & PositiveMask) || (~insn & NegativeMask);\n" + << " bool Fail = (insn & PositiveMask) != 0 || (~insn & " + "NegativeMask) != 0;\n" << " if (Fail)\n" << " S = MCDisassembler::SoftFail;\n" << " LLVM_DEBUG(dbgs() << Loc << \": OPC_SoftFail: \" << (Fail ? " @@ -2399,9 +2521,11 @@ static void emitDecodeInstruction(formatted_raw_ostream &OS) { } // Emits disassembler code for instruction decoding. -void FixedLenDecoderEmitter::run(raw_ostream &o) { +void DecoderEmitter::run(raw_ostream &o) { formatted_raw_ostream OS(o); OS << "#include \"llvm/MC/MCInst.h\"\n"; + OS << "#include \"llvm/MC/MCSubtargetInfo.h\"\n"; + OS << "#include \"llvm/MC/SubtargetFeature.h\"\n"; OS << "#include \"llvm/Support/DataTypes.h\"\n"; OS << "#include \"llvm/Support/Debug.h\"\n"; OS << "#include \"llvm/Support/LEB128.h\"\n"; @@ -2469,6 +2593,14 @@ void FixedLenDecoderEmitter::run(raw_ostream &o) { std::map<std::pair<std::string, unsigned>, std::vector<EncodingIDAndOpcode>> OpcMap; std::map<unsigned, std::vector<OperandInfo>> Operands; + std::vector<unsigned> InstrLen; + + bool IsVarLenInst = + any_of(NumberedInstructions, [](const CodeGenInstruction *CGI) { + RecordVal *RV = CGI->TheDef->getValue("Inst"); + return RV && isa<DagInit>(RV->getValue()); + }); + unsigned MaxInstLen = 0; for (unsigned i = 0; i < NumberedEncodings.size(); ++i) { const Record *EncodingDef = NumberedEncodings[i].EncodingDef; @@ -2487,10 +2619,18 @@ void FixedLenDecoderEmitter::run(raw_ostream &o) { NumInstructions++; NumEncodings++; - if (!Size) + if (!Size && !IsVarLenInst) continue; - if (populateInstruction(Target, *EncodingDef, *Inst, i, Operands)) { + if (IsVarLenInst) + InstrLen.resize(NumberedInstructions.size(), 0); + + if (unsigned Len = populateInstruction(Target, *EncodingDef, *Inst, i, + Operands, IsVarLenInst)) { + if (IsVarLenInst) { + MaxInstLen = std::max(MaxInstLen, Len); + InstrLen[i] = Len; + } std::string DecoderNamespace = std::string(EncodingDef->getValueAsString("DecoderNamespace")); if (!NumberedEncodings[i].HwModeName.empty()) @@ -2509,7 +2649,7 @@ void FixedLenDecoderEmitter::run(raw_ostream &o) { ArrayRef<EncodingAndInst> NumberedEncodingsRef( NumberedEncodings.data(), NumberedEncodings.size()); FilterChooser FC(NumberedEncodingsRef, Opc.second, Operands, - 8 * Opc.first.second, this); + IsVarLenInst ? MaxInstLen : 8 * Opc.first.second, this); // The decode table is cleared for each top level decoder function. The // predicates and decoders themselves, however, are shared across all @@ -2534,6 +2674,11 @@ void FixedLenDecoderEmitter::run(raw_ostream &o) { OS.flush(); } + // For variable instruction, we emit a instruction length table + // to let the decoder know how long the instructions are. + // You can see example usage in M68k's disassembler. + if (IsVarLenInst) + emitInstrLenTable(OS, InstrLen); // Emit the predicate function. emitPredicateFunction(OS, TableInfo.Predicates, 0); @@ -2541,20 +2686,20 @@ void FixedLenDecoderEmitter::run(raw_ostream &o) { emitDecoderFunction(OS, TableInfo.Decoders, 0); // Emit the main entry point for the decoder, decodeInstruction(). - emitDecodeInstruction(OS); + emitDecodeInstruction(OS, IsVarLenInst); OS << "\n} // end namespace llvm\n"; } namespace llvm { -void EmitFixedLenDecoder(RecordKeeper &RK, raw_ostream &OS, - const std::string &PredicateNamespace, - const std::string &GPrefix, - const std::string &GPostfix, const std::string &ROK, - const std::string &RFail, const std::string &L) { - FixedLenDecoderEmitter(RK, PredicateNamespace, GPrefix, GPostfix, - ROK, RFail, L).run(OS); +void EmitDecoder(RecordKeeper &RK, raw_ostream &OS, + const std::string &PredicateNamespace, + const std::string &GPrefix, const std::string &GPostfix, + const std::string &ROK, const std::string &RFail, + const std::string &L) { + DecoderEmitter(RK, PredicateNamespace, GPrefix, GPostfix, ROK, RFail, L) + .run(OS); } } // end namespace llvm diff --git a/llvm/utils/TableGen/DirectiveEmitter.cpp b/llvm/utils/TableGen/DirectiveEmitter.cpp index b21bf369d18e..f3751591f3d9 100644 --- a/llvm/utils/TableGen/DirectiveEmitter.cpp +++ b/llvm/utils/TableGen/DirectiveEmitter.cpp @@ -17,7 +17,6 @@ #include "llvm/ADT/StringSet.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" -#include "llvm/TableGen/TableGenBackend.h" using namespace llvm; @@ -368,8 +367,7 @@ void GenerateCaseForVersionedClauses(const std::vector<Record *> &Clauses, const auto ClauseFormattedName = VerClause.getClause().getFormattedName(); - if (Cases.find(ClauseFormattedName) == Cases.end()) { - Cases.insert(ClauseFormattedName); + if (Cases.insert(ClauseFormattedName).second) { OS << " case " << DirLang.getClausePrefix() << ClauseFormattedName << ":\n"; OS << " return " << VerClause.getMinVersion() diff --git a/llvm/utils/TableGen/DisassemblerEmitter.cpp b/llvm/utils/TableGen/DisassemblerEmitter.cpp index 7c3f53b31bf4..297d12c5d0e9 100644 --- a/llvm/utils/TableGen/DisassemblerEmitter.cpp +++ b/llvm/utils/TableGen/DisassemblerEmitter.cpp @@ -95,12 +95,11 @@ using namespace llvm::X86Disassembler; namespace llvm { -extern void EmitFixedLenDecoder(RecordKeeper &RK, raw_ostream &OS, - const std::string &PredicateNamespace, - const std::string &GPrefix, - const std::string &GPostfix, - const std::string &ROK, - const std::string &RFail, const std::string &L); +extern void EmitDecoder(RecordKeeper &RK, raw_ostream &OS, + const std::string &PredicateNamespace, + const std::string &GPrefix, const std::string &GPostfix, + const std::string &ROK, const std::string &RFail, + const std::string &L); void EmitDisassembler(RecordKeeper &Records, raw_ostream &OS) { CodeGenTarget Target(Records); @@ -140,17 +139,16 @@ void EmitDisassembler(RecordKeeper &Records, raw_ostream &OS) { if (PredicateNamespace == "Thumb") PredicateNamespace = "ARM"; - EmitFixedLenDecoder(Records, OS, PredicateNamespace, - "if (!Check(S, ", "))", - "S", "MCDisassembler::Fail", - " MCDisassembler::DecodeStatus S = " - "MCDisassembler::Success;\n(void)S;"); + EmitDecoder(Records, OS, PredicateNamespace, "if (!Check(S, ", "))", "S", + "MCDisassembler::Fail", + " MCDisassembler::DecodeStatus S = " + "MCDisassembler::Success;\n(void)S;"); return; } - EmitFixedLenDecoder(Records, OS, std::string(Target.getName()), "if (", - " == MCDisassembler::Fail)", "MCDisassembler::Success", - "MCDisassembler::Fail", ""); + EmitDecoder(Records, OS, std::string(Target.getName()), "if (", + " == MCDisassembler::Fail)", "MCDisassembler::Success", + "MCDisassembler::Fail", ""); } } // end namespace llvm diff --git a/llvm/utils/TableGen/ExegesisEmitter.cpp b/llvm/utils/TableGen/ExegesisEmitter.cpp index 77654cbc92fd..bc8ccdac557b 100644 --- a/llvm/utils/TableGen/ExegesisEmitter.cpp +++ b/llvm/utils/TableGen/ExegesisEmitter.cpp @@ -13,15 +13,11 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/TableGenBackend.h" -#include <algorithm> #include <cassert> -#include <cstdint> #include <map> #include <string> #include <vector> diff --git a/llvm/utils/TableGen/FastISelEmitter.cpp b/llvm/utils/TableGen/FastISelEmitter.cpp index ac9fe6db4328..49c2ead468e3 100644 --- a/llvm/utils/TableGen/FastISelEmitter.cpp +++ b/llvm/utils/TableGen/FastISelEmitter.cpp @@ -17,8 +17,8 @@ //===----------------------------------------------------------------------===// #include "CodeGenDAGPatterns.h" +#include "CodeGenInstruction.h" #include "llvm/ADT/StringSwitch.h" -#include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" diff --git a/llvm/utils/TableGen/GICombinerEmitter.cpp b/llvm/utils/TableGen/GICombinerEmitter.cpp index 0dea1ef00e4b..77e05aebf53a 100644 --- a/llvm/utils/TableGen/GICombinerEmitter.cpp +++ b/llvm/utils/TableGen/GICombinerEmitter.cpp @@ -933,28 +933,27 @@ void GICombinerEmitter::run(raw_ostream &OS) { "getRuleIdxForIdentifier(RangePair.first);\n" << " const auto Last = " "getRuleIdxForIdentifier(RangePair.second);\n" - << " if (!First.hasValue() || !Last.hasValue())\n" + << " if (!First || !Last)\n" << " return None;\n" << " if (First >= Last)\n" << " report_fatal_error(\"Beginning of range should be before " "end of range\");\n" << " return {{*First, *Last + 1}};\n" - << " } else if (RangePair.first == \"*\") {\n" + << " }\n" + << " if (RangePair.first == \"*\") {\n" << " return {{0, " << Rules.size() << "}};\n" - << " } else {\n" - << " const auto I = getRuleIdxForIdentifier(RangePair.first);\n" - << " if (!I.hasValue())\n" - << " return None;\n" - << " return {{*I, *I + 1}};\n" << " }\n" - << " return None;\n" + << " const auto I = getRuleIdxForIdentifier(RangePair.first);\n" + << " if (!I)\n" + << " return None;\n" + << " return {{*I, *I + 1}};\n" << "}\n\n"; for (bool Enabled : {true, false}) { OS << "bool " << getClassName() << "RuleConfig::setRule" << (Enabled ? "Enabled" : "Disabled") << "(StringRef RuleIdentifier) {\n" << " auto MaybeRange = getRuleRangeForIdentifier(RuleIdentifier);\n" - << " if (!MaybeRange.hasValue())\n" + << " if (!MaybeRange)\n" << " return false;\n" << " for (auto I = MaybeRange->first; I < MaybeRange->second; ++I)\n" << " DisabledRules." << (Enabled ? "reset" : "set") << "(I);\n" diff --git a/llvm/utils/TableGen/GlobalISel/GIMatchDag.cpp b/llvm/utils/TableGen/GlobalISel/GIMatchDag.cpp index 7e037dd03b60..8be32d2effa6 100644 --- a/llvm/utils/TableGen/GlobalISel/GIMatchDag.cpp +++ b/llvm/utils/TableGen/GlobalISel/GIMatchDag.cpp @@ -48,7 +48,7 @@ void GIMatchDag::writeDOTGraph(raw_ostream &OS, StringRef ID) const { << Assignment.first << ")"; Separator = ", "; } - OS << format("|%p|", &N); + OS << llvm::format("|%p|", &N); writePorts("d", N->getOperandInfo()); OS << "}\""; if (N->isMatchRoot()) @@ -82,7 +82,7 @@ void GIMatchDag::writeDOTGraph(raw_ostream &OS, StringRef ID) const { writePorts("s", N->getOperandInfo()); OS << "|" << N->getName() << "|"; N->printDescription(OS); - OS << format("|%p|", &N); + OS << llvm::format("|%p|", &N); writePorts("d", N->getOperandInfo()); OS << "}\",style=dotted]\n"; } diff --git a/llvm/utils/TableGen/GlobalISel/GIMatchTree.h b/llvm/utils/TableGen/GlobalISel/GIMatchTree.h index 56df37731c09..55a86259661d 100644 --- a/llvm/utils/TableGen/GlobalISel/GIMatchTree.h +++ b/llvm/utils/TableGen/GlobalISel/GIMatchTree.h @@ -32,11 +32,11 @@ public: Optional<unsigned> OpIdx = None) : Name(Name), InstrID(InstrID), OpIdx(OpIdx) {} - bool isInstr() const { return !OpIdx.hasValue(); } + bool isInstr() const { return !OpIdx; } StringRef getName() const { return Name; } unsigned getInstrID() const { return InstrID; } unsigned getOpIdx() const { - assert(OpIdx.hasValue() && "Is not an operand binding"); + assert(OpIdx && "Is not an operand binding"); return *OpIdx; } }; diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp index 018aa7ee2f71..c8eac56d03e6 100644 --- a/llvm/utils/TableGen/GlobalISelEmitter.cpp +++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp @@ -30,6 +30,7 @@ //===----------------------------------------------------------------------===// #include "CodeGenDAGPatterns.h" +#include "CodeGenInstruction.h" #include "SubtargetFeatureInfo.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/Statistic.h" @@ -465,9 +466,9 @@ public: MatchTableRecord(Optional<unsigned> LabelID_, StringRef EmitStr, unsigned NumElements, unsigned Flags, int64_t RawValue = std::numeric_limits<int64_t>::min()) - : LabelID(LabelID_.getValueOr(~0u)), EmitStr(EmitStr), + : LabelID(LabelID_.value_or(~0u)), EmitStr(EmitStr), NumElements(NumElements), Flags(Flags), RawValue(RawValue) { - assert((!LabelID_.hasValue() || LabelID != ~0u) && + assert((!LabelID_ || LabelID != ~0u) && "This value is reserved for non-labels"); } MatchTableRecord(const MatchTableRecord &Other) = default; @@ -2935,12 +2936,12 @@ public: } void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override { - Table << MatchTable::Opcode(SubOperand.hasValue() ? "GIR_ComplexSubOperandRenderer" - : "GIR_ComplexRenderer") + Table << MatchTable::Opcode(SubOperand ? "GIR_ComplexSubOperandRenderer" + : "GIR_ComplexRenderer") << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID) << MatchTable::Comment("RendererID") << MatchTable::IntValue(RendererID); - if (SubOperand.hasValue()) + if (SubOperand) Table << MatchTable::Comment("SubOperand") << MatchTable::IntValue(SubOperand.getValue()); Table << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak; @@ -3815,12 +3816,15 @@ Expected<InstructionMatcher &> GlobalISelEmitter::addBuiltinPredicates( if (!ParsedAddrSpaces.empty()) { InsnMatcher.addPredicate<MemoryAddressSpacePredicateMatcher>( 0, ParsedAddrSpaces); + return InsnMatcher; } } int64_t MinAlign = Predicate.getMinAlignment(); - if (MinAlign > 0) + if (MinAlign > 0) { InsnMatcher.addPredicate<MemoryAlignmentPredicateMatcher>(0, MinAlign); + return InsnMatcher; + } } // G_LOAD is used for both non-extending and any-extending loads. @@ -4269,7 +4273,7 @@ Error GlobalISelEmitter::importChildMatcher( auto MaybeInsnOperand = OM.addPredicate<InstructionOperandMatcher>( InsnMatcher.getRuleMatcher(), SrcChild->getName()); - if (!MaybeInsnOperand.hasValue()) { + if (!MaybeInsnOperand) { // This isn't strictly true. If the user were to provide exactly the same // matchers as the original operand then we could allow it. However, it's // simpler to not permit the redundant specification. @@ -4400,7 +4404,7 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderer( TreePatternNode *DstChild) { const auto &SubOperand = Rule.getComplexSubOperand(DstChild->getName()); - if (SubOperand.hasValue()) { + if (SubOperand) { DstMIBuilder.addRenderer<RenderComplexPatternOperand>( *std::get<0>(*SubOperand), DstChild->getName(), std::get<1>(*SubOperand), std::get<2>(*SubOperand)); @@ -4802,7 +4806,7 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderers( const auto SrcRCDstRCPair = RC->getMatchingSubClassWithSubRegs(CGRegs, SubIdx); - if (SrcRCDstRCPair.hasValue()) { + if (SrcRCDstRCPair) { assert(SrcRCDstRCPair->second && "Couldn't find a matching subclass"); if (SrcRCDstRCPair->first != RC) return failedImport("EXTRACT_SUBREG requires an additional COPY"); @@ -5533,6 +5537,7 @@ std::vector<Matcher *> GlobalISelEmitter::optimizeRules( ProcessCurrentGroup(); LLVM_DEBUG(dbgs() << "NumGroups: " << NumGroups << "\n"); + (void) NumGroups; assert(CurrentGroup->empty() && "The last group wasn't properly processed"); return OptRules; } diff --git a/llvm/utils/TableGen/InstrInfoEmitter.cpp b/llvm/utils/TableGen/InstrInfoEmitter.cpp index 3c92aa0cc27a..a7a4f4f5f1a7 100644 --- a/llvm/utils/TableGen/InstrInfoEmitter.cpp +++ b/llvm/utils/TableGen/InstrInfoEmitter.cpp @@ -36,6 +36,12 @@ using namespace llvm; +cl::OptionCategory InstrInfoEmitterCat("Options for -gen-instr-info"); +static cl::opt<bool> ExpandMIOperandInfo( + "instr-info-expand-mi-operand-info", + cl::desc("Expand operand's MIOperandInfo DAG into suboperands"), + cl::cat(InstrInfoEmitterCat), cl::init(true)); + namespace { class InstrInfoEmitter { @@ -379,6 +385,9 @@ void InstrInfoEmitter::emitOperandTypeMappings( OS << "namespace " << Namespace << " {\n"; OS << "LLVM_READONLY\n"; OS << "static int getOperandType(uint16_t Opcode, uint16_t OpIdx) {\n"; + auto getInstrName = [&](int I) -> StringRef { + return NumberedInstructions[I]->TheDef->getName(); + }; // TODO: Factor out duplicate operand lists to compress the tables. if (!NumberedInstructions.empty()) { std::vector<int> OperandOffsets; @@ -388,7 +397,7 @@ void InstrInfoEmitter::emitOperandTypeMappings( OperandOffsets.push_back(CurrentOffset); for (const auto &Op : Inst->Operands) { const DagInit *MIOI = Op.MIOperandInfo; - if (!MIOI || MIOI->getNumArgs() == 0) { + if (!ExpandMIOperandInfo || !MIOI || MIOI->getNumArgs() == 0) { // Single, anonymous, operand. OperandRecords.push_back(Op.Rec); ++CurrentOffset; @@ -408,8 +417,10 @@ void InstrInfoEmitter::emitOperandTypeMappings( OS << ((OperandRecords.size() <= UINT16_MAX) ? " const uint16_t" : " const uint32_t"); OS << " Offsets[] = {\n"; - for (int I = 0, E = OperandOffsets.size(); I != E; ++I) + for (int I = 0, E = OperandOffsets.size(); I != E; ++I) { + OS << " /* " << getInstrName(I) << " */\n"; OS << " " << OperandOffsets[I] << ",\n"; + } OS << " };\n"; // Add an entry for the end so that we don't need to special case it below. @@ -419,22 +430,22 @@ void InstrInfoEmitter::emitOperandTypeMappings( // Size the signed integer operand type to save space. assert(EnumVal <= INT16_MAX && "Too many operand types for operand types table"); + OS << "\n using namespace OpTypes;\n"; OS << ((EnumVal <= INT8_MAX) ? " const int8_t" : " const int16_t"); OS << " OpcodeOperandTypes[] = {\n "; - for (int I = 0, E = OperandRecords.size(), CurOffset = 1; I != E; ++I) { + for (int I = 0, E = OperandRecords.size(), CurOffset = 0; I != E; ++I) { // We print each Opcode's operands in its own row. if (I == OperandOffsets[CurOffset]) { - OS << "\n "; - // If there are empty rows, mark them with an empty comment. + OS << "\n /* " << getInstrName(CurOffset) << " */\n "; while (OperandOffsets[++CurOffset] == I) - OS << "/**/\n "; + OS << "/* " << getInstrName(CurOffset) << " */\n "; } Record *OpR = OperandRecords[I]; if ((OpR->isSubClassOf("Operand") || OpR->isSubClassOf("RegisterOperand") || OpR->isSubClassOf("RegisterClass")) && !OpR->isAnonymous()) - OS << "OpTypes::" << OpR->getName(); + OS << OpR->getName(); else OS << -1; OS << ", "; @@ -449,6 +460,31 @@ void InstrInfoEmitter::emitOperandTypeMappings( OS << "} // end namespace " << Namespace << "\n"; OS << "} // end namespace llvm\n"; OS << "#endif // GET_INSTRINFO_OPERAND_TYPE\n\n"; + + OS << "#ifdef GET_INSTRINFO_MEM_OPERAND_SIZE\n"; + OS << "#undef GET_INSTRINFO_MEM_OPERAND_SIZE\n"; + OS << "namespace llvm {\n"; + OS << "namespace " << Namespace << " {\n"; + OS << "LLVM_READONLY\n"; + OS << "static int getMemOperandSize(int OpType) {\n"; + OS << " switch (OpType) {\n"; + std::map<int, std::vector<StringRef>> SizeToOperandName; + for (const Record *Op : Operands) { + if (!Op->isSubClassOf("X86MemOperand")) + continue; + if (int Size = Op->getValueAsInt("Size")) + SizeToOperandName[Size].push_back(Op->getName()); + } + OS << " default: return 0;\n"; + for (auto KV : SizeToOperandName) { + for (const StringRef &OperandName : KV.second) + OS << " case OpTypes::" << OperandName << ":\n"; + OS << " return " << KV.first << ";\n\n"; + } + OS << " }\n}\n"; + OS << "} // end namespace " << Namespace << "\n"; + OS << "} // end namespace llvm\n"; + OS << "#endif // GET_INSTRINFO_MEM_OPERAND_SIZE\n\n"; } void InstrInfoEmitter::emitLogicalOperandSizeMappings( @@ -943,6 +979,7 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num, // Emit all of the target independent flags... if (Inst.isPreISelOpcode) OS << "|(1ULL<<MCID::PreISelOpcode)"; if (Inst.isPseudo) OS << "|(1ULL<<MCID::Pseudo)"; + if (Inst.isMeta) OS << "|(1ULL<<MCID::Meta)"; if (Inst.isReturn) OS << "|(1ULL<<MCID::Return)"; if (Inst.isEHScopeReturn) OS << "|(1ULL<<MCID::EHScopeReturn)"; if (Inst.isBranch) OS << "|(1ULL<<MCID::Branch)"; diff --git a/llvm/utils/TableGen/IntrinsicEmitter.cpp b/llvm/utils/TableGen/IntrinsicEmitter.cpp index a5aa4069e60f..fca2bc34e09a 100644 --- a/llvm/utils/TableGen/IntrinsicEmitter.cpp +++ b/llvm/utils/TableGen/IntrinsicEmitter.cpp @@ -46,7 +46,7 @@ public: raw_ostream &OS); void EmitGenerator(const CodeGenIntrinsicTable &Ints, raw_ostream &OS); void EmitAttributes(const CodeGenIntrinsicTable &Ints, raw_ostream &OS); - void EmitIntrinsicToBuiltinMap(const CodeGenIntrinsicTable &Ints, bool IsGCC, + void EmitIntrinsicToBuiltinMap(const CodeGenIntrinsicTable &Ints, bool IsClang, raw_ostream &OS); }; } // End anonymous namespace @@ -196,25 +196,25 @@ void IntrinsicEmitter::EmitIntrinsicToOverloadTable( enum IIT_Info { // Common values should be encoded with 0-15. IIT_Done = 0, - IIT_I1 = 1, - IIT_I8 = 2, - IIT_I16 = 3, - IIT_I32 = 4, - IIT_I64 = 5, - IIT_F16 = 6, - IIT_F32 = 7, - IIT_F64 = 8, - IIT_V2 = 9, - IIT_V4 = 10, - IIT_V8 = 11, - IIT_V16 = 12, - IIT_V32 = 13, - IIT_PTR = 14, - IIT_ARG = 15, + IIT_I1 = 1, + IIT_I8 = 2, + IIT_I16 = 3, + IIT_I32 = 4, + IIT_I64 = 5, + IIT_F16 = 6, + IIT_F32 = 7, + IIT_F64 = 8, + IIT_V2 = 9, + IIT_V4 = 10, + IIT_V8 = 11, + IIT_V16 = 12, + IIT_V32 = 13, + IIT_PTR = 14, + IIT_ARG = 15, // Values from 16+ are only encodable with the inefficient encoding. - IIT_V64 = 16, - IIT_MMX = 17, + IIT_V64 = 16, + IIT_MMX = 17, IIT_TOKEN = 18, IIT_METADATA = 19, IIT_EMPTYSTRUCT = 20, @@ -225,7 +225,7 @@ enum IIT_Info { IIT_EXTEND_ARG = 25, IIT_TRUNC_ARG = 26, IIT_ANYPTR = 27, - IIT_V1 = 28, + IIT_V1 = 28, IIT_VARARG = 29, IIT_HALF_VEC_ARG = 30, IIT_SAME_VEC_WIDTH_ARG = 31, @@ -248,20 +248,26 @@ enum IIT_Info { IIT_BF16 = 48, IIT_STRUCT9 = 49, IIT_V256 = 50, - IIT_AMX = 51, + IIT_AMX = 51, IIT_PPCF128 = 52, IIT_V3 = 53, IIT_EXTERNREF = 54, - IIT_FUNCREF = 55 + IIT_FUNCREF = 55, + IIT_ANYPTR_TO_ELT = 56, + IIT_I2 = 57, + IIT_I4 = 58, }; static void EncodeFixedValueType(MVT::SimpleValueType VT, std::vector<unsigned char> &Sig) { + // clang-format off if (MVT(VT).isInteger()) { unsigned BitWidth = MVT(VT).getFixedSizeInBits(); switch (BitWidth) { default: PrintFatalError("unhandled integer type width in intrinsic!"); case 1: return Sig.push_back(IIT_I1); + case 2: return Sig.push_back(IIT_I2); + case 4: return Sig.push_back(IIT_I4); case 8: return Sig.push_back(IIT_I8); case 16: return Sig.push_back(IIT_I16); case 32: return Sig.push_back(IIT_I32); @@ -291,6 +297,7 @@ static void EncodeFixedValueType(MVT::SimpleValueType VT, case MVT::funcref: return Sig.push_back(IIT_FUNCREF); } + // clang-format on } #if defined(_MSC_VER) && !defined(__clang__) @@ -327,6 +334,13 @@ static void EncodeFixedType(Record *R, std::vector<unsigned char> &ArgCodes, // Encode LLVMMatchType<Number> ArgNo Sig.push_back(Number); return; + } else if (R->isSubClassOf("LLVMAnyPointerToElt")) { + Sig.push_back(IIT_ANYPTR_TO_ELT); + // Encode overloaded ArgNo + Sig.push_back(NextArgCode++); + // Encode LLVMMatchType<Number> ArgNo + Sig.push_back(Number); + return; } else if (R->isSubClassOf("LLVMPointerToElt")) Sig.push_back(IIT_PTR_TO_ELT); else if (R->isSubClassOf("LLVMVectorElementType")) @@ -415,6 +429,9 @@ static void UpdateArgCodes(Record *R, std::vector<unsigned char> &ArgCodes, if (R->isSubClassOf("LLVMVectorOfAnyPointersToElt")) { ArgCodes.push_back(3 /*vAny*/); ++NumInserted; + } else if (R->isSubClassOf("LLVMAnyPointerToElt")) { + ArgCodes.push_back(4 /*iPTRAny*/); + ++NumInserted; } return; } @@ -599,6 +616,9 @@ struct AttributeComparator { if (L->isNoReturn != R->isNoReturn) return R->isNoReturn; + if (L->isNoCallback != R->isNoCallback) + return R->isNoCallback; + if (L->isNoSync != R->isNoSync) return R->isNoSync; @@ -748,16 +768,18 @@ void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints, if (!Intrinsic.canThrow || (Intrinsic.ModRef != CodeGenIntrinsic::ReadWriteMem && !Intrinsic.hasSideEffects) || - Intrinsic.isNoReturn || Intrinsic.isNoSync || Intrinsic.isNoFree || - Intrinsic.isWillReturn || Intrinsic.isCold || Intrinsic.isNoDuplicate || - Intrinsic.isNoMerge || Intrinsic.isConvergent || - Intrinsic.isSpeculatable) { + Intrinsic.isNoReturn || Intrinsic.isNoCallback || Intrinsic.isNoSync || + Intrinsic.isNoFree || Intrinsic.isWillReturn || Intrinsic.isCold || + Intrinsic.isNoDuplicate || Intrinsic.isNoMerge || + Intrinsic.isConvergent || Intrinsic.isSpeculatable) { OS << " const Attribute::AttrKind Atts[] = {"; ListSeparator LS(","); if (!Intrinsic.canThrow) OS << LS << "Attribute::NoUnwind"; if (Intrinsic.isNoReturn) OS << LS << "Attribute::NoReturn"; + if (Intrinsic.isNoCallback) + OS << LS << "Attribute::NoCallback"; if (Intrinsic.isNoSync) OS << LS << "Attribute::NoSync"; if (Intrinsic.isNoFree) @@ -858,14 +880,15 @@ void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints, } void IntrinsicEmitter::EmitIntrinsicToBuiltinMap( - const CodeGenIntrinsicTable &Ints, bool IsGCC, raw_ostream &OS) { - StringRef CompilerName = (IsGCC ? "GCC" : "MS"); + const CodeGenIntrinsicTable &Ints, bool IsClang, raw_ostream &OS) { + StringRef CompilerName = (IsClang ? "Clang" : "MS"); + StringRef UpperCompilerName = (IsClang ? "CLANG" : "MS"); typedef std::map<std::string, std::map<std::string, std::string>> BIMTy; BIMTy BuiltinMap; StringToOffsetTable Table; for (unsigned i = 0, e = Ints.size(); i != e; ++i) { const std::string &BuiltinName = - IsGCC ? Ints[i].GCCBuiltinName : Ints[i].MSBuiltinName; + IsClang ? Ints[i].ClangBuiltinName : Ints[i].MSBuiltinName; if (!BuiltinName.empty()) { // Get the map for this target prefix. std::map<std::string, std::string> &BIM = @@ -883,7 +906,7 @@ void IntrinsicEmitter::EmitIntrinsicToBuiltinMap( OS << "// This is used by the C front-end. The builtin name is passed\n"; OS << "// in as BuiltinName, and a target prefix (e.g. 'ppc') is passed\n"; OS << "// in as TargetPrefix. The result is assigned to 'IntrinsicID'.\n"; - OS << "#ifdef GET_LLVM_INTRINSIC_FOR_" << CompilerName << "_BUILTIN\n"; + OS << "#ifdef GET_LLVM_INTRINSIC_FOR_" << UpperCompilerName << "_BUILTIN\n"; OS << "Intrinsic::ID Intrinsic::getIntrinsicFor" << CompilerName << "Builtin(const char " diff --git a/llvm/utils/TableGen/OptParserEmitter.cpp b/llvm/utils/TableGen/OptParserEmitter.cpp index d54132f3190b..182cd0076090 100644 --- a/llvm/utils/TableGen/OptParserEmitter.cpp +++ b/llvm/utils/TableGen/OptParserEmitter.cpp @@ -172,7 +172,7 @@ static MarshallingInfo createMarshallingInfo(const Record &R) { Ret.NormalizedValuesScope = R.getValueAsString("NormalizedValuesScope"); Ret.ImpliedCheck = R.getValueAsString("ImpliedCheck"); Ret.ImpliedValue = - R.getValueAsOptionalString("ImpliedValue").getValueOr(Ret.DefaultValue); + R.getValueAsOptionalString("ImpliedValue").value_or(Ret.DefaultValue); Ret.ShouldParse = R.getValueAsString("ShouldParse"); Ret.Normalizer = R.getValueAsString("Normalizer"); diff --git a/llvm/utils/TableGen/OptRSTEmitter.cpp b/llvm/utils/TableGen/OptRSTEmitter.cpp index 11d896229f5b..03c7326e817a 100644 --- a/llvm/utils/TableGen/OptRSTEmitter.cpp +++ b/llvm/utils/TableGen/OptRSTEmitter.cpp @@ -60,18 +60,43 @@ void EmitOptRST(RecordKeeper &Records, raw_ostream &OS) { // Print the option name. OS << R->getValueAsString("Name"); + StringRef MetaVarName; // Print the meta-variable. if (!isa<UnsetInit>(R->getValueInit("MetaVarName"))) { + MetaVarName = R->getValueAsString("MetaVarName"); + } else if (!isa<UnsetInit>(R->getValueInit("Values"))) + MetaVarName = "<value>"; + + if (!MetaVarName.empty()) { OS << '='; - OS.write_escaped(R->getValueAsString("MetaVarName")); + OS.write_escaped(MetaVarName); } OS << "\n\n"; + std::string HelpText; // The option help text. if (!isa<UnsetInit>(R->getValueInit("HelpText"))) { + HelpText = R->getValueAsString("HelpText").trim().str(); + if (!HelpText.empty() && HelpText.back() != '.') + HelpText.push_back('.'); + } + + if (!isa<UnsetInit>(R->getValueInit("Values"))) { + SmallVector<StringRef> Values; + SplitString(R->getValueAsString("Values"), Values, ","); + HelpText += (" " + MetaVarName + " must be '").str(); + + if (Values.size() > 1) { + HelpText += join(Values.begin(), Values.end() - 1, "', '"); + HelpText += "' or '"; + } + HelpText += (Values.front() + "'.").str(); + } + + if (!HelpText.empty()) { OS << ' '; - OS.write_escaped(R->getValueAsString("HelpText")); + OS.write_escaped(HelpText); OS << "\n\n"; } } diff --git a/llvm/utils/TableGen/PseudoLoweringEmitter.cpp b/llvm/utils/TableGen/PseudoLoweringEmitter.cpp index 6acb630299c1..dc04174217fb 100644 --- a/llvm/utils/TableGen/PseudoLoweringEmitter.cpp +++ b/llvm/utils/TableGen/PseudoLoweringEmitter.cpp @@ -109,7 +109,8 @@ addDagOperandMapping(Record *Rec, DagInit *Dag, CodeGenInstruction &Insn, OperandMap[BaseIdx + i].Data.Imm = II->getValue(); ++OpsAdded; } else if (auto *BI = dyn_cast<BitsInit>(Dag->getArg(i))) { - auto *II = cast<IntInit>(BI->convertInitializerTo(IntRecTy::get())); + auto *II = + cast<IntInit>(BI->convertInitializerTo(IntRecTy::get(Records))); OperandMap[BaseIdx + i].Kind = OpData::Imm; OperandMap[BaseIdx + i].Data.Imm = II->getValue(); ++OpsAdded; diff --git a/llvm/utils/TableGen/RegisterBankEmitter.cpp b/llvm/utils/TableGen/RegisterBankEmitter.cpp index d97d7acb87a7..e6689b211a7d 100644 --- a/llvm/utils/TableGen/RegisterBankEmitter.cpp +++ b/llvm/utils/TableGen/RegisterBankEmitter.cpp @@ -172,9 +172,8 @@ static void visitRegisterBankClasses( SmallPtrSetImpl<const CodeGenRegisterClass *> &VisitedRCs) { // Make sure we only visit each class once to avoid infinite loops. - if (VisitedRCs.count(RC)) + if (!VisitedRCs.insert(RC).second) return; - VisitedRCs.insert(RC); // Visit each explicitly named class. VisitFn(RC, Kind.str()); @@ -266,9 +265,8 @@ void RegisterBankEmitter::emitBaseClassImplementation( << "::NumRegisterBanks) {\n" << " // Assert that RegBank indices match their ID's\n" << "#ifndef NDEBUG\n" - << " unsigned Index = 0;\n" - << " for (const auto &RB : RegBanks)\n" - << " assert(Index++ == RB->getID() && \"Index != ID\");\n" + << " for (auto RB : enumerate(RegBanks))\n" + << " assert(RB.index() == RB.value()->getID() && \"Index != ID\");\n" << "#endif // NDEBUG\n" << "}\n" << "} // end namespace llvm\n"; diff --git a/llvm/utils/TableGen/RegisterInfoEmitter.cpp b/llvm/utils/TableGen/RegisterInfoEmitter.cpp index 1ed7bc103f9c..3a0fa564074e 100644 --- a/llvm/utils/TableGen/RegisterInfoEmitter.cpp +++ b/llvm/utils/TableGen/RegisterInfoEmitter.cpp @@ -268,7 +268,7 @@ EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank, OS << "// Get the name of this register unit pressure set.\n" << "const char *" << ClassName << "::\n" << "getRegPressureSetName(unsigned Idx) const {\n" - << " static const char *const PressureNameTable[] = {\n"; + << " static const char *PressureNameTable[] = {\n"; unsigned MaxRegUnitWeight = 0; for (unsigned i = 0; i < NumSets; ++i ) { const RegUnitSet &RegUnits = RegBank.getRegSetAt(i); @@ -753,7 +753,7 @@ RegisterInfoEmitter::emitComposeSubRegIndices(raw_ostream &OS, } OS << " };\n\n"; - OS << " --IdxA; assert(IdxA < " << SubRegIndicesSize << ");\n" + OS << " --IdxA; assert(IdxA < " << SubRegIndicesSize << "); (void) IdxA;\n" << " --IdxB; assert(IdxB < " << SubRegIndicesSize << ");\n"; if (Rows.size() > 1) OS << " return Rows[RowMap[IdxA]][IdxB];\n"; @@ -814,12 +814,14 @@ RegisterInfoEmitter::emitComposeSubRegIndexLaneMask(raw_ostream &OS, OS << " // Sequence " << Idx << "\n"; Idx += Sequence.size() + 1; } + auto *IntType = getMinimalTypeForRange(*std::max_element( + SubReg2SequenceIndexMap.begin(), SubReg2SequenceIndexMap.end())); OS << " };\n" - " static const MaskRolOp *const CompositeSequences[] = {\n"; + " static const " + << IntType << " CompositeSequences[] = {\n"; for (size_t i = 0, e = SubRegIndices.size(); i != e; ++i) { OS << " "; - unsigned Idx = SubReg2SequenceIndexMap[i]; - OS << format("&LaneMaskComposeSequences[%u]", Idx); + OS << SubReg2SequenceIndexMap[i]; if (i+1 != e) OS << ","; OS << " // to " << SubRegIndices[i].getName() << "\n"; @@ -832,7 +834,9 @@ RegisterInfoEmitter::emitComposeSubRegIndexLaneMask(raw_ostream &OS, " --IdxA; assert(IdxA < " << SubRegIndices.size() << " && \"Subregister index out of bounds\");\n" " LaneBitmask Result;\n" - " for (const MaskRolOp *Ops = CompositeSequences[IdxA]; Ops->Mask.any(); ++Ops) {\n" + " for (const MaskRolOp *Ops =\n" + " &LaneMaskComposeSequences[CompositeSequences[IdxA]];\n" + " Ops->Mask.any(); ++Ops) {\n" " LaneBitmask::Type M = LaneMask.getAsInteger() & Ops->Mask.getAsInteger();\n" " if (unsigned S = Ops->RotateLeft)\n" " Result |= LaneBitmask((M << S) | (M >> (LaneBitmask::BitWidth - S)));\n" @@ -849,7 +853,9 @@ RegisterInfoEmitter::emitComposeSubRegIndexLaneMask(raw_ostream &OS, " --IdxA; assert(IdxA < " << SubRegIndices.size() << " && \"Subregister index out of bounds\");\n" " LaneBitmask Result;\n" - " for (const MaskRolOp *Ops = CompositeSequences[IdxA]; Ops->Mask.any(); ++Ops) {\n" + " for (const MaskRolOp *Ops =\n" + " &LaneMaskComposeSequences[CompositeSequences[IdxA]];\n" + " Ops->Mask.any(); ++Ops) {\n" " LaneBitmask::Type M = LaneMask.getAsInteger();\n" " if (unsigned S = Ops->RotateLeft)\n" " Result |= LaneBitmask((M >> S) | (M << (LaneBitmask::BitWidth - S)));\n" @@ -1046,25 +1052,24 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, RegClassStrings.add(Name); - // Emit the register list now. - OS << " // " << Name << " Register Class...\n" - << " const MCPhysReg " << Name - << "[] = {\n "; - for (Record *Reg : Order) { - OS << getQualifiedName(Reg) << ", "; - } - OS << "\n };\n\n"; + // Emit the register list now (unless it would be a zero-length array). + if (!Order.empty()) { + OS << " // " << Name << " Register Class...\n" + << " const MCPhysReg " << Name << "[] = {\n "; + for (Record *Reg : Order) { + OS << getQualifiedName(Reg) << ", "; + } + OS << "\n };\n\n"; - OS << " // " << Name << " Bit set.\n" - << " const uint8_t " << Name - << "Bits[] = {\n "; - BitVectorEmitter BVE; - for (Record *Reg : Order) { - BVE.add(Target.getRegBank().getReg(Reg)->EnumValue); + OS << " // " << Name << " Bit set.\n" + << " const uint8_t " << Name << "Bits[] = {\n "; + BitVectorEmitter BVE; + for (Record *Reg : Order) { + BVE.add(Target.getRegBank().getReg(Reg)->EnumValue); + } + BVE.print(OS); + OS << "\n };\n\n"; } - BVE.print(OS); - OS << "\n };\n\n"; - } OS << "} // end anonymous namespace\n\n"; @@ -1076,14 +1081,17 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, << "MCRegisterClasses[] = {\n"; for (const auto &RC : RegisterClasses) { + ArrayRef<Record *> Order = RC.getOrder(); + std::string RCName = Order.empty() ? "nullptr" : RC.getName(); + std::string RCBitsName = Order.empty() ? "nullptr" : RC.getName() + "Bits"; + std::string RCBitsSize = Order.empty() ? "0" : "sizeof(" + RCBitsName + ")"; assert(isInt<8>(RC.CopyCost) && "Copy cost too large."); uint32_t RegSize = 0; if (RC.RSI.isSimple()) RegSize = RC.RSI.getSimple().RegSize; - OS << " { " << RC.getName() << ", " << RC.getName() << "Bits, " + OS << " { " << RCName << ", " << RCBitsName << ", " << RegClassStrings.get(RC.getName()) << ", " << RC.getOrder().size() - << ", sizeof(" << RC.getName() << "Bits), " - << RC.getQualifiedName() + "RegClassID" + << ", " << RCBitsSize << ", " << RC.getQualifiedName() + "RegClassID" << ", " << RegSize << ", " << RC.CopyCost << ", " << (RC.Allocatable ? "true" : "false") << " },\n"; } @@ -1176,6 +1184,12 @@ RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target, << "unsigned RegUnit) const override;\n" << " ArrayRef<const char *> getRegMaskNames() const override;\n" << " ArrayRef<const uint32_t *> getRegMasks() const override;\n" + << " bool isGeneralPurposeRegister(const MachineFunction &, " + << "MCRegister) const override;\n" + << " bool isFixedRegister(const MachineFunction &, " + << "MCRegister) const override;\n" + << " bool isArgumentRegister(const MachineFunction &, " + << "MCRegister) const override;\n" << " /// Devirtualized TargetFrameLowering.\n" << " static const " << TargetName << "FrameLowering *getFrameLowering(\n" << " const MachineFunction &MF);\n" @@ -1250,7 +1264,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, OS << "};\n"; // Emit SubRegIndex names, skipping 0. - OS << "\nstatic const char *const SubRegIndexNameTable[] = { \""; + OS << "\nstatic const char *SubRegIndexNameTable[] = { \""; for (const auto &Idx : SubRegIndices) { OS << Idx.getName(); @@ -1620,10 +1634,54 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, } OS << "}\n\n"; + const std::list<CodeGenRegisterCategory> &RegCategories = + RegBank.getRegCategories(); + OS << "bool " << ClassName << "::\n" + << "isGeneralPurposeRegister(const MachineFunction &MF, " + << "MCRegister PhysReg) const {\n" + << " return\n"; + for (const CodeGenRegisterCategory &Category : RegCategories) + if (Category.getName() == "GeneralPurposeRegisters") { + for (const CodeGenRegisterClass *RC : Category.getClasses()) + OS << " " << RC->getQualifiedName() + << "RegClass.contains(PhysReg) ||\n"; + break; + } + OS << " false;\n"; + OS << "}\n\n"; + + OS << "bool " << ClassName << "::\n" + << "isFixedRegister(const MachineFunction &MF, " + << "MCRegister PhysReg) const {\n" + << " return\n"; + for (const CodeGenRegisterCategory &Category : RegCategories) + if (Category.getName() == "FixedRegisters") { + for (const CodeGenRegisterClass *RC : Category.getClasses()) + OS << " " << RC->getQualifiedName() + << "RegClass.contains(PhysReg) ||\n"; + break; + } + OS << " false;\n"; + OS << "}\n\n"; + + OS << "bool " << ClassName << "::\n" + << "isArgumentRegister(const MachineFunction &MF, " + << "MCRegister PhysReg) const {\n" + << " return\n"; + for (const CodeGenRegisterCategory &Category : RegCategories) + if (Category.getName() == "ArgumentRegisters") { + for (const CodeGenRegisterClass *RC : Category.getClasses()) + OS << " " << RC->getQualifiedName() + << "RegClass.contains(PhysReg) ||\n"; + break; + } + OS << " false;\n"; + OS << "}\n\n"; + OS << "ArrayRef<const char *> " << ClassName << "::getRegMaskNames() const {\n"; if (!CSRSets.empty()) { - OS << " static const char *const Names[] = {\n"; + OS << " static const char *Names[] = {\n"; for (Record *CSRSet : CSRSets) OS << " " << '"' << CSRSet->getName() << '"' << ",\n"; OS << " };\n"; @@ -1683,6 +1741,8 @@ void RegisterInfoEmitter::debugDump(raw_ostream &OS) { OS << "\tLaneMask: " << PrintLaneMask(RC.LaneMask) << '\n'; OS << "\tHasDisjunctSubRegs: " << RC.HasDisjunctSubRegs << '\n'; OS << "\tCoveredBySubRegs: " << RC.CoveredBySubRegs << '\n'; + OS << "\tAllocatable: " << RC.Allocatable << '\n'; + OS << "\tAllocationPriority: " << unsigned(RC.AllocationPriority) << '\n'; OS << "\tRegs:"; for (const CodeGenRegister *R : RC.getMembers()) { OS << " " << R->getName(); diff --git a/llvm/utils/TableGen/SearchableTableEmitter.cpp b/llvm/utils/TableGen/SearchableTableEmitter.cpp index dc5c96c662be..ea849807de03 100644 --- a/llvm/utils/TableGen/SearchableTableEmitter.cpp +++ b/llvm/utils/TableGen/SearchableTableEmitter.cpp @@ -30,7 +30,9 @@ using namespace llvm; namespace { int getAsInt(Init *B) { - return cast<IntInit>(B->convertInitializerTo(IntRecTy::get()))->getValue(); + return cast<IntInit>( + B->convertInitializerTo(IntRecTy::get(B->getRecordKeeper()))) + ->getValue(); } int getInt(Record *R, StringRef Field) { return getAsInt(R->getValueInit(Field)); diff --git a/llvm/utils/TableGen/SequenceToOffsetTable.h b/llvm/utils/TableGen/SequenceToOffsetTable.h index 41cdefdb1949..1b3451c24cb0 100644 --- a/llvm/utils/TableGen/SequenceToOffsetTable.h +++ b/llvm/utils/TableGen/SequenceToOffsetTable.h @@ -170,18 +170,18 @@ public: /// `EmitLongStrLiterals` is false void emitStringLiteralDef(raw_ostream &OS, const llvm::Twine &Decl) const { assert(Entries && "Call layout() before emitStringLiteralDef()"); - if (EmitLongStrLiterals) { - OS << "\n#ifdef __GNUC__\n" - << "#pragma GCC diagnostic push\n" - << "#pragma GCC diagnostic ignored \"-Woverlength-strings\"\n" - << "#endif\n" - << Decl << " = {\n"; - } else { + if (!EmitLongStrLiterals) { OS << Decl << " = {\n"; emit(OS, printChar, "0"); - OS << "\n};\n\n"; + OS << " 0\n};\n\n"; return; } + + OS << "\n#ifdef __GNUC__\n" + << "#pragma GCC diagnostic push\n" + << "#pragma GCC diagnostic ignored \"-Woverlength-strings\"\n" + << "#endif\n" + << Decl << " = {\n"; for (auto I : Seqs) { OS << " /* " << I.second << " */ \""; for (auto C : I.first) { diff --git a/llvm/utils/TableGen/SubtargetEmitter.cpp b/llvm/utils/TableGen/SubtargetEmitter.cpp index 78bbb3196e5c..88827607b517 100644 --- a/llvm/utils/TableGen/SubtargetEmitter.cpp +++ b/llvm/utils/TableGen/SubtargetEmitter.cpp @@ -74,6 +74,7 @@ class SubtargetEmitter { std::string Target; void Enumeration(raw_ostream &OS, DenseMap<Record *, unsigned> &FeatureMap); + void EmitSubtargetInfoMacroCalls(raw_ostream &OS); unsigned FeatureKeyValues(raw_ostream &OS, const DenseMap<Record *, unsigned> &FeatureMap); unsigned CPUKeyValues(raw_ostream &OS, @@ -122,8 +123,7 @@ class SubtargetEmitter { void EmitSchedModel(raw_ostream &OS); void EmitHwModeCheck(const std::string &ClassName, raw_ostream &OS); - void ParseFeaturesFunction(raw_ostream &OS, unsigned NumFeatures, - unsigned NumProcs); + void ParseFeaturesFunction(raw_ostream &OS); public: SubtargetEmitter(RecordKeeper &R, CodeGenTarget &TGT) @@ -193,6 +193,42 @@ static void printFeatureMask(raw_ostream &OS, RecVec &FeatureList, OS << "} } }"; } +/// Emit some information about the SubtargetFeature as calls to a macro so +/// that they can be used from C++. +void SubtargetEmitter::EmitSubtargetInfoMacroCalls(raw_ostream &OS) { + OS << "\n#ifdef GET_SUBTARGETINFO_MACRO\n"; + + std::vector<Record *> FeatureList = + Records.getAllDerivedDefinitions("SubtargetFeature"); + llvm::sort(FeatureList, LessRecordFieldName()); + + for (const Record *Feature : FeatureList) { + const StringRef Attribute = Feature->getValueAsString("Attribute"); + const StringRef Value = Feature->getValueAsString("Value"); + + // Only handle boolean features for now, excluding BitVectors and enums. + const bool IsBool = (Value == "false" || Value == "true") && + !StringRef(Attribute).contains('['); + if (!IsBool) + continue; + + // Some features default to true, with values set to false if enabled. + const char *Default = Value == "false" ? "true" : "false"; + + // Define the getter with lowercased first char: xxxYyy() { return XxxYyy; } + const std::string Getter = + Attribute.substr(0, 1).lower() + Attribute.substr(1).str(); + + OS << "GET_SUBTARGETINFO_MACRO(" << Attribute << ", " << Default << ", " + << Getter << ")\n"; + } + OS << "#undef GET_SUBTARGETINFO_MACRO\n"; + OS << "#endif // GET_SUBTARGETINFO_MACRO\n\n"; + + OS << "\n#ifdef GET_SUBTARGETINFO_MC_DESC\n"; + OS << "#undef GET_SUBTARGETINFO_MC_DESC\n\n"; +} + // // FeatureKeyValues - Emit data of all the subtarget features. Used by the // command line. @@ -1681,13 +1717,9 @@ void SubtargetEmitter::EmitHwModeCheck(const std::string &ClassName, OS << " return 0;\n}\n"; } -// -// ParseFeaturesFunction - Produces a subtarget specific function for parsing +// Produces a subtarget specific function for parsing // the subtarget features string. -// -void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS, - unsigned NumFeatures, - unsigned NumProcs) { +void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS) { std::vector<Record*> Features = Records.getAllDerivedDefinitions("SubtargetFeature"); llvm::sort(Features, LessRecord()); @@ -1803,8 +1835,7 @@ void SubtargetEmitter::run(raw_ostream &OS) { OS << "} // end namespace llvm\n\n"; OS << "#endif // GET_SUBTARGETINFO_ENUM\n\n"; - OS << "\n#ifdef GET_SUBTARGETINFO_MC_DESC\n"; - OS << "#undef GET_SUBTARGETINFO_MC_DESC\n\n"; + EmitSubtargetInfoMacroCalls(OS); OS << "namespace llvm {\n"; #if 0 @@ -1858,7 +1889,7 @@ void SubtargetEmitter::run(raw_ostream &OS) { OS << "#include \"llvm/Support/Debug.h\"\n"; OS << "#include \"llvm/Support/raw_ostream.h\"\n\n"; - ParseFeaturesFunction(OS, NumFeatures, NumProcs); + ParseFeaturesFunction(OS); OS << "#endif // GET_SUBTARGETINFO_TARGET_DESC\n\n"; diff --git a/llvm/utils/TableGen/SubtargetFeatureInfo.cpp b/llvm/utils/TableGen/SubtargetFeatureInfo.cpp index 33a22776f2df..f4f360fb5be2 100644 --- a/llvm/utils/TableGen/SubtargetFeatureInfo.cpp +++ b/llvm/utils/TableGen/SubtargetFeatureInfo.cpp @@ -108,6 +108,39 @@ void SubtargetFeatureInfo::emitComputeAvailableFeatures( OS << "}\n\n"; } +// If ParenIfBinOp is true, print a surrounding () if Val uses && or ||. +static bool emitFeaturesAux(StringRef TargetName, const Init &Val, + bool ParenIfBinOp, raw_ostream &OS) { + if (auto *D = dyn_cast<DefInit>(&Val)) { + if (!D->getDef()->isSubClassOf("SubtargetFeature")) + return true; + OS << "FB[" << TargetName << "::" << D->getAsString() << "]"; + return false; + } + if (auto *D = dyn_cast<DagInit>(&Val)) { + std::string Op = D->getOperator()->getAsString(); + if (Op == "not" && D->getNumArgs() == 1) { + OS << '!'; + return emitFeaturesAux(TargetName, *D->getArg(0), true, OS); + } + if ((Op == "any_of" || Op == "all_of") && D->getNumArgs() > 0) { + bool Paren = D->getNumArgs() > 1 && std::exchange(ParenIfBinOp, true); + if (Paren) + OS << '('; + ListSeparator LS(Op == "any_of" ? " || " : " && "); + for (auto *Arg : D->getArgs()) { + OS << LS; + if (emitFeaturesAux(TargetName, *Arg, ParenIfBinOp, OS)) + return true; + } + if (Paren) + OS << ')'; + return false; + } + } + return true; +} + void SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures( StringRef TargetName, StringRef ClassName, StringRef FuncName, SubtargetFeatureInfoMap &SubtargetFeatures, raw_ostream &OS) { @@ -118,37 +151,8 @@ void SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures( const SubtargetFeatureInfo &SFI = SF.second; OS << " if ("; - - const DagInit *D = SFI.TheDef->getValueAsDag("AssemblerCondDag"); - std::string CombineType = D->getOperator()->getAsString(); - if (CombineType != "any_of" && CombineType != "all_of") - PrintFatalError(SFI.TheDef->getLoc(), "Invalid AssemblerCondDag!"); - if (D->getNumArgs() == 0) - PrintFatalError(SFI.TheDef->getLoc(), "Invalid AssemblerCondDag!"); - bool IsOr = CombineType == "any_of"; - - if (IsOr) - OS << "("; - - ListSeparator LS(IsOr ? " || " : " && "); - for (auto *Arg : D->getArgs()) { - OS << LS; - if (auto *NotArg = dyn_cast<DagInit>(Arg)) { - if (NotArg->getOperator()->getAsString() != "not" || - NotArg->getNumArgs() != 1) - PrintFatalError(SFI.TheDef->getLoc(), "Invalid AssemblerCondDag!"); - Arg = NotArg->getArg(0); - OS << "!"; - } - if (!isa<DefInit>(Arg) || - !cast<DefInit>(Arg)->getDef()->isSubClassOf("SubtargetFeature")) - PrintFatalError(SFI.TheDef->getLoc(), "Invalid AssemblerCondDag!"); - OS << "FB[" << TargetName << "::" << Arg->getAsString() << "]"; - } - - if (IsOr) - OS << ")"; - + emitFeaturesAux(TargetName, *SFI.TheDef->getValueAsDag("AssemblerCondDag"), + /*ParenIfBinOp=*/false, OS); OS << ")\n"; OS << " Features.set(" << SFI.getEnumBitName() << ");\n"; } diff --git a/llvm/utils/TableGen/TableGen.cpp b/llvm/utils/TableGen/TableGen.cpp index 2d4a45f889be..efd641887232 100644 --- a/llvm/utils/TableGen/TableGen.cpp +++ b/llvm/utils/TableGen/TableGen.cpp @@ -25,7 +25,6 @@ enum ActionType { NullBackend, DumpJSON, GenEmitter, - GenCodeBeads, GenRegisterInfo, GenInstrInfo, GenInstrDocs, @@ -52,11 +51,13 @@ enum ActionType { GenGICombiner, GenX86EVEX2VEXTables, GenX86FoldTables, + GenX86MnemonicTables, GenRegisterBank, GenExegesis, GenAutomata, GenDirectivesEnumDecl, GenDirectivesEnumImpl, + GenDXILOperation, }; namespace llvm { @@ -81,8 +82,6 @@ cl::opt<ActionType> Action( clEnumValN(DumpJSON, "dump-json", "Dump all records as machine-readable JSON"), clEnumValN(GenEmitter, "gen-emitter", "Generate machine code emitter"), - clEnumValN(GenCodeBeads, "gen-code-beads", - "Generate machine code beads"), clEnumValN(GenRegisterInfo, "gen-register-info", "Generate registers and register classes info"), clEnumValN(GenInstrInfo, "gen-instr-info", @@ -130,6 +129,8 @@ cl::opt<ActionType> Action( "Generate X86 EVEX to VEX compress tables"), clEnumValN(GenX86FoldTables, "gen-x86-fold-tables", "Generate X86 fold tables"), + clEnumValN(GenX86MnemonicTables, "gen-x86-mnemonic-tables", + "Generate X86 mnemonic tables"), clEnumValN(GenRegisterBank, "gen-register-bank", "Generate registers bank descriptions"), clEnumValN(GenExegesis, "gen-exegesis", @@ -138,7 +139,9 @@ cl::opt<ActionType> Action( clEnumValN(GenDirectivesEnumDecl, "gen-directive-decl", "Generate directive related declaration code (header file)"), clEnumValN(GenDirectivesEnumImpl, "gen-directive-impl", - "Generate directive related implementation code"))); + "Generate directive related implementation code"), + clEnumValN(GenDXILOperation, "gen-dxil-operation", + "Generate DXIL operation information"))); cl::OptionCategory PrintEnumsCat("Options for -print-enums"); cl::opt<std::string> Class("class", cl::desc("Print Enum list for this class"), @@ -161,9 +164,6 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) { case GenEmitter: EmitCodeEmitter(Records, OS); break; - case GenCodeBeads: - EmitCodeBeads(Records, OS); - break; case GenRegisterInfo: EmitRegisterInfo(Records, OS); break; @@ -257,6 +257,9 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) { case GenX86EVEX2VEXTables: EmitX86EVEX2VEXTables(Records, OS); break; + case GenX86MnemonicTables: + EmitX86MnemonicTables(Records, OS); + break; case GenX86FoldTables: EmitX86FoldTables(Records, OS); break; @@ -272,6 +275,9 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) { case GenDirectivesEnumImpl: EmitDirectivesImpl(Records, OS); break; + case GenDXILOperation: + EmitDXILOperation(Records, OS); + break; } return false; diff --git a/llvm/utils/TableGen/TableGenBackends.h b/llvm/utils/TableGen/TableGenBackends.h index 71db8dc77b05..4dff13095696 100644 --- a/llvm/utils/TableGen/TableGenBackends.h +++ b/llvm/utils/TableGen/TableGenBackends.h @@ -67,7 +67,6 @@ void EmitAsmMatcher(RecordKeeper &RK, raw_ostream &OS); void EmitAsmWriter(RecordKeeper &RK, raw_ostream &OS); void EmitCallingConv(RecordKeeper &RK, raw_ostream &OS); void EmitCodeEmitter(RecordKeeper &RK, raw_ostream &OS); -void EmitCodeBeads(RecordKeeper &RK, raw_ostream &OS); void EmitDAGISel(RecordKeeper &RK, raw_ostream &OS); void EmitDFAPacketizer(RecordKeeper &RK, raw_ostream &OS); void EmitDisassembler(RecordKeeper &RK, raw_ostream &OS); @@ -88,11 +87,13 @@ void EmitGlobalISel(RecordKeeper &RK, raw_ostream &OS); void EmitGICombiner(RecordKeeper &RK, raw_ostream &OS); void EmitX86EVEX2VEXTables(RecordKeeper &RK, raw_ostream &OS); void EmitX86FoldTables(RecordKeeper &RK, raw_ostream &OS); +void EmitX86MnemonicTables(RecordKeeper &RK, raw_ostream &OS); void EmitRegisterBank(RecordKeeper &RK, raw_ostream &OS); void EmitExegesis(RecordKeeper &RK, raw_ostream &OS); void EmitAutomata(RecordKeeper &RK, raw_ostream &OS); void EmitDirectivesDecl(RecordKeeper &RK, raw_ostream &OS); void EmitDirectivesImpl(RecordKeeper &RK, raw_ostream &OS); +void EmitDXILOperation(RecordKeeper &RK, raw_ostream &OS); } // End llvm namespace diff --git a/llvm/utils/TableGen/VarLenCodeEmitterGen.cpp b/llvm/utils/TableGen/VarLenCodeEmitterGen.cpp new file mode 100644 index 000000000000..a6bbe2f7ff37 --- /dev/null +++ b/llvm/utils/TableGen/VarLenCodeEmitterGen.cpp @@ -0,0 +1,487 @@ +//===- VarLenCodeEmitterGen.cpp - CEG for variable-length insts -----------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// The CodeEmitterGen component for variable-length instructions. +// +// The basic CodeEmitterGen is almost exclusively designed for fixed- +// length instructions. A good analogy for its encoding scheme is how printf +// works: The (immutable) formatting string represent the fixed values in the +// encoded instruction. Placeholders (i.e. %something), on the other hand, +// represent encoding for instruction operands. +// ``` +// printf("1101 %src 1001 %dst", <encoded value for operand `src`>, +// <encoded value for operand `dst`>); +// ``` +// VarLenCodeEmitterGen in this file provides an alternative encoding scheme +// that works more like a C++ stream operator: +// ``` +// OS << 0b1101; +// if (Cond) +// OS << OperandEncoding0; +// OS << 0b1001 << OperandEncoding1; +// ``` +// You are free to concatenate arbitrary types (and sizes) of encoding +// fragments on any bit position, bringing more flexibilities on defining +// encoding for variable-length instructions. +// +// In a more specific way, instruction encoding is represented by a DAG type +// `Inst` field. Here is an example: +// ``` +// dag Inst = (descend 0b1101, (operand "$src", 4), 0b1001, +// (operand "$dst", 4)); +// ``` +// It represents the following instruction encoding: +// ``` +// MSB LSB +// 1101<encoding for operand src>1001<encoding for operand dst> +// ``` +// For more details about DAG operators in the above snippet, please +// refer to \file include/llvm/Target/Target.td. +// +// VarLenCodeEmitter will convert the above DAG into the same helper function +// generated by CodeEmitter, `MCCodeEmitter::getBinaryCodeForInstr` (except +// for few details). +// +//===----------------------------------------------------------------------===// + +#include "VarLenCodeEmitterGen.h" +#include "CodeGenHwModes.h" +#include "CodeGenInstruction.h" +#include "CodeGenTarget.h" +#include "InfoByHwMode.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/TableGen/Error.h" + +using namespace llvm; + +namespace { + +class VarLenCodeEmitterGen { + RecordKeeper &Records; + + DenseMap<Record *, VarLenInst> VarLenInsts; + + // Emit based values (i.e. fixed bits in the encoded instructions) + void emitInstructionBaseValues( + raw_ostream &OS, + ArrayRef<const CodeGenInstruction *> NumberedInstructions, + CodeGenTarget &Target, int HwMode = -1); + + std::string getInstructionCase(Record *R, CodeGenTarget &Target); + std::string getInstructionCaseForEncoding(Record *R, Record *EncodingDef, + CodeGenTarget &Target); + +public: + explicit VarLenCodeEmitterGen(RecordKeeper &R) : Records(R) {} + + void run(raw_ostream &OS); +}; + +} // end anonymous namespace + +VarLenInst::VarLenInst(const DagInit *DI, const RecordVal *TheDef) + : TheDef(TheDef), NumBits(0U) { + buildRec(DI); + for (const auto &S : Segments) + NumBits += S.BitWidth; +} + +void VarLenInst::buildRec(const DagInit *DI) { + assert(TheDef && "The def record is nullptr ?"); + + std::string Op = DI->getOperator()->getAsString(); + + if (Op == "ascend" || Op == "descend") { + bool Reverse = Op == "descend"; + int i = Reverse ? DI->getNumArgs() - 1 : 0; + int e = Reverse ? -1 : DI->getNumArgs(); + int s = Reverse ? -1 : 1; + for (; i != e; i += s) { + const Init *Arg = DI->getArg(i); + if (const auto *BI = dyn_cast<BitsInit>(Arg)) { + if (!BI->isComplete()) + PrintFatalError(TheDef->getLoc(), + "Expecting complete bits init in `" + Op + "`"); + Segments.push_back({BI->getNumBits(), BI}); + } else if (const auto *BI = dyn_cast<BitInit>(Arg)) { + if (!BI->isConcrete()) + PrintFatalError(TheDef->getLoc(), + "Expecting concrete bit init in `" + Op + "`"); + Segments.push_back({1, BI}); + } else if (const auto *SubDI = dyn_cast<DagInit>(Arg)) { + buildRec(SubDI); + } else { + PrintFatalError(TheDef->getLoc(), "Unrecognized type of argument in `" + + Op + "`: " + Arg->getAsString()); + } + } + } else if (Op == "operand") { + // (operand <operand name>, <# of bits>, [(encoder <custom encoder>)]) + if (DI->getNumArgs() < 2) + PrintFatalError(TheDef->getLoc(), + "Expecting at least 2 arguments for `operand`"); + HasDynamicSegment = true; + const Init *OperandName = DI->getArg(0), *NumBits = DI->getArg(1); + if (!isa<StringInit>(OperandName) || !isa<IntInit>(NumBits)) + PrintFatalError(TheDef->getLoc(), "Invalid argument types for `operand`"); + + auto NumBitsVal = cast<IntInit>(NumBits)->getValue(); + if (NumBitsVal <= 0) + PrintFatalError(TheDef->getLoc(), "Invalid number of bits for `operand`"); + + StringRef CustomEncoder; + if (DI->getNumArgs() >= 3) + CustomEncoder = getCustomEncoderName(DI->getArg(2)); + Segments.push_back( + {static_cast<unsigned>(NumBitsVal), OperandName, CustomEncoder}); + } else if (Op == "slice") { + // (slice <operand name>, <high / low bit>, <low / high bit>, + // [(encoder <custom encoder>)]) + if (DI->getNumArgs() < 3) + PrintFatalError(TheDef->getLoc(), + "Expecting at least 3 arguments for `slice`"); + HasDynamicSegment = true; + Init *OperandName = DI->getArg(0), *HiBit = DI->getArg(1), + *LoBit = DI->getArg(2); + if (!isa<StringInit>(OperandName) || !isa<IntInit>(HiBit) || + !isa<IntInit>(LoBit)) + PrintFatalError(TheDef->getLoc(), "Invalid argument types for `slice`"); + + auto HiBitVal = cast<IntInit>(HiBit)->getValue(), + LoBitVal = cast<IntInit>(LoBit)->getValue(); + if (HiBitVal < 0 || LoBitVal < 0) + PrintFatalError(TheDef->getLoc(), "Invalid bit range for `slice`"); + bool NeedSwap = false; + unsigned NumBits = 0U; + if (HiBitVal < LoBitVal) { + NeedSwap = true; + NumBits = static_cast<unsigned>(LoBitVal - HiBitVal + 1); + } else { + NumBits = static_cast<unsigned>(HiBitVal - LoBitVal + 1); + } + + StringRef CustomEncoder; + if (DI->getNumArgs() >= 4) + CustomEncoder = getCustomEncoderName(DI->getArg(3)); + + if (NeedSwap) { + // Normalization: Hi bit should always be the second argument. + Init *const NewArgs[] = {OperandName, LoBit, HiBit}; + Segments.push_back({NumBits, + DagInit::get(DI->getOperator(), nullptr, NewArgs, {}), + CustomEncoder}); + } else { + Segments.push_back({NumBits, DI, CustomEncoder}); + } + } +} + +void VarLenCodeEmitterGen::run(raw_ostream &OS) { + CodeGenTarget Target(Records); + auto Insts = Records.getAllDerivedDefinitions("Instruction"); + + auto NumberedInstructions = Target.getInstructionsByEnumValue(); + const CodeGenHwModes &HWM = Target.getHwModes(); + + // The set of HwModes used by instruction encodings. + std::set<unsigned> HwModes; + for (const CodeGenInstruction *CGI : NumberedInstructions) { + Record *R = CGI->TheDef; + + // Create the corresponding VarLenInst instance. + if (R->getValueAsString("Namespace") == "TargetOpcode" || + R->getValueAsBit("isPseudo")) + continue; + + if (const RecordVal *RV = R->getValue("EncodingInfos")) { + if (auto *DI = dyn_cast_or_null<DefInit>(RV->getValue())) { + EncodingInfoByHwMode EBM(DI->getDef(), HWM); + for (auto &KV : EBM) { + HwModes.insert(KV.first); + Record *EncodingDef = KV.second; + RecordVal *RV = EncodingDef->getValue("Inst"); + DagInit *DI = cast<DagInit>(RV->getValue()); + VarLenInsts.insert({EncodingDef, VarLenInst(DI, RV)}); + } + continue; + } + } + RecordVal *RV = R->getValue("Inst"); + DagInit *DI = cast<DagInit>(RV->getValue()); + VarLenInsts.insert({R, VarLenInst(DI, RV)}); + } + + // Emit function declaration + OS << "void " << Target.getName() + << "MCCodeEmitter::getBinaryCodeForInstr(const MCInst &MI,\n" + << " SmallVectorImpl<MCFixup> &Fixups,\n" + << " APInt &Inst,\n" + << " APInt &Scratch,\n" + << " const MCSubtargetInfo &STI) const {\n"; + + // Emit instruction base values + if (HwModes.empty()) { + emitInstructionBaseValues(OS, NumberedInstructions, Target); + } else { + for (unsigned HwMode : HwModes) + emitInstructionBaseValues(OS, NumberedInstructions, Target, (int)HwMode); + } + + if (!HwModes.empty()) { + OS << " const unsigned **Index;\n"; + OS << " const uint64_t *InstBits;\n"; + OS << " unsigned HwMode = STI.getHwMode();\n"; + OS << " switch (HwMode) {\n"; + OS << " default: llvm_unreachable(\"Unknown hardware mode!\"); break;\n"; + for (unsigned I : HwModes) { + OS << " case " << I << ": InstBits = InstBits_" << HWM.getMode(I).Name + << "; Index = Index_" << HWM.getMode(I).Name << "; break;\n"; + } + OS << " };\n"; + } + + // Emit helper function to retrieve base values. + OS << " auto getInstBits = [&](unsigned Opcode) -> APInt {\n" + << " unsigned NumBits = Index[Opcode][0];\n" + << " if (!NumBits)\n" + << " return APInt::getZeroWidth();\n" + << " unsigned Idx = Index[Opcode][1];\n" + << " ArrayRef<uint64_t> Data(&InstBits[Idx], " + << "APInt::getNumWords(NumBits));\n" + << " return APInt(NumBits, Data);\n" + << " };\n"; + + // Map to accumulate all the cases. + std::map<std::string, std::vector<std::string>> CaseMap; + + // Construct all cases statement for each opcode + for (Record *R : Insts) { + if (R->getValueAsString("Namespace") == "TargetOpcode" || + R->getValueAsBit("isPseudo")) + continue; + std::string InstName = + (R->getValueAsString("Namespace") + "::" + R->getName()).str(); + std::string Case = getInstructionCase(R, Target); + + CaseMap[Case].push_back(std::move(InstName)); + } + + // Emit initial function code + OS << " const unsigned opcode = MI.getOpcode();\n" + << " switch (opcode) {\n"; + + // Emit each case statement + for (const auto &C : CaseMap) { + const std::string &Case = C.first; + const auto &InstList = C.second; + + ListSeparator LS("\n"); + for (const auto &InstName : InstList) + OS << LS << " case " << InstName << ":"; + + OS << " {\n"; + OS << Case; + OS << " break;\n" + << " }\n"; + } + // Default case: unhandled opcode + OS << " default:\n" + << " std::string msg;\n" + << " raw_string_ostream Msg(msg);\n" + << " Msg << \"Not supported instr: \" << MI;\n" + << " report_fatal_error(Msg.str().c_str());\n" + << " }\n"; + OS << "}\n\n"; +} + +static void emitInstBits(raw_ostream &IS, raw_ostream &SS, const APInt &Bits, + unsigned &Index) { + if (!Bits.getNumWords()) { + IS.indent(4) << "{/*NumBits*/0, /*Index*/0},"; + return; + } + + IS.indent(4) << "{/*NumBits*/" << Bits.getBitWidth() << ", " + << "/*Index*/" << Index << "},"; + + SS.indent(4); + for (unsigned I = 0; I < Bits.getNumWords(); ++I, ++Index) + SS << "UINT64_C(" << utostr(Bits.getRawData()[I]) << "),"; +} + +void VarLenCodeEmitterGen::emitInstructionBaseValues( + raw_ostream &OS, ArrayRef<const CodeGenInstruction *> NumberedInstructions, + CodeGenTarget &Target, int HwMode) { + std::string IndexArray, StorageArray; + raw_string_ostream IS(IndexArray), SS(StorageArray); + + const CodeGenHwModes &HWM = Target.getHwModes(); + if (HwMode == -1) { + IS << " static const unsigned Index[][2] = {\n"; + SS << " static const uint64_t InstBits[] = {\n"; + } else { + StringRef Name = HWM.getMode(HwMode).Name; + IS << " static const unsigned Index_" << Name << "[][2] = {\n"; + SS << " static const uint64_t InstBits_" << Name << "[] = {\n"; + } + + unsigned NumFixedValueWords = 0U; + for (const CodeGenInstruction *CGI : NumberedInstructions) { + Record *R = CGI->TheDef; + + if (R->getValueAsString("Namespace") == "TargetOpcode" || + R->getValueAsBit("isPseudo")) { + IS.indent(4) << "{/*NumBits*/0, /*Index*/0},\n"; + continue; + } + + Record *EncodingDef = R; + if (const RecordVal *RV = R->getValue("EncodingInfos")) { + if (auto *DI = dyn_cast_or_null<DefInit>(RV->getValue())) { + EncodingInfoByHwMode EBM(DI->getDef(), HWM); + if (EBM.hasMode(HwMode)) + EncodingDef = EBM.get(HwMode); + } + } + + auto It = VarLenInsts.find(EncodingDef); + if (It == VarLenInsts.end()) + PrintFatalError(EncodingDef, "VarLenInst not found for this record"); + const VarLenInst &VLI = It->second; + + unsigned i = 0U, BitWidth = VLI.size(); + + // Start by filling in fixed values. + APInt Value(BitWidth, 0); + auto SI = VLI.begin(), SE = VLI.end(); + // Scan through all the segments that have fixed-bits values. + while (i < BitWidth && SI != SE) { + unsigned SegmentNumBits = SI->BitWidth; + if (const auto *BI = dyn_cast<BitsInit>(SI->Value)) { + for (unsigned Idx = 0U; Idx != SegmentNumBits; ++Idx) { + auto *B = cast<BitInit>(BI->getBit(Idx)); + Value.setBitVal(i + Idx, B->getValue()); + } + } + if (const auto *BI = dyn_cast<BitInit>(SI->Value)) + Value.setBitVal(i, BI->getValue()); + + i += SegmentNumBits; + ++SI; + } + + emitInstBits(IS, SS, Value, NumFixedValueWords); + IS << '\t' << "// " << R->getName() << "\n"; + if (Value.getNumWords()) + SS << '\t' << "// " << R->getName() << "\n"; + } + IS.indent(4) << "{/*NumBits*/0, /*Index*/0}\n };\n"; + SS.indent(4) << "UINT64_C(0)\n };\n"; + + OS << IS.str() << SS.str(); +} + +std::string VarLenCodeEmitterGen::getInstructionCase(Record *R, + CodeGenTarget &Target) { + std::string Case; + if (const RecordVal *RV = R->getValue("EncodingInfos")) { + if (auto *DI = dyn_cast_or_null<DefInit>(RV->getValue())) { + const CodeGenHwModes &HWM = Target.getHwModes(); + EncodingInfoByHwMode EBM(DI->getDef(), HWM); + Case += " switch (HwMode) {\n"; + Case += " default: llvm_unreachable(\"Unhandled HwMode\");\n"; + for (auto &KV : EBM) { + Case += " case " + itostr(KV.first) + ": {\n"; + Case += getInstructionCaseForEncoding(R, KV.second, Target); + Case += " break;\n"; + Case += " }\n"; + } + Case += " }\n"; + return Case; + } + } + return getInstructionCaseForEncoding(R, R, Target); +} + +std::string VarLenCodeEmitterGen::getInstructionCaseForEncoding( + Record *R, Record *EncodingDef, CodeGenTarget &Target) { + auto It = VarLenInsts.find(EncodingDef); + if (It == VarLenInsts.end()) + PrintFatalError(EncodingDef, "Parsed encoding record not found"); + const VarLenInst &VLI = It->second; + size_t BitWidth = VLI.size(); + + CodeGenInstruction &CGI = Target.getInstruction(R); + + std::string Case; + raw_string_ostream SS(Case); + // Resize the scratch buffer. + if (BitWidth && !VLI.isFixedValueOnly()) + SS.indent(6) << "Scratch = Scratch.zext(" << BitWidth << ");\n"; + // Populate based value. + SS.indent(6) << "Inst = getInstBits(opcode);\n"; + + // Process each segment in VLI. + size_t Offset = 0U; + for (const auto &ES : VLI) { + unsigned NumBits = ES.BitWidth; + const Init *Val = ES.Value; + // If it's a StringInit or DagInit, it's a reference to an operand + // or part of an operand. + if (isa<StringInit>(Val) || isa<DagInit>(Val)) { + StringRef OperandName; + unsigned LoBit = 0U; + if (const auto *SV = dyn_cast<StringInit>(Val)) { + OperandName = SV->getValue(); + } else { + // Normalized: (slice <operand name>, <high bit>, <low bit>) + const auto *DV = cast<DagInit>(Val); + OperandName = cast<StringInit>(DV->getArg(0))->getValue(); + LoBit = static_cast<unsigned>(cast<IntInit>(DV->getArg(2))->getValue()); + } + + auto OpIdx = CGI.Operands.ParseOperandName(OperandName); + unsigned FlatOpIdx = CGI.Operands.getFlattenedOperandNumber(OpIdx); + StringRef CustomEncoder = CGI.Operands[OpIdx.first].EncoderMethodName; + if (ES.CustomEncoder.size()) + CustomEncoder = ES.CustomEncoder; + + SS.indent(6) << "Scratch.clearAllBits();\n"; + SS.indent(6) << "// op: " << OperandName.drop_front(1) << "\n"; + if (CustomEncoder.empty()) + SS.indent(6) << "getMachineOpValue(MI, MI.getOperand(" + << utostr(FlatOpIdx) << ")"; + else + SS.indent(6) << CustomEncoder << "(MI, /*OpIdx=*/" << utostr(FlatOpIdx); + + SS << ", /*Pos=*/" << utostr(Offset) << ", Scratch, Fixups, STI);\n"; + + SS.indent(6) << "Inst.insertBits(" + << "Scratch.extractBits(" << utostr(NumBits) << ", " + << utostr(LoBit) << ")" + << ", " << Offset << ");\n"; + } + Offset += NumBits; + } + + StringRef PostEmitter = R->getValueAsString("PostEncoderMethod"); + if (!PostEmitter.empty()) + SS.indent(6) << "Inst = " << PostEmitter << "(MI, Inst, STI);\n"; + + return Case; +} + +namespace llvm { + +void emitVarLenCodeEmitter(RecordKeeper &R, raw_ostream &OS) { + VarLenCodeEmitterGen(R).run(OS); +} + +} // end namespace llvm diff --git a/llvm/utils/TableGen/VarLenCodeEmitterGen.h b/llvm/utils/TableGen/VarLenCodeEmitterGen.h new file mode 100644 index 000000000000..5bdedee1dd51 --- /dev/null +++ b/llvm/utils/TableGen/VarLenCodeEmitterGen.h @@ -0,0 +1,66 @@ +//===- VarLenCodeEmitterGen.h - CEG for variable-length insts ---*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file declare the CodeEmitterGen component for variable-length +// instructions. See the .cpp file for more details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_UTILS_TABLEGEN_VARLENCODEEMITTERGEN_H +#define LLVM_UTILS_TABLEGEN_VARLENCODEEMITTERGEN_H + +#include "llvm/TableGen/Record.h" + +namespace llvm { + +struct EncodingSegment { + unsigned BitWidth; + const Init *Value; + StringRef CustomEncoder = ""; +}; + +class VarLenInst { + const RecordVal *TheDef; + size_t NumBits; + + // Set if any of the segment is not fixed value. + bool HasDynamicSegment; + + SmallVector<EncodingSegment, 4> Segments; + + void buildRec(const DagInit *DI); + + StringRef getCustomEncoderName(const Init *EI) const { + if (const auto *DI = dyn_cast<DagInit>(EI)) { + if (DI->getNumArgs() && isa<StringInit>(DI->getArg(0))) + return cast<StringInit>(DI->getArg(0))->getValue(); + } + return ""; + } + +public: + VarLenInst() : TheDef(nullptr), NumBits(0U), HasDynamicSegment(false) {} + + explicit VarLenInst(const DagInit *DI, const RecordVal *TheDef); + + /// Number of bits + size_t size() const { return NumBits; } + + using const_iterator = decltype(Segments)::const_iterator; + + const_iterator begin() const { return Segments.begin(); } + const_iterator end() const { return Segments.end(); } + size_t getNumSegments() const { return Segments.size(); } + + bool isFixedValueOnly() const { return !HasDynamicSegment; } +}; + +void emitVarLenCodeEmitter(RecordKeeper &R, raw_ostream &OS); + +} // end namespace llvm +#endif diff --git a/llvm/utils/TableGen/WebAssemblyDisassemblerEmitter.cpp b/llvm/utils/TableGen/WebAssemblyDisassemblerEmitter.cpp index 74969053f095..dc037e4409ab 100644 --- a/llvm/utils/TableGen/WebAssemblyDisassemblerEmitter.cpp +++ b/llvm/utils/TableGen/WebAssemblyDisassemblerEmitter.cpp @@ -37,8 +37,9 @@ void emitWebAssemblyDisassemblerTables( if (!Def.getValue("Inst")) continue; auto &Inst = *Def.getValueAsBitsInit("Inst"); - auto Opc = static_cast<unsigned>( - reinterpret_cast<IntInit *>(Inst.convertInitializerTo(IntRecTy::get())) + RecordKeeper &RK = Inst.getRecordKeeper(); + unsigned Opc = static_cast<unsigned>( + cast<IntInit>(Inst.convertInitializerTo(IntRecTy::get(RK))) ->getValue()); if (Opc == 0xFFFFFFFF) continue; // No opcode defined. @@ -54,11 +55,7 @@ void emitWebAssemblyDisassemblerTables( auto &CGIP = OpcodeTable[Prefix][Opc]; // All wasm instructions have a StackBased field of type string, we only // want the instructions for which this is "true". - auto StackString = - Def.getValue("StackBased")->getValue()->getCastTo(StringRecTy::get()); - auto IsStackBased = - StackString && - reinterpret_cast<const StringInit *>(StackString)->getValue() == "true"; + bool IsStackBased = Def.getValueAsBit("StackBased"); if (!IsStackBased) continue; if (CGIP.second) { @@ -66,14 +63,11 @@ void emitWebAssemblyDisassemblerTables( // should be the canonical one. This determines which variant gets // printed in a disassembly. We want e.g. "call" not "i32.call", and // "end" when we don't know if its "end_loop" or "end_block" etc. - auto IsCanonicalExisting = CGIP.second->TheDef->getValue("IsCanonical") - ->getValue() - ->getAsString() == "1"; + bool IsCanonicalExisting = CGIP.second->TheDef->getValueAsBit("IsCanonical"); // We already have one marked explicitly as canonical, so keep it. if (IsCanonicalExisting) continue; - auto IsCanonicalNew = - Def.getValue("IsCanonical")->getValue()->getAsString() == "1"; + bool IsCanonicalNew = Def.getValueAsBit("IsCanonical"); // If the new one is explicitly marked as canonical, take it. if (!IsCanonicalNew) { // Neither the existing or new instruction is canonical. diff --git a/llvm/utils/TableGen/X86DisassemblerTables.cpp b/llvm/utils/TableGen/X86DisassemblerTables.cpp index 81ddea99740d..2fa8fce81422 100644 --- a/llvm/utils/TableGen/X86DisassemblerTables.cpp +++ b/llvm/utils/TableGen/X86DisassemblerTables.cpp @@ -105,8 +105,7 @@ static inline bool inheritsFrom(InstructionContext child, case IC_64BIT_ADSIZE: return (noPrefix && inheritsFrom(child, IC_64BIT_OPSIZE_ADSIZE, noPrefix)); case IC_64BIT_OPSIZE_ADSIZE: - return (noPrefix && - inheritsFrom(child, IC_64BIT_VEX_OPSIZE_ADSIZE, noPrefix)); + return false; case IC_XD: return inheritsFrom(child, IC_64BIT_XD); case IC_XS: @@ -127,11 +126,10 @@ static inline bool inheritsFrom(InstructionContext child, case IC_64BIT_OPSIZE: return inheritsFrom(child, IC_64BIT_REXW_OPSIZE) || (!AdSize64 && inheritsFrom(child, IC_64BIT_OPSIZE_ADSIZE)) || - (!AdSize64 && inheritsFrom(child, IC_64BIT_REXW_ADSIZE)) || - (!AdSize64 && inheritsFrom(child, IC_64BIT_VEX_OPSIZE_ADSIZE)); + (!AdSize64 && inheritsFrom(child, IC_64BIT_REXW_ADSIZE)); case IC_64BIT_XD: - return (inheritsFrom(child, IC_64BIT_REXW_XD) || - (!AdSize64 && inheritsFrom(child, IC_64BIT_XD_ADSIZE))); + return(inheritsFrom(child, IC_64BIT_REXW_XD) || + (!AdSize64 && inheritsFrom(child, IC_64BIT_XD_ADSIZE))); case IC_64BIT_XS: return(inheritsFrom(child, IC_64BIT_REXW_XS) || (!AdSize64 && inheritsFrom(child, IC_64BIT_XS_ADSIZE))); @@ -161,12 +159,7 @@ static inline bool inheritsFrom(InstructionContext child, case IC_VEX_OPSIZE: return (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_VEX_L_W_OPSIZE)) || (VEX_WIG && inheritsFrom(child, IC_VEX_W_OPSIZE)) || - (VEX_LIG && inheritsFrom(child, IC_VEX_L_OPSIZE)) || - inheritsFrom(child, IC_64BIT_VEX_OPSIZE); - case IC_64BIT_VEX_OPSIZE: - return inheritsFrom(child, IC_64BIT_VEX_OPSIZE_ADSIZE); - case IC_64BIT_VEX_OPSIZE_ADSIZE: - return false; + (VEX_LIG && inheritsFrom(child, IC_VEX_L_OPSIZE)); case IC_VEX_W: return VEX_LIG && inheritsFrom(child, IC_VEX_L_W); case IC_VEX_W_XS: @@ -673,7 +666,6 @@ void DisassemblerTables::emitModRMDecision(raw_ostream &o1, raw_ostream &o2, unsigned &i1, unsigned &i2, unsigned &ModRMTableNum, ModRMDecision &decision) const { - static uint32_t sTableNumber = 0; static uint32_t sEntryNumber = 1; ModRMDecisionType dt = getDecisionType(decision); @@ -753,8 +745,6 @@ void DisassemblerTables::emitModRMDecision(raw_ostream &o1, raw_ostream &o2, assert(sEntryNumber < 65536U && "Index into ModRMDecision is too large for uint16_t!"); (void)sEntryNumber; - - ++sTableNumber; } void DisassemblerTables::emitOpcodeDecision(raw_ostream &o1, raw_ostream &o2, @@ -891,9 +881,6 @@ void DisassemblerTables::emitContextTable(raw_ostream &o, unsigned &i) const { if ((index & ATTR_EVEX) || (index & ATTR_VEX) || (index & ATTR_VEXL)) { if (index & ATTR_EVEX) o << "IC_EVEX"; - else if ((index & (ATTR_64BIT | ATTR_VEXL | ATTR_REXW | ATTR_OPSIZE)) == - (ATTR_64BIT | ATTR_OPSIZE)) - o << "IC_64BIT_VEX"; else o << "IC_VEX"; @@ -905,13 +892,9 @@ void DisassemblerTables::emitContextTable(raw_ostream &o, unsigned &i) const { if (index & ATTR_REXW) o << "_W"; - if (index & ATTR_OPSIZE) { + if (index & ATTR_OPSIZE) o << "_OPSIZE"; - if ((index & (ATTR_64BIT | ATTR_EVEX | ATTR_VEX | ATTR_VEXL | - ATTR_REXW | ATTR_ADSIZE)) == - (ATTR_64BIT | ATTR_VEX | ATTR_ADSIZE)) - o << "_ADSIZE"; - } else if (index & ATTR_XD) + else if (index & ATTR_XD) o << "_XD"; else if (index & ATTR_XS) o << "_XS"; @@ -925,7 +908,8 @@ void DisassemblerTables::emitContextTable(raw_ostream &o, unsigned &i) const { if (index & ATTR_EVEXB) o << "_B"; } - } else if ((index & ATTR_64BIT) && (index & ATTR_REXW) && (index & ATTR_XS)) + } + else if ((index & ATTR_64BIT) && (index & ATTR_REXW) && (index & ATTR_XS)) o << "IC_64BIT_REXW_XS"; else if ((index & ATTR_64BIT) && (index & ATTR_REXW) && (index & ATTR_XD)) o << "IC_64BIT_REXW_XD"; diff --git a/llvm/utils/TableGen/X86EVEX2VEXTablesEmitter.cpp b/llvm/utils/TableGen/X86EVEX2VEXTablesEmitter.cpp index 36c71843d70e..1384330ee8a1 100644 --- a/llvm/utils/TableGen/X86EVEX2VEXTablesEmitter.cpp +++ b/llvm/utils/TableGen/X86EVEX2VEXTablesEmitter.cpp @@ -11,11 +11,14 @@ /// //===----------------------------------------------------------------------===// +#include "CodeGenInstruction.h" #include "CodeGenTarget.h" +#include "X86RecognizableInstr.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/TableGenBackend.h" using namespace llvm; +using namespace X86Disassembler; namespace { @@ -108,28 +111,25 @@ public: IsMatch(const CodeGenInstruction *EVEXInst) : EVEXInst(EVEXInst) {} bool operator()(const CodeGenInstruction *VEXInst) { - Record *RecE = EVEXInst->TheDef; - Record *RecV = VEXInst->TheDef; - bool EVEX_W = RecE->getValueAsBit("HasVEX_W"); - bool VEX_W = RecV->getValueAsBit("HasVEX_W"); - bool VEX_WIG = RecV->getValueAsBit("IgnoresVEX_W"); - bool EVEX_WIG = RecE->getValueAsBit("IgnoresVEX_W"); - bool EVEX_W1_VEX_W0 = RecE->getValueAsBit("EVEX_W1_VEX_W0"); + RecognizableInstrBase VEXRI(*VEXInst); + RecognizableInstrBase EVEXRI(*EVEXInst); + bool VEX_W = VEXRI.HasVEX_W; + bool EVEX_W = EVEXRI.HasVEX_W; + bool VEX_WIG = VEXRI.IgnoresVEX_W; + bool EVEX_WIG = EVEXRI.IgnoresVEX_W; + bool EVEX_W1_VEX_W0 = EVEXInst->TheDef->getValueAsBit("EVEX_W1_VEX_W0"); - if (RecV->getValueAsDef("OpEnc")->getName().str() != "EncVEX" || - RecV->getValueAsBit("isCodeGenOnly") != RecE->getValueAsBit("isCodeGenOnly") || + if (VEXRI.IsCodeGenOnly != EVEXRI.IsCodeGenOnly || // VEX/EVEX fields - RecV->getValueAsDef("OpPrefix") != RecE->getValueAsDef("OpPrefix") || - RecV->getValueAsDef("OpMap") != RecE->getValueAsDef("OpMap") || - RecV->getValueAsBit("hasVEX_4V") != RecE->getValueAsBit("hasVEX_4V") || - RecV->getValueAsBit("hasEVEX_L2") != RecE->getValueAsBit("hasEVEX_L2") || - RecV->getValueAsBit("hasVEX_L") != RecE->getValueAsBit("hasVEX_L") || + VEXRI.OpPrefix != EVEXRI.OpPrefix || VEXRI.OpMap != EVEXRI.OpMap || + VEXRI.HasVEX_4V != EVEXRI.HasVEX_4V || + VEXRI.HasVEX_L != EVEXRI.HasVEX_L || // Match is allowed if either is VEX_WIG, or they match, or EVEX // is VEX_W1X and VEX is VEX_W0. (!(VEX_WIG || (!EVEX_WIG && EVEX_W == VEX_W) || (EVEX_W1_VEX_W0 && EVEX_W && !VEX_W))) || // Instruction's format - RecV->getValueAsDef("Form") != RecE->getValueAsDef("Form")) + VEXRI.Form != EVEXRI.Form) return false; // This is needed for instructions with intrinsic version (_Int). @@ -160,31 +160,6 @@ public: return true; } - -private: - static inline bool isRegisterOperand(const Record *Rec) { - return Rec->isSubClassOf("RegisterClass") || - Rec->isSubClassOf("RegisterOperand"); - } - - static inline bool isMemoryOperand(const Record *Rec) { - return Rec->isSubClassOf("Operand") && - Rec->getValueAsString("OperandType") == "OPERAND_MEMORY"; - } - - static inline bool isImmediateOperand(const Record *Rec) { - return Rec->isSubClassOf("Operand") && - Rec->getValueAsString("OperandType") == "OPERAND_IMMEDIATE"; - } - - static inline unsigned int getRegOperandSize(const Record *RegRec) { - if (RegRec->isSubClassOf("RegisterClass")) - return RegRec->getValueAsInt("Alignment"); - if (RegRec->isSubClassOf("RegisterOperand")) - return RegRec->getValueAsDef("RegClass")->getValueAsInt("Alignment"); - - llvm_unreachable("Register operand's size not known!"); - } }; void X86EVEX2VEXTablesEmitter::run(raw_ostream &OS) { @@ -206,23 +181,19 @@ void X86EVEX2VEXTablesEmitter::run(raw_ostream &OS) { Target.getInstructionsByEnumValue(); for (const CodeGenInstruction *Inst : NumberedInstructions) { + const Record *Def = Inst->TheDef; // Filter non-X86 instructions. - if (!Inst->TheDef->isSubClassOf("X86Inst")) + if (!Def->isSubClassOf("X86Inst")) continue; + RecognizableInstrBase RI(*Inst); // Add VEX encoded instructions to one of VEXInsts vectors according to // it's opcode. - if (Inst->TheDef->getValueAsDef("OpEnc")->getName() == "EncVEX") { - uint64_t Opcode = getValueFromBitsInit(Inst->TheDef-> - getValueAsBitsInit("Opcode")); - VEXInsts[Opcode].push_back(Inst); - } + if (RI.Encoding == X86Local::VEX) + VEXInsts[RI.Opcode].push_back(Inst); // Add relevant EVEX encoded instructions to EVEXInsts - else if (Inst->TheDef->getValueAsDef("OpEnc")->getName() == "EncEVEX" && - !Inst->TheDef->getValueAsBit("hasEVEX_K") && - !Inst->TheDef->getValueAsBit("hasEVEX_B") && - !Inst->TheDef->getValueAsBit("hasEVEX_L2") && - !Inst->TheDef->getValueAsBit("notEVEX2VEXConvertible")) + else if (RI.Encoding == X86Local::EVEX && !RI.HasEVEX_K && !RI.HasEVEX_B && + !RI.HasEVEX_L2 && !Def->getValueAsBit("notEVEX2VEXConvertible")) EVEXInsts.push_back(Inst); } diff --git a/llvm/utils/TableGen/X86FoldTablesEmitter.cpp b/llvm/utils/TableGen/X86FoldTablesEmitter.cpp index 2a29331eb7e8..5b3f11848de6 100644 --- a/llvm/utils/TableGen/X86FoldTablesEmitter.cpp +++ b/llvm/utils/TableGen/X86FoldTablesEmitter.cpp @@ -18,6 +18,7 @@ #include "llvm/TableGen/TableGenBackend.h" using namespace llvm; +using namespace X86Disassembler; namespace { @@ -51,27 +52,32 @@ const char *ExplicitUnalign[] = {"MOVDQU", "MOVUPS", "MOVUPD", // For manually mapping instructions that do not match by their encoding. const ManualMapEntry ManualMapSet[] = { - { "ADD16ri_DB", "ADD16mi", NO_UNFOLD }, - { "ADD16ri8_DB", "ADD16mi8", NO_UNFOLD }, - { "ADD16rr_DB", "ADD16mr", NO_UNFOLD }, - { "ADD32ri_DB", "ADD32mi", NO_UNFOLD }, - { "ADD32ri8_DB", "ADD32mi8", NO_UNFOLD }, - { "ADD32rr_DB", "ADD32mr", NO_UNFOLD }, - { "ADD64ri32_DB", "ADD64mi32", NO_UNFOLD }, - { "ADD64ri8_DB", "ADD64mi8", NO_UNFOLD }, - { "ADD64rr_DB", "ADD64mr", NO_UNFOLD }, - { "ADD8ri_DB", "ADD8mi", NO_UNFOLD }, - { "ADD8rr_DB", "ADD8mr", NO_UNFOLD }, - { "ADD16rr_DB", "ADD16rm", NO_UNFOLD }, - { "ADD32rr_DB", "ADD32rm", NO_UNFOLD }, - { "ADD64rr_DB", "ADD64rm", NO_UNFOLD }, - { "ADD8rr_DB", "ADD8rm", NO_UNFOLD }, - { "PUSH16r", "PUSH16rmm", UNFOLD }, - { "PUSH32r", "PUSH32rmm", UNFOLD }, - { "PUSH64r", "PUSH64rmm", UNFOLD }, - { "TAILJMPr", "TAILJMPm", UNFOLD }, - { "TAILJMPr64", "TAILJMPm64", UNFOLD }, - { "TAILJMPr64_REX", "TAILJMPm64_REX", UNFOLD }, + { "ADD16ri_DB", "ADD16mi", NO_UNFOLD }, + { "ADD16ri8_DB", "ADD16mi8", NO_UNFOLD }, + { "ADD16rr_DB", "ADD16mr", NO_UNFOLD }, + { "ADD32ri_DB", "ADD32mi", NO_UNFOLD }, + { "ADD32ri8_DB", "ADD32mi8", NO_UNFOLD }, + { "ADD32rr_DB", "ADD32mr", NO_UNFOLD }, + { "ADD64ri32_DB", "ADD64mi32", NO_UNFOLD }, + { "ADD64ri8_DB", "ADD64mi8", NO_UNFOLD }, + { "ADD64rr_DB", "ADD64mr", NO_UNFOLD }, + { "ADD8ri_DB", "ADD8mi", NO_UNFOLD }, + { "ADD8rr_DB", "ADD8mr", NO_UNFOLD }, + { "ADD16rr_DB", "ADD16rm", NO_UNFOLD }, + { "ADD32rr_DB", "ADD32rm", NO_UNFOLD }, + { "ADD64rr_DB", "ADD64rm", NO_UNFOLD }, + { "ADD8rr_DB", "ADD8rm", NO_UNFOLD }, + { "MMX_MOVD64from64rr", "MMX_MOVQ64mr", UNFOLD }, + { "MMX_MOVD64grr", "MMX_MOVD64mr", UNFOLD }, + { "MOVLHPSrr", "MOVHPSrm", NO_UNFOLD }, + { "PUSH16r", "PUSH16rmm", UNFOLD }, + { "PUSH32r", "PUSH32rmm", UNFOLD }, + { "PUSH64r", "PUSH64rmm", UNFOLD }, + { "TAILJMPr", "TAILJMPm", UNFOLD }, + { "TAILJMPr64", "TAILJMPm64", UNFOLD }, + { "TAILJMPr64_REX", "TAILJMPm64_REX", UNFOLD }, + { "VMOVLHPSZrr", "VMOVHPSZ128rm", NO_UNFOLD }, + { "VMOVLHPSrr", "VMOVHPSrm", NO_UNFOLD }, }; @@ -114,16 +120,21 @@ class X86FoldTablesEmitter { OS << "X86::" << MemInst->TheDef->getName() << ","; OS.PadToColumn(75); + std::string Attrs; if (IsLoad) - OS << "TB_FOLDED_LOAD | "; + Attrs += "TB_FOLDED_LOAD | "; if (IsStore) - OS << "TB_FOLDED_STORE | "; + Attrs += "TB_FOLDED_STORE | "; if (CannotUnfold) - OS << "TB_NO_REVERSE | "; + Attrs += "TB_NO_REVERSE | "; if (IsAligned) - OS << "TB_ALIGN_" << Alignment << " | "; + Attrs += "TB_ALIGN_" + std::to_string(Alignment) + " | "; - OS << "0 },\n"; + StringRef SimplifiedAttrs = StringRef(Attrs).rtrim("| "); + if (SimplifiedAttrs.empty()) + SimplifiedAttrs = "0"; + + OS << SimplifiedAttrs << " },\n"; } bool operator<(const X86FoldTableEntry &RHS) const { @@ -207,56 +218,6 @@ static inline uint64_t getValueFromBitsInit(const BitsInit *B) { return Value; } -// Returns true if the two given BitsInits represent the same integer value -static inline bool equalBitsInits(const BitsInit *B1, const BitsInit *B2) { - if (B1->getNumBits() != B2->getNumBits()) - PrintFatalError("Comparing two BitsInits with different sizes!"); - - for (unsigned i = 0, e = B1->getNumBits(); i != e; ++i) { - BitInit *Bit1 = cast<BitInit>(B1->getBit(i)); - BitInit *Bit2 = cast<BitInit>(B2->getBit(i)); - if (Bit1->getValue() != Bit2->getValue()) - return false; - } - return true; -} - -// Return the size of the register operand -static inline unsigned int getRegOperandSize(const Record *RegRec) { - if (RegRec->isSubClassOf("RegisterOperand")) - RegRec = RegRec->getValueAsDef("RegClass"); - if (RegRec->isSubClassOf("RegisterClass")) - return RegRec->getValueAsListOfDefs("RegTypes")[0]->getValueAsInt("Size"); - - llvm_unreachable("Register operand's size not known!"); -} - -// Return the size of the memory operand -static inline unsigned getMemOperandSize(const Record *MemRec) { - if (MemRec->isSubClassOf("Operand")) { - StringRef Name = - MemRec->getValueAsDef("ParserMatchClass")->getValueAsString("Name"); - if (Name == "Mem8") - return 8; - if (Name == "Mem16") - return 16; - if (Name == "Mem32") - return 32; - if (Name == "Mem64") - return 64; - if (Name == "Mem80") - return 80; - if (Name == "Mem128") - return 128; - if (Name == "Mem256") - return 256; - if (Name == "Mem512") - return 512; - } - - llvm_unreachable("Memory operand's size not known!"); -} - // Return true if the instruction defined as a register flavor. static inline bool hasRegisterFormat(const Record *Inst) { const BitsInit *FormBits = Inst->getValueAsBitsInit("FormBits"); @@ -279,22 +240,6 @@ static inline bool isNOREXRegClass(const Record *Op) { return Op->getName().contains("_NOREX"); } -static inline bool isRegisterOperand(const Record *Rec) { - return Rec->isSubClassOf("RegisterClass") || - Rec->isSubClassOf("RegisterOperand") || - Rec->isSubClassOf("PointerLikeRegClass"); -} - -static inline bool isMemoryOperand(const Record *Rec) { - return Rec->isSubClassOf("Operand") && - Rec->getValueAsString("OperandType") == "OPERAND_MEMORY"; -} - -static inline bool isImmediateOperand(const Record *Rec) { - return Rec->isSubClassOf("Operand") && - Rec->getValueAsString("OperandType") == "OPERAND_IMMEDIATE"; -} - // Get the alternative instruction pointed by "FoldGenRegForm" field. static inline const CodeGenInstruction * getAltRegInst(const CodeGenInstruction *I, const RecordKeeper &Records, @@ -312,61 +257,59 @@ getAltRegInst(const CodeGenInstruction *I, const RecordKeeper &Records, // matches the EVEX instruction of this object. class IsMatch { const CodeGenInstruction *MemInst; + unsigned Variant; public: - IsMatch(const CodeGenInstruction *Inst, const RecordKeeper &Records) - : MemInst(Inst) {} + IsMatch(const CodeGenInstruction *Inst, unsigned V) + : MemInst(Inst), Variant(V) {} bool operator()(const CodeGenInstruction *RegInst) { - Record *MemRec = MemInst->TheDef; - Record *RegRec = RegInst->TheDef; + X86Disassembler::RecognizableInstrBase RegRI(*RegInst); + X86Disassembler::RecognizableInstrBase MemRI(*MemInst); + const Record *RegRec = RegInst->TheDef; + const Record *MemRec = MemInst->TheDef; + + // EVEX_B means different things for memory and register forms. + if (RegRI.HasEVEX_B != 0 || MemRI.HasEVEX_B != 0) + return false; + + // Instruction's format - The register form's "Form" field should be + // the opposite of the memory form's "Form" field. + if (!areOppositeForms(RegRI.Form, MemRI.Form)) + return false; + + // X86 encoding is crazy, e.g + // + // f3 0f c7 30 vmxon (%rax) + // f3 0f c7 f0 senduipi %rax + // + // This two instruction have similiar encoding fields but are unrelated + if (X86Disassembler::getMnemonic(MemInst, Variant) != + X86Disassembler::getMnemonic(RegInst, Variant)) + return false; // Return false if one (at least) of the encoding fields of both // instructions do not match. - if (RegRec->getValueAsDef("OpEnc") != MemRec->getValueAsDef("OpEnc") || - !equalBitsInits(RegRec->getValueAsBitsInit("Opcode"), - MemRec->getValueAsBitsInit("Opcode")) || - // VEX/EVEX fields - RegRec->getValueAsDef("OpPrefix") != - MemRec->getValueAsDef("OpPrefix") || - RegRec->getValueAsDef("OpMap") != MemRec->getValueAsDef("OpMap") || - RegRec->getValueAsDef("OpSize") != MemRec->getValueAsDef("OpSize") || - RegRec->getValueAsDef("AdSize") != MemRec->getValueAsDef("AdSize") || - RegRec->getValueAsBit("hasVEX_4V") != - MemRec->getValueAsBit("hasVEX_4V") || - RegRec->getValueAsBit("hasEVEX_K") != - MemRec->getValueAsBit("hasEVEX_K") || - RegRec->getValueAsBit("hasEVEX_Z") != - MemRec->getValueAsBit("hasEVEX_Z") || - // EVEX_B means different things for memory and register forms. - RegRec->getValueAsBit("hasEVEX_B") != 0 || - MemRec->getValueAsBit("hasEVEX_B") != 0 || + if (RegRI.Encoding != MemRI.Encoding || RegRI.Opcode != MemRI.Opcode || + RegRI.OpPrefix != MemRI.OpPrefix || RegRI.OpMap != MemRI.OpMap || + RegRI.OpSize != MemRI.OpSize || RegRI.AdSize != MemRI.AdSize || + RegRI.HasREX_W != MemRI.HasREX_W || + RegRI.HasVEX_4V != MemRI.HasVEX_4V || + RegRI.HasVEX_L != MemRI.HasVEX_L || + RegRI.HasVEX_W != MemRI.HasVEX_W || + RegRI.IgnoresVEX_L != MemRI.IgnoresVEX_L || + RegRI.IgnoresVEX_W != MemRI.IgnoresVEX_W || + RegRI.HasEVEX_K != MemRI.HasEVEX_K || + RegRI.HasEVEX_KZ != MemRI.HasEVEX_KZ || + RegRI.HasEVEX_L2 != MemRI.HasEVEX_L2 || RegRec->getValueAsBit("hasEVEX_RC") != MemRec->getValueAsBit("hasEVEX_RC") || - RegRec->getValueAsBit("hasREX_WPrefix") != - MemRec->getValueAsBit("hasREX_WPrefix") || RegRec->getValueAsBit("hasLockPrefix") != MemRec->getValueAsBit("hasLockPrefix") || RegRec->getValueAsBit("hasNoTrackPrefix") != MemRec->getValueAsBit("hasNoTrackPrefix") || - RegRec->getValueAsBit("hasVEX_L") != - MemRec->getValueAsBit("hasVEX_L") || - RegRec->getValueAsBit("hasEVEX_L2") != - MemRec->getValueAsBit("hasEVEX_L2") || - RegRec->getValueAsBit("ignoresVEX_L") != - MemRec->getValueAsBit("ignoresVEX_L") || - RegRec->getValueAsBit("HasVEX_W") != - MemRec->getValueAsBit("HasVEX_W") || - RegRec->getValueAsBit("IgnoresVEX_W") != - MemRec->getValueAsBit("IgnoresVEX_W") || RegRec->getValueAsBit("EVEX_W1_VEX_W0") != - MemRec->getValueAsBit("EVEX_W1_VEX_W0") || - // Instruction's format - The register form's "Form" field should be - // the opposite of the memory form's "Form" field. - !areOppositeForms(RegRec->getValueAsBitsInit("FormBits"), - MemRec->getValueAsBitsInit("FormBits")) || - RegRec->getValueAsBit("isAsmParserOnly") != - MemRec->getValueAsBit("isAsmParserOnly")) + MemRec->getValueAsBit("EVEX_W1_VEX_W0")) return false; // Make sure the sizes of the operands of both instructions suit each other. @@ -419,31 +362,24 @@ public: private: // Return true of the 2 given forms are the opposite of each other. - bool areOppositeForms(const BitsInit *RegFormBits, - const BitsInit *MemFormBits) { - uint64_t MemFormNum = getValueFromBitsInit(MemFormBits); - uint64_t RegFormNum = getValueFromBitsInit(RegFormBits); - - if ((MemFormNum == X86Local::MRM0m && RegFormNum == X86Local::MRM0r) || - (MemFormNum == X86Local::MRM1m && RegFormNum == X86Local::MRM1r) || - (MemFormNum == X86Local::MRM2m && RegFormNum == X86Local::MRM2r) || - (MemFormNum == X86Local::MRM3m && RegFormNum == X86Local::MRM3r) || - (MemFormNum == X86Local::MRM4m && RegFormNum == X86Local::MRM4r) || - (MemFormNum == X86Local::MRM5m && RegFormNum == X86Local::MRM5r) || - (MemFormNum == X86Local::MRM6m && RegFormNum == X86Local::MRM6r) || - (MemFormNum == X86Local::MRM7m && RegFormNum == X86Local::MRM7r) || - (MemFormNum == X86Local::MRMXm && RegFormNum == X86Local::MRMXr) || - (MemFormNum == X86Local::MRMXmCC && RegFormNum == X86Local::MRMXrCC) || - (MemFormNum == X86Local::MRMDestMem && - RegFormNum == X86Local::MRMDestReg) || - (MemFormNum == X86Local::MRMSrcMem && - RegFormNum == X86Local::MRMSrcReg) || - (MemFormNum == X86Local::MRMSrcMem4VOp3 && - RegFormNum == X86Local::MRMSrcReg4VOp3) || - (MemFormNum == X86Local::MRMSrcMemOp4 && - RegFormNum == X86Local::MRMSrcRegOp4) || - (MemFormNum == X86Local::MRMSrcMemCC && - RegFormNum == X86Local::MRMSrcRegCC)) + bool areOppositeForms(unsigned RegForm, unsigned MemForm) { + if ((MemForm == X86Local::MRM0m && RegForm == X86Local::MRM0r) || + (MemForm == X86Local::MRM1m && RegForm == X86Local::MRM1r) || + (MemForm == X86Local::MRM2m && RegForm == X86Local::MRM2r) || + (MemForm == X86Local::MRM3m && RegForm == X86Local::MRM3r) || + (MemForm == X86Local::MRM4m && RegForm == X86Local::MRM4r) || + (MemForm == X86Local::MRM5m && RegForm == X86Local::MRM5r) || + (MemForm == X86Local::MRM6m && RegForm == X86Local::MRM6r) || + (MemForm == X86Local::MRM7m && RegForm == X86Local::MRM7r) || + (MemForm == X86Local::MRMXm && RegForm == X86Local::MRMXr) || + (MemForm == X86Local::MRMXmCC && RegForm == X86Local::MRMXrCC) || + (MemForm == X86Local::MRMDestMem && RegForm == X86Local::MRMDestReg) || + (MemForm == X86Local::MRMSrcMem && RegForm == X86Local::MRMSrcReg) || + (MemForm == X86Local::MRMSrcMem4VOp3 && + RegForm == X86Local::MRMSrcReg4VOp3) || + (MemForm == X86Local::MRMSrcMemOp4 && + RegForm == X86Local::MRMSrcRegOp4) || + (MemForm == X86Local::MRMSrcMemCC && RegForm == X86Local::MRMSrcRegCC)) return true; return false; @@ -535,7 +471,10 @@ void X86FoldTablesEmitter::updateTables(const CodeGenInstruction *RegInstr, for (unsigned i = RegOutSize, e = RegInstr->Operands.size(); i < e; i++) { Record *RegOpRec = RegInstr->Operands[i].Rec; Record *MemOpRec = MemInstr->Operands[i].Rec; - if (isRegisterOperand(RegOpRec) && isMemoryOperand(MemOpRec)) { + // PointerLikeRegClass: For instructions like TAILJMPr, TAILJMPr64, TAILJMPr64_REX + if ((isRegisterOperand(RegOpRec) || + RegOpRec->isSubClassOf("PointerLikeRegClass")) && + isMemoryOperand(MemOpRec)) { switch (i) { case 0: addEntryWithFlags(Table0, RegInstr, MemInstr, S, 0); @@ -583,10 +522,9 @@ void X86FoldTablesEmitter::run(formatted_raw_ostream &OS) { Target.getInstructionsByEnumValue(); for (const CodeGenInstruction *Inst : NumberedInstructions) { - if (!Inst->TheDef->getNameInit() || !Inst->TheDef->isSubClassOf("X86Inst")) - continue; - const Record *Rec = Inst->TheDef; + if (!Rec->isSubClassOf("X86Inst") || Rec->getValueAsBit("isAsmParserOnly")) + continue; // - Do not proceed if the instruction is marked as notMemoryFoldable. // - Instructions including RST register class operands are not relevant @@ -611,6 +549,8 @@ void X86FoldTablesEmitter::run(formatted_raw_ostream &OS) { } } + Record *AsmWriter = Target.getAsmWriter(); + unsigned Variant = AsmWriter->getValueAsInt("Variant"); // For each memory form instruction, try to find its register form // instruction. for (const CodeGenInstruction *MemInst : MemInsts) { @@ -626,7 +566,7 @@ void X86FoldTablesEmitter::run(formatted_raw_ostream &OS) { // opcode. std::vector<const CodeGenInstruction *> &OpcRegInsts = RegInstsIt->second; - auto Match = find_if(OpcRegInsts, IsMatch(MemInst, Records)); + auto Match = find_if(OpcRegInsts, IsMatch(MemInst, Variant)); if (Match != OpcRegInsts.end()) { const CodeGenInstruction *RegInst = *Match; // If the matched instruction has it's "FoldGenRegForm" set, map the diff --git a/llvm/utils/TableGen/X86MnemonicTables.cpp b/llvm/utils/TableGen/X86MnemonicTables.cpp new file mode 100644 index 000000000000..f405e051e355 --- /dev/null +++ b/llvm/utils/TableGen/X86MnemonicTables.cpp @@ -0,0 +1,94 @@ +//==- X86MnemonicTables.cpp - Generate mnemonic extraction tables. -*- 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 +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend is responsible for emitting tables that group +// instructions by their mnemonic name wrt AsmWriter Variant (e.g. isADD, etc). +// +//===----------------------------------------------------------------------===// + +#include "CodeGenInstruction.h" +#include "CodeGenTarget.h" +#include "X86RecognizableInstr.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/TableGenBackend.h" + +using namespace llvm; + +namespace { + +class X86MnemonicTablesEmitter { + CodeGenTarget Target; + +public: + X86MnemonicTablesEmitter(RecordKeeper &R) : Target(R) {} + + // Output X86 mnemonic tables. + void run(raw_ostream &OS); +}; + +void X86MnemonicTablesEmitter::run(raw_ostream &OS) { + emitSourceFileHeader("X86 Mnemonic tables", OS); + OS << "namespace llvm {\nnamespace X86 {\n\n"; + Record *AsmWriter = Target.getAsmWriter(); + unsigned Variant = AsmWriter->getValueAsInt("Variant"); + + // Hold all instructions grouped by mnemonic + StringMap<SmallVector<const CodeGenInstruction *, 0>> MnemonicToCGInstrMap; + + ArrayRef<const CodeGenInstruction *> NumberedInstructions = + Target.getInstructionsByEnumValue(); + for (const CodeGenInstruction *I : NumberedInstructions) { + const Record *Def = I->TheDef; + // Filter non-X86 instructions. + if (!Def->isSubClassOf("X86Inst")) + continue; + X86Disassembler::RecognizableInstrBase RI(*I); + if (!RI.shouldBeEmitted()) + continue; + if ( // Non-parsable instruction defs contain prefix as part of AsmString + Def->getValueAsString("AsmVariantName") == "NonParsable" || + // Skip prefix byte + RI.Form == X86Local::PrefixByte) + continue; + std::string Mnemonic = X86Disassembler::getMnemonic(I, Variant); + MnemonicToCGInstrMap[Mnemonic].push_back(I); + } + + OS << "#ifdef GET_X86_MNEMONIC_TABLES_H\n"; + OS << "#undef GET_X86_MNEMONIC_TABLES_H\n\n"; + for (StringRef Mnemonic : MnemonicToCGInstrMap.keys()) + OS << "bool is" << Mnemonic << "(unsigned Opcode);\n"; + OS << "#endif // GET_X86_MNEMONIC_TABLES_H\n\n"; + + OS << "#ifdef GET_X86_MNEMONIC_TABLES_CPP\n"; + OS << "#undef GET_X86_MNEMONIC_TABLES_CPP\n\n"; + for (StringRef Mnemonic : MnemonicToCGInstrMap.keys()) { + OS << "bool is" << Mnemonic << "(unsigned Opcode) {\n"; + auto Mnemonics = MnemonicToCGInstrMap[Mnemonic]; + if (Mnemonics.size() == 1) { + const CodeGenInstruction *CGI = *Mnemonics.begin(); + OS << "\treturn Opcode == " << CGI->TheDef->getName() << ";\n}\n\n"; + } else { + OS << "\tswitch (Opcode) {\n"; + for (const CodeGenInstruction *CGI : Mnemonics) { + OS << "\tcase " << CGI->TheDef->getName() << ":\n"; + } + OS << "\t\treturn true;\n\t}\n\treturn false;\n}\n\n"; + } + } + OS << "#endif // GET_X86_MNEMONIC_TABLES_CPP\n\n"; + OS << "} // end namespace X86\n} // end namespace llvm"; +} + +} // namespace + +namespace llvm { +void EmitX86MnemonicTables(RecordKeeper &RK, raw_ostream &OS) { + X86MnemonicTablesEmitter(RK).run(OS); +} +} // namespace llvm diff --git a/llvm/utils/TableGen/X86RecognizableInstr.cpp b/llvm/utils/TableGen/X86RecognizableInstr.cpp index 4023d8f57318..9afde66fe6f3 100644 --- a/llvm/utils/TableGen/X86RecognizableInstr.cpp +++ b/llvm/utils/TableGen/X86RecognizableInstr.cpp @@ -24,6 +24,51 @@ using namespace llvm; using namespace X86Disassembler; +std::string X86Disassembler::getMnemonic(const CodeGenInstruction *I, unsigned Variant) { + std::string AsmString = I->FlattenAsmStringVariants(I->AsmString, Variant); + StringRef Mnemonic(AsmString); + // Extract a mnemonic assuming it's separated by \t + Mnemonic = Mnemonic.take_until([](char C) { return C == '\t'; }); + + // Special case: CMOVCC, JCC, SETCC have "${cond}" in mnemonic. + // Replace it with "CC" in-place. + size_t CondPos = Mnemonic.find("${cond}"); + if (CondPos != StringRef::npos) + Mnemonic = AsmString.replace(CondPos, StringRef::npos, "CC"); + return Mnemonic.upper(); +} + +bool X86Disassembler::isRegisterOperand(const Record *Rec) { + return Rec->isSubClassOf("RegisterClass") || + Rec->isSubClassOf("RegisterOperand"); +} + +bool X86Disassembler::isMemoryOperand(const Record *Rec) { + return Rec->isSubClassOf("Operand") && + Rec->getValueAsString("OperandType") == "OPERAND_MEMORY"; +} + +bool X86Disassembler::isImmediateOperand(const Record *Rec) { + return Rec->isSubClassOf("Operand") && + Rec->getValueAsString("OperandType") == "OPERAND_IMMEDIATE"; +} + +unsigned X86Disassembler::getRegOperandSize(const Record *RegRec) { + if (RegRec->isSubClassOf("RegisterClass")) + return RegRec->getValueAsInt("Alignment"); + if (RegRec->isSubClassOf("RegisterOperand")) + return RegRec->getValueAsDef("RegClass")->getValueAsInt("Alignment"); + + llvm_unreachable("Register operand's size not known!"); +} + +unsigned X86Disassembler::getMemOperandSize(const Record *MemRec) { + if (MemRec->isSubClassOf("X86MemOperand")) + return MemRec->getValueAsInt("Size"); + + llvm_unreachable("Memory operand's size not known!"); +} + /// byteFromBitsInit - Extracts a value at most 8 bits in width from a BitsInit. /// Useful for switch statements and the like. /// @@ -61,55 +106,49 @@ static uint8_t byteFromRec(const Record* rec, StringRef name) { return byteFromBitsInit(*bits); } -RecognizableInstr::RecognizableInstr(DisassemblerTables &tables, - const CodeGenInstruction &insn, - InstrUID uid) { - UID = uid; - - Rec = insn.TheDef; - Name = std::string(Rec->getName()); - Spec = &tables.specForUID(UID); - - if (!Rec->isSubClassOf("X86Inst")) { - ShouldBeEmitted = false; - return; - } - +RecognizableInstrBase::RecognizableInstrBase(const CodeGenInstruction &insn) { + const Record *Rec = insn.TheDef; + assert(Rec->isSubClassOf("X86Inst") && "Not a X86 Instruction"); OpPrefix = byteFromRec(Rec, "OpPrefixBits"); - OpMap = byteFromRec(Rec, "OpMapBits"); - Opcode = byteFromRec(Rec, "Opcode"); - Form = byteFromRec(Rec, "FormBits"); + OpMap = byteFromRec(Rec, "OpMapBits"); + Opcode = byteFromRec(Rec, "Opcode"); + Form = byteFromRec(Rec, "FormBits"); Encoding = byteFromRec(Rec, "OpEncBits"); - - OpSize = byteFromRec(Rec, "OpSizeBits"); - AdSize = byteFromRec(Rec, "AdSizeBits"); - HasREX_WPrefix = Rec->getValueAsBit("hasREX_WPrefix"); - HasVEX_4V = Rec->getValueAsBit("hasVEX_4V"); - HasVEX_W = Rec->getValueAsBit("HasVEX_W"); - IgnoresVEX_W = Rec->getValueAsBit("IgnoresVEX_W"); - IgnoresVEX_L = Rec->getValueAsBit("ignoresVEX_L"); - HasEVEX_L2Prefix = Rec->getValueAsBit("hasEVEX_L2"); - HasEVEX_K = Rec->getValueAsBit("hasEVEX_K"); - HasEVEX_KZ = Rec->getValueAsBit("hasEVEX_Z"); - HasEVEX_B = Rec->getValueAsBit("hasEVEX_B"); - IsCodeGenOnly = Rec->getValueAsBit("isCodeGenOnly"); - ForceDisassemble = Rec->getValueAsBit("ForceDisassemble"); - CD8_Scale = byteFromRec(Rec, "CD8_Scale"); - - Name = std::string(Rec->getName()); - - Operands = &insn.Operands.OperandList; - - HasVEX_LPrefix = Rec->getValueAsBit("hasVEX_L"); + OpSize = byteFromRec(Rec, "OpSizeBits"); + AdSize = byteFromRec(Rec, "AdSizeBits"); + HasREX_W = Rec->getValueAsBit("hasREX_W"); + HasVEX_4V = Rec->getValueAsBit("hasVEX_4V"); + HasVEX_W = Rec->getValueAsBit("HasVEX_W"); + IgnoresVEX_W = Rec->getValueAsBit("IgnoresVEX_W"); + IgnoresVEX_L = Rec->getValueAsBit("ignoresVEX_L"); + HasEVEX_L2 = Rec->getValueAsBit("hasEVEX_L2"); + HasEVEX_K = Rec->getValueAsBit("hasEVEX_K"); + HasEVEX_KZ = Rec->getValueAsBit("hasEVEX_Z"); + HasEVEX_B = Rec->getValueAsBit("hasEVEX_B"); + IsCodeGenOnly = Rec->getValueAsBit("isCodeGenOnly"); + IsAsmParserOnly = Rec->getValueAsBit("isAsmParserOnly"); + ForceDisassemble = Rec->getValueAsBit("ForceDisassemble"); + CD8_Scale = byteFromRec(Rec, "CD8_Scale"); + HasVEX_L = Rec->getValueAsBit("hasVEX_L"); EncodeRC = HasEVEX_B && (Form == X86Local::MRMDestReg || Form == X86Local::MRMSrcReg); +} + +bool RecognizableInstrBase::shouldBeEmitted() const { + return Form != X86Local::Pseudo && (!IsCodeGenOnly || ForceDisassemble) && + !IsAsmParserOnly; +} +RecognizableInstr::RecognizableInstr(DisassemblerTables &tables, + const CodeGenInstruction &insn, + InstrUID uid) + : RecognizableInstrBase(insn), Rec(insn.TheDef), Name(Rec->getName().str()), + Is32Bit(false), Is64Bit(false), Operands(&insn.Operands.OperandList), + UID(uid), Spec(&tables.specForUID(uid)) { // Check for 64-bit inst which does not require REX - Is32Bit = false; - Is64Bit = false; // FIXME: Is there some better way to check for In64BitMode? - std::vector<Record*> Predicates = Rec->getValueAsListOfDefs("Predicates"); + std::vector<Record *> Predicates = Rec->getValueAsListOfDefs("Predicates"); for (unsigned i = 0, e = Predicates.size(); i != e; ++i) { if (Predicates[i]->getName().contains("Not64Bit") || Predicates[i]->getName().contains("In32Bit")) { @@ -121,29 +160,19 @@ RecognizableInstr::RecognizableInstr(DisassemblerTables &tables, break; } } - - if (Form == X86Local::Pseudo || (IsCodeGenOnly && !ForceDisassemble)) { - ShouldBeEmitted = false; - return; - } - - ShouldBeEmitted = true; } void RecognizableInstr::processInstr(DisassemblerTables &tables, const CodeGenInstruction &insn, - InstrUID uid) -{ - // Ignore "asm parser only" instructions. - if (insn.TheDef->getValueAsBit("isAsmParserOnly")) + InstrUID uid) { + if (!insn.TheDef->isSubClassOf("X86Inst")) return; - RecognizableInstr recogInstr(tables, insn, uid); - if (recogInstr.shouldBeEmitted()) { - recogInstr.emitInstructionSpecifier(); - recogInstr.emitDecodePath(tables); - } + if (!recogInstr.shouldBeEmitted()) + return; + recogInstr.emitInstructionSpecifier(); + recogInstr.emitDecodePath(tables); } #define EVEX_KB(n) (HasEVEX_KZ && HasEVEX_B ? n##_KZ_B : \ @@ -155,12 +184,12 @@ InstructionContext RecognizableInstr::insnContext() const { InstructionContext insnContext; if (Encoding == X86Local::EVEX) { - if (HasVEX_LPrefix && HasEVEX_L2Prefix) { + if (HasVEX_L && HasEVEX_L2) { errs() << "Don't support VEX.L if EVEX_L2 is enabled: " << Name << "\n"; llvm_unreachable("Don't support VEX.L if EVEX_L2 is enabled"); } // VEX_L & VEX_W - if (!EncodeRC && HasVEX_LPrefix && HasVEX_W) { + if (!EncodeRC && HasVEX_L && HasVEX_W) { if (OpPrefix == X86Local::PD) insnContext = EVEX_KB(IC_EVEX_L_W_OPSIZE); else if (OpPrefix == X86Local::XS) @@ -173,7 +202,7 @@ InstructionContext RecognizableInstr::insnContext() const { errs() << "Instruction does not use a prefix: " << Name << "\n"; llvm_unreachable("Invalid prefix"); } - } else if (!EncodeRC && HasVEX_LPrefix) { + } else if (!EncodeRC && HasVEX_L) { // VEX_L if (OpPrefix == X86Local::PD) insnContext = EVEX_KB(IC_EVEX_L_OPSIZE); @@ -187,7 +216,7 @@ InstructionContext RecognizableInstr::insnContext() const { errs() << "Instruction does not use a prefix: " << Name << "\n"; llvm_unreachable("Invalid prefix"); } - } else if (!EncodeRC && HasEVEX_L2Prefix && HasVEX_W) { + } else if (!EncodeRC && HasEVEX_L2 && HasVEX_W) { // EVEX_L2 & VEX_W if (OpPrefix == X86Local::PD) insnContext = EVEX_KB(IC_EVEX_L2_W_OPSIZE); @@ -201,7 +230,7 @@ InstructionContext RecognizableInstr::insnContext() const { errs() << "Instruction does not use a prefix: " << Name << "\n"; llvm_unreachable("Invalid prefix"); } - } else if (!EncodeRC && HasEVEX_L2Prefix) { + } else if (!EncodeRC && HasEVEX_L2) { // EVEX_L2 if (OpPrefix == X86Local::PD) insnContext = EVEX_KB(IC_EVEX_L2_OPSIZE); @@ -246,7 +275,7 @@ InstructionContext RecognizableInstr::insnContext() const { } /// eof EVEX } else if (Encoding == X86Local::VEX || Encoding == X86Local::XOP) { - if (HasVEX_LPrefix && HasVEX_W) { + if (HasVEX_L && HasVEX_W) { if (OpPrefix == X86Local::PD) insnContext = IC_VEX_L_W_OPSIZE; else if (OpPrefix == X86Local::XS) @@ -259,20 +288,15 @@ InstructionContext RecognizableInstr::insnContext() const { errs() << "Instruction does not use a prefix: " << Name << "\n"; llvm_unreachable("Invalid prefix"); } - } else if (OpPrefix == X86Local::PD && HasVEX_LPrefix) + } else if (OpPrefix == X86Local::PD && HasVEX_L) insnContext = IC_VEX_L_OPSIZE; else if (OpPrefix == X86Local::PD && HasVEX_W) insnContext = IC_VEX_W_OPSIZE; - else if (OpPrefix == X86Local::PD && Is64Bit && - AdSize == X86Local::AdSize32) - insnContext = IC_64BIT_VEX_OPSIZE_ADSIZE; - else if (OpPrefix == X86Local::PD && Is64Bit) - insnContext = IC_64BIT_VEX_OPSIZE; else if (OpPrefix == X86Local::PD) insnContext = IC_VEX_OPSIZE; - else if (HasVEX_LPrefix && OpPrefix == X86Local::XS) + else if (HasVEX_L && OpPrefix == X86Local::XS) insnContext = IC_VEX_L_XS; - else if (HasVEX_LPrefix && OpPrefix == X86Local::XD) + else if (HasVEX_L && OpPrefix == X86Local::XD) insnContext = IC_VEX_L_XD; else if (HasVEX_W && OpPrefix == X86Local::XS) insnContext = IC_VEX_W_XS; @@ -280,7 +304,7 @@ InstructionContext RecognizableInstr::insnContext() const { insnContext = IC_VEX_W_XD; else if (HasVEX_W && OpPrefix == X86Local::PS) insnContext = IC_VEX_W; - else if (HasVEX_LPrefix && OpPrefix == X86Local::PS) + else if (HasVEX_L && OpPrefix == X86Local::PS) insnContext = IC_VEX_L; else if (OpPrefix == X86Local::XD) insnContext = IC_VEX_XD; @@ -292,10 +316,10 @@ InstructionContext RecognizableInstr::insnContext() const { errs() << "Instruction does not use a prefix: " << Name << "\n"; llvm_unreachable("Invalid prefix"); } - } else if (Is64Bit || HasREX_WPrefix || AdSize == X86Local::AdSize64) { - if (HasREX_WPrefix && (OpSize == X86Local::OpSize16 || OpPrefix == X86Local::PD)) + } else if (Is64Bit || HasREX_W || AdSize == X86Local::AdSize64) { + if (HasREX_W && (OpSize == X86Local::OpSize16 || OpPrefix == X86Local::PD)) insnContext = IC_64BIT_REXW_OPSIZE; - else if (HasREX_WPrefix && AdSize == X86Local::AdSize32) + else if (HasREX_W && AdSize == X86Local::AdSize32) insnContext = IC_64BIT_REXW_ADSIZE; else if (OpSize == X86Local::OpSize16 && OpPrefix == X86Local::XD) insnContext = IC_64BIT_XD_OPSIZE; @@ -309,15 +333,15 @@ InstructionContext RecognizableInstr::insnContext() const { insnContext = IC_64BIT_OPSIZE; else if (AdSize == X86Local::AdSize32) insnContext = IC_64BIT_ADSIZE; - else if (HasREX_WPrefix && OpPrefix == X86Local::XS) + else if (HasREX_W && OpPrefix == X86Local::XS) insnContext = IC_64BIT_REXW_XS; - else if (HasREX_WPrefix && OpPrefix == X86Local::XD) + else if (HasREX_W && OpPrefix == X86Local::XD) insnContext = IC_64BIT_REXW_XD; else if (OpPrefix == X86Local::XD) insnContext = IC_64BIT_XD; else if (OpPrefix == X86Local::XS) insnContext = IC_64BIT_XS; - else if (HasREX_WPrefix) + else if (HasREX_W) insnContext = IC_64BIT_REXW; else insnContext = IC_64BIT; @@ -392,7 +416,7 @@ void RecognizableInstr::handleOperand(bool optional, unsigned &operandIndex, adjustOperandEncoding(encoding); Spec->operands[operandIndex].encoding = encoding; Spec->operands[operandIndex].type = - typeFromString(std::string(typeName), HasREX_WPrefix, OpSize); + typeFromString(std::string(typeName), HasREX_W, OpSize); ++operandIndex; ++physicalOperandIndex; @@ -835,13 +859,13 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const { if (Form == X86Local::AddRegFrm || Form == X86Local::MRMSrcRegCC || Form == X86Local::MRMSrcMemCC || Form == X86Local::MRMXrCC || Form == X86Local::MRMXmCC || Form == X86Local::AddCCFrm) { - unsigned Count = Form == X86Local::AddRegFrm ? 8 : 16; + uint8_t Count = Form == X86Local::AddRegFrm ? 8 : 16; assert(((opcodeToSet % Count) == 0) && "ADDREG_FRM opcode not aligned"); uint8_t currentOpcode; - for (currentOpcode = opcodeToSet; currentOpcode < opcodeToSet + Count; - ++currentOpcode) + for (currentOpcode = opcodeToSet; + currentOpcode < (uint8_t)(opcodeToSet + Count); ++currentOpcode) tables.setTableFields(*opcodeType, insnContext(), currentOpcode, *filter, UID, Is32Bit, OpPrefix == 0, IgnoresVEX_L || EncodeRC, @@ -857,9 +881,9 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const { #define TYPE(str, type) if (s == str) return type; OperandType RecognizableInstr::typeFromString(const std::string &s, - bool hasREX_WPrefix, + bool hasREX_W, uint8_t OpSize) { - if(hasREX_WPrefix) { + if(hasREX_W) { // For instructions with a REX_W prefix, a declared 32-bit register encoding // is special. TYPE("GR32", TYPE_R32) diff --git a/llvm/utils/TableGen/X86RecognizableInstr.h b/llvm/utils/TableGen/X86RecognizableInstr.h index 8f557d9ee5f5..67aba26a142b 100644 --- a/llvm/utils/TableGen/X86RecognizableInstr.h +++ b/llvm/utils/TableGen/X86RecognizableInstr.h @@ -158,16 +158,8 @@ namespace X86Disassembler { class DisassemblerTables; -/// RecognizableInstr - Encapsulates all information required to decode a single -/// instruction, as extracted from the LLVM instruction tables. Has methods -/// to interpret the information available in the LLVM tables, and to emit the -/// instruction into DisassemblerTables. -class RecognizableInstr { -private: - /// The opcode of the instruction, as used in an MCInst - InstrUID UID; - /// The record from the .td files corresponding to this instruction - const Record* Rec; +/// Extract common fields of a single X86 instruction from a CodeGenInstruction +struct RecognizableInstrBase { /// The OpPrefix field from the record uint8_t OpPrefix; /// The OpMap field from the record @@ -183,20 +175,20 @@ private: uint8_t OpSize; /// The AdSize field from the record uint8_t AdSize; - /// The hasREX_WPrefix field from the record - bool HasREX_WPrefix; + /// The hasREX_W field from the record + bool HasREX_W; /// The hasVEX_4V field from the record bool HasVEX_4V; /// The HasVEX_WPrefix field from the record bool HasVEX_W; /// The IgnoresVEX_W field from the record bool IgnoresVEX_W; - /// Inferred from the operands; indicates whether the L bit in the VEX prefix is set - bool HasVEX_LPrefix; + /// The hasVEX_L field from the record + bool HasVEX_L; /// The ignoreVEX_L field from the record bool IgnoresVEX_L; /// The hasEVEX_L2Prefix field from the record - bool HasEVEX_L2Prefix; + bool HasEVEX_L2; /// The hasEVEX_K field from the record bool HasEVEX_K; /// The hasEVEX_KZ field from the record @@ -207,27 +199,39 @@ private: bool EncodeRC; /// The isCodeGenOnly field from the record bool IsCodeGenOnly; + /// The isAsmParserOnly field from the record + bool IsAsmParserOnly; /// The ForceDisassemble field from the record bool ForceDisassemble; // The CD8_Scale field from the record uint8_t CD8_Scale; - // Whether the instruction has the predicate "In64BitMode" - bool Is64Bit; - // Whether the instruction has the predicate "In32BitMode" - bool Is32Bit; + /// \param insn The CodeGenInstruction to extract information from. + RecognizableInstrBase(const CodeGenInstruction &insn); + /// \returns true if this instruction should be emitted + bool shouldBeEmitted() const; +}; +/// RecognizableInstr - Encapsulates all information required to decode a single +/// instruction, as extracted from the LLVM instruction tables. Has methods +/// to interpret the information available in the LLVM tables, and to emit the +/// instruction into DisassemblerTables. +class RecognizableInstr : public RecognizableInstrBase { +private: + /// The record from the .td files corresponding to this instruction + const Record* Rec; /// The instruction name as listed in the tables std::string Name; - - /// Indicates whether the instruction should be emitted into the decode - /// tables; regardless, it will be emitted into the instruction info table - bool ShouldBeEmitted; - + // Whether the instruction has the predicate "In32BitMode" + bool Is32Bit; + // Whether the instruction has the predicate "In64BitMode" + bool Is64Bit; /// The operands of the instruction, as listed in the CodeGenInstruction. /// They are not one-to-one with operands listed in the MCInst; for example, /// memory operands expand to 5 operands in the MCInst const std::vector<CGIOperandList::OperandInfo>* Operands; + /// The opcode of the instruction, as used in an MCInst + InstrUID UID; /// The description of the instruction that is emitted into the instruction /// info table InstructionSpecifier* Spec; @@ -243,7 +247,7 @@ private: /// /// @param s - The string, as extracted by calling Rec->getName() /// on a CodeGenInstruction::OperandInfo. - /// @param hasREX_WPrefix - Indicates whether the instruction has a REX.W + /// @param hasREX_W - Indicates whether the instruction has a REX.W /// prefix. If it does, 32-bit register operands stay /// 32-bit regardless of the operand size. /// @param OpSize Indicates the operand size of the instruction. @@ -251,7 +255,7 @@ private: /// register sizes keep their size. /// @return - The operand's type. static OperandType typeFromString(const std::string& s, - bool hasREX_WPrefix, uint8_t OpSize); + bool hasREX_W, uint8_t OpSize); /// immediateEncodingFromString - Translates an immediate encoding from the /// string provided in the LLVM tables to an OperandEncoding for use in @@ -314,19 +318,6 @@ private: (const std::string&, uint8_t OpSize)); - /// shouldBeEmitted - Returns the shouldBeEmitted field. Although filter() - /// filters out many instructions, at various points in decoding we - /// determine that the instruction should not actually be decodable. In - /// particular, MMX MOV instructions aren't emitted, but they're only - /// identified during operand parsing. - /// - /// @return - true if at this point we believe the instruction should be - /// emitted; false if not. This will return false if filter() returns false - /// once emitInstructionSpecifier() has been called. - bool shouldBeEmitted() const { - return ShouldBeEmitted; - } - /// emitInstructionSpecifier - Loads the instruction specifier for the current /// instruction into a DisassemblerTables. /// @@ -339,6 +330,7 @@ private: /// decode information for the current instruction. void emitDecodePath(DisassemblerTables &tables) const; +public: /// Constructor - Initializes a RecognizableInstr with the appropriate fields /// from a CodeGenInstruction. /// @@ -348,7 +340,6 @@ private: RecognizableInstr(DisassemblerTables &tables, const CodeGenInstruction &insn, InstrUID uid); -public: /// processInstr - Accepts a CodeGenInstruction and loads decode information /// for it into a DisassemblerTables if appropriate. /// @@ -362,6 +353,12 @@ public: InstrUID uid); }; +std::string getMnemonic(const CodeGenInstruction *I, unsigned Variant); +bool isRegisterOperand(const Record *Rec); +bool isMemoryOperand(const Record *Rec); +bool isImmediateOperand(const Record *Rec); +unsigned getRegOperandSize(const Record *RegRec); +unsigned getMemOperandSize(const Record *MemRec); } // namespace X86Disassembler } // namespace llvm |
