aboutsummaryrefslogtreecommitdiff
path: root/llvm/utils/TableGen
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/utils/TableGen')
-rw-r--r--llvm/utils/TableGen/AsmMatcherEmitter.cpp3
-rw-r--r--llvm/utils/TableGen/AsmWriterEmitter.cpp23
-rw-r--r--llvm/utils/TableGen/AsmWriterInst.cpp1
-rw-r--r--llvm/utils/TableGen/Attributes.cpp3
-rw-r--r--llvm/utils/TableGen/CallingConvEmitter.cpp139
-rw-r--r--llvm/utils/TableGen/CodeBeadsGen.cpp137
-rw-r--r--llvm/utils/TableGen/CodeEmitterGen.cpp250
-rw-r--r--llvm/utils/TableGen/CodeGenDAGPatterns.cpp14
-rw-r--r--llvm/utils/TableGen/CodeGenDAGPatterns.h1
-rw-r--r--llvm/utils/TableGen/CodeGenInstruction.cpp6
-rw-r--r--llvm/utils/TableGen/CodeGenInstruction.h3
-rw-r--r--llvm/utils/TableGen/CodeGenIntrinsics.h5
-rw-r--r--llvm/utils/TableGen/CodeGenMapTable.cpp2
-rw-r--r--llvm/utils/TableGen/CodeGenRegisters.cpp38
-rw-r--r--llvm/utils/TableGen/CodeGenRegisters.h36
-rw-r--r--llvm/utils/TableGen/CodeGenSchedule.cpp1
-rw-r--r--llvm/utils/TableGen/CodeGenSchedule.h3
-rw-r--r--llvm/utils/TableGen/CodeGenTarget.cpp24
-rw-r--r--llvm/utils/TableGen/CodeGenTarget.h7
-rw-r--r--llvm/utils/TableGen/DAGISelEmitter.cpp1
-rw-r--r--llvm/utils/TableGen/DAGISelMatcherEmitter.cpp2
-rw-r--r--llvm/utils/TableGen/DAGISelMatcherGen.cpp3
-rw-r--r--llvm/utils/TableGen/DFAEmitter.cpp4
-rw-r--r--llvm/utils/TableGen/DFAPacketizerEmitter.cpp2
-rw-r--r--llvm/utils/TableGen/DXILEmitter.cpp374
-rw-r--r--llvm/utils/TableGen/DecoderEmitter.cpp (renamed from llvm/utils/TableGen/FixedLenDecoderEmitter.cpp)777
-rw-r--r--llvm/utils/TableGen/DirectiveEmitter.cpp4
-rw-r--r--llvm/utils/TableGen/DisassemblerEmitter.cpp26
-rw-r--r--llvm/utils/TableGen/ExegesisEmitter.cpp4
-rw-r--r--llvm/utils/TableGen/FastISelEmitter.cpp2
-rw-r--r--llvm/utils/TableGen/GICombinerEmitter.cpp17
-rw-r--r--llvm/utils/TableGen/GlobalISel/GIMatchDag.cpp4
-rw-r--r--llvm/utils/TableGen/GlobalISel/GIMatchTree.h4
-rw-r--r--llvm/utils/TableGen/GlobalISelEmitter.cpp23
-rw-r--r--llvm/utils/TableGen/InstrInfoEmitter.cpp51
-rw-r--r--llvm/utils/TableGen/IntrinsicEmitter.cpp81
-rw-r--r--llvm/utils/TableGen/OptParserEmitter.cpp2
-rw-r--r--llvm/utils/TableGen/OptRSTEmitter.cpp29
-rw-r--r--llvm/utils/TableGen/PseudoLoweringEmitter.cpp3
-rw-r--r--llvm/utils/TableGen/RegisterBankEmitter.cpp8
-rw-r--r--llvm/utils/TableGen/RegisterInfoEmitter.cpp118
-rw-r--r--llvm/utils/TableGen/SearchableTableEmitter.cpp4
-rw-r--r--llvm/utils/TableGen/SequenceToOffsetTable.h16
-rw-r--r--llvm/utils/TableGen/SubtargetEmitter.cpp53
-rw-r--r--llvm/utils/TableGen/SubtargetFeatureInfo.cpp66
-rw-r--r--llvm/utils/TableGen/TableGen.cpp20
-rw-r--r--llvm/utils/TableGen/TableGenBackends.h3
-rw-r--r--llvm/utils/TableGen/VarLenCodeEmitterGen.cpp487
-rw-r--r--llvm/utils/TableGen/VarLenCodeEmitterGen.h66
-rw-r--r--llvm/utils/TableGen/WebAssemblyDisassemblerEmitter.cpp18
-rw-r--r--llvm/utils/TableGen/X86DisassemblerTables.cpp34
-rw-r--r--llvm/utils/TableGen/X86EVEX2VEXTablesEmitter.cpp73
-rw-r--r--llvm/utils/TableGen/X86FoldTablesEmitter.cpp266
-rw-r--r--llvm/utils/TableGen/X86MnemonicTables.cpp94
-rw-r--r--llvm/utils/TableGen/X86RecognizableInstr.cpp192
-rw-r--r--llvm/utils/TableGen/X86RecognizableInstr.h77
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