aboutsummaryrefslogtreecommitdiff
path: root/llvm/utils
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2023-07-26 19:03:47 +0000
committerDimitry Andric <dim@FreeBSD.org>2023-07-26 19:04:23 +0000
commit7fa27ce4a07f19b07799a767fc29416f3b625afb (patch)
tree27825c83636c4de341eb09a74f49f5d38a15d165 /llvm/utils
parente3b557809604d036af6e00c60f012c2025b59a5e (diff)
Diffstat (limited to 'llvm/utils')
-rw-r--r--llvm/utils/TableGen/AsmMatcherEmitter.cpp78
-rw-r--r--llvm/utils/TableGen/AsmWriterEmitter.cpp19
-rw-r--r--llvm/utils/TableGen/AsmWriterInst.cpp1
-rw-r--r--llvm/utils/TableGen/AsmWriterInst.h1
-rw-r--r--llvm/utils/TableGen/Attributes.cpp15
-rw-r--r--llvm/utils/TableGen/CTagsEmitter.cpp11
-rw-r--r--llvm/utils/TableGen/CallingConvEmitter.cpp24
-rw-r--r--llvm/utils/TableGen/CodeEmitterGen.cpp242
-rw-r--r--llvm/utils/TableGen/CodeGenDAGPatterns.cpp333
-rw-r--r--llvm/utils/TableGen/CodeGenDAGPatterns.h127
-rw-r--r--llvm/utils/TableGen/CodeGenHwModes.cpp43
-rw-r--r--llvm/utils/TableGen/CodeGenHwModes.h9
-rw-r--r--llvm/utils/TableGen/CodeGenInstAlias.cpp283
-rw-r--r--llvm/utils/TableGen/CodeGenInstAlias.h105
-rw-r--r--llvm/utils/TableGen/CodeGenInstruction.cpp266
-rw-r--r--llvm/utils/TableGen/CodeGenInstruction.h71
-rw-r--r--llvm/utils/TableGen/CodeGenIntrinsics.cpp270
-rw-r--r--llvm/utils/TableGen/CodeGenIntrinsics.h20
-rw-r--r--llvm/utils/TableGen/CodeGenMapTable.cpp1
-rw-r--r--llvm/utils/TableGen/CodeGenRegisters.cpp13
-rw-r--r--llvm/utils/TableGen/CodeGenRegisters.h16
-rw-r--r--llvm/utils/TableGen/CodeGenSchedule.cpp10
-rw-r--r--llvm/utils/TableGen/CodeGenSchedule.h7
-rw-r--r--llvm/utils/TableGen/CodeGenTarget.cpp326
-rw-r--r--llvm/utils/TableGen/CodeGenTarget.h21
-rw-r--r--llvm/utils/TableGen/CompressInstEmitter.cpp10
-rw-r--r--llvm/utils/TableGen/DAGISelEmitter.cpp16
-rw-r--r--llvm/utils/TableGen/DAGISelMatcher.cpp11
-rw-r--r--llvm/utils/TableGen/DAGISelMatcher.h83
-rw-r--r--llvm/utils/TableGen/DAGISelMatcherEmitter.cpp17
-rw-r--r--llvm/utils/TableGen/DAGISelMatcherGen.cpp104
-rw-r--r--llvm/utils/TableGen/DAGISelMatcherOpt.cpp284
-rw-r--r--llvm/utils/TableGen/DFAEmitter.cpp11
-rw-r--r--llvm/utils/TableGen/DFAEmitter.h2
-rw-r--r--llvm/utils/TableGen/DFAPacketizerEmitter.cpp12
-rw-r--r--llvm/utils/TableGen/DXILEmitter.cpp28
-rw-r--r--llvm/utils/TableGen/DecoderEmitter.cpp186
-rw-r--r--llvm/utils/TableGen/DirectiveEmitter.cpp127
-rw-r--r--llvm/utils/TableGen/DisassemblerEmitter.cpp11
-rw-r--r--llvm/utils/TableGen/ExegesisEmitter.cpp9
-rw-r--r--llvm/utils/TableGen/FastISelEmitter.cpp10
-rw-r--r--llvm/utils/TableGen/GICombinerEmitter.cpp71
-rw-r--r--llvm/utils/TableGen/GlobalISel/CodeExpander.h2
-rw-r--r--llvm/utils/TableGen/GlobalISel/CombinerUtils.h72
-rw-r--r--llvm/utils/TableGen/GlobalISel/GIMatchDag.h2
-rw-r--r--llvm/utils/TableGen/GlobalISel/GIMatchDagEdge.h2
-rw-r--r--llvm/utils/TableGen/GlobalISel/GIMatchDagInstr.h2
-rw-r--r--llvm/utils/TableGen/GlobalISel/GIMatchDagOperands.h2
-rw-r--r--llvm/utils/TableGen/GlobalISel/GIMatchDagPredicate.h2
-rw-r--r--llvm/utils/TableGen/GlobalISel/GIMatchTree.cpp109
-rw-r--r--llvm/utils/TableGen/GlobalISel/GIMatchTree.h2
-rw-r--r--llvm/utils/TableGen/GlobalISelCombinerMatchTableEmitter.cpp1575
-rw-r--r--llvm/utils/TableGen/GlobalISelEmitter.cpp4427
-rw-r--r--llvm/utils/TableGen/GlobalISelMatchTable.cpp2019
-rw-r--r--llvm/utils/TableGen/GlobalISelMatchTable.h2162
-rw-r--r--llvm/utils/TableGen/GlobalISelMatchTableExecutorEmitter.cpp267
-rw-r--r--llvm/utils/TableGen/GlobalISelMatchTableExecutorEmitter.h228
-rw-r--r--llvm/utils/TableGen/InfoByHwMode.cpp6
-rw-r--r--llvm/utils/TableGen/InfoByHwMode.h85
-rw-r--r--llvm/utils/TableGen/InstrDocsEmitter.cpp18
-rw-r--r--llvm/utils/TableGen/InstrInfoEmitter.cpp291
-rw-r--r--llvm/utils/TableGen/IntrinsicEmitter.cpp406
-rw-r--r--llvm/utils/TableGen/OptParserEmitter.cpp9
-rw-r--r--llvm/utils/TableGen/OptRSTEmitter.cpp8
-rw-r--r--llvm/utils/TableGen/PredicateExpander.cpp1
-rw-r--r--llvm/utils/TableGen/PseudoLoweringEmitter.cpp9
-rw-r--r--llvm/utils/TableGen/RISCVTargetDefEmitter.cpp14
-rw-r--r--llvm/utils/TableGen/RegisterBankEmitter.cpp79
-rw-r--r--llvm/utils/TableGen/RegisterInfoEmitter.cpp82
-rw-r--r--llvm/utils/TableGen/SearchableTableEmitter.cpp12
-rw-r--r--llvm/utils/TableGen/SubtargetEmitter.cpp131
-rw-r--r--llvm/utils/TableGen/SubtargetFeatureInfo.cpp14
-rw-r--r--llvm/utils/TableGen/SubtargetFeatureInfo.h6
-rw-r--r--llvm/utils/TableGen/TableGen.cpp294
-rw-r--r--llvm/utils/TableGen/TableGenBackends.h41
-rw-r--r--llvm/utils/TableGen/Types.cpp8
-rw-r--r--llvm/utils/TableGen/Types.h3
-rw-r--r--llvm/utils/TableGen/VTEmitter.cpp130
-rw-r--r--llvm/utils/TableGen/VarLenCodeEmitterGen.cpp1
-rw-r--r--llvm/utils/TableGen/X86DisassemblerTables.cpp270
-rw-r--r--llvm/utils/TableGen/X86EVEX2VEXTablesEmitter.cpp18
-rw-r--r--llvm/utils/TableGen/X86FoldTablesEmitter.cpp536
-rw-r--r--llvm/utils/TableGen/X86ManualFoldTables.def288
-rw-r--r--llvm/utils/TableGen/X86MnemonicTables.cpp9
-rw-r--r--llvm/utils/TableGen/X86ModRMFilters.h2
-rw-r--r--llvm/utils/TableGen/X86RecognizableInstr.cpp31
-rw-r--r--llvm/utils/TableGen/X86RecognizableInstr.h10
87 files changed, 9691 insertions, 7298 deletions
diff --git a/llvm/utils/TableGen/AsmMatcherEmitter.cpp b/llvm/utils/TableGen/AsmMatcherEmitter.cpp
index c13e5b5deff6..1c195200a888 100644
--- a/llvm/utils/TableGen/AsmMatcherEmitter.cpp
+++ b/llvm/utils/TableGen/AsmMatcherEmitter.cpp
@@ -95,7 +95,9 @@
//
//===----------------------------------------------------------------------===//
+#include "CodeGenInstAlias.h"
#include "CodeGenInstruction.h"
+#include "CodeGenRegisters.h"
#include "CodeGenTarget.h"
#include "SubtargetFeatureInfo.h"
#include "Types.h"
@@ -105,7 +107,6 @@
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/Config/llvm-config.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
@@ -505,9 +506,9 @@ struct MatchableInfo {
PointerUnion<const CodeGenInstruction*, const CodeGenInstAlias*> DefRec;
const CodeGenInstruction *getResultInst() const {
- if (DefRec.is<const CodeGenInstruction*>())
- return DefRec.get<const CodeGenInstruction*>();
- return DefRec.get<const CodeGenInstAlias*>()->ResultInst;
+ if (isa<const CodeGenInstruction *>(DefRec))
+ return cast<const CodeGenInstruction *>(DefRec);
+ return cast<const CodeGenInstAlias *>(DefRec)->ResultInst;
}
/// ResOperands - This is the operand list that should be built for the result
@@ -533,7 +534,7 @@ struct MatchableInfo {
std::string ConversionFnKind;
/// If this instruction is deprecated in some form.
- bool HasDeprecation;
+ bool HasDeprecation = false;
/// If this is an alias, this is use to determine whether or not to using
/// the conversion function defined by the instruction's AsmMatchConverter
@@ -563,11 +564,11 @@ struct MatchableInfo {
ConversionFnKind(RHS.ConversionFnKind),
HasDeprecation(RHS.HasDeprecation),
UseInstAsmMatchConverter(RHS.UseInstAsmMatchConverter) {
- assert(!DefRec.is<const CodeGenInstAlias *>());
+ assert(!isa<const CodeGenInstAlias *>(DefRec));
}
~MatchableInfo() {
- delete DefRec.dyn_cast<const CodeGenInstAlias*>();
+ delete dyn_cast_if_present<const CodeGenInstAlias *>(DefRec);
}
// Two-operand aliases clone from the main matchable, but mark the second
@@ -629,6 +630,17 @@ struct MatchableInfo {
return false;
}
+ // For X86 AVX/AVX512 instructions, we prefer vex encoding because the
+ // vex encoding size is smaller. Since X86InstrSSE.td is included ahead
+ // of X86InstrAVX512.td, the AVX instruction ID is less than AVX512 ID.
+ // We use the ID to sort AVX instruction before AVX512 instruction in
+ // matching table.
+ if (TheDef->isSubClassOf("Instruction") &&
+ TheDef->getValueAsBit("HasPositionOrder") &&
+ RHS.TheDef->isSubClassOf("Instruction") &&
+ RHS.TheDef->getValueAsBit("HasPositionOrder"))
+ return TheDef->getID() < RHS.TheDef->getID();
+
// Give matches that require more features higher precedence. This is useful
// because we cannot define AssemblerPredicates with the negation of
// processor features. For example, ARM v6 "nop" may be either a HINT or
@@ -638,15 +650,6 @@ struct MatchableInfo {
if (RequiredFeatures.size() != RHS.RequiredFeatures.size())
return RequiredFeatures.size() > RHS.RequiredFeatures.size();
- // For X86 AVX/AVX512 instructions, we prefer vex encoding because the
- // vex encoding size is smaller. Since X86InstrSSE.td is included ahead
- // of X86InstrAVX512.td, the AVX instruction ID is less than AVX512 ID.
- // We use the ID to sort AVX instruction before AVX512 instruction in
- // matching table.
- if (TheDef->isSubClassOf("Instruction") &&
- TheDef->getValueAsBit("HasPositionOrder"))
- return TheDef->getID() < RHS.TheDef->getID();
-
return false;
}
@@ -1613,13 +1616,13 @@ void AsmMatcherInfo::buildInfo() {
else
OperandName = Token.substr(1);
- if (II->DefRec.is<const CodeGenInstruction*>())
+ if (isa<const CodeGenInstruction *>(II->DefRec))
buildInstructionOperandReference(II.get(), OperandName, i);
else
buildAliasOperandReference(II.get(), OperandName, Op);
}
- if (II->DefRec.is<const CodeGenInstruction*>()) {
+ if (isa<const CodeGenInstruction *>(II->DefRec)) {
II->buildInstructionResultOperands();
// If the instruction has a two-operand alias, build up the
// matchable here. We'll add them in bulk at the end to avoid
@@ -1682,7 +1685,7 @@ void AsmMatcherInfo::
buildInstructionOperandReference(MatchableInfo *II,
StringRef OperandName,
unsigned AsmOpIdx) {
- const CodeGenInstruction &CGI = *II->DefRec.get<const CodeGenInstruction*>();
+ const CodeGenInstruction &CGI = *cast<const CodeGenInstruction *>(II->DefRec);
const CGIOperandList &Operands = CGI.Operands;
MatchableInfo::AsmOperand *Op = &II->AsmOperands[AsmOpIdx];
@@ -1745,7 +1748,7 @@ buildInstructionOperandReference(MatchableInfo *II,
void AsmMatcherInfo::buildAliasOperandReference(MatchableInfo *II,
StringRef OperandName,
MatchableInfo::AsmOperand &Op) {
- const CodeGenInstAlias &CGA = *II->DefRec.get<const CodeGenInstAlias*>();
+ const CodeGenInstAlias &CGA = *cast<const CodeGenInstAlias *>(II->DefRec);
// Set up the operand class.
for (unsigned i = 0, e = CGA.ResultOperands.size(); i != e; ++i)
@@ -1818,7 +1821,7 @@ void MatchableInfo::buildInstructionResultOperands() {
}
void MatchableInfo::buildAliasResultOperands(bool AliasConstraintsAreChecked) {
- const CodeGenInstAlias &CGA = *DefRec.get<const CodeGenInstAlias*>();
+ const CodeGenInstAlias &CGA = *cast<const CodeGenInstAlias *>(DefRec);
const CodeGenInstruction *ResultInst = getResultInst();
// Map of: $reg -> #lastref
@@ -2924,7 +2927,7 @@ emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
// Emit the operand class switch to call the correct custom parser for
// the found operand class.
- OS << "OperandMatchResultTy " << Target.getName() << ClassName << "::\n"
+ OS << "ParseStatus " << Target.getName() << ClassName << "::\n"
<< "tryCustomParseOperand(OperandVector"
<< " &Operands,\n unsigned MCK) {\n\n"
<< " switch(MCK) {\n";
@@ -2937,15 +2940,15 @@ emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
}
OS << " default:\n";
- OS << " return MatchOperand_NoMatch;\n";
+ OS << " return ParseStatus::NoMatch;\n";
OS << " }\n";
- OS << " return MatchOperand_NoMatch;\n";
+ OS << " return ParseStatus::NoMatch;\n";
OS << "}\n\n";
// Emit the static custom operand parser. This code is very similar with
// the other matcher. Also use MatchResultTy here just in case we go for
// a better error handling.
- OS << "OperandMatchResultTy " << Target.getName() << ClassName << "::\n"
+ OS << "ParseStatus " << Target.getName() << ClassName << "::\n"
<< "MatchOperandParserImpl(OperandVector"
<< " &Operands,\n StringRef Mnemonic,\n"
<< " bool ParseForAllFeatures) {\n";
@@ -2976,7 +2979,7 @@ emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
}
OS << " if (MnemonicRange.first == MnemonicRange.second)\n";
- OS << " return MatchOperand_NoMatch;\n\n";
+ OS << " return ParseStatus::NoMatch;\n\n";
OS << " for (const OperandMatchEntry *it = MnemonicRange.first,\n"
<< " *ie = MnemonicRange.second; it != ie; ++it) {\n";
@@ -3002,14 +3005,13 @@ emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
if (ParserName.empty())
ParserName = "tryCustomParseOperand";
OS << " // call custom parse method to handle the operand\n";
- OS << " OperandMatchResultTy Result = " << ParserName
- << "(Operands, it->Class);\n";
- OS << " if (Result != MatchOperand_NoMatch)\n";
+ OS << " ParseStatus Result = " << ParserName << "(Operands, it->Class);\n";
+ OS << " if (!Result.isNoMatch())\n";
OS << " return Result;\n";
OS << " }\n\n";
OS << " // Okay, we had no match.\n";
- OS << " return MatchOperand_NoMatch;\n";
+ OS << " return ParseStatus::NoMatch;\n";
OS << "}\n\n";
}
@@ -3202,6 +3204,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
Record *AsmParser = Target.getAsmParser();
StringRef ClassName = AsmParser->getValueAsString("AsmParserClassName");
+ emitSourceFileHeader("Assembly Matcher Source Fragment", OS);
+
// Compute the information on the instructions to match.
AsmMatcherInfo Info(AsmParser, Target, Records);
Info.buildInfo();
@@ -3303,12 +3307,12 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
if (!Info.OperandMatchInfo.empty()) {
- OS << " OperandMatchResultTy MatchOperandParserImpl(\n";
+ OS << " ParseStatus MatchOperandParserImpl(\n";
OS << " OperandVector &Operands,\n";
OS << " StringRef Mnemonic,\n";
OS << " bool ParseForAllFeatures = false);\n";
- OS << " OperandMatchResultTy tryCustomParseOperand(\n";
+ OS << " ParseStatus tryCustomParseOperand(\n";
OS << " OperandVector &Operands,\n";
OS << " unsigned MCK);\n\n";
}
@@ -3999,11 +4003,5 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << "#endif // GET_MNEMONIC_CHECKER\n\n";
}
-namespace llvm {
-
-void EmitAsmMatcher(RecordKeeper &RK, raw_ostream &OS) {
- emitSourceFileHeader("Assembly Matcher Source Fragment", OS);
- AsmMatcherEmitter(RK).run(OS);
-}
-
-} // end namespace llvm
+static TableGen::Emitter::OptClass<AsmMatcherEmitter>
+ X("gen-asm-matcher", "Generate assembly instruction matcher");
diff --git a/llvm/utils/TableGen/AsmWriterEmitter.cpp b/llvm/utils/TableGen/AsmWriterEmitter.cpp
index f2e4d15a2c75..92e71910a800 100644
--- a/llvm/utils/TableGen/AsmWriterEmitter.cpp
+++ b/llvm/utils/TableGen/AsmWriterEmitter.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "AsmWriterInst.h"
+#include "CodeGenInstAlias.h"
#include "CodeGenInstruction.h"
#include "CodeGenRegisters.h"
#include "CodeGenTarget.h"
@@ -994,7 +995,10 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
for (Record *const R : ReqFeatures) {
const DagInit *D = R->getValueAsDag("AssemblerCondDag");
- std::string CombineType = D->getOperator()->getAsString();
+ auto *Op = dyn_cast<DefInit>(D->getOperator());
+ if (!Op)
+ PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!");
+ StringRef CombineType = Op->getDef()->getName();
if (CombineType != "any_of" && CombineType != "all_of")
PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!");
if (D->getNumArgs() == 0)
@@ -1002,7 +1006,7 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
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));
+ DagInit *RHS = 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) {
@@ -1298,17 +1302,12 @@ void AsmWriterEmitter::run(raw_ostream &O) {
std::vector<std::vector<std::string>> TableDrivenOperandPrinters;
unsigned BitsLeft = 0;
unsigned AsmStrBits = 0;
+ emitSourceFileHeader("Assembly Writer Source Fragment", O);
EmitGetMnemonic(O, TableDrivenOperandPrinters, BitsLeft, AsmStrBits);
EmitPrintInstruction(O, TableDrivenOperandPrinters, BitsLeft, AsmStrBits);
EmitGetRegisterName(O);
EmitPrintAliasInstruction(O);
}
-namespace llvm {
-
-void EmitAsmWriter(RecordKeeper &RK, raw_ostream &OS) {
- emitSourceFileHeader("Assembly Writer Source Fragment", OS);
- AsmWriterEmitter(RK).run(OS);
-}
-
-} // end namespace llvm
+static TableGen::Emitter::OptClass<AsmWriterEmitter>
+ X("gen-asm-writer", "Generate assembly writer");
diff --git a/llvm/utils/TableGen/AsmWriterInst.cpp b/llvm/utils/TableGen/AsmWriterInst.cpp
index 4a78108d6f4a..c9558593e142 100644
--- a/llvm/utils/TableGen/AsmWriterInst.cpp
+++ b/llvm/utils/TableGen/AsmWriterInst.cpp
@@ -12,7 +12,6 @@
#include "AsmWriterInst.h"
#include "CodeGenInstruction.h"
-#include "CodeGenTarget.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
diff --git a/llvm/utils/TableGen/AsmWriterInst.h b/llvm/utils/TableGen/AsmWriterInst.h
index fe2b934e266f..9c93e82b611b 100644
--- a/llvm/utils/TableGen/AsmWriterInst.h
+++ b/llvm/utils/TableGen/AsmWriterInst.h
@@ -21,7 +21,6 @@
namespace llvm {
class CodeGenInstruction;
- class Record;
struct AsmWriterOperand {
enum OpType {
diff --git a/llvm/utils/TableGen/Attributes.cpp b/llvm/utils/TableGen/Attributes.cpp
index 735c53dd6fcf..474042a3e9a3 100644
--- a/llvm/utils/TableGen/Attributes.cpp
+++ b/llvm/utils/TableGen/Attributes.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
#include <vector>
using namespace llvm;
@@ -17,7 +18,7 @@ namespace {
class Attributes {
public:
Attributes(RecordKeeper &R) : Records(R) {}
- void emit(raw_ostream &OS);
+ void run(raw_ostream &OS);
private:
void emitTargetIndependentNames(raw_ostream &OS);
@@ -54,6 +55,7 @@ void Attributes::emitTargetIndependentNames(raw_ostream &OS) {
// Emit attribute enums in the same order llvm::Attribute::operator< expects.
Emit({"EnumAttr", "TypeAttr", "IntAttr"}, "ATTRIBUTE_ENUM");
Emit({"StrBoolAttr"}, "ATTRIBUTE_STRBOOL");
+ Emit({"ComplexStrAttr"}, "ATTRIBUTE_COMPLEXSTR");
OS << "#undef ATTRIBUTE_ALL\n";
OS << "#endif\n\n";
@@ -123,16 +125,11 @@ void Attributes::emitAttributeProperties(raw_ostream &OS) {
OS << "#endif\n";
}
-void Attributes::emit(raw_ostream &OS) {
+void Attributes::run(raw_ostream &OS) {
emitTargetIndependentNames(OS);
emitFnAttrCompatCheck(OS, false);
emitAttributeProperties(OS);
}
-namespace llvm {
-
-void EmitAttributes(RecordKeeper &RK, raw_ostream &OS) {
- Attributes(RK).emit(OS);
-}
-
-} // End llvm namespace.
+static TableGen::Emitter::OptClass<Attributes> X("gen-attrs",
+ "Generate attributes");
diff --git a/llvm/utils/TableGen/CTagsEmitter.cpp b/llvm/utils/TableGen/CTagsEmitter.cpp
index fe62d6a9b67f..b8e27d057d95 100644
--- a/llvm/utils/TableGen/CTagsEmitter.cpp
+++ b/llvm/utils/TableGen/CTagsEmitter.cpp
@@ -12,12 +12,12 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/SourceMgr.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
#include <algorithm>
-#include <string>
#include <vector>
using namespace llvm;
@@ -86,8 +86,5 @@ void CTagsEmitter::run(raw_ostream &OS) {
T.emit(OS);
}
-namespace llvm {
-
-void EmitCTags(RecordKeeper &RK, raw_ostream &OS) { CTagsEmitter(RK).run(OS); }
-
-} // End llvm namespace.
+static TableGen::Emitter::OptClass<CTagsEmitter>
+ X("gen-ctags", "Generate ctags-compatible index");
diff --git a/llvm/utils/TableGen/CallingConvEmitter.cpp b/llvm/utils/TableGen/CallingConvEmitter.cpp
index e8ec90e9c078..de3810b2e227 100644
--- a/llvm/utils/TableGen/CallingConvEmitter.cpp
+++ b/llvm/utils/TableGen/CallingConvEmitter.cpp
@@ -15,14 +15,16 @@
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
+#include <deque>
+
using namespace llvm;
namespace {
class CallingConvEmitter {
RecordKeeper &Records;
- unsigned Counter;
+ unsigned Counter = 0u;
std::string CurrentAction;
- bool SwiftAction;
+ bool SwiftAction = false;
std::map<std::string, std::set<std::string>> AssignedRegsMap;
std::map<std::string, std::set<std::string>> AssignedSwiftRegsMap;
@@ -41,7 +43,9 @@ private:
} // End anonymous namespace
void CallingConvEmitter::run(raw_ostream &O) {
- std::vector<Record*> CCs = Records.getAllDerivedDefinitions("CallingConv");
+ emitSourceFileHeader("Calling Convention Implementation Fragment", O);
+
+ std::vector<Record *> CCs = Records.getAllDerivedDefinitions("CallingConv");
// Emit prototypes for all of the non-custom CC's so that they can forward ref
// each other.
@@ -247,7 +251,7 @@ void CallingConvEmitter::EmitAction(Record *Action,
int Size = Action->getValueAsInt("Size");
int Align = Action->getValueAsInt("Align");
- O << IndentStr << "unsigned Offset" << ++Counter
+ O << IndentStr << "int64_t Offset" << ++Counter
<< " = State.AllocateStack(";
if (Size)
O << Size << ", ";
@@ -283,7 +287,7 @@ void CallingConvEmitter::EmitAction(Record *Action,
O << LS << getQualifiedName(ShadowRegList->getElementAsRecord(i));
O << "\n" << IndentStr << "};\n";
- O << IndentStr << "unsigned Offset" << ++Counter
+ O << IndentStr << "int64_t Offset" << ++Counter
<< " = State.AllocateStack(" << Size << ", Align(" << Align << "), "
<< "ShadowRegList" << ShadowRegListNumber << ");\n";
O << IndentStr << "State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset"
@@ -426,11 +430,5 @@ void CallingConvEmitter::EmitArgRegisterLists(raw_ostream &O) {
}
}
-namespace llvm {
-
-void EmitCallingConv(RecordKeeper &RK, raw_ostream &OS) {
- emitSourceFileHeader("Calling Convention Implementation Fragment", OS);
- CallingConvEmitter(RK).run(OS);
-}
-
-} // End llvm namespace
+static TableGen::Emitter::OptClass<CallingConvEmitter>
+ X("gen-callingconv", "Generate calling convention descriptions");
diff --git a/llvm/utils/TableGen/CodeEmitterGen.cpp b/llvm/utils/TableGen/CodeEmitterGen.cpp
index dc4fd589eaa8..48ed319bf06f 100644
--- a/llvm/utils/TableGen/CodeEmitterGen.cpp
+++ b/llvm/utils/TableGen/CodeEmitterGen.cpp
@@ -7,15 +7,25 @@
//===----------------------------------------------------------------------===//
//
// CodeEmitterGen uses the descriptions of instructions and their fields to
-// construct an automated code emitter: a function that, given a MachineInstr,
-// returns the (currently, 32-bit unsigned) value of the instruction.
+// construct an automated code emitter: a function called
+// getBinaryCodeForInstr() that, given a MCInst, returns the value of the
+// instruction - either as an uint64_t or as an APInt, depending on the
+// maximum bit width of all Inst definitions.
+//
+// In addition, it generates another function called getOperandBitOffset()
+// that, given a MCInst and an operand index, returns the minimum of indices of
+// all bits that carry some portion of the respective operand. When the target's
+// encodeInstruction() stores the instruction in a little-endian byte order, the
+// returned value is the offset of the start of the operand in the encoded
+// instruction. Other targets might need to adjust the returned value according
+// to their encodeInstruction() implementation.
//
//===----------------------------------------------------------------------===//
+#include "CodeGenHwModes.h"
#include "CodeGenInstruction.h"
#include "CodeGenTarget.h"
-#include "SubtargetFeatureInfo.h"
-#include "Types.h"
+#include "InfoByHwMode.h"
#include "VarLenCodeEmitterGen.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/ArrayRef.h"
@@ -46,19 +56,24 @@ public:
private:
int getVariableBit(const std::string &VarName, BitsInit *BI, int bit);
- std::string getInstructionCase(Record *R, CodeGenTarget &Target);
- std::string getInstructionCaseForEncoding(Record *R, Record *EncodingDef,
- CodeGenTarget &Target);
+ std::pair<std::string, std::string>
+ getInstructionCases(Record *R, CodeGenTarget &Target);
+ void addInstructionCasesForEncoding(Record *R, Record *EncodingDef,
+ CodeGenTarget &Target, std::string &Case,
+ std::string &BitOffsetCase);
bool addCodeToMergeInOperand(Record *R, BitsInit *BI,
- const std::string &VarName, unsigned &NumberedOp,
- std::set<unsigned> &NamedOpIndices,
- std::string &Case, CodeGenTarget &Target);
+ const std::string &VarName, std::string &Case,
+ std::string &BitOffsetCase,
+ CodeGenTarget &Target);
void emitInstructionBaseValues(
raw_ostream &o, ArrayRef<const CodeGenInstruction *> NumberedInstructions,
CodeGenTarget &Target, int HwMode = -1);
- unsigned BitWidth;
- bool UseAPInt;
+ void
+ emitCaseMap(raw_ostream &o,
+ const std::map<std::string, std::vector<std::string>> &CaseMap);
+ unsigned BitWidth = 0u;
+ bool UseAPInt = false;
};
// If the VarBitInit at position 'bit' matches the specified variable then
@@ -80,9 +95,8 @@ int CodeEmitterGen::getVariableBit(const std::string &VarName,
// Returns true if it succeeds, false if an error.
bool CodeEmitterGen::addCodeToMergeInOperand(Record *R, BitsInit *BI,
const std::string &VarName,
- unsigned &NumberedOp,
- std::set<unsigned> &NamedOpIndices,
std::string &Case,
+ std::string &BitOffsetCase,
CodeGenTarget &Target) {
CodeGenInstruction &CGI = Target.getInstruction(R);
@@ -113,52 +127,8 @@ bool CodeEmitterGen::addCodeToMergeInOperand(Record *R, BitsInit *BI,
// Get the machine operand number for the indicated operand.
OpIdx = CGI.Operands[OpIdx].MIOperandNo;
} else {
- // Fall back to positional lookup. By default, we now disable positional
- // lookup (and print an error, below), but even so, we'll do the lookup to
- // help print a helpful diagnostic message.
- //
- // TODO: When we remove useDeprecatedPositionallyEncodedOperands, delete all
- // this code, just leaving a "no operand named X in record Y" error.
-
- unsigned NumberOps = CGI.Operands.size();
- /// If this operand is not supposed to be emitted by the
- /// generated emitter, skip it.
- while (NumberedOp < NumberOps &&
- (CGI.Operands.isFlatOperandNotEmitted(NumberedOp) ||
- (!NamedOpIndices.empty() && NamedOpIndices.count(
- CGI.Operands.getSubOperandNumber(NumberedOp).first)))) {
- ++NumberedOp;
- }
-
- if (NumberedOp >=
- CGI.Operands.back().MIOperandNo + CGI.Operands.back().MINumOperands) {
- if (!Target.getInstructionSet()->getValueAsBit(
- "useDeprecatedPositionallyEncodedOperands")) {
- PrintError(R, Twine("No operand named ") + VarName + " in record " +
- R->getName() +
- " (would've given 'too few operands' error with "
- "useDeprecatedPositionallyEncodedOperands=true)");
- } else {
- PrintError(R, "Too few operands in record " + R->getName() +
- " (no match for variable " + VarName + ")");
- }
- return false;
- }
-
- OpIdx = NumberedOp++;
-
- if (!Target.getInstructionSet()->getValueAsBit(
- "useDeprecatedPositionallyEncodedOperands")) {
- std::pair<unsigned, unsigned> SO =
- CGI.Operands.getSubOperandNumber(OpIdx);
- std::string OpName = CGI.Operands[SO.first].Name;
- PrintError(R, Twine("No operand named ") + VarName + " in record " +
- R->getName() + " (would've used positional operand #" +
- Twine(SO.first) + " ('" + OpName + "') sub-op #" +
- Twine(SO.second) +
- " with useDeprecatedPositionallyEncodedOperands=true)");
- return false;
- }
+ PrintError(R, Twine("No operand named ") + VarName + " in record " + R->getName());
+ return false;
}
if (CGI.Operands.isFlatOperandNotEmitted(OpIdx)) {
@@ -222,6 +192,7 @@ bool CodeEmitterGen::addCodeToMergeInOperand(Record *R, BitsInit *BI,
++numOperandLits;
}
+ unsigned BitOffset = -1;
for (; bit >= 0; ) {
int varBit = getVariableBit(VarName, BI, bit);
@@ -230,7 +201,7 @@ bool CodeEmitterGen::addCodeToMergeInOperand(Record *R, BitsInit *BI,
--bit;
continue;
}
-
+
// Figure out the consecutive range of bits covered by this operand, in
// order to generate better encoding code.
int beginInstBit = bit;
@@ -249,6 +220,7 @@ bool CodeEmitterGen::addCodeToMergeInOperand(Record *R, BitsInit *BI,
unsigned loBit = beginVarBit - N + 1;
unsigned hiBit = loBit + N;
unsigned loInstBit = beginInstBit - N + 1;
+ BitOffset = loInstBit;
if (UseAPInt) {
std::string extractStr;
if (N >= 64) {
@@ -290,65 +262,71 @@ bool CodeEmitterGen::addCodeToMergeInOperand(Record *R, BitsInit *BI,
}
}
}
+
+ if (BitOffset != (unsigned)-1) {
+ BitOffsetCase += " case " + utostr(OpIdx) + ":\n";
+ BitOffsetCase += " // op: " + VarName + "\n";
+ BitOffsetCase += " return " + utostr(BitOffset) + ";\n";
+ }
+
return true;
}
-std::string CodeEmitterGen::getInstructionCase(Record *R,
- CodeGenTarget &Target) {
- std::string Case;
+std::pair<std::string, std::string>
+CodeEmitterGen::getInstructionCases(Record *R, CodeGenTarget &Target) {
+ std::string Case, BitOffsetCase;
+
+ auto append = [&](const char *S) {
+ Case += S;
+ BitOffsetCase += S;
+ };
+
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";
+ append(" switch (HwMode) {\n");
+ append(" 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";
+ append((" case " + itostr(KV.first) + ": {\n").c_str());
+ addInstructionCasesForEncoding(R, KV.second, Target, Case,
+ BitOffsetCase);
+ append(" break;\n");
+ append(" }\n");
}
- Case += " }\n";
- return Case;
+ append(" }\n");
+ return std::make_pair(std::move(Case), std::move(BitOffsetCase));
}
}
- return getInstructionCaseForEncoding(R, R, Target);
+ addInstructionCasesForEncoding(R, R, Target, Case, BitOffsetCase);
+ return std::make_pair(std::move(Case), std::move(BitOffsetCase));
}
-std::string CodeEmitterGen::getInstructionCaseForEncoding(Record *R, Record *EncodingDef,
- CodeGenTarget &Target) {
- std::string Case;
+void CodeEmitterGen::addInstructionCasesForEncoding(
+ Record *R, Record *EncodingDef, CodeGenTarget &Target, std::string &Case,
+ std::string &BitOffsetCase) {
BitsInit *BI = EncodingDef->getValueAsBitsInit("Inst");
- unsigned NumberedOp = 0;
- std::set<unsigned> NamedOpIndices;
-
- // Collect the set of operand indices that might correspond to named
- // operand, and skip these when assigning operands based on position.
- if (Target.getInstructionSet()->
- getValueAsBit("noNamedPositionallyEncodedOperands")) {
- CodeGenInstruction &CGI = Target.getInstruction(R);
- for (const RecordVal &RV : R->getValues()) {
- unsigned OpIdx;
- if (!CGI.Operands.hasOperandNamed(RV.getName(), OpIdx))
- continue;
-
- NamedOpIndices.insert(OpIdx);
- }
- }
// Loop over all of the fields in the instruction, determining which are the
// operands to the instruction.
bool Success = true;
+ size_t OrigBitOffsetCaseSize = BitOffsetCase.size();
+ BitOffsetCase += " switch (OpNum) {\n";
+ size_t BitOffsetCaseSizeBeforeLoop = BitOffsetCase.size();
for (const RecordVal &RV : EncodingDef->getValues()) {
// Ignore fixed fields in the record, we're looking for values like:
// bits<5> RST = { ?, ?, ?, ?, ? };
if (RV.isNonconcreteOK() || RV.getValue()->isComplete())
continue;
- Success &=
- addCodeToMergeInOperand(R, BI, std::string(RV.getName()), NumberedOp,
- NamedOpIndices, Case, Target);
+ Success &= addCodeToMergeInOperand(R, BI, std::string(RV.getName()), Case,
+ BitOffsetCase, Target);
}
+ // Avoid empty switches.
+ if (BitOffsetCase.size() == BitOffsetCaseSizeBeforeLoop)
+ BitOffsetCase.resize(OrigBitOffsetCaseSize);
+ else
+ BitOffsetCase += " }\n";
if (!Success) {
// Dump the record, so we can see what's going on...
@@ -367,8 +345,6 @@ std::string CodeEmitterGen::getInstructionCaseForEncoding(Record *R, Record *Enc
Case += ", STI";
Case += ");\n";
}
-
- return Case;
}
static void emitInstBits(raw_ostream &OS, const APInt &Bits) {
@@ -419,7 +395,29 @@ void CodeEmitterGen::emitInstructionBaseValues(
o << " UINT64_C(0)\n };\n";
}
+void CodeEmitterGen::emitCaseMap(
+ raw_ostream &o,
+ const std::map<std::string, std::vector<std::string>> &CaseMap) {
+ std::map<std::string, std::vector<std::string>>::const_iterator IE, EE;
+ for (IE = CaseMap.begin(), EE = CaseMap.end(); IE != EE; ++IE) {
+ const std::string &Case = IE->first;
+ const 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] << ":";
+ }
+ o << " {\n";
+ o << Case;
+ o << " break;\n"
+ << " }\n";
+ }
+}
+
void CodeEmitterGen::run(raw_ostream &o) {
+ emitSourceFileHeader("Machine Code Emitter", o);
+
CodeGenTarget Target(Records);
std::vector<Record*> Insts = Records.getAllDerivedDefinitions("Instruction");
@@ -498,6 +496,7 @@ void CodeEmitterGen::run(raw_ostream &o) {
// Map to accumulate all the cases.
std::map<std::string, std::vector<std::string>> CaseMap;
+ std::map<std::string, std::vector<std::string>> BitOffsetCaseMap;
// Construct all cases statement for each opcode
for (Record *R : Insts) {
@@ -506,9 +505,11 @@ void CodeEmitterGen::run(raw_ostream &o) {
continue;
std::string InstName =
(R->getValueAsString("Namespace") + "::" + R->getName()).str();
- std::string Case = getInstructionCase(R, Target);
+ std::string Case, BitOffsetCase;
+ std::tie(Case, BitOffsetCase) = getInstructionCases(R, Target);
- CaseMap[Case].push_back(std::move(InstName));
+ CaseMap[Case].push_back(InstName);
+ BitOffsetCaseMap[BitOffsetCase].push_back(std::move(InstName));
}
// Emit initial function code
@@ -531,21 +532,7 @@ void CodeEmitterGen::run(raw_ostream &o) {
}
// 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] << ":";
- }
- o << " {\n";
- o << Case;
- o << " break;\n"
- << " }\n";
- }
+ emitCaseMap(o, CaseMap);
// Default case: unhandled opcode
o << " default:\n"
@@ -559,16 +546,27 @@ void CodeEmitterGen::run(raw_ostream &o) {
else
o << " return Value;\n";
o << "}\n\n";
+
+ o << "#ifdef GET_OPERAND_BIT_OFFSET\n"
+ << "#undef GET_OPERAND_BIT_OFFSET\n\n"
+ << "uint32_t " << Target.getName()
+ << "MCCodeEmitter::getOperandBitOffset(const MCInst &MI,\n"
+ << " unsigned OpNum,\n"
+ << " const MCSubtargetInfo &STI) const {\n"
+ << " switch (MI.getOpcode()) {\n";
+ emitCaseMap(o, BitOffsetCaseMap);
+ o << " }\n"
+ << " std::string msg;\n"
+ << " raw_string_ostream Msg(msg);\n"
+ << " Msg << \"Not supported instr[opcode]: \" << MI << \"[\" << OpNum "
+ "<< \"]\";\n"
+ << " report_fatal_error(Msg.str().c_str());\n"
+ << "}\n\n"
+ << "#endif // GET_OPERAND_BIT_OFFSET\n\n";
}
}
} // end anonymous namespace
-namespace llvm {
-
-void EmitCodeEmitter(RecordKeeper &RK, raw_ostream &OS) {
- emitSourceFileHeader("Machine Code Emitter", OS);
- CodeEmitterGen(RK).run(OS);
-}
-
-} // end namespace llvm
+static TableGen::Emitter::OptClass<CodeEmitterGen>
+ X("gen-emitter", "Generate machine code emitter");
diff --git a/llvm/utils/TableGen/CodeGenDAGPatterns.cpp b/llvm/utils/TableGen/CodeGenDAGPatterns.cpp
index dd04778e2dbe..e481f7e38e6a 100644
--- a/llvm/utils/TableGen/CodeGenDAGPatterns.cpp
+++ b/llvm/utils/TableGen/CodeGenDAGPatterns.cpp
@@ -13,6 +13,7 @@
#include "CodeGenDAGPatterns.h"
#include "CodeGenInstruction.h"
+#include "CodeGenRegisters.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/STLExtras.h"
@@ -82,10 +83,12 @@ void MachineValueTypeSet::writeToStream(raw_ostream &OS) const {
// inference will apply to each mode separately.
TypeSetByHwMode::TypeSetByHwMode(ArrayRef<ValueTypeByHwMode> VTList) {
- for (const ValueTypeByHwMode &VVT : VTList) {
+ // Take the address space from the first type in the list.
+ if (!VTList.empty())
+ AddrSpace = VTList[0].PtrAddrSpace;
+
+ for (const ValueTypeByHwMode &VVT : VTList)
insert(VVT);
- AddrSpaces.push_back(VVT.PtrAddrSpace);
- }
}
bool TypeSetByHwMode::isValueTypeByHwMode(bool AllowEmpty) const {
@@ -102,13 +105,11 @@ ValueTypeByHwMode TypeSetByHwMode::getValueTypeByHwMode() const {
assert(isValueTypeByHwMode(true) &&
"The type set has multiple types for at least one HW mode");
ValueTypeByHwMode VVT;
- auto ASI = AddrSpaces.begin();
+ VVT.PtrAddrSpace = AddrSpace;
for (const auto &I : *this) {
MVT T = I.second.empty() ? MVT::Other : *I.second.begin();
VVT.getOrCreateTypeForMode(I.first, T);
- if (ASI != AddrSpaces.end())
- VVT.PtrAddrSpace = *ASI++;
}
return VVT;
}
@@ -217,7 +218,7 @@ bool TypeSetByHwMode::operator==(const TypeSetByHwMode &VTS) const {
bool IsSimple = isSimple();
bool VTSIsSimple = VTS.isSimple();
if (IsSimple && VTSIsSimple)
- return *begin() == *VTS.begin();
+ return getSimple() == VTS.getSimple();
// Speedup: We have a default if the set is simple.
bool HaveDefault = IsSimple || hasDefault();
@@ -354,21 +355,18 @@ bool TypeSetByHwMode::intersect(SetType &Out, const SetType &In) {
}
bool TypeSetByHwMode::validate() const {
-#ifndef NDEBUG
if (empty())
return true;
bool AllEmpty = true;
for (const auto &I : *this)
AllEmpty &= I.second.empty();
return !AllEmpty;
-#endif
- return true;
}
// --- TypeInfer
bool TypeInfer::MergeInTypeInfo(TypeSetByHwMode &Out,
- const TypeSetByHwMode &In) {
+ const TypeSetByHwMode &In) const {
ValidateOnExit _1(Out, *this);
In.validate();
if (In.empty() || Out == In || TP.hasError())
@@ -809,72 +807,57 @@ bool TypeInfer::EnforceSameSize(TypeSetByHwMode &A, TypeSetByHwMode &B) {
return Changed;
}
-void TypeInfer::expandOverloads(TypeSetByHwMode &VTS) {
+void TypeInfer::expandOverloads(TypeSetByHwMode &VTS) const {
ValidateOnExit _1(VTS, *this);
const TypeSetByHwMode &Legal = getLegalTypes();
- assert(Legal.isDefaultOnly() && "Default-mode only expected");
- const TypeSetByHwMode::SetType &LegalTypes = Legal.get(DefaultMode);
+ assert(Legal.isSimple() && "Default-mode only expected");
+ const TypeSetByHwMode::SetType &LegalTypes = Legal.getSimple();
for (auto &I : VTS)
expandOverloads(I.second, LegalTypes);
}
void TypeInfer::expandOverloads(TypeSetByHwMode::SetType &Out,
- const TypeSetByHwMode::SetType &Legal) {
- std::set<MVT> Ovs;
- for (MVT T : Out) {
- if (!T.isOverloaded())
- continue;
-
- Ovs.insert(T);
- // MachineValueTypeSet allows iteration and erasing.
- Out.erase(T);
- }
-
- for (MVT Ov : Ovs) {
- switch (Ov.SimpleTy) {
- case MVT::iPTRAny:
- Out.insert(MVT::iPTR);
- return;
- case MVT::iAny:
- for (MVT T : MVT::integer_valuetypes())
- if (Legal.count(T))
- Out.insert(T);
- for (MVT T : MVT::integer_fixedlen_vector_valuetypes())
- if (Legal.count(T))
- Out.insert(T);
- for (MVT T : MVT::integer_scalable_vector_valuetypes())
- if (Legal.count(T))
- Out.insert(T);
- return;
- case MVT::fAny:
- for (MVT T : MVT::fp_valuetypes())
- if (Legal.count(T))
- Out.insert(T);
- for (MVT T : MVT::fp_fixedlen_vector_valuetypes())
- if (Legal.count(T))
- Out.insert(T);
- for (MVT T : MVT::fp_scalable_vector_valuetypes())
- if (Legal.count(T))
- Out.insert(T);
- return;
- case MVT::vAny:
- for (MVT T : MVT::vector_valuetypes())
- if (Legal.count(T))
- Out.insert(T);
- return;
- case MVT::Any:
- for (MVT T : MVT::all_valuetypes())
- if (Legal.count(T))
- Out.insert(T);
- return;
- default:
- break;
- }
+ const TypeSetByHwMode::SetType &Legal) const {
+ if (Out.count(MVT::iPTRAny)) {
+ Out.erase(MVT::iPTRAny);
+ Out.insert(MVT::iPTR);
+ } else if (Out.count(MVT::iAny)) {
+ Out.erase(MVT::iAny);
+ for (MVT T : MVT::integer_valuetypes())
+ if (Legal.count(T))
+ Out.insert(T);
+ for (MVT T : MVT::integer_fixedlen_vector_valuetypes())
+ if (Legal.count(T))
+ Out.insert(T);
+ for (MVT T : MVT::integer_scalable_vector_valuetypes())
+ if (Legal.count(T))
+ Out.insert(T);
+ } else if (Out.count(MVT::fAny)) {
+ Out.erase(MVT::fAny);
+ for (MVT T : MVT::fp_valuetypes())
+ if (Legal.count(T))
+ Out.insert(T);
+ for (MVT T : MVT::fp_fixedlen_vector_valuetypes())
+ if (Legal.count(T))
+ Out.insert(T);
+ for (MVT T : MVT::fp_scalable_vector_valuetypes())
+ if (Legal.count(T))
+ Out.insert(T);
+ } else if (Out.count(MVT::vAny)) {
+ Out.erase(MVT::vAny);
+ for (MVT T : MVT::vector_valuetypes())
+ if (Legal.count(T))
+ Out.insert(T);
+ } else if (Out.count(MVT::Any)) {
+ Out.erase(MVT::Any);
+ for (MVT T : MVT::all_valuetypes())
+ if (Legal.count(T))
+ Out.insert(T);
}
}
-const TypeSetByHwMode &TypeInfer::getLegalTypes() {
+const TypeSetByHwMode &TypeInfer::getLegalTypes() const {
if (!LegalTypesCached) {
TypeSetByHwMode::SetType &LegalTypes = LegalCache.getOrCreate(DefaultMode);
// Stuff all types from all modes into the default mode.
@@ -883,26 +866,26 @@ const TypeSetByHwMode &TypeInfer::getLegalTypes() {
LegalTypes.insert(I.second);
LegalTypesCached = true;
}
- assert(LegalCache.isDefaultOnly() && "Default-mode only expected");
+ assert(LegalCache.isSimple() && "Default-mode only expected");
return LegalCache;
}
-#ifndef NDEBUG
TypeInfer::ValidateOnExit::~ValidateOnExit() {
if (Infer.Validate && !VTS.validate()) {
- dbgs() << "Type set is empty for each HW mode:\n"
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+ errs() << "Type set is empty for each HW mode:\n"
"possible type contradiction in the pattern below "
"(use -print-records with llvm-tblgen to see all "
"expanded records).\n";
Infer.TP.dump();
- dbgs() << "Generated from record:\n";
+ errs() << "Generated from record:\n";
Infer.TP.getRecord()->dump();
+#endif
PrintFatalError(Infer.TP.getRecord()->getLoc(),
"Type set is empty for each HW mode in '" +
Infer.TP.getRecord()->getName() + "'");
}
}
-#endif
//===----------------------------------------------------------------------===//
@@ -1512,6 +1495,9 @@ void PatternToMatch::getPredicateRecords(
}
// Sort so that different orders get canonicalized to the same string.
llvm::sort(PredicateRecs, LessRecord());
+ // Remove duplicate predicates.
+ PredicateRecs.erase(std::unique(PredicateRecs.begin(), PredicateRecs.end()),
+ PredicateRecs.end());
}
/// getPredicateCheck - Return a single string containing all of this
@@ -1522,22 +1508,17 @@ std::string PatternToMatch::getPredicateCheck() const {
getPredicateRecords(PredicateRecs);
SmallString<128> PredicateCheck;
+ raw_svector_ostream OS(PredicateCheck);
+ ListSeparator LS(" && ");
for (Record *Pred : PredicateRecs) {
StringRef CondString = Pred->getValueAsString("CondString");
if (CondString.empty())
continue;
- if (!PredicateCheck.empty())
- PredicateCheck += " && ";
- PredicateCheck += "(";
- PredicateCheck += CondString;
- PredicateCheck += ")";
+ OS << LS << '(' << CondString << ')';
}
- if (!HwModeFeatures.empty()) {
- if (!PredicateCheck.empty())
- PredicateCheck += " && ";
- PredicateCheck += HwModeFeatures;
- }
+ if (!HwModeFeatures.empty())
+ OS << LS << HwModeFeatures;
return std::string(PredicateCheck);
}
@@ -1792,7 +1773,7 @@ bool TreePatternNode::ContainsUnresolvedType(TreePattern &TP) const {
bool TreePatternNode::hasProperTypeByHwMode() const {
for (const TypeSetByHwMode &S : Types)
- if (!S.isDefaultOnly())
+ if (!S.isSimple())
return true;
for (const TreePatternNodePtr &C : Children)
if (C->hasProperTypeByHwMode())
@@ -1880,7 +1861,7 @@ static unsigned GetNumNodeResults(Record *Operator, CodeGenDAGPatterns &CDP) {
return 0; // All return nothing.
if (Operator->isSubClassOf("Intrinsic"))
- return CDP.getIntrinsic(Operator).IS.RetVTs.size();
+ return CDP.getIntrinsic(Operator).IS.RetTys.size();
if (Operator->isSubClassOf("SDNode"))
return CDP.getSDNodeInfo(Operator).getNumResults();
@@ -1996,7 +1977,17 @@ void TreePatternNode::dump() const {
bool TreePatternNode::isIsomorphicTo(const TreePatternNode *N,
const MultipleUseVarSet &DepVars) const {
if (N == this) return true;
- if (N->isLeaf() != isLeaf() || getExtTypes() != N->getExtTypes() ||
+ if (N->isLeaf() != isLeaf())
+ return false;
+
+ // Check operator of non-leaves early since it can be cheaper than checking
+ // types.
+ if (!isLeaf())
+ if (N->getOperator() != getOperator() ||
+ N->getNumChildren() != getNumChildren())
+ return false;
+
+ if (getExtTypes() != N->getExtTypes() ||
getPredicateCalls() != N->getPredicateCalls() ||
getTransformFn() != N->getTransformFn())
return false;
@@ -2004,16 +1995,13 @@ bool TreePatternNode::isIsomorphicTo(const TreePatternNode *N,
if (isLeaf()) {
if (DefInit *DI = dyn_cast<DefInit>(getLeafValue())) {
if (DefInit *NDI = dyn_cast<DefInit>(N->getLeafValue())) {
- return ((DI->getDef() == NDI->getDef())
- && (DepVars.find(getName()) == DepVars.end()
- || getName() == N->getName()));
+ return ((DI->getDef() == NDI->getDef()) &&
+ (!DepVars.contains(getName()) || getName() == N->getName()));
}
}
return getLeafValue() == N->getLeafValue();
}
- if (N->getOperator() != getOperator() ||
- N->getNumChildren() != getNumChildren()) return false;
for (unsigned i = 0, e = getNumChildren(); i != e; ++i)
if (!getChild(i)->isIsomorphicTo(N->getChild(i), DepVars))
return false;
@@ -2025,19 +2013,20 @@ bool TreePatternNode::isIsomorphicTo(const TreePatternNode *N,
TreePatternNodePtr TreePatternNode::clone() const {
TreePatternNodePtr New;
if (isLeaf()) {
- New = std::make_shared<TreePatternNode>(getLeafValue(), getNumTypes());
+ New = makeIntrusiveRefCnt<TreePatternNode>(getLeafValue(), getNumTypes());
} else {
std::vector<TreePatternNodePtr> CChildren;
CChildren.reserve(Children.size());
for (unsigned i = 0, e = getNumChildren(); i != e; ++i)
CChildren.push_back(getChild(i)->clone());
- New = std::make_shared<TreePatternNode>(getOperator(), std::move(CChildren),
- getNumTypes());
+ New = makeIntrusiveRefCnt<TreePatternNode>(
+ getOperator(), std::move(CChildren), getNumTypes());
}
New->setName(getName());
New->setNamesAsPredicateArg(getNamesAsPredicateArg());
New->Types = Types;
New->setPredicateCalls(getPredicateCalls());
+ New->setGISelFlagsRecord(getGISelFlagsRecord());
New->setTransformFn(getTransformFn());
return New;
}
@@ -2085,14 +2074,13 @@ void TreePatternNode::SubstituteFormalArguments(
/// fragments, return the set of inlined versions (this can be more than
/// one if a PatFrags record has multiple alternatives).
void TreePatternNode::InlinePatternFragments(
- TreePatternNodePtr T, TreePattern &TP,
- std::vector<TreePatternNodePtr> &OutAlternatives) {
+ TreePattern &TP, std::vector<TreePatternNodePtr> &OutAlternatives) {
if (TP.hasError())
return;
if (isLeaf()) {
- OutAlternatives.push_back(T); // nothing to do.
+ OutAlternatives.push_back(this); // nothing to do.
return;
}
@@ -2100,16 +2088,16 @@ void TreePatternNode::InlinePatternFragments(
if (!Op->isSubClassOf("PatFrags")) {
if (getNumChildren() == 0) {
- OutAlternatives.push_back(T);
+ OutAlternatives.push_back(this);
return;
}
// Recursively inline children nodes.
- std::vector<std::vector<TreePatternNodePtr> > ChildAlternatives;
- ChildAlternatives.resize(getNumChildren());
+ std::vector<std::vector<TreePatternNodePtr>> ChildAlternatives(
+ getNumChildren());
for (unsigned i = 0, e = getNumChildren(); i != e; ++i) {
TreePatternNodePtr Child = getChildShared(i);
- Child->InlinePatternFragments(Child, TP, ChildAlternatives[i]);
+ Child->InlinePatternFragments(TP, ChildAlternatives[i]);
// If there are no alternatives for any child, there are no
// alternatives for this expression as whole.
if (ChildAlternatives[i].empty())
@@ -2125,21 +2113,22 @@ void TreePatternNode::InlinePatternFragments(
}
// The end result is an all-pairs construction of the resultant pattern.
- std::vector<unsigned> Idxs;
- Idxs.resize(ChildAlternatives.size());
+ std::vector<unsigned> Idxs(ChildAlternatives.size());
bool NotDone;
do {
// Create the variant and add it to the output list.
std::vector<TreePatternNodePtr> NewChildren;
+ NewChildren.reserve(ChildAlternatives.size());
for (unsigned i = 0, e = ChildAlternatives.size(); i != e; ++i)
NewChildren.push_back(ChildAlternatives[i][Idxs[i]]);
- TreePatternNodePtr R = std::make_shared<TreePatternNode>(
+ TreePatternNodePtr R = makeIntrusiveRefCnt<TreePatternNode>(
getOperator(), std::move(NewChildren), getNumTypes());
// Copy over properties.
R->setName(getName());
R->setNamesAsPredicateArg(getNamesAsPredicateArg());
R->setPredicateCalls(getPredicateCalls());
+ R->setGISelFlagsRecord(getGISelFlagsRecord());
R->setTransformFn(getTransformFn());
for (unsigned i = 0, e = getNumTypes(); i != e; ++i)
R->setType(i, getExtType(i));
@@ -2170,7 +2159,7 @@ void TreePatternNode::InlinePatternFragments(
TreePattern *Frag = TP.getDAGPatterns().getPatternFragment(Op);
// Verify that we are passing the right number of operands.
- if (Frag->getNumArgs() != Children.size()) {
+ if (Frag->getNumArgs() != getNumChildren()) {
TP.error("'" + Op->getName() + "' fragment requires " +
Twine(Frag->getNumArgs()) + " operands!");
return;
@@ -2209,13 +2198,16 @@ void TreePatternNode::InlinePatternFragments(
for (unsigned i = 0, e = FragTree->getNumTypes(); i != e; ++i)
FragTree->UpdateNodeType(i, getExtType(i), TP);
+ if (Op->isSubClassOf("GISelFlags"))
+ FragTree->setGISelFlagsRecord(Op);
+
// Transfer in the old predicates.
for (const TreePredicateCall &Pred : getPredicateCalls())
FragTree->addPredicateCall(Pred);
// The fragment we inlined could have recursive inlining that is needed. See
// if there are any pattern fragments in it and inline them as needed.
- FragTree->InlinePatternFragments(FragTree, TP, OutAlternatives);
+ FragTree->InlinePatternFragments(TP, OutAlternatives);
}
}
@@ -2408,10 +2400,10 @@ bool TreePatternNode::NodeHasProperty(SDNP Property,
return Int->hasProperty(Property);
}
- if (!Operator->isSubClassOf("SDPatternOperator"))
+ if (!getOperator()->isSubClassOf("SDPatternOperator"))
return false;
- return CGP.getSDNodeInfo(Operator).hasProperty(Property);
+ return CGP.getSDNodeInfo(getOperator()).hasProperty(Property);
}
@@ -2522,11 +2514,12 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
bool MadeChange = false;
// Apply the result type to the node.
- unsigned NumRetVTs = Int->IS.RetVTs.size();
- unsigned NumParamVTs = Int->IS.ParamVTs.size();
+ unsigned NumRetVTs = Int->IS.RetTys.size();
+ unsigned NumParamVTs = Int->IS.ParamTys.size();
for (unsigned i = 0, e = NumRetVTs; i != e; ++i)
- MadeChange |= UpdateNodeType(i, Int->IS.RetVTs[i], TP);
+ MadeChange |= UpdateNodeType(
+ i, getValueType(Int->IS.RetTys[i]->getValueAsDef("VT")), TP);
if (getNumChildren() != NumParamVTs + 1) {
TP.error("Intrinsic '" + Int->Name + "' expects " + Twine(NumParamVTs) +
@@ -2540,9 +2533,10 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
for (unsigned i = 0, e = getNumChildren()-1; i != e; ++i) {
MadeChange |= getChild(i+1)->ApplyTypeConstraints(TP, NotRegisters);
- MVT::SimpleValueType OpVT = Int->IS.ParamVTs[i];
- assert(getChild(i+1)->getNumTypes() == 1 && "Unhandled case");
- MadeChange |= getChild(i+1)->UpdateNodeType(0, OpVT, TP);
+ MVT::SimpleValueType OpVT =
+ getValueType(Int->IS.ParamTys[i]->getValueAsDef("VT"));
+ assert(getChild(i + 1)->getNumTypes() == 1 && "Unhandled case");
+ MadeChange |= getChild(i + 1)->UpdateNodeType(0, OpVT, TP);
}
return MadeChange;
}
@@ -2872,7 +2866,7 @@ TreePatternNodePtr TreePattern::ParseTreePattern(Init *TheInit,
OpName);
// Input argument?
- TreePatternNodePtr Res = std::make_shared<TreePatternNode>(DI, 1);
+ TreePatternNodePtr Res = makeIntrusiveRefCnt<TreePatternNode>(DI, 1);
if (R->getName() == "node" && !OpName.empty()) {
if (OpName.empty())
error("'node' argument requires a name to match with operand list");
@@ -2887,7 +2881,7 @@ TreePatternNodePtr TreePattern::ParseTreePattern(Init *TheInit,
if (isa<UnsetInit>(TheInit)) {
if (OpName.empty())
error("'?' argument requires a name to match with operand list");
- TreePatternNodePtr Res = std::make_shared<TreePatternNode>(TheInit, 1);
+ TreePatternNodePtr Res = makeIntrusiveRefCnt<TreePatternNode>(TheInit, 1);
Args.push_back(std::string(OpName));
Res->setName(OpName);
return Res;
@@ -2898,7 +2892,7 @@ TreePatternNodePtr TreePattern::ParseTreePattern(Init *TheInit,
error("Constant int or bit argument should not have a name!");
if (isa<BitInit>(TheInit))
TheInit = TheInit->convertInitializerTo(IntRecTy::get(RK));
- return std::make_shared<TreePatternNode>(TheInit, 1);
+ return makeIntrusiveRefCnt<TreePatternNode>(TheInit, 1);
}
if (BitsInit *BI = dyn_cast<BitsInit>(TheInit)) {
@@ -2906,16 +2900,20 @@ TreePatternNodePtr TreePattern::ParseTreePattern(Init *TheInit,
Init *II = BI->convertInitializerTo(IntRecTy::get(RK));
if (!II || !isa<IntInit>(II))
error("Bits value must be constants!");
- return ParseTreePattern(II, OpName);
+ return II ? ParseTreePattern(II, OpName) : nullptr;
}
DagInit *Dag = dyn_cast<DagInit>(TheInit);
if (!Dag) {
TheInit->print(errs());
error("Pattern has unexpected init kind!");
+ return nullptr;
}
DefInit *OpDef = dyn_cast<DefInit>(Dag->getOperator());
- if (!OpDef) error("Pattern has unexpected operator type!");
+ if (!OpDef) {
+ error("Pattern has unexpected operator type!");
+ return nullptr;
+ }
Record *Operator = OpDef->getDef();
if (Operator->isSubClassOf("ValueType")) {
@@ -2994,7 +2992,7 @@ TreePatternNodePtr TreePattern::ParseTreePattern(Init *TheInit,
// If this intrinsic returns void, it must have side-effects and thus a
// chain.
- if (Int.IS.RetVTs.empty())
+ if (Int.IS.RetTys.empty())
Operator = getDAGPatterns().get_intrinsic_void_sdnode();
else if (!Int.ME.doesNotAccessMemory() || Int.hasSideEffects)
// Has side-effects, requires chain.
@@ -3002,7 +3000,7 @@ TreePatternNodePtr TreePattern::ParseTreePattern(Init *TheInit,
else // Otherwise, no chain.
Operator = getDAGPatterns().get_intrinsic_wo_chain_sdnode();
- Children.insert(Children.begin(), std::make_shared<TreePatternNode>(
+ Children.insert(Children.begin(), makeIntrusiveRefCnt<TreePatternNode>(
IntInit::get(RK, IID), 1));
}
@@ -3027,9 +3025,8 @@ TreePatternNodePtr TreePattern::ParseTreePattern(Init *TheInit,
}
}
- TreePatternNodePtr Result =
- std::make_shared<TreePatternNode>(Operator, std::move(Children),
- NumResults);
+ TreePatternNodePtr Result = makeIntrusiveRefCnt<TreePatternNode>(
+ Operator, std::move(Children), NumResults);
Result->setName(OpName);
if (Dag->getName()) {
@@ -3069,11 +3066,9 @@ static bool SimplifyTree(TreePatternNodePtr &N) {
// Walk all children.
bool MadeChange = false;
- for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i) {
- TreePatternNodePtr Child = N->getChildShared(i);
- MadeChange |= SimplifyTree(Child);
- N->setChild(i, std::move(Child));
- }
+ for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i)
+ MadeChange |= SimplifyTree(N->getChildSharedPtr(i));
+
return MadeChange;
}
@@ -3492,7 +3487,8 @@ void CodeGenDAGPatterns::FindPatternInputsAndOutputs(
DefInit *Val = dyn_cast<DefInit>(Dest->getLeafValue());
if (!Val || !Val->getDef()->isSubClassOf("Register"))
I.error("implicitly defined value should be a register!");
- InstImpResults.push_back(Val->getDef());
+ if (Val)
+ InstImpResults.push_back(Val->getDef());
}
return;
}
@@ -3913,7 +3909,7 @@ void CodeGenDAGPatterns::parseInstructionPattern(
OpNode->setTransformFn(nullptr);
std::vector<TreePatternNodePtr> Children;
Children.push_back(OpNode);
- OpNode = std::make_shared<TreePatternNode>(Xform, std::move(Children),
+ OpNode = makeIntrusiveRefCnt<TreePatternNode>(Xform, std::move(Children),
OpNode->getNumTypes());
}
@@ -3924,7 +3920,7 @@ void CodeGenDAGPatterns::parseInstructionPattern(
I.error("Input operand $" + InstInputs.begin()->first +
" occurs in pattern but not in operands list!");
- TreePatternNodePtr ResultPattern = std::make_shared<TreePatternNode>(
+ TreePatternNodePtr ResultPattern = makeIntrusiveRefCnt<TreePatternNode>(
I.getRecord(), std::move(ResultNodeOperands),
GetNumNodeResults(I.getRecord(), *this));
// Copy fully inferred output node types to instruction result pattern.
@@ -3948,9 +3944,8 @@ void CodeGenDAGPatterns::parseInstructionPattern(
// Create and insert the instruction.
// FIXME: InstImpResults should not be part of DAGInstruction.
Record *R = I.getRecord();
- DAGInsts.emplace(std::piecewise_construct, std::forward_as_tuple(R),
- std::forward_as_tuple(Results, Operands, InstImpResults,
- SrcPattern, ResultPattern));
+ DAGInsts.try_emplace(R, std::move(Results), std::move(Operands),
+ std::move(InstImpResults), SrcPattern, ResultPattern);
LLVM_DEBUG(I.dump());
}
@@ -3990,9 +3985,8 @@ void CodeGenDAGPatterns::ParseInstructions() {
}
// Create and insert the instruction.
- std::vector<Record*> ImpResults;
- Instructions.insert(std::make_pair(Instr,
- DAGInstruction(Results, Operands, ImpResults)));
+ Instructions.try_emplace(Instr, std::move(Results), std::move(Operands),
+ std::vector<Record *>());
continue; // no pattern.
}
@@ -4246,7 +4240,7 @@ static TreePatternNodePtr PromoteXForms(TreePatternNodePtr N) {
N->setTransformFn(nullptr);
std::vector<TreePatternNodePtr> Children;
Children.push_back(PromoteXForms(N));
- return std::make_shared<TreePatternNode>(Xform, std::move(Children),
+ return makeIntrusiveRefCnt<TreePatternNode>(Xform, std::move(Children),
N->getNumTypes());
}
@@ -4342,13 +4336,24 @@ void CodeGenDAGPatterns::ParseOnePattern(Record *TheDef,
// that register class does not accept that type, the type inference
// will lead to a contradiction, which is not an error however, but
// a sign that this pattern will simply never match.
- if (Temp.getOnlyTree()->hasPossibleType())
- for (const auto &T : Pattern.getTrees())
+ if (Temp.getOnlyTree()->hasPossibleType()) {
+ for (const auto &T : Pattern.getTrees()) {
if (T->hasPossibleType())
AddPatternToMatch(&Pattern,
PatternToMatch(TheDef, Preds, T, Temp.getOnlyTree(),
InstImpResults, Complexity,
TheDef->getID()));
+ }
+ } else {
+ // Show a message about a dropped pattern with some info to make it
+ // easier to identify it in the .td files.
+ LLVM_DEBUG({
+ dbgs() << "Dropping: ";
+ Pattern.dump();
+ Temp.getOnlyTree()->dump();
+ dbgs() << "\n";
+ });
+ }
}
void CodeGenDAGPatterns::ParsePatterns() {
@@ -4397,6 +4402,9 @@ static void collectModes(std::set<unsigned> &Modes, const TreePatternNode *N) {
void CodeGenDAGPatterns::ExpandHwModeBasedTypes() {
const CodeGenHwModes &CGH = getTargetInfo().getHwModes();
+ if (CGH.getNumModeIds() == 1)
+ return;
+
std::vector<PatternToMatch> Copy;
PatternsToMatch.swap(Copy);
@@ -4411,15 +4419,15 @@ void CodeGenDAGPatterns::ExpandHwModeBasedTypes() {
PatternsToMatch.emplace_back(P.getSrcRecord(), P.getPredicates(),
std::move(NewSrc), std::move(NewDst),
P.getDstRegs(), P.getAddedComplexity(),
- Record::getNewUID(Records), Mode, Check);
+ Record::getNewUID(Records), Check);
};
for (PatternToMatch &P : Copy) {
- TreePatternNodePtr SrcP = nullptr, DstP = nullptr;
+ const TreePatternNode *SrcP = nullptr, *DstP = nullptr;
if (P.getSrcPattern()->hasProperTypeByHwMode())
- SrcP = P.getSrcPatternShared();
+ SrcP = P.getSrcPattern();
if (P.getDstPattern()->hasProperTypeByHwMode())
- DstP = P.getDstPatternShared();
+ DstP = P.getDstPattern();
if (!SrcP && !DstP) {
PatternsToMatch.push_back(P);
continue;
@@ -4427,9 +4435,9 @@ void CodeGenDAGPatterns::ExpandHwModeBasedTypes() {
std::set<unsigned> Modes;
if (SrcP)
- collectModes(Modes, SrcP.get());
+ collectModes(Modes, SrcP);
if (DstP)
- collectModes(Modes, DstP.get());
+ collectModes(Modes, DstP);
// The predicate for the default mode needs to be constructed for each
// pattern separately.
@@ -4450,14 +4458,14 @@ void CodeGenDAGPatterns::ExpandHwModeBasedTypes() {
// Fill the map entry for this mode.
const HwMode &HM = CGH.getMode(M);
- AppendPattern(P, M, "(MF->getSubtarget().checkFeatures(\"" + HM.Features + "\"))");
+ AppendPattern(P, M, HM.Predicates);
// Add negations of the HM's predicates to the default predicate.
if (!DefaultCheck.empty())
DefaultCheck += " && ";
- DefaultCheck += "(!(MF->getSubtarget().checkFeatures(\"";
- DefaultCheck += HM.Features;
- DefaultCheck += "\")))";
+ DefaultCheck += "!(";
+ DefaultCheck += HM.Predicates;
+ DefaultCheck += ")";
}
bool HasDefault = Modes.count(DefaultMode);
@@ -4518,8 +4526,7 @@ static void CombineChildVariants(
return;
// The end result is an all-pairs construction of the resultant pattern.
- std::vector<unsigned> Idxs;
- Idxs.resize(ChildVariants.size());
+ std::vector<unsigned> Idxs(ChildVariants.size());
bool NotDone;
do {
#ifndef NDEBUG
@@ -4533,15 +4540,17 @@ static void CombineChildVariants(
#endif
// Create the variant and add it to the output list.
std::vector<TreePatternNodePtr> NewChildren;
+ NewChildren.reserve(ChildVariants.size());
for (unsigned i = 0, e = ChildVariants.size(); i != e; ++i)
NewChildren.push_back(ChildVariants[i][Idxs[i]]);
- TreePatternNodePtr R = std::make_shared<TreePatternNode>(
+ TreePatternNodePtr R = makeIntrusiveRefCnt<TreePatternNode>(
Orig->getOperator(), std::move(NewChildren), Orig->getNumTypes());
// Copy over properties.
R->setName(Orig->getName());
R->setNamesAsPredicateArg(Orig->getNamesAsPredicateArg());
R->setPredicateCalls(Orig->getPredicateCalls());
+ R->setGISelFlagsRecord(Orig->getGISelFlagsRecord());
R->setTransformFn(Orig->getTransformFn());
for (unsigned i = 0, e = Orig->getNumTypes(); i != e; ++i)
R->setType(i, Orig->getExtType(i));
@@ -4679,8 +4688,8 @@ static void GenerateVariantsOf(TreePatternNodePtr N,
}
// Compute permutations of all children.
- std::vector<std::vector<TreePatternNodePtr>> ChildVariants;
- ChildVariants.resize(N->getNumChildren());
+ std::vector<std::vector<TreePatternNodePtr>> ChildVariants(
+ N->getNumChildren());
for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i)
GenerateVariantsOf(N->getChildShared(i), ChildVariants[i], CDP, DepVars);
@@ -4708,17 +4717,10 @@ static void GenerateVariantsOf(TreePatternNodePtr N,
}
// Consider the commuted order.
if (NoRegisters) {
- std::vector<std::vector<TreePatternNodePtr>> Variants;
- unsigned i = 0;
- if (isCommIntrinsic)
- Variants.push_back(std::move(ChildVariants[i++])); // Intrinsic id.
- Variants.push_back(std::move(ChildVariants[i + 1]));
- Variants.push_back(std::move(ChildVariants[i]));
- i += 2;
- // Remaining operands are not commuted.
- for (; i != N->getNumChildren(); ++i)
- Variants.push_back(std::move(ChildVariants[i]));
- CombineChildVariants(N, Variants, OutVariants, CDP, DepVars);
+ // Swap the first two operands after the intrinsic id, if present.
+ unsigned i = isCommIntrinsic ? 1 : 0;
+ std::swap(ChildVariants[i], ChildVariants[i + 1]);
+ CombineChildVariants(N, ChildVariants, OutVariants, CDP, DepVars);
}
}
}
@@ -4788,7 +4790,6 @@ void CodeGenDAGPatterns::GenerateVariants() {
Variant, PatternsToMatch[i].getDstPatternShared(),
PatternsToMatch[i].getDstRegs(),
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 ec35e6680088..2611fe06f55c 100644
--- a/llvm/utils/TableGen/CodeGenDAGPatterns.h
+++ b/llvm/utils/TableGen/CodeGenDAGPatterns.h
@@ -17,12 +17,16 @@
#include "CodeGenIntrinsics.h"
#include "CodeGenTarget.h"
#include "SDNodeProperties.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSet.h"
+#include "llvm/ADT/Twine.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
+#include "llvm/TableGen/Record.h"
#include <algorithm>
#include <array>
#include <functional>
@@ -32,7 +36,6 @@
namespace llvm {
-class Record;
class Init;
class ListInit;
class DagInit;
@@ -42,7 +45,7 @@ class TreePatternNode;
class CodeGenDAGPatterns;
/// Shared pointer for TreePatternNode.
-using TreePatternNodePtr = std::shared_ptr<TreePatternNode>;
+using TreePatternNodePtr = IntrusiveRefCntPtr<TreePatternNode>;
/// This represents a set of MVTs. Since the underlying type for the MVT
/// is uint8_t, there are at most 256 values. To reduce the number of memory
@@ -191,7 +194,7 @@ raw_ostream &operator<<(raw_ostream &OS, const MachineValueTypeSet &T);
struct TypeSetByHwMode : public InfoByHwMode<MachineValueTypeSet> {
using SetType = MachineValueTypeSet;
- SmallVector<unsigned, 16> AddrSpaces;
+ unsigned AddrSpace = std::numeric_limits<unsigned>::max();
TypeSetByHwMode() = default;
TypeSetByHwMode(const TypeSetByHwMode &VTS) = default;
@@ -211,22 +214,17 @@ struct TypeSetByHwMode : public InfoByHwMode<MachineValueTypeSet> {
LLVM_ATTRIBUTE_ALWAYS_INLINE
bool isMachineValueType() const {
- return isDefaultOnly() && Map.begin()->second.size() == 1;
+ return isSimple() && getSimple().size() == 1;
}
LLVM_ATTRIBUTE_ALWAYS_INLINE
MVT getMachineValueType() const {
assert(isMachineValueType());
- return *Map.begin()->second.begin();
+ return *getSimple().begin();
}
bool isPossible() const;
- LLVM_ATTRIBUTE_ALWAYS_INLINE
- bool isDefaultOnly() const {
- return Map.size() == 1 && Map.begin()->first == DefaultMode;
- }
-
bool isPointer() const {
return getValueTypeByHwMode().isPointer();
}
@@ -259,7 +257,7 @@ private:
raw_ostream &operator<<(raw_ostream &OS, const TypeSetByHwMode &T);
struct TypeInfer {
- TypeInfer(TreePattern &T) : TP(T), ForceMode(0) {}
+ TypeInfer(TreePattern &T) : TP(T) {}
bool isConcrete(const TypeSetByHwMode &VTS, bool AllowEmpty) const {
return VTS.isValueTypeByHwMode(AllowEmpty);
@@ -274,11 +272,11 @@ struct TypeInfer {
/// expand*) is to return "true" if a change has been made, "false"
/// otherwise.
- bool MergeInTypeInfo(TypeSetByHwMode &Out, const TypeSetByHwMode &In);
- bool MergeInTypeInfo(TypeSetByHwMode &Out, MVT::SimpleValueType InVT) {
+ bool MergeInTypeInfo(TypeSetByHwMode &Out, const TypeSetByHwMode &In) const;
+ bool MergeInTypeInfo(TypeSetByHwMode &Out, MVT::SimpleValueType InVT) const {
return MergeInTypeInfo(Out, TypeSetByHwMode(InVT));
}
- bool MergeInTypeInfo(TypeSetByHwMode &Out, ValueTypeByHwMode InVT) {
+ bool MergeInTypeInfo(TypeSetByHwMode &Out, ValueTypeByHwMode InVT) const {
return MergeInTypeInfo(Out, TypeSetByHwMode(InVT));
}
@@ -332,19 +330,16 @@ struct TypeInfer {
/// For each overloaded type (i.e. of form *Any), replace it with the
/// corresponding subset of legal, specific types.
- void expandOverloads(TypeSetByHwMode &VTS);
+ void expandOverloads(TypeSetByHwMode &VTS) const;
void expandOverloads(TypeSetByHwMode::SetType &Out,
- const TypeSetByHwMode::SetType &Legal);
+ const TypeSetByHwMode::SetType &Legal) const;
struct ValidateOnExit {
- ValidateOnExit(TypeSetByHwMode &T, TypeInfer &TI) : Infer(TI), VTS(T) {}
- #ifndef NDEBUG
+ ValidateOnExit(const TypeSetByHwMode &T, const TypeInfer &TI)
+ : Infer(TI), VTS(T) {}
~ValidateOnExit();
- #else
- ~ValidateOnExit() {} // Empty destructor with NDEBUG.
- #endif
- TypeInfer &Infer;
- TypeSetByHwMode &VTS;
+ const TypeInfer &Infer;
+ const TypeSetByHwMode &VTS;
};
struct SuppressValidation {
@@ -359,16 +354,14 @@ struct TypeInfer {
};
TreePattern &TP;
- unsigned ForceMode; // Mode to use when set.
- bool CodeGen = false; // Set during generation of matcher code.
bool Validate = true; // Indicate whether to validate types.
private:
- const TypeSetByHwMode &getLegalTypes();
+ const TypeSetByHwMode &getLegalTypes() const;
/// Cached legal types (in default mode).
- bool LegalTypesCached = false;
- TypeSetByHwMode LegalCache;
+ mutable bool LegalTypesCached = false;
+ mutable TypeSetByHwMode LegalCache;
};
/// Set type used to track multiply used variables in patterns
@@ -632,7 +625,7 @@ struct TreePredicateCall {
}
};
-class TreePatternNode {
+class TreePatternNode : public RefCountedBase<TreePatternNode> {
/// The type of each node result. Before and during type inference, each
/// result may be a set of possible types. After (successful) type inference,
/// each is a single concrete type.
@@ -641,13 +634,10 @@ class TreePatternNode {
/// The index of each result in results of the pattern.
std::vector<unsigned> ResultPerm;
- /// Operator - The Record for the operator if this is an interior node (not
- /// a leaf).
- Record *Operator;
-
- /// Val - The init value (e.g. the "GPRC" record, or "7") for a leaf.
- ///
- Init *Val;
+ /// OperatorOrVal - The Record for the operator if this is an interior node
+ /// (not a leaf) or the init value (e.g. the "GPRC" record, or "7") for a
+ /// leaf.
+ PointerUnion<Record *, Init *> OperatorOrVal;
/// Name - The name given to this node with the :$foo notation.
///
@@ -665,17 +655,20 @@ class TreePatternNode {
std::vector<TreePatternNodePtr> Children;
+ /// If this was instantiated from a PatFrag node, and the PatFrag was derived
+ /// from "GISelFlags": the original Record derived from GISelFlags.
+ const Record *GISelFlags = nullptr;
+
public:
TreePatternNode(Record *Op, std::vector<TreePatternNodePtr> Ch,
unsigned NumResults)
- : Operator(Op), Val(nullptr), TransformFn(nullptr),
- Children(std::move(Ch)) {
+ : OperatorOrVal(Op), TransformFn(nullptr), Children(std::move(Ch)) {
Types.resize(NumResults);
ResultPerm.resize(NumResults);
std::iota(ResultPerm.begin(), ResultPerm.end(), 0);
}
- TreePatternNode(Init *val, unsigned NumResults) // leaf ctor
- : Operator(nullptr), Val(val), TransformFn(nullptr) {
+ TreePatternNode(Init *val, unsigned NumResults) // leaf ctor
+ : OperatorOrVal(val), TransformFn(nullptr) {
Types.resize(NumResults);
ResultPerm.resize(NumResults);
std::iota(ResultPerm.begin(), ResultPerm.end(), 0);
@@ -695,7 +688,7 @@ public:
NamesAsPredicateArg.push_back(N);
}
- bool isLeaf() const { return Val != nullptr; }
+ bool isLeaf() const { return isa<Init *>(OperatorOrVal); }
// Type accessors.
unsigned getNumTypes() const { return Types.size(); }
@@ -723,14 +716,26 @@ public:
unsigned getResultIndex(unsigned ResNo) const { return ResultPerm[ResNo]; }
void setResultIndex(unsigned ResNo, unsigned RI) { ResultPerm[ResNo] = RI; }
- Init *getLeafValue() const { assert(isLeaf()); return Val; }
- Record *getOperator() const { assert(!isLeaf()); return Operator; }
+ Init *getLeafValue() const {
+ assert(isLeaf());
+ return cast<Init *>(OperatorOrVal);
+ }
+ Record *getOperator() const {
+ assert(!isLeaf());
+ return cast<Record *>(OperatorOrVal);
+ }
unsigned getNumChildren() const { return Children.size(); }
- TreePatternNode *getChild(unsigned N) const { return Children[N].get(); }
+ const TreePatternNode *getChild(unsigned N) const {
+ return Children[N].get();
+ }
+ TreePatternNode *getChild(unsigned N) { return Children[N].get(); }
const TreePatternNodePtr &getChildShared(unsigned N) const {
return Children[N];
}
+ TreePatternNodePtr &getChildSharedPtr(unsigned N) {
+ return Children[N];
+ }
void setChild(unsigned i, TreePatternNodePtr N) { Children[i] = N; }
/// hasChild - Return true if N is any of our children.
@@ -794,6 +799,9 @@ public:
/// marked isCommutative.
bool isCommutativeIntrinsic(const CodeGenDAGPatterns &CDP) const;
+ void setGISelFlagsRecord(const Record *R) { GISelFlags = R; }
+ const Record *getGISelFlagsRecord() const { return GISelFlags; }
+
void print(raw_ostream &OS) const;
void dump() const;
@@ -818,11 +826,10 @@ public: // Higher level manipulation routines.
void
SubstituteFormalArguments(std::map<std::string, TreePatternNodePtr> &ArgMap);
- /// InlinePatternFragments - If this pattern refers to any pattern
+ /// InlinePatternFragments - If \p T pattern refers to any pattern
/// fragments, return the set of inlined versions (this can be more than
/// one if a PatFrags record has multiple alternatives).
- void InlinePatternFragments(TreePatternNodePtr T,
- TreePattern &TP,
+ void InlinePatternFragments(TreePattern &TP,
std::vector<TreePatternNodePtr> &OutAlternatives);
/// ApplyTypeConstraints - Apply all of the type constraints relevant to
@@ -860,7 +867,6 @@ inline raw_ostream &operator<<(raw_ostream &OS, const TreePatternNode &TPN) {
return OS;
}
-
/// TreePattern - Represent a pattern, used for instructions, pattern
/// fragments, etc.
///
@@ -950,10 +956,10 @@ public:
/// PatFrags references. This may increase the number of trees in the
/// pattern if a PatFrags has multiple alternatives.
void InlinePatternFragments() {
- std::vector<TreePatternNodePtr> Copy = Trees;
- Trees.clear();
- for (unsigned i = 0, e = Copy.size(); i != e; ++i)
- Copy[i]->InlinePatternFragments(Copy[i], *this, Trees);
+ std::vector<TreePatternNodePtr> Copy;
+ Trees.swap(Copy);
+ for (const TreePatternNodePtr &C : Copy)
+ C->InlinePatternFragments(*this, Trees);
}
/// InferAllTypes - Infer/propagate as many types throughout the expression
@@ -1023,13 +1029,14 @@ class DAGInstruction {
TreePatternNodePtr ResultPattern;
public:
- DAGInstruction(const std::vector<Record*> &results,
- const std::vector<Record*> &operands,
- const std::vector<Record*> &impresults,
+ DAGInstruction(std::vector<Record *> &&results,
+ std::vector<Record *> &&operands,
+ std::vector<Record *> &&impresults,
TreePatternNodePtr srcpattern = nullptr,
TreePatternNodePtr resultpattern = nullptr)
- : Results(results), Operands(operands), ImpResults(impresults),
- SrcPattern(srcpattern), ResultPattern(resultpattern) {}
+ : Results(std::move(results)), Operands(std::move(operands)),
+ ImpResults(std::move(impresults)), SrcPattern(srcpattern),
+ ResultPattern(resultpattern) {}
unsigned getNumResults() const { return Results.size(); }
unsigned getNumOperands() const { return Operands.size(); }
@@ -1066,17 +1073,16 @@ class PatternToMatch {
std::string HwModeFeatures;
int AddedComplexity; // Add to matching pattern complexity.
unsigned ID; // Unique ID for the record.
- unsigned ForceMode; // Force this mode in type inference when set.
public:
PatternToMatch(Record *srcrecord, ListInit *preds, TreePatternNodePtr src,
TreePatternNodePtr dst, std::vector<Record *> dstregs,
- int complexity, unsigned uid, unsigned setmode = 0,
+ int complexity, unsigned uid,
const Twine &hwmodefeatures = "")
: SrcRecord(srcrecord), Predicates(preds), SrcPattern(src),
DstPattern(dst), Dstregs(std::move(dstregs)),
HwModeFeatures(hwmodefeatures.str()), AddedComplexity(complexity),
- ID(uid), ForceMode(setmode) {}
+ ID(uid) {}
Record *getSrcRecord() const { return SrcRecord; }
ListInit *getPredicates() const { return Predicates; }
@@ -1088,7 +1094,6 @@ public:
StringRef getHwModeFeatures() const { return HwModeFeatures; }
int getAddedComplexity() const { return AddedComplexity; }
unsigned getID() const { return ID; }
- unsigned getForceMode() const { return ForceMode; }
std::string getPredicateCheck() const;
void getPredicateRecords(SmallVectorImpl<Record *> &PredicateRecs) const;
diff --git a/llvm/utils/TableGen/CodeGenHwModes.cpp b/llvm/utils/TableGen/CodeGenHwModes.cpp
index 2fec46c44100..2171507f4c63 100644
--- a/llvm/utils/TableGen/CodeGenHwModes.cpp
+++ b/llvm/utils/TableGen/CodeGenHwModes.cpp
@@ -21,6 +21,19 @@ StringRef CodeGenHwModes::DefaultModeName = "DefaultMode";
HwMode::HwMode(Record *R) {
Name = R->getName();
Features = std::string(R->getValueAsString("Features"));
+
+ std::vector<Record *> PredicateRecs = R->getValueAsListOfDefs("Predicates");
+ SmallString<128> PredicateCheck;
+ raw_svector_ostream OS(PredicateCheck);
+ ListSeparator LS(" && ");
+ for (Record *Pred : PredicateRecs) {
+ StringRef CondString = Pred->getValueAsString("CondString");
+ if (CondString.empty())
+ continue;
+ OS << LS << '(' << CondString << ')';
+ }
+
+ Predicates = std::string(PredicateCheck);
}
LLVM_DUMP_METHOD
@@ -38,7 +51,7 @@ HwModeSelect::HwModeSelect(Record *R, CodeGenHwModes &CGH) {
report_fatal_error("error in target description.");
}
for (unsigned i = 0, e = Modes.size(); i != e; ++i) {
- unsigned ModeId = CGH.getHwModeId(Modes[i]->getName());
+ unsigned ModeId = CGH.getHwModeId(Modes[i]);
Items.push_back(std::make_pair(ModeId, Objects[i]));
}
}
@@ -52,34 +65,26 @@ void HwModeSelect::dump() const {
}
CodeGenHwModes::CodeGenHwModes(RecordKeeper &RK) : Records(RK) {
- std::vector<Record*> MRs = Records.getAllDerivedDefinitions("HwMode");
- // The default mode needs a definition in the .td sources for TableGen
- // to accept references to it. We need to ignore the definition here.
- for (auto I = MRs.begin(), E = MRs.end(); I != E; ++I) {
- if ((*I)->getName() != DefaultModeName)
+ for (Record *R : Records.getAllDerivedDefinitions("HwMode")) {
+ // The default mode needs a definition in the .td sources for TableGen
+ // to accept references to it. We need to ignore the definition here.
+ if (R->getName() == DefaultModeName)
continue;
- MRs.erase(I);
- break;
- }
-
- for (Record *R : MRs) {
Modes.emplace_back(R);
- unsigned NewId = Modes.size();
- ModeIds.insert(std::make_pair(Modes[NewId-1].Name, NewId));
+ ModeIds.insert(std::make_pair(R, Modes.size()));
}
- std::vector<Record*> MSs = Records.getAllDerivedDefinitions("HwModeSelect");
- for (Record *R : MSs) {
+ for (Record *R : Records.getAllDerivedDefinitions("HwModeSelect")) {
auto P = ModeSelects.emplace(std::make_pair(R, HwModeSelect(R, *this)));
assert(P.second);
(void)P;
}
}
-unsigned CodeGenHwModes::getHwModeId(StringRef Name) const {
- if (Name == DefaultModeName)
+unsigned CodeGenHwModes::getHwModeId(Record *R) const {
+ if (R->getName() == DefaultModeName)
return DefaultMode;
- auto F = ModeIds.find(Name);
+ auto F = ModeIds.find(R);
assert(F != ModeIds.end() && "Unknown mode name");
return F->second;
}
@@ -101,7 +106,7 @@ void CodeGenHwModes::dump() const {
dbgs() << "ModeIds: {\n";
for (const auto &P : ModeIds)
- dbgs() << " " << P.first() << " -> " << P.second << '\n';
+ dbgs() << " " << P.first->getName() << " -> " << P.second << '\n';
dbgs() << "}\n";
dbgs() << "ModeSelects: {\n";
diff --git a/llvm/utils/TableGen/CodeGenHwModes.h b/llvm/utils/TableGen/CodeGenHwModes.h
index 55507cbca37d..09d20ad85c5e 100644
--- a/llvm/utils/TableGen/CodeGenHwModes.h
+++ b/llvm/utils/TableGen/CodeGenHwModes.h
@@ -11,10 +11,12 @@
#ifndef LLVM_UTILS_TABLEGEN_CODEGENHWMODES_H
#define LLVM_UTILS_TABLEGEN_CODEGENHWMODES_H
-#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
#include <cassert>
#include <map>
#include <string>
+#include <utility>
#include <vector>
// HwModeId -> list of predicates (definition)
@@ -29,6 +31,7 @@ namespace llvm {
HwMode(Record *R);
StringRef Name;
std::string Features;
+ std::string Predicates;
void dump() const;
};
@@ -44,7 +47,7 @@ namespace llvm {
static StringRef DefaultModeName;
CodeGenHwModes(RecordKeeper &R);
- unsigned getHwModeId(StringRef Name) const;
+ unsigned getHwModeId(Record *R) const;
const HwMode &getMode(unsigned Id) const {
assert(Id != 0 && "Mode id of 0 is reserved for the default mode");
return Modes[Id-1];
@@ -55,7 +58,7 @@ namespace llvm {
private:
RecordKeeper &Records;
- StringMap<unsigned> ModeIds; // HwMode (string) -> HwModeId
+ DenseMap<Record *, unsigned> ModeIds; // HwMode Record -> HwModeId
std::vector<HwMode> Modes;
std::map<Record*,HwModeSelect> ModeSelects;
};
diff --git a/llvm/utils/TableGen/CodeGenInstAlias.cpp b/llvm/utils/TableGen/CodeGenInstAlias.cpp
new file mode 100644
index 000000000000..8634d45eafc7
--- /dev/null
+++ b/llvm/utils/TableGen/CodeGenInstAlias.cpp
@@ -0,0 +1,283 @@
+//===- CodeGenInstAlias.cpp - CodeGen InstAlias Class Wrapper -------------===//
+//
+// 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 implements the CodeGenInstAlias class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeGenInstAlias.h"
+#include "CodeGenInstruction.h"
+#include "CodeGenRegisters.h"
+#include "CodeGenTarget.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/TableGen/Error.h"
+#include "llvm/TableGen/Record.h"
+
+using namespace llvm;
+
+/// tryAliasOpMatch - This is a helper function for the CodeGenInstAlias
+/// constructor. It checks if an argument in an InstAlias pattern matches
+/// the corresponding operand of the instruction. It returns true on a
+/// successful match, with ResOp set to the result operand to be used.
+bool CodeGenInstAlias::tryAliasOpMatch(DagInit *Result, unsigned AliasOpNo,
+ Record *InstOpRec, bool hasSubOps,
+ ArrayRef<SMLoc> Loc, CodeGenTarget &T,
+ ResultOperand &ResOp) {
+ Init *Arg = Result->getArg(AliasOpNo);
+ DefInit *ADI = dyn_cast<DefInit>(Arg);
+ Record *ResultRecord = ADI ? ADI->getDef() : nullptr;
+
+ if (ADI && ADI->getDef() == InstOpRec) {
+ // If the operand is a record, it must have a name, and the record type
+ // must match up with the instruction's argument type.
+ if (!Result->getArgName(AliasOpNo))
+ PrintFatalError(Loc, "result argument #" + Twine(AliasOpNo) +
+ " must have a name!");
+ ResOp = ResultOperand(std::string(Result->getArgNameStr(AliasOpNo)),
+ ResultRecord);
+ return true;
+ }
+
+ // For register operands, the source register class can be a subclass
+ // of the instruction register class, not just an exact match.
+ if (InstOpRec->isSubClassOf("RegisterOperand"))
+ InstOpRec = InstOpRec->getValueAsDef("RegClass");
+
+ if (ADI && ADI->getDef()->isSubClassOf("RegisterOperand"))
+ ADI = ADI->getDef()->getValueAsDef("RegClass")->getDefInit();
+
+ if (ADI && ADI->getDef()->isSubClassOf("RegisterClass")) {
+ if (!InstOpRec->isSubClassOf("RegisterClass"))
+ return false;
+ if (!T.getRegisterClass(InstOpRec).hasSubClass(
+ &T.getRegisterClass(ADI->getDef())))
+ return false;
+ ResOp = ResultOperand(std::string(Result->getArgNameStr(AliasOpNo)),
+ ResultRecord);
+ return true;
+ }
+
+ // Handle explicit registers.
+ if (ADI && ADI->getDef()->isSubClassOf("Register")) {
+ if (InstOpRec->isSubClassOf("OptionalDefOperand")) {
+ DagInit *DI = InstOpRec->getValueAsDag("MIOperandInfo");
+ // The operand info should only have a single (register) entry. We
+ // want the register class of it.
+ InstOpRec = cast<DefInit>(DI->getArg(0))->getDef();
+ }
+
+ if (!InstOpRec->isSubClassOf("RegisterClass"))
+ return false;
+
+ if (!T.getRegisterClass(InstOpRec).contains(
+ T.getRegBank().getReg(ADI->getDef())))
+ PrintFatalError(Loc, "fixed register " + ADI->getDef()->getName() +
+ " is not a member of the " +
+ InstOpRec->getName() + " register class!");
+
+ if (Result->getArgName(AliasOpNo))
+ PrintFatalError(Loc, "result fixed register argument must "
+ "not have a name!");
+
+ ResOp = ResultOperand(ResultRecord);
+ return true;
+ }
+
+ // Handle "zero_reg" for optional def operands.
+ if (ADI && ADI->getDef()->getName() == "zero_reg") {
+
+ // Check if this is an optional def.
+ // Tied operands where the source is a sub-operand of a complex operand
+ // need to represent both operands in the alias destination instruction.
+ // Allow zero_reg for the tied portion. This can and should go away once
+ // the MC representation of things doesn't use tied operands at all.
+ // if (!InstOpRec->isSubClassOf("OptionalDefOperand"))
+ // throw TGError(Loc, "reg0 used for result that is not an "
+ // "OptionalDefOperand!");
+
+ ResOp = ResultOperand(static_cast<Record *>(nullptr));
+ return true;
+ }
+
+ // Literal integers.
+ if (IntInit *II = dyn_cast<IntInit>(Arg)) {
+ if (hasSubOps || !InstOpRec->isSubClassOf("Operand"))
+ return false;
+ // Integer arguments can't have names.
+ if (Result->getArgName(AliasOpNo))
+ PrintFatalError(Loc, "result argument #" + Twine(AliasOpNo) +
+ " must not have a name!");
+ ResOp = ResultOperand(II->getValue());
+ return true;
+ }
+
+ // Bits<n> (also used for 0bxx literals)
+ if (BitsInit *BI = dyn_cast<BitsInit>(Arg)) {
+ if (hasSubOps || !InstOpRec->isSubClassOf("Operand"))
+ return false;
+ 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(BI->getRecordKeeper())));
+ if (!II)
+ return false;
+ ResOp = ResultOperand(II->getValue());
+ return true;
+ }
+
+ // If both are Operands with the same MVT, allow the conversion. It's
+ // up to the user to make sure the values are appropriate, just like
+ // for isel Pat's.
+ if (InstOpRec->isSubClassOf("Operand") && ADI &&
+ ADI->getDef()->isSubClassOf("Operand")) {
+ // FIXME: What other attributes should we check here? Identical
+ // MIOperandInfo perhaps?
+ if (InstOpRec->getValueInit("Type") != ADI->getDef()->getValueInit("Type"))
+ return false;
+ ResOp = ResultOperand(std::string(Result->getArgNameStr(AliasOpNo)),
+ ADI->getDef());
+ return true;
+ }
+
+ return false;
+}
+
+unsigned CodeGenInstAlias::ResultOperand::getMINumOperands() const {
+ if (!isRecord())
+ return 1;
+
+ Record *Rec = getRecord();
+ if (!Rec->isSubClassOf("Operand"))
+ return 1;
+
+ DagInit *MIOpInfo = Rec->getValueAsDag("MIOperandInfo");
+ if (MIOpInfo->getNumArgs() == 0) {
+ // Unspecified, so it defaults to 1
+ return 1;
+ }
+
+ return MIOpInfo->getNumArgs();
+}
+
+CodeGenInstAlias::CodeGenInstAlias(Record *R, CodeGenTarget &T) : TheDef(R) {
+ Result = R->getValueAsDag("ResultInst");
+ AsmString = std::string(R->getValueAsString("AsmString"));
+
+ // Verify that the root of the result is an instruction.
+ DefInit *DI = dyn_cast<DefInit>(Result->getOperator());
+ if (!DI || !DI->getDef()->isSubClassOf("Instruction"))
+ PrintFatalError(R->getLoc(),
+ "result of inst alias should be an instruction");
+
+ ResultInst = &T.getInstruction(DI->getDef());
+
+ // NameClass - If argument names are repeated, we need to verify they have
+ // the same class.
+ StringMap<Record *> NameClass;
+ for (unsigned i = 0, e = Result->getNumArgs(); i != e; ++i) {
+ DefInit *ADI = dyn_cast<DefInit>(Result->getArg(i));
+ if (!ADI || !Result->getArgName(i))
+ continue;
+ // Verify we don't have something like: (someinst GR16:$foo, GR32:$foo)
+ // $foo can exist multiple times in the result list, but it must have the
+ // same type.
+ Record *&Entry = NameClass[Result->getArgNameStr(i)];
+ if (Entry && Entry != ADI->getDef())
+ PrintFatalError(R->getLoc(), "result value $" + Result->getArgNameStr(i) +
+ " is both " + Entry->getName() +
+ " and " + ADI->getDef()->getName() +
+ "!");
+ Entry = ADI->getDef();
+ }
+
+ // Decode and validate the arguments of the result.
+ unsigned AliasOpNo = 0;
+ for (unsigned i = 0, e = ResultInst->Operands.size(); i != e; ++i) {
+
+ // Tied registers don't have an entry in the result dag unless they're part
+ // of a complex operand, in which case we include them anyways, as we
+ // don't have any other way to specify the whole operand.
+ if (ResultInst->Operands[i].MINumOperands == 1 &&
+ ResultInst->Operands[i].getTiedRegister() != -1) {
+ // Tied operands of different RegisterClass should be explicit within an
+ // instruction's syntax and so cannot be skipped.
+ int TiedOpNum = ResultInst->Operands[i].getTiedRegister();
+ if (ResultInst->Operands[i].Rec->getName() ==
+ ResultInst->Operands[TiedOpNum].Rec->getName())
+ continue;
+ }
+
+ if (AliasOpNo >= Result->getNumArgs())
+ PrintFatalError(R->getLoc(), "not enough arguments for instruction!");
+
+ Record *InstOpRec = ResultInst->Operands[i].Rec;
+ unsigned NumSubOps = ResultInst->Operands[i].MINumOperands;
+ ResultOperand ResOp(static_cast<int64_t>(0));
+ if (tryAliasOpMatch(Result, AliasOpNo, InstOpRec, (NumSubOps > 1),
+ R->getLoc(), T, ResOp)) {
+ // If this is a simple operand, or a complex operand with a custom match
+ // class, then we can match is verbatim.
+ if (NumSubOps == 1 || (InstOpRec->getValue("ParserMatchClass") &&
+ InstOpRec->getValueAsDef("ParserMatchClass")
+ ->getValueAsString("Name") != "Imm")) {
+ ResultOperands.push_back(ResOp);
+ ResultInstOperandIndex.push_back(std::make_pair(i, -1));
+ ++AliasOpNo;
+
+ // Otherwise, we need to match each of the suboperands individually.
+ } else {
+ DagInit *MIOI = ResultInst->Operands[i].MIOperandInfo;
+ for (unsigned SubOp = 0; SubOp != NumSubOps; ++SubOp) {
+ Record *SubRec = cast<DefInit>(MIOI->getArg(SubOp))->getDef();
+
+ // Take care to instantiate each of the suboperands with the correct
+ // nomenclature: $foo.bar
+ ResultOperands.emplace_back(
+ Result->getArgName(AliasOpNo)->getAsUnquotedString() + "." +
+ MIOI->getArgName(SubOp)->getAsUnquotedString(),
+ SubRec);
+ ResultInstOperandIndex.push_back(std::make_pair(i, SubOp));
+ }
+ ++AliasOpNo;
+ }
+ continue;
+ }
+
+ // If the argument did not match the instruction operand, and the operand
+ // is composed of multiple suboperands, try matching the suboperands.
+ if (NumSubOps > 1) {
+ DagInit *MIOI = ResultInst->Operands[i].MIOperandInfo;
+ for (unsigned SubOp = 0; SubOp != NumSubOps; ++SubOp) {
+ if (AliasOpNo >= Result->getNumArgs())
+ PrintFatalError(R->getLoc(), "not enough arguments for instruction!");
+ Record *SubRec = cast<DefInit>(MIOI->getArg(SubOp))->getDef();
+ if (tryAliasOpMatch(Result, AliasOpNo, SubRec, false, R->getLoc(), T,
+ ResOp)) {
+ ResultOperands.push_back(ResOp);
+ ResultInstOperandIndex.push_back(std::make_pair(i, SubOp));
+ ++AliasOpNo;
+ } else {
+ PrintFatalError(
+ R->getLoc(),
+ "result argument #" + Twine(AliasOpNo) +
+ " does not match instruction operand class " +
+ (SubOp == 0 ? InstOpRec->getName() : SubRec->getName()));
+ }
+ }
+ continue;
+ }
+ PrintFatalError(R->getLoc(),
+ "result argument #" + Twine(AliasOpNo) +
+ " does not match instruction operand class " +
+ InstOpRec->getName());
+ }
+
+ if (AliasOpNo != Result->getNumArgs())
+ PrintFatalError(R->getLoc(), "too many operands for instruction!");
+}
diff --git a/llvm/utils/TableGen/CodeGenInstAlias.h b/llvm/utils/TableGen/CodeGenInstAlias.h
new file mode 100644
index 000000000000..2a05273e7270
--- /dev/null
+++ b/llvm/utils/TableGen/CodeGenInstAlias.h
@@ -0,0 +1,105 @@
+//===- CodeGenInstAlias.h - InstAlias Class Wrapper -------------*- 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 defines a wrapper class for the 'InstAlias' TableGen class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_UTILS_TABLEGEN_CODEGENINSTALIAS_H
+#define LLVM_UTILS_TABLEGEN_CODEGENINSTALIAS_H
+
+#include "llvm/ADT/StringRef.h"
+#include <cassert>
+#include <cstdint>
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace llvm {
+
+template <typename T> class ArrayRef;
+class CodeGenInstruction;
+class CodeGenTarget;
+class DagInit;
+class SMLoc;
+class Record;
+
+/// CodeGenInstAlias - This represents an InstAlias definition.
+class CodeGenInstAlias {
+public:
+ Record *TheDef; // The actual record defining this InstAlias.
+
+ /// AsmString - The format string used to emit a .s file for the
+ /// instruction.
+ std::string AsmString;
+
+ /// Result - The result instruction.
+ DagInit *Result;
+
+ /// ResultInst - The instruction generated by the alias (decoded from
+ /// Result).
+ CodeGenInstruction *ResultInst;
+
+ struct ResultOperand {
+ private:
+ std::string Name;
+ Record *R = nullptr;
+ int64_t Imm = 0;
+
+ public:
+ enum { K_Record, K_Imm, K_Reg } Kind;
+
+ ResultOperand(std::string N, Record *r)
+ : Name(std::move(N)), R(r), Kind(K_Record) {}
+ ResultOperand(int64_t I) : Imm(I), Kind(K_Imm) {}
+ ResultOperand(Record *r) : R(r), Kind(K_Reg) {}
+
+ bool isRecord() const { return Kind == K_Record; }
+ bool isImm() const { return Kind == K_Imm; }
+ bool isReg() const { return Kind == K_Reg; }
+
+ StringRef getName() const {
+ assert(isRecord());
+ return Name;
+ }
+ Record *getRecord() const {
+ assert(isRecord());
+ return R;
+ }
+ int64_t getImm() const {
+ assert(isImm());
+ return Imm;
+ }
+ Record *getRegister() const {
+ assert(isReg());
+ return R;
+ }
+
+ unsigned getMINumOperands() const;
+ };
+
+ /// ResultOperands - The decoded operands for the result instruction.
+ std::vector<ResultOperand> ResultOperands;
+
+ /// ResultInstOperandIndex - For each operand, this vector holds a pair of
+ /// indices to identify the corresponding operand in the result
+ /// instruction. The first index specifies the operand and the second
+ /// index specifies the suboperand. If there are no suboperands or if all
+ /// of them are matched by the operand, the second value should be -1.
+ std::vector<std::pair<unsigned, int>> ResultInstOperandIndex;
+
+ CodeGenInstAlias(Record *R, CodeGenTarget &T);
+
+ bool tryAliasOpMatch(DagInit *Result, unsigned AliasOpNo, Record *InstOpRec,
+ bool hasSubOps, ArrayRef<SMLoc> Loc, CodeGenTarget &T,
+ ResultOperand &ResOp);
+};
+
+} // namespace llvm
+
+#endif // LLVM_UTILS_TABLEGEN_CODEGENINSTALIAS_H
diff --git a/llvm/utils/TableGen/CodeGenInstruction.cpp b/llvm/utils/TableGen/CodeGenInstruction.cpp
index 238c6a1b6ba8..8662b6fb52da 100644
--- a/llvm/utils/TableGen/CodeGenInstruction.cpp
+++ b/llvm/utils/TableGen/CodeGenInstruction.cpp
@@ -13,7 +13,6 @@
#include "CodeGenInstruction.h"
#include "CodeGenTarget.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/StringMap.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include <set>
@@ -176,7 +175,7 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) {
}
OpInfo.SubOpNames[j] = SubArgName;
- SubOpAliases[SubArgName] = std::make_pair(MIOperandNo, j);
+ SubOpAliases[SubArgName] = std::make_pair(i, j);
}
} else if (!EncoderMethod.empty()) {
// If we have no explicit sub-op dag, but have an top-level encoder
@@ -592,266 +591,3 @@ bool CodeGenInstruction::isOperandImpl(StringRef OpListName, unsigned i,
return Constraint->getDef()->isSubClassOf("TypedOperand") &&
Constraint->getDef()->getValueAsBit(PropertyName);
}
-
-//===----------------------------------------------------------------------===//
-/// CodeGenInstAlias Implementation
-//===----------------------------------------------------------------------===//
-
-/// tryAliasOpMatch - This is a helper function for the CodeGenInstAlias
-/// constructor. It checks if an argument in an InstAlias pattern matches
-/// the corresponding operand of the instruction. It returns true on a
-/// successful match, with ResOp set to the result operand to be used.
-bool CodeGenInstAlias::tryAliasOpMatch(DagInit *Result, unsigned AliasOpNo,
- Record *InstOpRec, bool hasSubOps,
- ArrayRef<SMLoc> Loc, CodeGenTarget &T,
- ResultOperand &ResOp) {
- Init *Arg = Result->getArg(AliasOpNo);
- DefInit *ADI = dyn_cast<DefInit>(Arg);
- Record *ResultRecord = ADI ? ADI->getDef() : nullptr;
-
- if (ADI && ADI->getDef() == InstOpRec) {
- // If the operand is a record, it must have a name, and the record type
- // must match up with the instruction's argument type.
- if (!Result->getArgName(AliasOpNo))
- PrintFatalError(Loc, "result argument #" + Twine(AliasOpNo) +
- " must have a name!");
- ResOp = ResultOperand(std::string(Result->getArgNameStr(AliasOpNo)),
- ResultRecord);
- return true;
- }
-
- // For register operands, the source register class can be a subclass
- // of the instruction register class, not just an exact match.
- if (InstOpRec->isSubClassOf("RegisterOperand"))
- InstOpRec = InstOpRec->getValueAsDef("RegClass");
-
- if (ADI && ADI->getDef()->isSubClassOf("RegisterOperand"))
- ADI = ADI->getDef()->getValueAsDef("RegClass")->getDefInit();
-
- if (ADI && ADI->getDef()->isSubClassOf("RegisterClass")) {
- if (!InstOpRec->isSubClassOf("RegisterClass"))
- return false;
- if (!T.getRegisterClass(InstOpRec)
- .hasSubClass(&T.getRegisterClass(ADI->getDef())))
- return false;
- ResOp = ResultOperand(std::string(Result->getArgNameStr(AliasOpNo)),
- ResultRecord);
- return true;
- }
-
- // Handle explicit registers.
- if (ADI && ADI->getDef()->isSubClassOf("Register")) {
- if (InstOpRec->isSubClassOf("OptionalDefOperand")) {
- DagInit *DI = InstOpRec->getValueAsDag("MIOperandInfo");
- // The operand info should only have a single (register) entry. We
- // want the register class of it.
- InstOpRec = cast<DefInit>(DI->getArg(0))->getDef();
- }
-
- if (!InstOpRec->isSubClassOf("RegisterClass"))
- return false;
-
- if (!T.getRegisterClass(InstOpRec)
- .contains(T.getRegBank().getReg(ADI->getDef())))
- PrintFatalError(Loc, "fixed register " + ADI->getDef()->getName() +
- " is not a member of the " + InstOpRec->getName() +
- " register class!");
-
- if (Result->getArgName(AliasOpNo))
- PrintFatalError(Loc, "result fixed register argument must "
- "not have a name!");
-
- ResOp = ResultOperand(ResultRecord);
- return true;
- }
-
- // Handle "zero_reg" for optional def operands.
- if (ADI && ADI->getDef()->getName() == "zero_reg") {
-
- // Check if this is an optional def.
- // Tied operands where the source is a sub-operand of a complex operand
- // need to represent both operands in the alias destination instruction.
- // Allow zero_reg for the tied portion. This can and should go away once
- // the MC representation of things doesn't use tied operands at all.
- //if (!InstOpRec->isSubClassOf("OptionalDefOperand"))
- // throw TGError(Loc, "reg0 used for result that is not an "
- // "OptionalDefOperand!");
-
- ResOp = ResultOperand(static_cast<Record*>(nullptr));
- return true;
- }
-
- // Literal integers.
- if (IntInit *II = dyn_cast<IntInit>(Arg)) {
- if (hasSubOps || !InstOpRec->isSubClassOf("Operand"))
- return false;
- // Integer arguments can't have names.
- if (Result->getArgName(AliasOpNo))
- PrintFatalError(Loc, "result argument #" + Twine(AliasOpNo) +
- " must not have a name!");
- ResOp = ResultOperand(II->getValue());
- return true;
- }
-
- // Bits<n> (also used for 0bxx literals)
- if (BitsInit *BI = dyn_cast<BitsInit>(Arg)) {
- if (hasSubOps || !InstOpRec->isSubClassOf("Operand"))
- return false;
- 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(BI->getRecordKeeper())));
- if (!II)
- return false;
- ResOp = ResultOperand(II->getValue());
- return true;
- }
-
- // If both are Operands with the same MVT, allow the conversion. It's
- // up to the user to make sure the values are appropriate, just like
- // for isel Pat's.
- if (InstOpRec->isSubClassOf("Operand") && ADI &&
- ADI->getDef()->isSubClassOf("Operand")) {
- // FIXME: What other attributes should we check here? Identical
- // MIOperandInfo perhaps?
- if (InstOpRec->getValueInit("Type") != ADI->getDef()->getValueInit("Type"))
- return false;
- ResOp = ResultOperand(std::string(Result->getArgNameStr(AliasOpNo)),
- ADI->getDef());
- return true;
- }
-
- return false;
-}
-
-unsigned CodeGenInstAlias::ResultOperand::getMINumOperands() const {
- if (!isRecord())
- return 1;
-
- Record *Rec = getRecord();
- if (!Rec->isSubClassOf("Operand"))
- return 1;
-
- DagInit *MIOpInfo = Rec->getValueAsDag("MIOperandInfo");
- if (MIOpInfo->getNumArgs() == 0) {
- // Unspecified, so it defaults to 1
- return 1;
- }
-
- return MIOpInfo->getNumArgs();
-}
-
-CodeGenInstAlias::CodeGenInstAlias(Record *R, CodeGenTarget &T)
- : TheDef(R) {
- Result = R->getValueAsDag("ResultInst");
- AsmString = std::string(R->getValueAsString("AsmString"));
-
- // Verify that the root of the result is an instruction.
- DefInit *DI = dyn_cast<DefInit>(Result->getOperator());
- if (!DI || !DI->getDef()->isSubClassOf("Instruction"))
- PrintFatalError(R->getLoc(),
- "result of inst alias should be an instruction");
-
- ResultInst = &T.getInstruction(DI->getDef());
-
- // NameClass - If argument names are repeated, we need to verify they have
- // the same class.
- StringMap<Record*> NameClass;
- for (unsigned i = 0, e = Result->getNumArgs(); i != e; ++i) {
- DefInit *ADI = dyn_cast<DefInit>(Result->getArg(i));
- if (!ADI || !Result->getArgName(i))
- continue;
- // Verify we don't have something like: (someinst GR16:$foo, GR32:$foo)
- // $foo can exist multiple times in the result list, but it must have the
- // same type.
- Record *&Entry = NameClass[Result->getArgNameStr(i)];
- if (Entry && Entry != ADI->getDef())
- PrintFatalError(R->getLoc(), "result value $" + Result->getArgNameStr(i) +
- " is both " + Entry->getName() + " and " +
- ADI->getDef()->getName() + "!");
- Entry = ADI->getDef();
- }
-
- // Decode and validate the arguments of the result.
- unsigned AliasOpNo = 0;
- for (unsigned i = 0, e = ResultInst->Operands.size(); i != e; ++i) {
-
- // Tied registers don't have an entry in the result dag unless they're part
- // of a complex operand, in which case we include them anyways, as we
- // don't have any other way to specify the whole operand.
- if (ResultInst->Operands[i].MINumOperands == 1 &&
- ResultInst->Operands[i].getTiedRegister() != -1) {
- // Tied operands of different RegisterClass should be explicit within an
- // instruction's syntax and so cannot be skipped.
- int TiedOpNum = ResultInst->Operands[i].getTiedRegister();
- if (ResultInst->Operands[i].Rec->getName() ==
- ResultInst->Operands[TiedOpNum].Rec->getName())
- continue;
- }
-
- if (AliasOpNo >= Result->getNumArgs())
- PrintFatalError(R->getLoc(), "not enough arguments for instruction!");
-
- Record *InstOpRec = ResultInst->Operands[i].Rec;
- unsigned NumSubOps = ResultInst->Operands[i].MINumOperands;
- ResultOperand ResOp(static_cast<int64_t>(0));
- if (tryAliasOpMatch(Result, AliasOpNo, InstOpRec, (NumSubOps > 1),
- R->getLoc(), T, ResOp)) {
- // If this is a simple operand, or a complex operand with a custom match
- // class, then we can match is verbatim.
- if (NumSubOps == 1 ||
- (InstOpRec->getValue("ParserMatchClass") &&
- InstOpRec->getValueAsDef("ParserMatchClass")
- ->getValueAsString("Name") != "Imm")) {
- ResultOperands.push_back(ResOp);
- ResultInstOperandIndex.push_back(std::make_pair(i, -1));
- ++AliasOpNo;
-
- // Otherwise, we need to match each of the suboperands individually.
- } else {
- DagInit *MIOI = ResultInst->Operands[i].MIOperandInfo;
- for (unsigned SubOp = 0; SubOp != NumSubOps; ++SubOp) {
- Record *SubRec = cast<DefInit>(MIOI->getArg(SubOp))->getDef();
-
- // Take care to instantiate each of the suboperands with the correct
- // nomenclature: $foo.bar
- ResultOperands.emplace_back(
- Result->getArgName(AliasOpNo)->getAsUnquotedString() + "." +
- MIOI->getArgName(SubOp)->getAsUnquotedString(), SubRec);
- ResultInstOperandIndex.push_back(std::make_pair(i, SubOp));
- }
- ++AliasOpNo;
- }
- continue;
- }
-
- // If the argument did not match the instruction operand, and the operand
- // is composed of multiple suboperands, try matching the suboperands.
- if (NumSubOps > 1) {
- DagInit *MIOI = ResultInst->Operands[i].MIOperandInfo;
- for (unsigned SubOp = 0; SubOp != NumSubOps; ++SubOp) {
- if (AliasOpNo >= Result->getNumArgs())
- PrintFatalError(R->getLoc(), "not enough arguments for instruction!");
- Record *SubRec = cast<DefInit>(MIOI->getArg(SubOp))->getDef();
- if (tryAliasOpMatch(Result, AliasOpNo, SubRec, false,
- R->getLoc(), T, ResOp)) {
- ResultOperands.push_back(ResOp);
- ResultInstOperandIndex.push_back(std::make_pair(i, SubOp));
- ++AliasOpNo;
- } else {
- PrintFatalError(R->getLoc(), "result argument #" + Twine(AliasOpNo) +
- " does not match instruction operand class " +
- (SubOp == 0 ? InstOpRec->getName() :SubRec->getName()));
- }
- }
- continue;
- }
- PrintFatalError(R->getLoc(), "result argument #" + Twine(AliasOpNo) +
- " does not match instruction operand class " +
- InstOpRec->getName());
- }
-
- if (AliasOpNo != Result->getNumArgs())
- PrintFatalError(R->getLoc(), "too many operands for instruction!");
-}
diff --git a/llvm/utils/TableGen/CodeGenInstruction.h b/llvm/utils/TableGen/CodeGenInstruction.h
index 72626caada56..ee7a1696bab9 100644
--- a/llvm/utils/TableGen/CodeGenInstruction.h
+++ b/llvm/utils/TableGen/CodeGenInstruction.h
@@ -16,15 +16,13 @@
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/MachineValueType.h"
+#include "llvm/CodeGen/MachineValueType.h"
#include <cassert>
#include <string>
#include <utility>
#include <vector>
namespace llvm {
-class SMLoc;
-template <typename T> class ArrayRef;
class Record;
class DagInit;
class CodeGenTarget;
@@ -340,71 +338,6 @@ template <typename T> class ArrayRef;
bool isOperandImpl(StringRef OpListName, unsigned i,
StringRef PropertyName) const;
};
-
-
- /// CodeGenInstAlias - This represents an InstAlias definition.
- class CodeGenInstAlias {
- public:
- Record *TheDef; // The actual record defining this InstAlias.
-
- /// AsmString - The format string used to emit a .s file for the
- /// instruction.
- std::string AsmString;
-
- /// Result - The result instruction.
- DagInit *Result;
-
- /// ResultInst - The instruction generated by the alias (decoded from
- /// Result).
- CodeGenInstruction *ResultInst;
-
-
- struct ResultOperand {
- private:
- std::string Name;
- Record *R = nullptr;
- int64_t Imm = 0;
-
- public:
- enum {
- K_Record,
- K_Imm,
- K_Reg
- } Kind;
-
- ResultOperand(std::string N, Record *r)
- : Name(std::move(N)), R(r), Kind(K_Record) {}
- ResultOperand(int64_t I) : Imm(I), Kind(K_Imm) {}
- ResultOperand(Record *r) : R(r), Kind(K_Reg) {}
-
- bool isRecord() const { return Kind == K_Record; }
- bool isImm() const { return Kind == K_Imm; }
- bool isReg() const { return Kind == K_Reg; }
-
- StringRef getName() const { assert(isRecord()); return Name; }
- Record *getRecord() const { assert(isRecord()); return R; }
- int64_t getImm() const { assert(isImm()); return Imm; }
- Record *getRegister() const { assert(isReg()); return R; }
-
- unsigned getMINumOperands() const;
- };
-
- /// ResultOperands - The decoded operands for the result instruction.
- std::vector<ResultOperand> ResultOperands;
-
- /// ResultInstOperandIndex - For each operand, this vector holds a pair of
- /// indices to identify the corresponding operand in the result
- /// instruction. The first index specifies the operand and the second
- /// index specifies the suboperand. If there are no suboperands or if all
- /// of them are matched by the operand, the second value should be -1.
- std::vector<std::pair<unsigned, int> > ResultInstOperandIndex;
-
- CodeGenInstAlias(Record *R, CodeGenTarget &T);
-
- bool tryAliasOpMatch(DagInit *Result, unsigned AliasOpNo,
- Record *InstOpRec, bool hasSubOps, ArrayRef<SMLoc> Loc,
- CodeGenTarget &T, ResultOperand &ResOp);
- };
-}
+} // namespace llvm
#endif
diff --git a/llvm/utils/TableGen/CodeGenIntrinsics.cpp b/llvm/utils/TableGen/CodeGenIntrinsics.cpp
new file mode 100644
index 000000000000..7cb86ad95266
--- /dev/null
+++ b/llvm/utils/TableGen/CodeGenIntrinsics.cpp
@@ -0,0 +1,270 @@
+//===- CodeGenIntrinsics.cpp - Intrinsic Class Wrapper --------------------===//
+//
+// 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 defines a wrapper class for the 'Intrinsic' TableGen class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeGenIntrinsics.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/TableGen/Error.h"
+#include "llvm/TableGen/Record.h"
+#include <algorithm>
+#include <cassert>
+using namespace llvm;
+
+//===----------------------------------------------------------------------===//
+// CodeGenIntrinsic Implementation
+//===----------------------------------------------------------------------===//
+
+CodeGenIntrinsicTable::CodeGenIntrinsicTable(const RecordKeeper &RC) {
+ std::vector<Record *> IntrProperties =
+ RC.getAllDerivedDefinitions("IntrinsicProperty");
+
+ std::vector<Record *> DefaultProperties;
+ for (Record *Rec : IntrProperties)
+ if (Rec->getValueAsBit("IsDefault"))
+ DefaultProperties.push_back(Rec);
+
+ std::vector<Record *> Defs = RC.getAllDerivedDefinitions("Intrinsic");
+ Intrinsics.reserve(Defs.size());
+
+ for (unsigned I = 0, e = Defs.size(); I != e; ++I)
+ Intrinsics.push_back(CodeGenIntrinsic(Defs[I], DefaultProperties));
+
+ llvm::sort(Intrinsics,
+ [](const CodeGenIntrinsic &LHS, const CodeGenIntrinsic &RHS) {
+ return std::tie(LHS.TargetPrefix, LHS.Name) <
+ std::tie(RHS.TargetPrefix, RHS.Name);
+ });
+ Targets.push_back({"", 0, 0});
+ for (size_t I = 0, E = Intrinsics.size(); I < E; ++I)
+ if (Intrinsics[I].TargetPrefix != Targets.back().Name) {
+ Targets.back().Count = I - Targets.back().Offset;
+ Targets.push_back({Intrinsics[I].TargetPrefix, I, 0});
+ }
+ Targets.back().Count = Intrinsics.size() - Targets.back().Offset;
+}
+
+CodeGenIntrinsic::CodeGenIntrinsic(Record *R,
+ std::vector<Record *> DefaultProperties) {
+ TheDef = R;
+ std::string DefName = std::string(R->getName());
+ ArrayRef<SMLoc> DefLoc = R->getLoc();
+ Properties = 0;
+ isOverloaded = false;
+ isCommutative = false;
+ canThrow = false;
+ isNoReturn = false;
+ isNoCallback = false;
+ isNoSync = false;
+ isNoFree = false;
+ isWillReturn = false;
+ isCold = false;
+ isNoDuplicate = false;
+ isNoMerge = false;
+ isConvergent = false;
+ isSpeculatable = false;
+ hasSideEffects = false;
+ isStrictFP = false;
+
+ if (DefName.size() <= 4 || DefName.substr(0, 4) != "int_")
+ PrintFatalError(DefLoc,
+ "Intrinsic '" + DefName + "' does not start with 'int_'!");
+
+ EnumName = DefName.substr(4);
+
+ 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"));
+
+ TargetPrefix = std::string(R->getValueAsString("TargetPrefix"));
+ Name = std::string(R->getValueAsString("LLVMName"));
+
+ if (Name == "") {
+ // If an explicit name isn't specified, derive one from the DefName.
+ Name = "llvm.";
+
+ for (unsigned i = 0, e = EnumName.size(); i != e; ++i)
+ Name += (EnumName[i] == '_') ? '.' : EnumName[i];
+ } else {
+ // Verify it starts with "llvm.".
+ if (Name.size() <= 5 || Name.substr(0, 5) != "llvm.")
+ PrintFatalError(DefLoc, "Intrinsic '" + DefName +
+ "'s name does not start with 'llvm.'!");
+ }
+
+ // If TargetPrefix is specified, make sure that Name starts with
+ // "llvm.<targetprefix>.".
+ if (!TargetPrefix.empty()) {
+ if (Name.size() < 6 + TargetPrefix.size() ||
+ Name.substr(5, 1 + TargetPrefix.size()) != (TargetPrefix + "."))
+ PrintFatalError(DefLoc, "Intrinsic '" + DefName +
+ "' does not start with 'llvm." +
+ TargetPrefix + ".'!");
+ }
+
+ if (auto *Types = R->getValue("Types")) {
+ auto *TypeList = cast<ListInit>(Types->getValue());
+ isOverloaded = R->getValueAsBit("isOverloaded");
+
+ unsigned I = 0;
+ for (unsigned E = R->getValueAsListInit("RetTypes")->size(); I < E; ++I)
+ IS.RetTys.push_back(TypeList->getElementAsRecord(I));
+
+ for (unsigned E = TypeList->size(); I < E; ++I)
+ IS.ParamTys.push_back(TypeList->getElementAsRecord(I));
+ }
+
+ // Parse the intrinsic properties.
+ ListInit *PropList = R->getValueAsListInit("IntrProperties");
+ for (unsigned i = 0, e = PropList->size(); i != e; ++i) {
+ Record *Property = PropList->getElementAsRecord(i);
+ assert(Property->isSubClassOf("IntrinsicProperty") &&
+ "Expected a property!");
+
+ setProperty(Property);
+ }
+
+ // Set default properties to true.
+ setDefaultProperties(R, DefaultProperties);
+
+ // Also record the SDPatternOperator Properties.
+ Properties = parseSDPatternOperatorProperties(R);
+
+ // Sort the argument attributes for later benefit.
+ for (auto &Attrs : ArgumentAttributes)
+ llvm::sort(Attrs);
+}
+
+void CodeGenIntrinsic::setDefaultProperties(
+ Record *R, std::vector<Record *> DefaultProperties) {
+ // opt-out of using default attributes.
+ if (R->getValueAsBit("DisableDefaultAttributes"))
+ return;
+
+ for (Record *Rec : DefaultProperties)
+ setProperty(Rec);
+}
+
+void CodeGenIntrinsic::setProperty(Record *R) {
+ if (R->getName() == "IntrNoMem")
+ ME = MemoryEffects::none();
+ else if (R->getName() == "IntrReadMem") {
+ if (ME.onlyWritesMemory())
+ PrintFatalError(TheDef->getLoc(),
+ Twine("IntrReadMem cannot be used after IntrNoMem or "
+ "IntrWriteMem. Default is ReadWrite"));
+ ME &= MemoryEffects::readOnly();
+ } else if (R->getName() == "IntrWriteMem") {
+ if (ME.onlyReadsMemory())
+ PrintFatalError(TheDef->getLoc(),
+ Twine("IntrWriteMem cannot be used after IntrNoMem or "
+ "IntrReadMem. Default is ReadWrite"));
+ ME &= MemoryEffects::writeOnly();
+ } else if (R->getName() == "IntrArgMemOnly")
+ ME &= MemoryEffects::argMemOnly();
+ else if (R->getName() == "IntrInaccessibleMemOnly")
+ ME &= MemoryEffects::inaccessibleMemOnly();
+ else if (R->getName() == "IntrInaccessibleMemOrArgMemOnly")
+ ME &= MemoryEffects::inaccessibleOrArgMemOnly();
+ else if (R->getName() == "Commutative")
+ isCommutative = true;
+ else if (R->getName() == "Throws")
+ canThrow = true;
+ else if (R->getName() == "IntrNoDuplicate")
+ isNoDuplicate = true;
+ else if (R->getName() == "IntrNoMerge")
+ isNoMerge = true;
+ else if (R->getName() == "IntrConvergent")
+ 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")
+ isNoFree = true;
+ else if (R->getName() == "IntrWillReturn")
+ isWillReturn = !isNoReturn;
+ else if (R->getName() == "IntrCold")
+ isCold = true;
+ else if (R->getName() == "IntrSpeculatable")
+ isSpeculatable = true;
+ else if (R->getName() == "IntrHasSideEffects")
+ hasSideEffects = true;
+ else if (R->getName() == "IntrStrictFP")
+ isStrictFP = true;
+ else if (R->isSubClassOf("NoCapture")) {
+ unsigned ArgNo = R->getValueAsInt("ArgNo");
+ addArgAttribute(ArgNo, NoCapture);
+ } else if (R->isSubClassOf("NoAlias")) {
+ unsigned ArgNo = R->getValueAsInt("ArgNo");
+ addArgAttribute(ArgNo, NoAlias);
+ } else if (R->isSubClassOf("NoUndef")) {
+ unsigned ArgNo = R->getValueAsInt("ArgNo");
+ addArgAttribute(ArgNo, NoUndef);
+ } else if (R->isSubClassOf("NonNull")) {
+ unsigned ArgNo = R->getValueAsInt("ArgNo");
+ addArgAttribute(ArgNo, NonNull);
+ } else if (R->isSubClassOf("Returned")) {
+ unsigned ArgNo = R->getValueAsInt("ArgNo");
+ addArgAttribute(ArgNo, Returned);
+ } else if (R->isSubClassOf("ReadOnly")) {
+ unsigned ArgNo = R->getValueAsInt("ArgNo");
+ addArgAttribute(ArgNo, ReadOnly);
+ } else if (R->isSubClassOf("WriteOnly")) {
+ unsigned ArgNo = R->getValueAsInt("ArgNo");
+ addArgAttribute(ArgNo, WriteOnly);
+ } else if (R->isSubClassOf("ReadNone")) {
+ unsigned ArgNo = R->getValueAsInt("ArgNo");
+ addArgAttribute(ArgNo, ReadNone);
+ } else if (R->isSubClassOf("ImmArg")) {
+ unsigned ArgNo = R->getValueAsInt("ArgNo");
+ addArgAttribute(ArgNo, ImmArg);
+ } else if (R->isSubClassOf("Align")) {
+ unsigned ArgNo = R->getValueAsInt("ArgNo");
+ uint64_t Align = R->getValueAsInt("Align");
+ addArgAttribute(ArgNo, Alignment, Align);
+ } else if (R->isSubClassOf("Dereferenceable")) {
+ unsigned ArgNo = R->getValueAsInt("ArgNo");
+ uint64_t Bytes = R->getValueAsInt("Bytes");
+ addArgAttribute(ArgNo, Dereferenceable, Bytes);
+ } else
+ llvm_unreachable("Unknown property!");
+}
+
+bool CodeGenIntrinsic::isParamAPointer(unsigned ParamIdx) const {
+ if (ParamIdx >= IS.ParamTys.size())
+ return false;
+ return (IS.ParamTys[ParamIdx]->isSubClassOf("LLVMQualPointerType") ||
+ IS.ParamTys[ParamIdx]->isSubClassOf("LLVMAnyPointerType"));
+}
+
+bool CodeGenIntrinsic::isParamImmArg(unsigned ParamIdx) const {
+ // Convert argument index to attribute index starting from `FirstArgIndex`.
+ ++ParamIdx;
+ if (ParamIdx >= ArgumentAttributes.size())
+ return false;
+ ArgAttribute Val{ImmArg, 0};
+ return std::binary_search(ArgumentAttributes[ParamIdx].begin(),
+ ArgumentAttributes[ParamIdx].end(), Val);
+}
+
+void CodeGenIntrinsic::addArgAttribute(unsigned Idx, ArgAttrKind AK,
+ uint64_t V) {
+ if (Idx >= ArgumentAttributes.size())
+ ArgumentAttributes.resize(Idx + 1);
+ ArgumentAttributes[Idx].emplace_back(AK, V);
+}
diff --git a/llvm/utils/TableGen/CodeGenIntrinsics.h b/llvm/utils/TableGen/CodeGenIntrinsics.h
index 0558918b3028..f3452f5acea8 100644
--- a/llvm/utils/TableGen/CodeGenIntrinsics.h
+++ b/llvm/utils/TableGen/CodeGenIntrinsics.h
@@ -1,4 +1,4 @@
-//===- CodeGenIntrinsic.h - Intrinsic Class Wrapper ------------*- C++ -*--===//
+//===- CodeGenIntrinsics.h - Intrinsic Class Wrapper -----------*- C++ -*--===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -15,9 +15,9 @@
#include "SDNodeProperties.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/Support/MachineValueType.h"
#include "llvm/Support/ModRef.h"
#include <string>
+#include <tuple>
#include <vector>
namespace llvm {
@@ -42,19 +42,13 @@ struct CodeGenIntrinsic {
/// only populated when in the context of a target .td file. When building
/// Intrinsics.td, this isn't available, because we don't know the target
/// pointer size.
- std::vector<MVT::SimpleValueType> RetVTs;
-
- /// The records for each return type.
- std::vector<Record *> RetTypeDefs;
+ std::vector<Record *> RetTys;
/// The MVT::SimpleValueType for each parameter type. Note that this list is
/// only populated when in the context of a target .td file. When building
/// Intrinsics.td, this isn't available, because we don't know the target
/// pointer size.
- std::vector<MVT::SimpleValueType> ParamVTs;
-
- /// The records for each parameter type.
- std::vector<Record *> ParamTypeDefs;
+ std::vector<Record *> ParamTys;
};
IntrinsicSignature IS;
@@ -109,6 +103,9 @@ struct CodeGenIntrinsic {
// True if the intrinsic is marked as speculatable.
bool isSpeculatable;
+ // True if the intrinsic is marked as strictfp.
+ bool isStrictFP;
+
enum ArgAttrKind {
NoCapture,
NoAlias,
@@ -119,7 +116,8 @@ struct CodeGenIntrinsic {
WriteOnly,
ReadNone,
ImmArg,
- Alignment
+ Alignment,
+ Dereferenceable
};
struct ArgAttribute {
diff --git a/llvm/utils/TableGen/CodeGenMapTable.cpp b/llvm/utils/TableGen/CodeGenMapTable.cpp
index 02695942f5c1..fd375735dfd2 100644
--- a/llvm/utils/TableGen/CodeGenMapTable.cpp
+++ b/llvm/utils/TableGen/CodeGenMapTable.cpp
@@ -78,6 +78,7 @@
#include "CodeGenInstruction.h"
#include "CodeGenTarget.h"
#include "llvm/TableGen/Error.h"
+#include "llvm/TableGen/Record.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 8ad8a7a5bc9b..5c45290a0657 100644
--- a/llvm/utils/TableGen/CodeGenRegisters.cpp
+++ b/llvm/utils/TableGen/CodeGenRegisters.cpp
@@ -872,7 +872,7 @@ bool CodeGenRegisterClass::hasType(const ValueTypeByHwMode &VT) const {
// If VT is not identical to any of this class's types, but is a simple
// type, check if any of the types for this class contain it under some
// mode.
- // The motivating example came from RISCV, where (likely because of being
+ // The motivating example came from RISC-V, where (likely because of being
// guarded by "64-bit" predicate), the type of X5 was {*:[i64]}, but the
// type in GRC was {*:[i32], m1:[i64]}.
if (VT.isSimple()) {
@@ -1659,8 +1659,8 @@ static void computeUberSets(std::vector<UberRegSet> &UberSets,
"register enum value mismatch");
// For simplicitly make the SetID the same as EnumValue.
- IntEqClasses UberSetIDs(Registers.size()+1);
- std::set<unsigned> AllocatableRegs;
+ IntEqClasses UberSetIDs(Registers.size() + 1);
+ BitVector AllocatableRegs(Registers.size() + 1);
for (auto &RegClass : RegBank.getRegClasses()) {
if (!RegClass.Allocatable)
continue;
@@ -1672,16 +1672,16 @@ static void computeUberSets(std::vector<UberRegSet> &UberSets,
unsigned USetID = UberSetIDs.findLeader((*Regs.begin())->EnumValue);
assert(USetID && "register number 0 is invalid");
- AllocatableRegs.insert((*Regs.begin())->EnumValue);
+ AllocatableRegs.set((*Regs.begin())->EnumValue);
for (const CodeGenRegister *CGR : llvm::drop_begin(Regs)) {
- AllocatableRegs.insert(CGR->EnumValue);
+ AllocatableRegs.set(CGR->EnumValue);
UberSetIDs.join(USetID, CGR->EnumValue);
}
}
// Combine non-allocatable regs.
for (const auto &Reg : Registers) {
unsigned RegNum = Reg.EnumValue;
- if (AllocatableRegs.count(RegNum))
+ if (AllocatableRegs.test(RegNum))
continue;
UberSetIDs.join(0, RegNum);
@@ -1704,7 +1704,6 @@ static void computeUberSets(std::vector<UberRegSet> &UberSets,
UberRegSet *USet = &UberSets[USetID];
USet->Regs.push_back(&Reg);
- sortAndUniqueRegisters(USet->Regs);
RegSets[i++] = USet;
}
}
diff --git a/llvm/utils/TableGen/CodeGenRegisters.h b/llvm/utils/TableGen/CodeGenRegisters.h
index 765425ed68cb..15f08d1431f9 100644
--- a/llvm/utils/TableGen/CodeGenRegisters.h
+++ b/llvm/utils/TableGen/CodeGenRegisters.h
@@ -14,6 +14,7 @@
#ifndef LLVM_UTILS_TABLEGEN_CODEGENREGISTERS_H
#define LLVM_UTILS_TABLEGEN_CODEGENREGISTERS_H
+#include "CodeGenHwModes.h"
#include "InfoByHwMode.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
@@ -32,8 +33,11 @@
#include <cassert>
#include <cstdint>
#include <deque>
+#include <functional>
#include <list>
#include <map>
+#include <memory>
+#include <optional>
#include <string>
#include <utility>
#include <vector>
@@ -41,7 +45,6 @@
namespace llvm {
class CodeGenRegBank;
- template <typename T, typename Vector, typename Set> class SetVector;
/// Used to encode a step in a register lane mask transformation.
/// Mask the bits specified in Mask, then rotate them Rol bits to the left
@@ -147,14 +150,15 @@ namespace llvm {
};
/// CodeGenRegister - Represents a register definition.
- struct CodeGenRegister {
+ class CodeGenRegister {
+ public:
Record *TheDef;
unsigned EnumValue;
std::vector<int64_t> CostPerUse;
- bool CoveredBySubRegs;
- bool HasDisjunctSubRegs;
- bool Artificial;
- bool Constant;
+ bool CoveredBySubRegs = true;
+ bool HasDisjunctSubRegs = false;
+ bool Artificial = true;
+ bool Constant = false;
// Map SubRegIndex -> Register.
typedef std::map<CodeGenSubRegIndex *, CodeGenRegister *,
diff --git a/llvm/utils/TableGen/CodeGenSchedule.cpp b/llvm/utils/TableGen/CodeGenSchedule.cpp
index 441a088c1731..04219a6e54d9 100644
--- a/llvm/utils/TableGen/CodeGenSchedule.cpp
+++ b/llvm/utils/TableGen/CodeGenSchedule.cpp
@@ -298,12 +298,12 @@ processSTIPredicate(STIPredicateFunction &Fn,
RecVec Classes = Def->getValueAsListOfDefs("Classes");
for (const Record *EC : Classes) {
const Record *Pred = EC->getValueAsDef("Predicate");
- if (Predicate2Index.find(Pred) == Predicate2Index.end())
+ if (!Predicate2Index.contains(Pred))
Predicate2Index[Pred] = NumUniquePredicates++;
RecVec Opcodes = EC->getValueAsListOfDefs("Opcodes");
for (const Record *Opcode : Opcodes) {
- if (Opcode2Index.find(Opcode) == Opcode2Index.end()) {
+ if (!Opcode2Index.contains(Opcode)) {
Opcode2Index[Opcode] = OpcodeMappings.size();
OpcodeMappings.emplace_back(Opcode, OpcodeInfo());
}
@@ -370,11 +370,11 @@ processSTIPredicate(STIPredicateFunction &Fn,
const std::pair<APInt, APInt> &RhsMasks = OpcodeMasks[RhsIdx];
auto LessThan = [](const APInt &Lhs, const APInt &Rhs) {
- unsigned LhsCountPopulation = Lhs.countPopulation();
- unsigned RhsCountPopulation = Rhs.countPopulation();
+ unsigned LhsCountPopulation = Lhs.popcount();
+ unsigned RhsCountPopulation = Rhs.popcount();
return ((LhsCountPopulation < RhsCountPopulation) ||
((LhsCountPopulation == RhsCountPopulation) &&
- (Lhs.countLeadingZeros() > Rhs.countLeadingZeros())));
+ (Lhs.countl_zero() > Rhs.countl_zero())));
};
if (LhsMasks.first != RhsMasks.first)
diff --git a/llvm/utils/TableGen/CodeGenSchedule.h b/llvm/utils/TableGen/CodeGenSchedule.h
index bbf5381ad086..76ef1e439530 100644
--- a/llvm/utils/TableGen/CodeGenSchedule.h
+++ b/llvm/utils/TableGen/CodeGenSchedule.h
@@ -15,10 +15,17 @@
#define LLVM_UTILS_TABLEGEN_CODEGENSCHEDULE_H
#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/SetTheory.h"
+#include <cassert>
+#include <string>
+#include <utility>
+#include <vector>
namespace llvm {
diff --git a/llvm/utils/TableGen/CodeGenTarget.cpp b/llvm/utils/TableGen/CodeGenTarget.cpp
index b7240f01300c..fbdc0499a8cf 100644
--- a/llvm/utils/TableGen/CodeGenTarget.cpp
+++ b/llvm/utils/TableGen/CodeGenTarget.cpp
@@ -15,13 +15,17 @@
#include "CodeGenTarget.h"
#include "CodeGenInstruction.h"
-#include "CodeGenIntrinsics.h"
+#include "CodeGenRegisters.h"
#include "CodeGenSchedule.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Twine.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include <algorithm>
+#include <iterator>
+#include <tuple>
using namespace llvm;
cl::OptionCategory AsmParserCat("Options for -gen-asm-parser");
@@ -77,6 +81,7 @@ StringRef llvm::getEnumName(MVT::SimpleValueType T) {
case MVT::ppcf128: return "MVT::ppcf128";
case MVT::x86mmx: return "MVT::x86mmx";
case MVT::x86amx: return "MVT::x86amx";
+ case MVT::aarch64svcount: return "MVT::aarch64svcount";
case MVT::i64x8: return "MVT::i64x8";
case MVT::Glue: return "MVT::Glue";
case MVT::isVoid: return "MVT::isVoid";
@@ -427,6 +432,10 @@ const CodeGenRegister *CodeGenTarget::getRegisterByName(StringRef Name) const {
return getRegBank().getRegistersByName().lookup(Name);
}
+const CodeGenRegisterClass &CodeGenTarget::getRegisterClass(Record *R) const {
+ return *getRegBank().getRegClass(R);
+}
+
std::vector<ValueTypeByHwMode> CodeGenTarget::getRegisterVTs(Record *R)
const {
const CodeGenRegister *Reg = getRegBank().getReg(R);
@@ -635,318 +644,3 @@ ComplexPattern::ComplexPattern(Record *R) {
"'!");
}
}
-
-//===----------------------------------------------------------------------===//
-// CodeGenIntrinsic Implementation
-//===----------------------------------------------------------------------===//
-
-CodeGenIntrinsicTable::CodeGenIntrinsicTable(const RecordKeeper &RC) {
- std::vector<Record *> IntrProperties =
- RC.getAllDerivedDefinitions("IntrinsicProperty");
-
- std::vector<Record *> DefaultProperties;
- for (Record *Rec : IntrProperties)
- if (Rec->getValueAsBit("IsDefault"))
- DefaultProperties.push_back(Rec);
-
- std::vector<Record *> Defs = RC.getAllDerivedDefinitions("Intrinsic");
- Intrinsics.reserve(Defs.size());
-
- for (unsigned I = 0, e = Defs.size(); I != e; ++I)
- Intrinsics.push_back(CodeGenIntrinsic(Defs[I], DefaultProperties));
-
- llvm::sort(Intrinsics,
- [](const CodeGenIntrinsic &LHS, const CodeGenIntrinsic &RHS) {
- return std::tie(LHS.TargetPrefix, LHS.Name) <
- std::tie(RHS.TargetPrefix, RHS.Name);
- });
- Targets.push_back({"", 0, 0});
- for (size_t I = 0, E = Intrinsics.size(); I < E; ++I)
- if (Intrinsics[I].TargetPrefix != Targets.back().Name) {
- Targets.back().Count = I - Targets.back().Offset;
- Targets.push_back({Intrinsics[I].TargetPrefix, I, 0});
- }
- Targets.back().Count = Intrinsics.size() - Targets.back().Offset;
-}
-
-CodeGenIntrinsic::CodeGenIntrinsic(Record *R,
- std::vector<Record *> DefaultProperties) {
- TheDef = R;
- std::string DefName = std::string(R->getName());
- ArrayRef<SMLoc> DefLoc = R->getLoc();
- Properties = 0;
- isOverloaded = false;
- isCommutative = false;
- canThrow = false;
- isNoReturn = false;
- isNoCallback = false;
- isNoSync = false;
- isNoFree = false;
- isWillReturn = false;
- isCold = false;
- isNoDuplicate = false;
- isNoMerge = false;
- isConvergent = false;
- isSpeculatable = false;
- hasSideEffects = false;
-
- if (DefName.size() <= 4 || DefName.substr(0, 4) != "int_")
- PrintFatalError(DefLoc,
- "Intrinsic '" + DefName + "' does not start with 'int_'!");
-
- EnumName = DefName.substr(4);
-
- 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"));
-
- TargetPrefix = std::string(R->getValueAsString("TargetPrefix"));
- Name = std::string(R->getValueAsString("LLVMName"));
-
- if (Name == "") {
- // If an explicit name isn't specified, derive one from the DefName.
- Name = "llvm.";
-
- for (unsigned i = 0, e = EnumName.size(); i != e; ++i)
- Name += (EnumName[i] == '_') ? '.' : EnumName[i];
- } else {
- // Verify it starts with "llvm.".
- if (Name.size() <= 5 || Name.substr(0, 5) != "llvm.")
- PrintFatalError(DefLoc, "Intrinsic '" + DefName +
- "'s name does not start with 'llvm.'!");
- }
-
- // If TargetPrefix is specified, make sure that Name starts with
- // "llvm.<targetprefix>.".
- if (!TargetPrefix.empty()) {
- if (Name.size() < 6+TargetPrefix.size() ||
- Name.substr(5, 1 + TargetPrefix.size()) != (TargetPrefix + "."))
- PrintFatalError(DefLoc, "Intrinsic '" + DefName +
- "' does not start with 'llvm." +
- TargetPrefix + ".'!");
- }
-
- ListInit *RetTypes = R->getValueAsListInit("RetTypes");
- ListInit *ParamTypes = R->getValueAsListInit("ParamTypes");
-
- // First collate a list of overloaded types.
- std::vector<MVT::SimpleValueType> OverloadedVTs;
- for (ListInit *TypeList : {RetTypes, ParamTypes}) {
- for (unsigned i = 0, e = TypeList->size(); i != e; ++i) {
- Record *TyEl = TypeList->getElementAsRecord(i);
- assert(TyEl->isSubClassOf("LLVMType") && "Expected a type!");
-
- if (TyEl->isSubClassOf("LLVMMatchType"))
- continue;
-
- MVT::SimpleValueType VT = getValueType(TyEl->getValueAsDef("VT"));
- if (MVT(VT).isOverloaded()) {
- OverloadedVTs.push_back(VT);
- isOverloaded = true;
- }
- }
- }
-
- // Parse the list of return types.
- ListInit *TypeList = RetTypes;
- for (unsigned i = 0, e = TypeList->size(); i != e; ++i) {
- Record *TyEl = TypeList->getElementAsRecord(i);
- assert(TyEl->isSubClassOf("LLVMType") && "Expected a type!");
- MVT::SimpleValueType VT;
- if (TyEl->isSubClassOf("LLVMMatchType")) {
- unsigned MatchTy = TyEl->getValueAsInt("Number");
- assert(MatchTy < OverloadedVTs.size() &&
- "Invalid matching number!");
- VT = OverloadedVTs[MatchTy];
- // It only makes sense to use the extended and truncated vector element
- // variants with iAny types; otherwise, if the intrinsic is not
- // overloaded, all the types can be specified directly.
- assert(((!TyEl->isSubClassOf("LLVMExtendedType") &&
- !TyEl->isSubClassOf("LLVMTruncatedType")) ||
- VT == MVT::iAny || VT == MVT::vAny) &&
- "Expected iAny or vAny type");
- } else {
- VT = getValueType(TyEl->getValueAsDef("VT"));
- }
-
- // Reject invalid types.
- if (VT == MVT::isVoid)
- PrintFatalError(DefLoc, "Intrinsic '" + DefName +
- " has void in result type list!");
-
- IS.RetVTs.push_back(VT);
- IS.RetTypeDefs.push_back(TyEl);
- }
-
- // Parse the list of parameter types.
- TypeList = ParamTypes;
- for (unsigned i = 0, e = TypeList->size(); i != e; ++i) {
- Record *TyEl = TypeList->getElementAsRecord(i);
- assert(TyEl->isSubClassOf("LLVMType") && "Expected a type!");
- MVT::SimpleValueType VT;
- if (TyEl->isSubClassOf("LLVMMatchType")) {
- unsigned MatchTy = TyEl->getValueAsInt("Number");
- if (MatchTy >= OverloadedVTs.size()) {
- PrintError(R->getLoc(),
- "Parameter #" + Twine(i) + " has out of bounds matching "
- "number " + Twine(MatchTy));
- PrintFatalError(DefLoc,
- Twine("ParamTypes is ") + TypeList->getAsString());
- }
- VT = OverloadedVTs[MatchTy];
- // It only makes sense to use the extended and truncated vector element
- // variants with iAny types; otherwise, if the intrinsic is not
- // overloaded, all the types can be specified directly.
- assert(((!TyEl->isSubClassOf("LLVMExtendedType") &&
- !TyEl->isSubClassOf("LLVMTruncatedType")) ||
- VT == MVT::iAny || VT == MVT::vAny) &&
- "Expected iAny or vAny type");
- } else
- VT = getValueType(TyEl->getValueAsDef("VT"));
-
- // Reject invalid types.
- if (VT == MVT::isVoid && i != e-1 /*void at end means varargs*/)
- PrintFatalError(DefLoc, "Intrinsic '" + DefName +
- " has void in result type list!");
-
- IS.ParamVTs.push_back(VT);
- IS.ParamTypeDefs.push_back(TyEl);
- }
-
- // Parse the intrinsic properties.
- ListInit *PropList = R->getValueAsListInit("IntrProperties");
- for (unsigned i = 0, e = PropList->size(); i != e; ++i) {
- Record *Property = PropList->getElementAsRecord(i);
- assert(Property->isSubClassOf("IntrinsicProperty") &&
- "Expected a property!");
-
- setProperty(Property);
- }
-
- // Set default properties to true.
- setDefaultProperties(R, DefaultProperties);
-
- // Also record the SDPatternOperator Properties.
- Properties = parseSDPatternOperatorProperties(R);
-
- // Sort the argument attributes for later benefit.
- for (auto &Attrs : ArgumentAttributes)
- llvm::sort(Attrs);
-}
-
-void CodeGenIntrinsic::setDefaultProperties(
- Record *R, std::vector<Record *> DefaultProperties) {
- // opt-out of using default attributes.
- if (R->getValueAsBit("DisableDefaultAttributes"))
- return;
-
- for (Record *Rec : DefaultProperties)
- setProperty(Rec);
-}
-
-void CodeGenIntrinsic::setProperty(Record *R) {
- if (R->getName() == "IntrNoMem")
- ME = MemoryEffects::none();
- else if (R->getName() == "IntrReadMem") {
- if (ME.onlyWritesMemory())
- PrintFatalError(TheDef->getLoc(),
- Twine("IntrReadMem cannot be used after IntrNoMem or "
- "IntrWriteMem. Default is ReadWrite"));
- ME &= MemoryEffects::readOnly();
- } else if (R->getName() == "IntrWriteMem") {
- if (ME.onlyReadsMemory())
- PrintFatalError(TheDef->getLoc(),
- Twine("IntrWriteMem cannot be used after IntrNoMem or "
- "IntrReadMem. Default is ReadWrite"));
- ME &= MemoryEffects::writeOnly();
- } else if (R->getName() == "IntrArgMemOnly")
- ME &= MemoryEffects::argMemOnly();
- else if (R->getName() == "IntrInaccessibleMemOnly")
- ME &= MemoryEffects::inaccessibleMemOnly();
- else if (R->getName() == "IntrInaccessibleMemOrArgMemOnly")
- ME &= MemoryEffects::inaccessibleOrArgMemOnly();
- else if (R->getName() == "Commutative")
- isCommutative = true;
- else if (R->getName() == "Throws")
- canThrow = true;
- else if (R->getName() == "IntrNoDuplicate")
- isNoDuplicate = true;
- else if (R->getName() == "IntrNoMerge")
- isNoMerge = true;
- else if (R->getName() == "IntrConvergent")
- 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")
- isNoFree = true;
- else if (R->getName() == "IntrWillReturn")
- isWillReturn = !isNoReturn;
- else if (R->getName() == "IntrCold")
- isCold = true;
- else if (R->getName() == "IntrSpeculatable")
- isSpeculatable = true;
- else if (R->getName() == "IntrHasSideEffects")
- hasSideEffects = true;
- else if (R->isSubClassOf("NoCapture")) {
- unsigned ArgNo = R->getValueAsInt("ArgNo");
- addArgAttribute(ArgNo, NoCapture);
- } else if (R->isSubClassOf("NoAlias")) {
- unsigned ArgNo = R->getValueAsInt("ArgNo");
- addArgAttribute(ArgNo, NoAlias);
- } else if (R->isSubClassOf("NoUndef")) {
- unsigned ArgNo = R->getValueAsInt("ArgNo");
- addArgAttribute(ArgNo, NoUndef);
- } else if (R->isSubClassOf("NonNull")) {
- unsigned ArgNo = R->getValueAsInt("ArgNo");
- addArgAttribute(ArgNo, NonNull);
- } else if (R->isSubClassOf("Returned")) {
- unsigned ArgNo = R->getValueAsInt("ArgNo");
- addArgAttribute(ArgNo, Returned);
- } else if (R->isSubClassOf("ReadOnly")) {
- unsigned ArgNo = R->getValueAsInt("ArgNo");
- addArgAttribute(ArgNo, ReadOnly);
- } else if (R->isSubClassOf("WriteOnly")) {
- unsigned ArgNo = R->getValueAsInt("ArgNo");
- addArgAttribute(ArgNo, WriteOnly);
- } else if (R->isSubClassOf("ReadNone")) {
- unsigned ArgNo = R->getValueAsInt("ArgNo");
- addArgAttribute(ArgNo, ReadNone);
- } else if (R->isSubClassOf("ImmArg")) {
- unsigned ArgNo = R->getValueAsInt("ArgNo");
- addArgAttribute(ArgNo, ImmArg);
- } else if (R->isSubClassOf("Align")) {
- unsigned ArgNo = R->getValueAsInt("ArgNo");
- uint64_t Align = R->getValueAsInt("Align");
- addArgAttribute(ArgNo, Alignment, Align);
- } else
- llvm_unreachable("Unknown property!");
-}
-
-bool CodeGenIntrinsic::isParamAPointer(unsigned ParamIdx) const {
- if (ParamIdx >= IS.ParamVTs.size())
- return false;
- MVT ParamType = MVT(IS.ParamVTs[ParamIdx]);
- return ParamType == MVT::iPTR || ParamType == MVT::iPTRAny;
-}
-
-bool CodeGenIntrinsic::isParamImmArg(unsigned ParamIdx) const {
- // Convert argument index to attribute index starting from `FirstArgIndex`.
- ++ParamIdx;
- if (ParamIdx >= ArgumentAttributes.size())
- return false;
- ArgAttribute Val{ImmArg, 0};
- return std::binary_search(ArgumentAttributes[ParamIdx].begin(),
- ArgumentAttributes[ParamIdx].end(), Val);
-}
-
-void CodeGenIntrinsic::addArgAttribute(unsigned Idx, ArgAttrKind AK,
- uint64_t V) {
- if (Idx >= ArgumentAttributes.size())
- ArgumentAttributes.resize(Idx + 1);
- ArgumentAttributes[Idx].emplace_back(AK, V);
-}
diff --git a/llvm/utils/TableGen/CodeGenTarget.h b/llvm/utils/TableGen/CodeGenTarget.h
index 6846e6b5c77a..2ba3af724d36 100644
--- a/llvm/utils/TableGen/CodeGenTarget.h
+++ b/llvm/utils/TableGen/CodeGenTarget.h
@@ -17,18 +17,29 @@
#define LLVM_UTILS_TABLEGEN_CODEGENTARGET_H
#include "CodeGenHwModes.h"
-#include "CodeGenRegisters.h"
#include "InfoByHwMode.h"
#include "SDNodeProperties.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/CodeGen/MachineValueType.h"
+#include <cassert>
+#include <memory>
+#include <optional>
+#include <string>
+#include <vector>
namespace llvm {
class RecordKeeper;
class Record;
class CodeGenInstruction;
-struct CodeGenRegister;
+class CodeGenRegBank;
+class CodeGenRegister;
+class CodeGenRegisterClass;
class CodeGenSchedModels;
-class CodeGenTarget;
+class CodeGenSubRegIndex;
/// getValueType - Return the MVT::SimpleValueType that the specified TableGen
/// record corresponds to.
@@ -122,9 +133,7 @@ public:
return RegAltNameIndices;
}
- const CodeGenRegisterClass &getRegisterClass(Record *R) const {
- return *getRegBank().getRegClass(R);
- }
+ const CodeGenRegisterClass &getRegisterClass(Record *R) const;
/// getRegisterVTs - Find the union of all possible SimpleValueTypes for the
/// specified physical register.
diff --git a/llvm/utils/TableGen/CompressInstEmitter.cpp b/llvm/utils/TableGen/CompressInstEmitter.cpp
index a18d6a6b8854..9d9b69f4cfbd 100644
--- a/llvm/utils/TableGen/CompressInstEmitter.cpp
+++ b/llvm/utils/TableGen/CompressInstEmitter.cpp
@@ -65,6 +65,7 @@
//===----------------------------------------------------------------------===//
#include "CodeGenInstruction.h"
+#include "CodeGenRegisters.h"
#include "CodeGenTarget.h"
#include "llvm/ADT/IndexedMap.h"
#include "llvm/ADT/SmallVector.h"
@@ -902,10 +903,5 @@ void CompressInstEmitter::run(raw_ostream &o) {
emitCompressInstEmitter(o, EmitterType::CheckCompress);
}
-namespace llvm {
-
-void EmitCompressInst(RecordKeeper &RK, raw_ostream &OS) {
- CompressInstEmitter(RK).run(OS);
-}
-
-} // namespace llvm
+static TableGen::Emitter::OptClass<CompressInstEmitter>
+ X("gen-compress-inst-emitter", "Generate compressed instructions.");
diff --git a/llvm/utils/TableGen/DAGISelEmitter.cpp b/llvm/utils/TableGen/DAGISelEmitter.cpp
index d012a0172a8f..eaf7f7f9f0a3 100644
--- a/llvm/utils/TableGen/DAGISelEmitter.cpp
+++ b/llvm/utils/TableGen/DAGISelEmitter.cpp
@@ -12,6 +12,7 @@
#include "CodeGenDAGPatterns.h"
#include "CodeGenInstruction.h"
+#include "CodeGenTarget.h"
#include "DAGISelMatcher.h"
#include "llvm/Support/Debug.h"
#include "llvm/TableGen/Record.h"
@@ -123,6 +124,7 @@ struct PatternSortingPredicate {
void DAGISelEmitter::run(raw_ostream &OS) {
+ Records.startTimer("Parse patterns");
emitSourceFileHeader("DAG Instruction Selector for the " +
CGP.getTargetInfo().getName().str() + " target", OS);
@@ -163,7 +165,7 @@ void DAGISelEmitter::run(raw_ostream &OS) {
// Convert each variant of each pattern into a Matcher.
Records.startTimer("Convert to matchers");
- std::vector<Matcher*> PatternMatchers;
+ SmallVector<Matcher *, 0> PatternMatchers;
for (const PatternToMatch *PTM : Patterns) {
for (unsigned Variant = 0; ; ++Variant) {
if (Matcher *M = ConvertPatternToMatcher(*PTM, Variant, CGP))
@@ -174,7 +176,7 @@ void DAGISelEmitter::run(raw_ostream &OS) {
}
std::unique_ptr<Matcher> TheMatcher =
- std::make_unique<ScopeMatcher>(PatternMatchers);
+ std::make_unique<ScopeMatcher>(std::move(PatternMatchers));
Records.startTimer("Optimize matchers");
OptimizeMatcher(TheMatcher, CGP);
@@ -185,11 +187,5 @@ void DAGISelEmitter::run(raw_ostream &OS) {
EmitMatcherTable(TheMatcher.get(), CGP, OS);
}
-namespace llvm {
-
-void EmitDAGISel(RecordKeeper &RK, raw_ostream &OS) {
- RK.startTimer("Parse patterns");
- DAGISelEmitter(RK).run(OS);
-}
-
-} // End llvm namespace
+static TableGen::Emitter::OptClass<DAGISelEmitter>
+ X("gen-dag-isel", "Generate a DAG instruction selector");
diff --git a/llvm/utils/TableGen/DAGISelMatcher.cpp b/llvm/utils/TableGen/DAGISelMatcher.cpp
index e436a931a9f5..0609f006763b 100644
--- a/llvm/utils/TableGen/DAGISelMatcher.cpp
+++ b/llvm/utils/TableGen/DAGISelMatcher.cpp
@@ -8,6 +8,8 @@
#include "DAGISelMatcher.h"
#include "CodeGenDAGPatterns.h"
+#include "CodeGenInstruction.h"
+#include "CodeGenRegisters.h"
#include "CodeGenTarget.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TableGen/Record.h"
@@ -290,7 +292,7 @@ void EmitNodeXFormMatcher::printImpl(raw_ostream &OS, unsigned indent) const {
void EmitNodeMatcherCommon::printImpl(raw_ostream &OS, unsigned indent) const {
OS.indent(indent);
OS << (isa<MorphNodeToMatcher>(this) ? "MorphNodeTo: " : "EmitNode: ")
- << OpcodeName << ": <todo flags> ";
+ << CGI.Namespace << "::" << CGI.TheDef->getName() << ": <todo flags> ";
for (unsigned i = 0, e = VTs.size(); i != e; ++i)
OS << ' ' << getEnumName(VTs[i]);
@@ -315,10 +317,9 @@ bool CheckOpcodeMatcher::isEqualImpl(const Matcher *M) const {
bool EmitNodeMatcherCommon::isEqualImpl(const Matcher *m) const {
const EmitNodeMatcherCommon *M = cast<EmitNodeMatcherCommon>(m);
- return M->OpcodeName == OpcodeName && M->VTs == VTs &&
- M->Operands == Operands && M->HasChain == HasChain &&
- M->HasInGlue == HasInGlue && M->HasOutGlue == HasOutGlue &&
- M->HasMemRefs == HasMemRefs &&
+ return &M->CGI == &CGI && M->VTs == VTs && M->Operands == Operands &&
+ M->HasChain == HasChain && M->HasInGlue == HasInGlue &&
+ M->HasOutGlue == HasOutGlue && M->HasMemRefs == HasMemRefs &&
M->NumFixedArityOperands == NumFixedArityOperands;
}
diff --git a/llvm/utils/TableGen/DAGISelMatcher.h b/llvm/utils/TableGen/DAGISelMatcher.h
index 77280acaf4ca..e3cf847edd12 100644
--- a/llvm/utils/TableGen/DAGISelMatcher.h
+++ b/llvm/utils/TableGen/DAGISelMatcher.h
@@ -12,12 +12,18 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/CodeGen/MachineValueType.h"
#include "llvm/Support/Casting.h"
-#include "llvm/Support/MachineValueType.h"
+#include <cassert>
+#include <cstddef>
+#include <memory>
+#include <string>
+#include <utility>
namespace llvm {
- struct CodeGenRegister;
+ class CodeGenRegister;
class CodeGenDAGPatterns;
+ class CodeGenInstruction;
class Matcher;
class PatternToMatch;
class raw_ostream;
@@ -41,7 +47,7 @@ class Matcher {
// The next matcher node that is executed after this one. Null if this is the
// last stage of a match.
std::unique_ptr<Matcher> Next;
- size_t Size; // Size in bytes of matcher and all its children (if any).
+ size_t Size = 0; // Size in bytes of matcher and all its children (if any).
virtual void anchor();
public:
enum KindTy {
@@ -189,9 +195,8 @@ protected:
class ScopeMatcher : public Matcher {
SmallVector<Matcher*, 4> Children;
public:
- ScopeMatcher(ArrayRef<Matcher *> children)
- : Matcher(Scope), Children(children.begin(), children.end()) {
- }
+ ScopeMatcher(SmallVectorImpl<Matcher *> &&children)
+ : Matcher(Scope), Children(std::move(children)) {}
~ScopeMatcher() override;
unsigned getNumChildren() const { return Children.size(); }
@@ -473,8 +478,9 @@ private:
class SwitchOpcodeMatcher : public Matcher {
SmallVector<std::pair<const SDNodeInfo*, Matcher*>, 8> Cases;
public:
- SwitchOpcodeMatcher(ArrayRef<std::pair<const SDNodeInfo*, Matcher*> > cases)
- : Matcher(SwitchOpcode), Cases(cases.begin(), cases.end()) {}
+ SwitchOpcodeMatcher(
+ SmallVectorImpl<std::pair<const SDNodeInfo *, Matcher *>> &&cases)
+ : Matcher(SwitchOpcode), Cases(std::move(cases)) {}
~SwitchOpcodeMatcher() override;
static bool classof(const Matcher *N) {
@@ -523,8 +529,9 @@ private:
class SwitchTypeMatcher : public Matcher {
SmallVector<std::pair<MVT::SimpleValueType, Matcher*>, 8> Cases;
public:
- SwitchTypeMatcher(ArrayRef<std::pair<MVT::SimpleValueType, Matcher*> > cases)
- : Matcher(SwitchType), Cases(cases.begin(), cases.end()) {}
+ SwitchTypeMatcher(
+ SmallVectorImpl<std::pair<MVT::SimpleValueType, Matcher *>> &&cases)
+ : Matcher(SwitchType), Cases(std::move(cases)) {}
~SwitchTypeMatcher() override;
static bool classof(const Matcher *N) {
@@ -991,7 +998,7 @@ private:
/// EmitNodeMatcherCommon - Common class shared between EmitNode and
/// MorphNodeTo.
class EmitNodeMatcherCommon : public Matcher {
- std::string OpcodeName;
+ const CodeGenInstruction &CGI;
const SmallVector<MVT::SimpleValueType, 3> VTs;
const SmallVector<unsigned, 6> Operands;
bool HasChain, HasInGlue, HasOutGlue, HasMemRefs;
@@ -1001,18 +1008,17 @@ class EmitNodeMatcherCommon : public Matcher {
/// operands in the root of the pattern. The rest are appended to this node.
int NumFixedArityOperands;
public:
- EmitNodeMatcherCommon(const std::string &opcodeName,
+ EmitNodeMatcherCommon(const CodeGenInstruction &cgi,
ArrayRef<MVT::SimpleValueType> vts,
- ArrayRef<unsigned> operands,
- bool hasChain, bool hasInGlue, bool hasOutGlue,
- bool hasmemrefs,
+ ArrayRef<unsigned> operands, bool hasChain,
+ bool hasInGlue, bool hasOutGlue, bool hasmemrefs,
int numfixedarityoperands, bool isMorphNodeTo)
- : Matcher(isMorphNodeTo ? MorphNodeTo : EmitNode), OpcodeName(opcodeName),
- VTs(vts.begin(), vts.end()), Operands(operands.begin(), operands.end()),
- HasChain(hasChain), HasInGlue(hasInGlue), HasOutGlue(hasOutGlue),
- HasMemRefs(hasmemrefs), NumFixedArityOperands(numfixedarityoperands) {}
+ : Matcher(isMorphNodeTo ? MorphNodeTo : EmitNode), CGI(cgi),
+ VTs(vts.begin(), vts.end()), Operands(operands.begin(), operands.end()),
+ HasChain(hasChain), HasInGlue(hasInGlue), HasOutGlue(hasOutGlue),
+ HasMemRefs(hasmemrefs), NumFixedArityOperands(numfixedarityoperands) {}
- const std::string &getOpcodeName() const { return OpcodeName; }
+ const CodeGenInstruction &getInstruction() const { return CGI; }
unsigned getNumVTs() const { return VTs.size(); }
MVT::SimpleValueType getVT(unsigned i) const {
@@ -1031,8 +1037,8 @@ public:
bool hasChain() const { return HasChain; }
- bool hasInFlag() const { return HasInGlue; }
- bool hasOutFlag() const { return HasOutGlue; }
+ bool hasInGlue() const { return HasInGlue; }
+ bool hasOutGlue() const { return HasOutGlue; }
bool hasMemRefs() const { return HasMemRefs; }
int getNumFixedArityOperands() const { return NumFixedArityOperands; }
@@ -1050,16 +1056,15 @@ class EmitNodeMatcher : public EmitNodeMatcherCommon {
void anchor() override;
unsigned FirstResultSlot;
public:
- EmitNodeMatcher(const std::string &opcodeName,
+ EmitNodeMatcher(const CodeGenInstruction &cgi,
ArrayRef<MVT::SimpleValueType> vts,
- ArrayRef<unsigned> operands,
- bool hasChain, bool hasInFlag, bool hasOutFlag,
- bool hasmemrefs,
- int numfixedarityoperands, unsigned firstresultslot)
- : EmitNodeMatcherCommon(opcodeName, vts, operands, hasChain,
- hasInFlag, hasOutFlag, hasmemrefs,
- numfixedarityoperands, false),
- FirstResultSlot(firstresultslot) {}
+ ArrayRef<unsigned> operands, bool hasChain, bool hasInGlue,
+ bool hasOutGlue, bool hasmemrefs, int numfixedarityoperands,
+ unsigned firstresultslot)
+ : EmitNodeMatcherCommon(cgi, vts, operands, hasChain, hasInGlue,
+ hasOutGlue, hasmemrefs, numfixedarityoperands,
+ false),
+ FirstResultSlot(firstresultslot) {}
unsigned getFirstResultSlot() const { return FirstResultSlot; }
@@ -1073,17 +1078,15 @@ class MorphNodeToMatcher : public EmitNodeMatcherCommon {
void anchor() override;
const PatternToMatch &Pattern;
public:
- MorphNodeToMatcher(const std::string &opcodeName,
+ MorphNodeToMatcher(const CodeGenInstruction &cgi,
ArrayRef<MVT::SimpleValueType> vts,
- ArrayRef<unsigned> operands,
- bool hasChain, bool hasInFlag, bool hasOutFlag,
- bool hasmemrefs,
+ ArrayRef<unsigned> operands, bool hasChain, bool hasInGlue,
+ bool hasOutGlue, bool hasmemrefs,
int numfixedarityoperands, const PatternToMatch &pattern)
- : EmitNodeMatcherCommon(opcodeName, vts, operands, hasChain,
- hasInFlag, hasOutFlag, hasmemrefs,
- numfixedarityoperands, true),
- Pattern(pattern) {
- }
+ : EmitNodeMatcherCommon(cgi, vts, operands, hasChain, hasInGlue,
+ hasOutGlue, hasmemrefs, numfixedarityoperands,
+ true),
+ Pattern(pattern) {}
const PatternToMatch &getPattern() const { return Pattern; }
diff --git a/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp b/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp
index 777e75dcd929..28d4d585f3dd 100644
--- a/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp
+++ b/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp
@@ -11,7 +11,11 @@
//===----------------------------------------------------------------------===//
#include "CodeGenDAGPatterns.h"
+#include "CodeGenInstruction.h"
+#include "CodeGenRegisters.h"
+#include "CodeGenTarget.h"
#include "DAGISelMatcher.h"
+#include "SDNodeProperties.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/StringMap.h"
@@ -80,9 +84,8 @@ class MatcherTableEmitter {
}
public:
- MatcherTableEmitter(const CodeGenDAGPatterns &cgp) : CGP(cgp) {
- OpcodeCounts.assign(Matcher::HighestKind+1, 0);
- }
+ MatcherTableEmitter(const CodeGenDAGPatterns &cgp)
+ : CGP(cgp), OpcodeCounts(Matcher::HighestKind + 1, 0) {}
unsigned EmitMatcherList(const Matcher *N, const unsigned Indent,
unsigned StartIdx, raw_ostream &OS);
@@ -772,11 +775,13 @@ EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
if (CompressVTs)
OS << EN->getNumVTs();
- OS << ", TARGET_VAL(" << EN->getOpcodeName() << "), 0";
+ const CodeGenInstruction &CGI = EN->getInstruction();
+ OS << ", TARGET_VAL(" << CGI.Namespace << "::" << CGI.TheDef->getName()
+ << "), 0";
if (EN->hasChain()) OS << "|OPFL_Chain";
- if (EN->hasInFlag()) OS << "|OPFL_GlueInput";
- if (EN->hasOutFlag()) OS << "|OPFL_GlueOutput";
+ if (EN->hasInGlue()) OS << "|OPFL_GlueInput";
+ if (EN->hasOutGlue()) OS << "|OPFL_GlueOutput";
if (EN->hasMemRefs()) OS << "|OPFL_MemRefs";
if (EN->getNumFixedArityOperands() != -1)
OS << "|OPFL_Variadic" << EN->getNumFixedArityOperands();
diff --git a/llvm/utils/TableGen/DAGISelMatcherGen.cpp b/llvm/utils/TableGen/DAGISelMatcherGen.cpp
index 44bff4c67ab3..f773f7c77a77 100644
--- a/llvm/utils/TableGen/DAGISelMatcherGen.cpp
+++ b/llvm/utils/TableGen/DAGISelMatcherGen.cpp
@@ -9,7 +9,10 @@
#include "CodeGenDAGPatterns.h"
#include "CodeGenInstruction.h"
#include "CodeGenRegisters.h"
+#include "CodeGenTarget.h"
#include "DAGISelMatcher.h"
+#include "InfoByHwMode.h"
+#include "SDNodeProperties.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/TableGen/Error.h"
@@ -19,8 +22,8 @@ using namespace llvm;
/// getRegisterValueType - Look up and return the ValueType of the specified
-/// register. If the register is a member of multiple register classes which
-/// have different associated types, return MVT::Other.
+/// register. If the register is a member of multiple register classes, they
+/// must all have the same type.
static MVT::SimpleValueType getRegisterValueType(Record *R,
const CodeGenTarget &T) {
bool FoundRC = false;
@@ -34,15 +37,15 @@ static MVT::SimpleValueType getRegisterValueType(Record *R,
if (!FoundRC) {
FoundRC = true;
const ValueTypeByHwMode &VVT = RC.getValueTypeNum(0);
- if (VVT.isSimple())
- VT = VVT.getSimple().SimpleTy;
+ assert(VVT.isSimple());
+ VT = VVT.getSimple().SimpleTy;
continue;
}
#ifndef NDEBUG
// If this occurs in multiple register classes, they all have to agree.
- const ValueTypeByHwMode &T = RC.getValueTypeNum(0);
- assert((!T.isSimple() || T.getSimple().SimpleTy == VT) &&
+ const ValueTypeByHwMode &VVT = RC.getValueTypeNum(0);
+ assert(VVT.isSimple() && VVT.getSimple().SimpleTy == VT &&
"ValueType mismatch between register classes for this register");
#endif
}
@@ -107,15 +110,13 @@ namespace {
Matcher *GetMatcher() const { return TheMatcher; }
private:
void AddMatcher(Matcher *NewNode);
- void InferPossibleTypes(unsigned ForceMode);
+ void InferPossibleTypes();
// Matcher Generation.
- void EmitMatchCode(const TreePatternNode *N, TreePatternNode *NodeNoTypes,
- unsigned ForceMode);
+ void EmitMatchCode(const TreePatternNode *N, TreePatternNode *NodeNoTypes);
void EmitLeafMatchCode(const TreePatternNode *N);
void EmitOperatorMatchCode(const TreePatternNode *N,
- TreePatternNode *NodeNoTypes,
- unsigned ForceMode);
+ TreePatternNode *NodeNoTypes);
/// If this is the first time a node with unique identifier Name has been
/// seen, record it. Otherwise, emit a check to make sure this is the same
@@ -164,19 +165,17 @@ MatcherGen::MatcherGen(const PatternToMatch &pattern,
PatWithNoTypes->RemoveAllTypes();
// If there are types that are manifestly known, infer them.
- InferPossibleTypes(Pattern.getForceMode());
+ InferPossibleTypes();
}
/// InferPossibleTypes - As we emit the pattern, we end up generating type
/// checks and applying them to the 'PatWithNoTypes' tree. As we do this, we
/// want to propagate implied types as far throughout the tree as possible so
/// that we avoid doing redundant type checks. This does the type propagation.
-void MatcherGen::InferPossibleTypes(unsigned ForceMode) {
+void MatcherGen::InferPossibleTypes() {
// TP - Get *SOME* tree pattern, we don't care which. It is only used for
// diagnostics, which we know are impossible at this point.
TreePattern &TP = *CGP.pf_begin()->second;
- TP.getInfer().CodeGen = true;
- TP.getInfer().ForceMode = ForceMode;
bool MadeChange = true;
while (MadeChange)
@@ -278,7 +277,8 @@ void MatcherGen::EmitLeafMatchCode(const TreePatternNode *N) {
return;
}
- if (LeafRec->getName() == "immAllOnesV") {
+ if (LeafRec->getName() == "immAllOnesV" ||
+ LeafRec->getName() == "immAllZerosV") {
// If this is the root of the dag we're matching, we emit a redundant opcode
// check to ensure that this gets folded into the normal top-level
// OpcodeSwitch.
@@ -288,19 +288,11 @@ void MatcherGen::EmitLeafMatchCode(const TreePatternNode *N) {
const SDNodeInfo &NI = CGP.getSDNodeInfo(CGP.getSDNodeNamed(Name));
AddMatcher(new CheckOpcodeMatcher(NI));
}
- return AddMatcher(new CheckImmAllOnesVMatcher());
- }
- if (LeafRec->getName() == "immAllZerosV") {
- // If this is the root of the dag we're matching, we emit a redundant opcode
- // check to ensure that this gets folded into the normal top-level
- // OpcodeSwitch.
- if (N == Pattern.getSrcPattern()) {
- MVT VT = N->getSimpleType(0);
- StringRef Name = VT.isScalableVector() ? "splat_vector" : "build_vector";
- const SDNodeInfo &NI = CGP.getSDNodeInfo(CGP.getSDNodeNamed(Name));
- AddMatcher(new CheckOpcodeMatcher(NI));
- }
- return AddMatcher(new CheckImmAllZerosVMatcher());
+ if (LeafRec->getName() == "immAllOnesV")
+ AddMatcher(new CheckImmAllOnesVMatcher());
+ else
+ AddMatcher(new CheckImmAllZerosVMatcher());
+ return;
}
errs() << "Unknown leaf kind: " << *N << "\n";
@@ -308,8 +300,7 @@ void MatcherGen::EmitLeafMatchCode(const TreePatternNode *N) {
}
void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N,
- TreePatternNode *NodeNoTypes,
- unsigned ForceMode) {
+ TreePatternNode *NodeNoTypes) {
assert(!N->isLeaf() && "Not an operator?");
if (N->getOperator()->isSubClassOf("ComplexPattern")) {
@@ -347,7 +338,8 @@ void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N,
N->getChild(1)->isLeaf() && N->getChild(1)->getPredicateCalls().empty() &&
N->getPredicateCalls().empty()) {
if (IntInit *II = dyn_cast<IntInit>(N->getChild(1)->getLeafValue())) {
- if (!isPowerOf2_32(II->getValue())) { // Don't bother with single bits.
+ if (!llvm::has_single_bit<uint32_t>(
+ II->getValue())) { // Don't bother with single bits.
// If this is at the root of the pattern, we emit a redundant
// CheckOpcode so that the following checks get factored properly under
// a single opcode check.
@@ -362,7 +354,7 @@ void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N,
// Match the LHS of the AND as appropriate.
AddMatcher(new MoveChildMatcher(0));
- EmitMatchCode(N->getChild(0), NodeNoTypes->getChild(0), ForceMode);
+ EmitMatchCode(N->getChild(0), NodeNoTypes->getChild(0));
AddMatcher(new MoveParentMatcher());
return;
}
@@ -461,7 +453,7 @@ void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N,
// Get the code suitable for matching this child. Move to the child, check
// it then move back to the parent.
AddMatcher(new MoveChildMatcher(OpNo));
- EmitMatchCode(N->getChild(i), NodeNoTypes->getChild(i), ForceMode);
+ EmitMatchCode(N->getChild(i), NodeNoTypes->getChild(i));
AddMatcher(new MoveParentMatcher());
}
}
@@ -502,8 +494,7 @@ bool MatcherGen::recordUniqueNode(ArrayRef<std::string> Names) {
}
void MatcherGen::EmitMatchCode(const TreePatternNode *N,
- TreePatternNode *NodeNoTypes,
- unsigned ForceMode) {
+ TreePatternNode *NodeNoTypes) {
// If N and NodeNoTypes don't agree on a type, then this is a case where we
// need to do a type check. Emit the check, apply the type to NodeNoTypes and
// reinfer any correlated types.
@@ -512,7 +503,7 @@ void MatcherGen::EmitMatchCode(const TreePatternNode *N,
for (unsigned i = 0, e = NodeNoTypes->getNumTypes(); i != e; ++i) {
if (NodeNoTypes->getExtType(i) == N->getExtType(i)) continue;
NodeNoTypes->setType(i, N->getExtType(i));
- InferPossibleTypes(ForceMode);
+ InferPossibleTypes();
ResultsToTypeCheck.push_back(i);
}
@@ -534,7 +525,7 @@ void MatcherGen::EmitMatchCode(const TreePatternNode *N,
if (N->isLeaf())
EmitLeafMatchCode(N);
else
- EmitOperatorMatchCode(N, NodeNoTypes, ForceMode);
+ EmitOperatorMatchCode(N, NodeNoTypes);
// If there are node predicates for this node, generate their checks.
for (unsigned i = 0, e = N->getPredicateCalls().size(); i != e; ++i) {
@@ -576,13 +567,13 @@ bool MatcherGen::EmitMatcherCode(unsigned Variant) {
}
// Emit the matcher for the pattern structure and types.
- EmitMatchCode(Pattern.getSrcPattern(), PatWithNoTypes.get(),
- Pattern.getForceMode());
+ EmitMatchCode(Pattern.getSrcPattern(), PatWithNoTypes.get());
// If the pattern has a predicate on it (e.g. only enabled when a subtarget
// feature is around, do the check).
- if (!Pattern.getPredicateCheck().empty())
- AddMatcher(new CheckPatternPredicateMatcher(Pattern.getPredicateCheck()));
+ std::string PredicateCheck = Pattern.getPredicateCheck();
+ if (!PredicateCheck.empty())
+ AddMatcher(new CheckPatternPredicateMatcher(PredicateCheck));
// Now that we've completed the structural type match, emit any ComplexPattern
// checks (e.g. addrmode matches). We emit this after the structural match
@@ -605,16 +596,17 @@ bool MatcherGen::EmitMatcherCode(unsigned Variant) {
// Get the slot we recorded the value in from the name on the node.
unsigned RecNodeEntry = MatchedComplexPatterns[i].second;
- const ComplexPattern &CP = *N->getComplexPatternInfo(CGP);
+ const ComplexPattern *CP = N->getComplexPatternInfo(CGP);
+ assert(CP && "Not a valid ComplexPattern!");
// Emit a CheckComplexPat operation, which does the match (aborting if it
// fails) and pushes the matched operands onto the recorded nodes list.
- AddMatcher(new CheckComplexPatMatcher(CP, RecNodeEntry,
- N->getName(), NextRecordedOperandNo));
+ AddMatcher(new CheckComplexPatMatcher(*CP, RecNodeEntry, N->getName(),
+ NextRecordedOperandNo));
// Record the right number of operands.
- NextRecordedOperandNo += CP.getNumOperands();
- if (CP.hasProperty(SDNPHasChain)) {
+ NextRecordedOperandNo += CP->getNumOperands();
+ if (CP->hasProperty(SDNPHasChain)) {
// If the complex pattern has a chain, then we need to keep track of the
// fact that we just recorded a chain input. The chain input will be
// matched as the last operand of the predicate if it was successful.
@@ -697,12 +689,12 @@ void MatcherGen::EmitResultLeafAsOperand(const TreePatternNode *N,
}
if (Def->getName() == "undef_tied_input") {
- std::array<MVT::SimpleValueType, 1> ResultVTs = {{ N->getSimpleType(0) }};
- std::array<unsigned, 0> InstOps;
+ MVT::SimpleValueType ResultVT = N->getSimpleType(0);
auto IDOperandNo = NextRecordedOperandNo++;
- AddMatcher(new EmitNodeMatcher("TargetOpcode::IMPLICIT_DEF",
- ResultVTs, InstOps, false, false, false,
- false, -1, IDOperandNo));
+ Record *ImpDef = Def->getRecords().getDef("IMPLICIT_DEF");
+ CodeGenInstruction &II = CGP.getTargetInfo().getInstruction(ImpDef);
+ AddMatcher(new EmitNodeMatcher(II, ResultVT, std::nullopt, false, false,
+ false, false, -1, IDOperandNo));
ResultOps.push_back(IDOperandNo);
return;
}
@@ -983,11 +975,9 @@ EmitResultInstructionAsOperand(const TreePatternNode *N,
assert((!ResultVTs.empty() || TreeHasOutGlue || NodeHasChain) &&
"Node has no result");
- AddMatcher(new EmitNodeMatcher(II.Namespace.str()+"::"+II.TheDef->getName().str(),
- ResultVTs, InstOps,
- NodeHasChain, TreeHasInGlue, TreeHasOutGlue,
- NodeHasMemRefs, NumFixedArityOperands,
- NextRecordedOperandNo));
+ AddMatcher(new EmitNodeMatcher(II, ResultVTs, InstOps, NodeHasChain,
+ TreeHasInGlue, TreeHasOutGlue, NodeHasMemRefs,
+ NumFixedArityOperands, NextRecordedOperandNo));
// The non-chain and non-glue results of the newly emitted node get recorded.
for (unsigned i = 0, e = ResultVTs.size(); i != e; ++i) {
diff --git a/llvm/utils/TableGen/DAGISelMatcherOpt.cpp b/llvm/utils/TableGen/DAGISelMatcherOpt.cpp
index 4273bd69b87d..bf2a24241e84 100644
--- a/llvm/utils/TableGen/DAGISelMatcherOpt.cpp
+++ b/llvm/utils/TableGen/DAGISelMatcherOpt.cpp
@@ -10,8 +10,9 @@
//
//===----------------------------------------------------------------------===//
-#include "DAGISelMatcher.h"
#include "CodeGenDAGPatterns.h"
+#include "DAGISelMatcher.h"
+#include "SDNodeProperties.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
@@ -25,8 +26,9 @@ static void ContractNodes(std::unique_ptr<Matcher> &MatcherPtr,
const CodeGenDAGPatterns &CGP) {
// If we reached the end of the chain, we're done.
Matcher *N = MatcherPtr.get();
- if (!N) return;
-
+ if (!N)
+ return;
+
// If we have a scope node, walk down all of the children.
if (ScopeMatcher *Scope = dyn_cast<ScopeMatcher>(N)) {
for (unsigned i = 0, e = Scope->getNumChildren(); i != e; ++i) {
@@ -36,31 +38,31 @@ static void ContractNodes(std::unique_ptr<Matcher> &MatcherPtr,
}
return;
}
-
+
// If we found a movechild node with a node that comes in a 'foochild' form,
// transform it.
if (MoveChildMatcher *MC = dyn_cast<MoveChildMatcher>(N)) {
Matcher *New = nullptr;
if (RecordMatcher *RM = dyn_cast<RecordMatcher>(MC->getNext()))
- if (MC->getChildNo() < 8) // Only have RecordChild0...7
+ if (MC->getChildNo() < 8) // Only have RecordChild0...7
New = new RecordChildMatcher(MC->getChildNo(), RM->getWhatFor(),
RM->getResultNo());
if (CheckTypeMatcher *CT = dyn_cast<CheckTypeMatcher>(MC->getNext()))
- if (MC->getChildNo() < 8 && // Only have CheckChildType0...7
- CT->getResNo() == 0) // CheckChildType checks res #0
+ if (MC->getChildNo() < 8 && // Only have CheckChildType0...7
+ CT->getResNo() == 0) // CheckChildType checks res #0
New = new CheckChildTypeMatcher(MC->getChildNo(), CT->getType());
if (CheckSameMatcher *CS = dyn_cast<CheckSameMatcher>(MC->getNext()))
- if (MC->getChildNo() < 4) // Only have CheckChildSame0...3
+ if (MC->getChildNo() < 4) // Only have CheckChildSame0...3
New = new CheckChildSameMatcher(MC->getChildNo(), CS->getMatchNumber());
if (CheckIntegerMatcher *CI = dyn_cast<CheckIntegerMatcher>(MC->getNext()))
- if (MC->getChildNo() < 5) // Only have CheckChildInteger0...4
+ if (MC->getChildNo() < 5) // Only have CheckChildInteger0...4
New = new CheckChildIntegerMatcher(MC->getChildNo(), CI->getValue());
if (auto *CCC = dyn_cast<CheckCondCodeMatcher>(MC->getNext()))
- if (MC->getChildNo() == 2) // Only have CheckChild2CondCode
+ if (MC->getChildNo() == 2) // Only have CheckChild2CondCode
New = new CheckChild2CondCodeMatcher(CCC->getCondCodeName());
if (New) {
@@ -72,11 +74,10 @@ static void ContractNodes(std::unique_ptr<Matcher> &MatcherPtr,
return ContractNodes(MatcherPtr, CGP);
}
}
-
+
// Zap movechild -> moveparent.
if (MoveChildMatcher *MC = dyn_cast<MoveChildMatcher>(N))
- if (MoveParentMatcher *MP =
- dyn_cast<MoveParentMatcher>(MC->getNext())) {
+ if (MoveParentMatcher *MP = dyn_cast<MoveParentMatcher>(MC->getNext())) {
MatcherPtr.reset(MP->takeNext());
return ContractNodes(MatcherPtr, CGP);
}
@@ -84,19 +85,19 @@ static void ContractNodes(std::unique_ptr<Matcher> &MatcherPtr,
// Turn EmitNode->CompleteMatch into MorphNodeTo if we can.
if (EmitNodeMatcher *EN = dyn_cast<EmitNodeMatcher>(N))
if (CompleteMatchMatcher *CM =
- dyn_cast<CompleteMatchMatcher>(EN->getNext())) {
+ dyn_cast<CompleteMatchMatcher>(EN->getNext())) {
// We can only use MorphNodeTo if the result values match up.
unsigned RootResultFirst = EN->getFirstResultSlot();
bool ResultsMatch = true;
for (unsigned i = 0, e = CM->getNumResults(); i != e; ++i)
- if (CM->getResult(i) != RootResultFirst+i)
+ if (CM->getResult(i) != RootResultFirst + i)
ResultsMatch = false;
-
+
// If the selected node defines a subset of the glue/chain results, we
// can't use MorphNodeTo. For example, we can't use MorphNodeTo if the
// matched pattern has a chain but the root node doesn't.
const PatternToMatch &Pattern = CM->getPattern();
-
+
if (!EN->hasChain() &&
Pattern.getSrcPattern()->NodeHasProperty(SDNPHasChain, CGP))
ResultsMatch = false;
@@ -107,40 +108,35 @@ static void ContractNodes(std::unique_ptr<Matcher> &MatcherPtr,
// NOTE: Strictly speaking, we don't have to check for glue here
// because the code in the pattern generator doesn't handle it right. We
// do it anyway for thoroughness.
- if (!EN->hasOutFlag() &&
+ if (!EN->hasOutGlue() &&
Pattern.getSrcPattern()->NodeHasProperty(SDNPOutGlue, CGP))
ResultsMatch = false;
-
-
+
+#if 0
// If the root result node defines more results than the source root node
// *and* has a chain or glue input, then we can't match it because it
// would end up replacing the extra result with the chain/glue.
-#if 0
if ((EN->hasGlue() || EN->hasChain()) &&
EN->getNumNonChainGlueVTs() > ... need to get no results reliably ...)
ResultMatch = false;
#endif
-
+
if (ResultsMatch) {
const SmallVectorImpl<MVT::SimpleValueType> &VTs = EN->getVTList();
const SmallVectorImpl<unsigned> &Operands = EN->getOperandList();
- MatcherPtr.reset(new MorphNodeToMatcher(EN->getOpcodeName(),
- VTs, Operands,
- EN->hasChain(), EN->hasInFlag(),
- EN->hasOutFlag(),
- EN->hasMemRefs(),
- EN->getNumFixedArityOperands(),
- Pattern));
+ MatcherPtr.reset(new MorphNodeToMatcher(
+ EN->getInstruction(), VTs, Operands, EN->hasChain(),
+ EN->hasInGlue(), EN->hasOutGlue(), EN->hasMemRefs(),
+ EN->getNumFixedArityOperands(), Pattern));
return;
}
// FIXME2: Kill off all the SelectionDAG::SelectNodeTo and getMachineNode
// variants.
}
-
+
ContractNodes(N->getNextPtr(), CGP);
-
-
+
// If we have a CheckType/CheckChildType/Record node followed by a
// CheckOpcode, invert the two nodes. We prefer to do structural checks
// before type checks, as this opens opportunities for factoring on targets
@@ -152,7 +148,7 @@ static void ContractNodes(std::unique_ptr<Matcher> &MatcherPtr,
Matcher *CheckType = MatcherPtr.release();
Matcher *CheckOpcode = CheckType->takeNext();
Matcher *Tail = CheckOpcode->takeNext();
-
+
// Relink them.
MatcherPtr.reset(CheckOpcode);
CheckOpcode->setNext(CheckType);
@@ -171,7 +167,6 @@ static Matcher *FindNodeWithKind(Matcher *M, Matcher::KindTy Kind) {
return nullptr;
}
-
/// FactorNodes - Turn matches like this:
/// Scope
/// OPC_CheckType i32
@@ -191,7 +186,8 @@ static void FactorNodes(std::unique_ptr<Matcher> &InputMatcherPtr) {
while (!Scope) {
// If we reached the end of the chain, we're done.
Matcher *N = RebindableMatcherPtr->get();
- if (!N) return;
+ if (!N)
+ return;
// If this is not a push node, just scan for one.
Scope = dyn_cast<ScopeMatcher>(N);
@@ -199,78 +195,73 @@ static void FactorNodes(std::unique_ptr<Matcher> &InputMatcherPtr) {
RebindableMatcherPtr = &(N->getNextPtr());
}
std::unique_ptr<Matcher> &MatcherPtr = *RebindableMatcherPtr;
-
+
// Okay, pull together the children of the scope node into a vector so we can
// inspect it more easily.
- SmallVector<Matcher*, 32> OptionsToMatch;
-
+ SmallVector<Matcher *, 32> OptionsToMatch;
+
for (unsigned i = 0, e = Scope->getNumChildren(); i != e; ++i) {
// Factor the subexpression.
std::unique_ptr<Matcher> Child(Scope->takeChild(i));
FactorNodes(Child);
-
- if (Child) {
- // If the child is a ScopeMatcher we can just merge its contents.
- if (auto *SM = dyn_cast<ScopeMatcher>(Child.get())) {
- for (unsigned j = 0, e = SM->getNumChildren(); j != e; ++j)
- OptionsToMatch.push_back(SM->takeChild(j));
- } else {
- OptionsToMatch.push_back(Child.release());
- }
+
+ // If the child is a ScopeMatcher we can just merge its contents.
+ if (auto *SM = dyn_cast<ScopeMatcher>(Child.get())) {
+ for (unsigned j = 0, e = SM->getNumChildren(); j != e; ++j)
+ OptionsToMatch.push_back(SM->takeChild(j));
+ } else {
+ OptionsToMatch.push_back(Child.release());
}
}
-
- SmallVector<Matcher*, 32> NewOptionsToMatch;
-
+
// Loop over options to match, merging neighboring patterns with identical
// starting nodes into a shared matcher.
- for (unsigned OptionIdx = 0, e = OptionsToMatch.size(); OptionIdx != e;) {
+ auto E = OptionsToMatch.end();
+ for (auto I = OptionsToMatch.begin(); I != E; ++I) {
+ // If there are no other matchers left, there's nothing to merge with.
+ auto J = std::next(I);
+ if (J == E)
+ break;
+
+ // Remember where we started. We'll use this to move non-equal elements.
+ auto K = J;
+
// Find the set of matchers that start with this node.
- Matcher *Optn = OptionsToMatch[OptionIdx++];
+ Matcher *Optn = *I;
- if (OptionIdx == e) {
- NewOptionsToMatch.push_back(Optn);
- continue;
- }
-
// See if the next option starts with the same matcher. If the two
// neighbors *do* start with the same matcher, we can factor the matcher out
// of at least these two patterns. See what the maximal set we can merge
// together is.
- SmallVector<Matcher*, 8> EqualMatchers;
+ SmallVector<Matcher *, 8> EqualMatchers;
EqualMatchers.push_back(Optn);
-
+
// Factor all of the known-equal matchers after this one into the same
// group.
- while (OptionIdx != e && OptionsToMatch[OptionIdx]->isEqual(Optn))
- EqualMatchers.push_back(OptionsToMatch[OptionIdx++]);
+ while (J != E && (*J)->isEqual(Optn))
+ EqualMatchers.push_back(*J++);
// If we found a non-equal matcher, see if it is contradictory with the
// current node. If so, we know that the ordering relation between the
// current sets of nodes and this node don't matter. Look past it to see if
// we can merge anything else into this matching group.
- unsigned Scan = OptionIdx;
- while (true) {
- // If we ran out of stuff to scan, we're done.
- if (Scan == e) break;
-
- Matcher *ScanMatcher = OptionsToMatch[Scan];
-
+ while (J != E) {
+ Matcher *ScanMatcher = *J;
+
// If we found an entry that matches out matcher, merge it into the set to
// handle.
if (Optn->isEqual(ScanMatcher)) {
- // If is equal after all, add the option to EqualMatchers and remove it
- // from OptionsToMatch.
+ // It is equal after all, add the option to EqualMatchers.
EqualMatchers.push_back(ScanMatcher);
- OptionsToMatch.erase(OptionsToMatch.begin()+Scan);
- --e;
+ ++J;
continue;
}
-
+
// If the option we're checking for contradicts the start of the list,
- // skip over it.
+ // move it earlier in OptionsToMatch for the next iteration of the outer
+ // loop. Then continue searching for equal or contradictory matchers.
if (Optn->isContradictory(ScanMatcher)) {
- ++Scan;
+ *K++ = *J++;
continue;
}
@@ -279,38 +270,47 @@ static void FactorNodes(std::unique_ptr<Matcher> &InputMatcherPtr) {
// or the same as what we're looking for. If so, reorder it.
if (Optn->isSimplePredicateOrRecordNode()) {
Matcher *M2 = FindNodeWithKind(ScanMatcher, Optn->getKind());
- if (M2 && M2 != ScanMatcher &&
- M2->canMoveBefore(ScanMatcher) &&
+ if (M2 && M2 != ScanMatcher && M2->canMoveBefore(ScanMatcher) &&
(M2->isEqual(Optn) || M2->isContradictory(Optn))) {
Matcher *MatcherWithoutM2 = ScanMatcher->unlinkNode(M2);
M2->setNext(MatcherWithoutM2);
- OptionsToMatch[Scan] = M2;
+ *J = M2;
continue;
}
}
-
+
// Otherwise, we don't know how to handle this entry, we have to bail.
break;
}
-
- if (Scan != e &&
- // Don't print it's obvious nothing extra could be merged anyway.
- Scan+1 != e) {
+
+ if (J != E &&
+ // Don't print if it's obvious nothing extract could be merged anyway.
+ std::next(J) != E) {
LLVM_DEBUG(errs() << "Couldn't merge this:\n"; Optn->print(errs(), 4);
errs() << "into this:\n";
- OptionsToMatch[Scan]->print(errs(), 4);
- if (Scan + 1 != e) OptionsToMatch[Scan + 1]->printOne(errs());
- if (Scan + 2 < e) OptionsToMatch[Scan + 2]->printOne(errs());
+ (*J)->print(errs(), 4);
+ (*std::next(J))->printOne(errs());
+ if (std::next(J, 2) != E) (*std::next(J, 2))->printOne(errs());
errs() << "\n");
}
-
+
+ // If we removed any equal matchers, we may need to slide the rest of the
+ // elements down for the next iteration of the outer loop.
+ if (J != K) {
+ while (J != E)
+ *K++ = *J++;
+
+ // Update end pointer for outer loop.
+ E = K;
+ }
+
// If we only found one option starting with this matcher, no factoring is
- // possible.
+ // possible. Put the Matcher back in OptionsToMatch.
if (EqualMatchers.size() == 1) {
- NewOptionsToMatch.push_back(EqualMatchers[0]);
+ *I = EqualMatchers[0];
continue;
}
-
+
// Factor these checks by pulling the first node off each entry and
// discarding it. Take the first one off the first entry to reuse.
Matcher *Shared = Optn;
@@ -322,42 +322,49 @@ static void FactorNodes(std::unique_ptr<Matcher> &InputMatcherPtr) {
Matcher *Tmp = EqualMatchers[i]->takeNext();
delete EqualMatchers[i];
EqualMatchers[i] = Tmp;
+ assert(!Optn == !Tmp && "Expected all to be null if any are null");
}
-
- Shared->setNext(new ScopeMatcher(EqualMatchers));
- // Recursively factor the newly created node.
- FactorNodes(Shared->getNextPtr());
-
- NewOptionsToMatch.push_back(Shared);
+ if (EqualMatchers[0]) {
+ Shared->setNext(new ScopeMatcher(std::move(EqualMatchers)));
+
+ // Recursively factor the newly created node.
+ FactorNodes(Shared->getNextPtr());
+ }
+
+ // Put the new Matcher where we started in OptionsToMatch.
+ *I = Shared;
}
-
+
+ // Trim the array to match the updated end.
+ if (E != OptionsToMatch.end())
+ OptionsToMatch.erase(E, OptionsToMatch.end());
+
// If we're down to a single pattern to match, then we don't need this scope
// anymore.
- if (NewOptionsToMatch.size() == 1) {
- MatcherPtr.reset(NewOptionsToMatch[0]);
+ if (OptionsToMatch.size() == 1) {
+ MatcherPtr.reset(OptionsToMatch[0]);
return;
}
-
- if (NewOptionsToMatch.empty()) {
+
+ if (OptionsToMatch.empty()) {
MatcherPtr.reset();
return;
}
-
+
// If our factoring failed (didn't achieve anything) see if we can simplify in
// other ways.
-
+
// Check to see if all of the leading entries are now opcode checks. If so,
// we can convert this Scope to be a OpcodeSwitch instead.
bool AllOpcodeChecks = true, AllTypeChecks = true;
- for (unsigned i = 0, e = NewOptionsToMatch.size(); i != e; ++i) {
+ for (unsigned i = 0, e = OptionsToMatch.size(); i != e; ++i) {
// Check to see if this breaks a series of CheckOpcodeMatchers.
- if (AllOpcodeChecks &&
- !isa<CheckOpcodeMatcher>(NewOptionsToMatch[i])) {
+ if (AllOpcodeChecks && !isa<CheckOpcodeMatcher>(OptionsToMatch[i])) {
#if 0
if (i > 3) {
errs() << "FAILING OPC #" << i << "\n";
- NewOptionsToMatch[i]->dump();
+ OptionsToMatch[i]->dump();
}
#endif
AllOpcodeChecks = false;
@@ -365,9 +372,8 @@ static void FactorNodes(std::unique_ptr<Matcher> &InputMatcherPtr) {
// Check to see if this breaks a series of CheckTypeMatcher's.
if (AllTypeChecks) {
- CheckTypeMatcher *CTM =
- cast_or_null<CheckTypeMatcher>(FindNodeWithKind(NewOptionsToMatch[i],
- Matcher::CheckType));
+ CheckTypeMatcher *CTM = cast_or_null<CheckTypeMatcher>(
+ FindNodeWithKind(OptionsToMatch[i], Matcher::CheckType));
if (!CTM ||
// iPTR checks could alias any other case without us knowing, don't
// bother with them.
@@ -376,66 +382,66 @@ static void FactorNodes(std::unique_ptr<Matcher> &InputMatcherPtr) {
CTM->getResNo() != 0 ||
// If the CheckType isn't at the start of the list, see if we can move
// it there.
- !CTM->canMoveBefore(NewOptionsToMatch[i])) {
+ !CTM->canMoveBefore(OptionsToMatch[i])) {
#if 0
if (i > 3 && AllTypeChecks) {
errs() << "FAILING TYPE #" << i << "\n";
- NewOptionsToMatch[i]->dump();
+ OptionsToMatch[i]->dump();
}
#endif
AllTypeChecks = false;
}
}
}
-
+
// If all the options are CheckOpcode's, we can form the SwitchOpcode, woot.
if (AllOpcodeChecks) {
StringSet<> Opcodes;
- SmallVector<std::pair<const SDNodeInfo*, Matcher*>, 8> Cases;
- for (unsigned i = 0, e = NewOptionsToMatch.size(); i != e; ++i) {
- CheckOpcodeMatcher *COM = cast<CheckOpcodeMatcher>(NewOptionsToMatch[i]);
+ SmallVector<std::pair<const SDNodeInfo *, Matcher *>, 8> Cases;
+ for (unsigned i = 0, e = OptionsToMatch.size(); i != e; ++i) {
+ CheckOpcodeMatcher *COM = cast<CheckOpcodeMatcher>(OptionsToMatch[i]);
assert(Opcodes.insert(COM->getOpcode().getEnumName()).second &&
"Duplicate opcodes not factored?");
Cases.push_back(std::make_pair(&COM->getOpcode(), COM->takeNext()));
delete COM;
}
-
- MatcherPtr.reset(new SwitchOpcodeMatcher(Cases));
+
+ MatcherPtr.reset(new SwitchOpcodeMatcher(std::move(Cases)));
return;
}
-
+
// If all the options are CheckType's, we can form the SwitchType, woot.
if (AllTypeChecks) {
DenseMap<unsigned, unsigned> TypeEntry;
- SmallVector<std::pair<MVT::SimpleValueType, Matcher*>, 8> Cases;
- for (unsigned i = 0, e = NewOptionsToMatch.size(); i != e; ++i) {
- Matcher* M = FindNodeWithKind(NewOptionsToMatch[i], Matcher::CheckType);
+ SmallVector<std::pair<MVT::SimpleValueType, Matcher *>, 8> Cases;
+ for (unsigned i = 0, e = OptionsToMatch.size(); i != e; ++i) {
+ Matcher *M = FindNodeWithKind(OptionsToMatch[i], Matcher::CheckType);
assert(M && isa<CheckTypeMatcher>(M) && "Unknown Matcher type");
auto *CTM = cast<CheckTypeMatcher>(M);
- Matcher *MatcherWithoutCTM = NewOptionsToMatch[i]->unlinkNode(CTM);
+ Matcher *MatcherWithoutCTM = OptionsToMatch[i]->unlinkNode(CTM);
MVT::SimpleValueType CTMTy = CTM->getType();
delete CTM;
unsigned &Entry = TypeEntry[CTMTy];
if (Entry != 0) {
// If we have unfactored duplicate types, then we should factor them.
- Matcher *PrevMatcher = Cases[Entry-1].second;
+ Matcher *PrevMatcher = Cases[Entry - 1].second;
if (ScopeMatcher *SM = dyn_cast<ScopeMatcher>(PrevMatcher)) {
- SM->setNumChildren(SM->getNumChildren()+1);
- SM->resetChild(SM->getNumChildren()-1, MatcherWithoutCTM);
+ SM->setNumChildren(SM->getNumChildren() + 1);
+ SM->resetChild(SM->getNumChildren() - 1, MatcherWithoutCTM);
continue;
}
-
- Matcher *Entries[2] = { PrevMatcher, MatcherWithoutCTM };
- Cases[Entry-1].second = new ScopeMatcher(Entries);
+
+ SmallVector<Matcher *, 2> Entries = {PrevMatcher, MatcherWithoutCTM};
+ Cases[Entry - 1].second = new ScopeMatcher(std::move(Entries));
continue;
}
-
- Entry = Cases.size()+1;
+
+ Entry = Cases.size() + 1;
Cases.push_back(std::make_pair(CTMTy, MatcherWithoutCTM));
}
-
+
// Make sure we recursively factor any scopes we may have created.
for (auto &M : Cases) {
if (ScopeMatcher *SM = dyn_cast<ScopeMatcher>(M.second)) {
@@ -447,7 +453,7 @@ static void FactorNodes(std::unique_ptr<Matcher> &InputMatcherPtr) {
}
if (Cases.size() != 1) {
- MatcherPtr.reset(new SwitchTypeMatcher(Cases));
+ MatcherPtr.reset(new SwitchTypeMatcher(std::move(Cases)));
} else {
// If we factored and ended up with one case, create it now.
MatcherPtr.reset(new CheckTypeMatcher(Cases[0].first, 0));
@@ -455,17 +461,15 @@ static void FactorNodes(std::unique_ptr<Matcher> &InputMatcherPtr) {
}
return;
}
-
// Reassemble the Scope node with the adjusted children.
- Scope->setNumChildren(NewOptionsToMatch.size());
- for (unsigned i = 0, e = NewOptionsToMatch.size(); i != e; ++i)
- Scope->resetChild(i, NewOptionsToMatch[i]);
+ Scope->setNumChildren(OptionsToMatch.size());
+ for (unsigned i = 0, e = OptionsToMatch.size(); i != e; ++i)
+ Scope->resetChild(i, OptionsToMatch[i]);
}
-void
-llvm::OptimizeMatcher(std::unique_ptr<Matcher> &MatcherPtr,
- const CodeGenDAGPatterns &CGP) {
+void llvm::OptimizeMatcher(std::unique_ptr<Matcher> &MatcherPtr,
+ const CodeGenDAGPatterns &CGP) {
ContractNodes(MatcherPtr, CGP);
FactorNodes(MatcherPtr);
}
diff --git a/llvm/utils/TableGen/DFAEmitter.cpp b/llvm/utils/TableGen/DFAEmitter.cpp
index 705908226fa1..54ad81cbebe8 100644
--- a/llvm/utils/TableGen/DFAEmitter.cpp
+++ b/llvm/utils/TableGen/DFAEmitter.cpp
@@ -22,13 +22,13 @@
#include "DFAEmitter.h"
#include "SequenceToOffsetTable.h"
-#include "TableGenBackends.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/UniqueVector.h"
#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>
@@ -370,10 +370,5 @@ void CustomDfaEmitter::printActionValue(action_type A, raw_ostream &OS) {
OS << ")";
}
-namespace llvm {
-
-void EmitAutomata(RecordKeeper &RK, raw_ostream &OS) {
- AutomatonEmitter(RK).run(OS);
-}
-
-} // namespace llvm
+static TableGen::Emitter::OptClass<AutomatonEmitter>
+ X("gen-automata", "Generate generic automata");
diff --git a/llvm/utils/TableGen/DFAEmitter.h b/llvm/utils/TableGen/DFAEmitter.h
index 44e5d97d544f..c831a65a73cd 100644
--- a/llvm/utils/TableGen/DFAEmitter.h
+++ b/llvm/utils/TableGen/DFAEmitter.h
@@ -21,6 +21,8 @@
#include "llvm/ADT/UniqueVector.h"
#include <map>
#include <set>
+#include <utility>
+#include <vector>
namespace llvm {
diff --git a/llvm/utils/TableGen/DFAPacketizerEmitter.cpp b/llvm/utils/TableGen/DFAPacketizerEmitter.cpp
index 6704d747f715..64c7884616a5 100644
--- a/llvm/utils/TableGen/DFAPacketizerEmitter.cpp
+++ b/llvm/utils/TableGen/DFAPacketizerEmitter.cpp
@@ -24,6 +24,7 @@
#include "llvm/TableGen/TableGenBackend.h"
#include <cassert>
#include <cstdint>
+#include <deque>
#include <map>
#include <set>
#include <string>
@@ -205,6 +206,7 @@ void DFAPacketizerEmitter::createScheduleClasses(unsigned ItineraryIdx,
// Run the worklist algorithm to generate the DFA.
//
void DFAPacketizerEmitter::run(raw_ostream &OS) {
+ emitSourceFileHeader("Target DFA Packetizer Tables", OS);
OS << "\n"
<< "#include \"llvm/CodeGen/DFAPacketizer.h\"\n";
OS << "namespace llvm {\n";
@@ -352,11 +354,5 @@ void DFAPacketizerEmitter::emitForItineraries(
<< "\n}\n\n";
}
-namespace llvm {
-
-void EmitDFAPacketizer(RecordKeeper &RK, raw_ostream &OS) {
- emitSourceFileHeader("Target DFA Packetizer Tables", OS);
- DFAPacketizerEmitter(RK).run(OS);
-}
-
-} // end namespace llvm
+static TableGen::Emitter::OptClass<DFAPacketizerEmitter>
+ X("gen-dfa-packetizer", "Generate DFA Packetizer for VLIW targets");
diff --git a/llvm/utils/TableGen/DXILEmitter.cpp b/llvm/utils/TableGen/DXILEmitter.cpp
index 44c1df3e9ac4..b294c66007f8 100644
--- a/llvm/utils/TableGen/DXILEmitter.cpp
+++ b/llvm/utils/TableGen/DXILEmitter.cpp
@@ -17,8 +17,8 @@
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/DXILOperationCommon.h"
-#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
using namespace llvm;
using namespace llvm::dxil;
@@ -26,8 +26,8 @@ using namespace llvm::dxil;
namespace {
struct DXILShaderModel {
- int Major;
- int Minor;
+ int Major = 0;
+ int Minor = 0;
};
struct DXILParam {
@@ -56,12 +56,13 @@ struct DXILOperationData {
// 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
+ bool IsDeriv = false; // whether this is some kind of derivative
+ bool IsGradient = false; // whether this requires a gradient calculation
+ bool IsFeedback = false; // whether this is a sampler feedback op
+ bool IsWave = false; // whether this requires in-wave, cross-lane functionality
+ bool RequiresUniformInputs = false; // 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
@@ -322,7 +323,7 @@ static void emitDXILOperationTable(std::vector<DXILOperationData> &DXILOps,
for (auto &DXILOp : DXILOps) {
OpStrings.add(DXILOp.DXILOp.str());
- if (ClassSet.find(DXILOp.DXILClass) != ClassSet.end())
+ if (ClassSet.contains(DXILOp.DXILClass))
continue;
ClassSet.insert(DXILOp.DXILClass);
OpClassStrings.add(getDXILOpClassName(DXILOp.DXILClass));
@@ -411,9 +412,7 @@ static void emitDXILOperationTable(std::vector<DXILOperationData> &DXILOps,
OS << "}\n ";
}
-namespace llvm {
-
-void EmitDXILOperation(RecordKeeper &Records, raw_ostream &OS) {
+static void EmitDXILOperation(RecordKeeper &Records, raw_ostream &OS) {
std::vector<Record *> Ops = Records.getAllDerivedDefinitions("dxil_op");
OS << "// Generated code, do not edit.\n";
OS << "\n";
@@ -439,4 +438,5 @@ void EmitDXILOperation(RecordKeeper &Records, raw_ostream &OS) {
OS << "\n";
}
-} // namespace llvm
+static TableGen::Emitter::Opt X("gen-dxil-operation", EmitDXILOperation,
+ "Generate DXIL operation information");
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index 8f816744370c..607f19653c7a 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -11,9 +11,11 @@
//
//===----------------------------------------------------------------------===//
+#include "CodeGenHwModes.h"
#include "CodeGenInstruction.h"
#include "CodeGenTarget.h"
#include "InfoByHwMode.h"
+#include "TableGenBackends.h"
#include "VarLenCodeEmitterGen.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/ArrayRef.h"
@@ -2028,193 +2030,11 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef,
if (IsVarLenInst) {
parseVarLenInstOperand(EncodingDef, InsnOperands, CGI);
} else {
- std::map<std::string, std::vector<OperandInfo>> NumberedInsnOperands;
- std::set<std::string> NumberedInsnOperandsNoTie;
- bool SupportPositionalDecoding =
- Target.getInstructionSet()->getValueAsBit(
- "useDeprecatedPositionallyEncodedOperands") &&
- Target.getInstructionSet()->getValueAsBit(
- "decodePositionallyEncodedOperands");
- if (SupportPositionalDecoding) {
- 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);
- }
-
- 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));
-
- if (Var && Var->getName() == Vals[i].getName())
- break;
- }
-
- if (bi == Bits.getNumBits())
- continue;
-
- // Skip variables that correspond to explicitly-named operands.
- unsigned OpIdx;
- std::pair<unsigned, unsigned> SubOp;
- if (CGI.Operands.hasSubOperandAlias(Vals[i].getName(), SubOp) ||
- 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));
-
- if (!Var)
- break;
-
- if (Var->getName() != Vals[i].getName())
- break;
-
- ++bitWidth;
- }
-
- 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 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");
-
- 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());
-
- 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;
- }
-
- 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;
-
- OperandInfo OpInfo(Decoder, HasCompleteDecoder);
- OpInfo.addField(bitStart, bitWidth, 0);
-
- 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);
- }
- }
-
// For each operand, see if we can figure out where it is encoded.
for (const auto &Op : InOutOperands) {
Init *OpInit = Op.first;
StringRef OpName = Op.second;
- if (SupportPositionalDecoding) {
- if (!NumberedInsnOperands[std::string(OpName)].empty()) {
- llvm::append_range(InsnOperands,
- NumberedInsnOperands[std::string(OpName)]);
- continue;
- }
- if (!NumberedInsnOperands[TiedNames[std::string(OpName)]].empty()) {
- if (!NumberedInsnOperandsNoTie.count(
- TiedNames[std::string(OpName)])) {
- // Figure out to which (sub)operand we're tied.
- unsigned i =
- CGI.Operands.getOperandNamed(TiedNames[std::string(OpName)]);
- int tiedTo = CGI.Operands[i].getTiedRegister();
- if (tiedTo == -1) {
- i = CGI.Operands.getOperandNamed(OpName);
- tiedTo = CGI.Operands[i].getTiedRegister();
- }
-
- if (tiedTo != -1) {
- std::pair<unsigned, unsigned> SO =
- CGI.Operands.getSubOperandNumber(tiedTo);
-
- InsnOperands.push_back(
- NumberedInsnOperands[TiedNames[std::string(OpName)]]
- [SO.second]);
- }
- }
- continue;
- }
- }
-
// We're ready to find the instruction encoding locations for this operand.
// First, find the operand type ("OpInit"), and sub-op names
@@ -2597,11 +2417,11 @@ void DecoderEmitter::run(raw_ostream &o) {
formatted_raw_ostream OS(o);
OS << "#include \"llvm/MC/MCInst.h\"\n";
OS << "#include \"llvm/MC/MCSubtargetInfo.h\"\n";
- OS << "#include \"llvm/MC/SubtargetFeature.h\"\n";
OS << "#include \"llvm/Support/DataTypes.h\"\n";
OS << "#include \"llvm/Support/Debug.h\"\n";
OS << "#include \"llvm/Support/LEB128.h\"\n";
OS << "#include \"llvm/Support/raw_ostream.h\"\n";
+ OS << "#include \"llvm/TargetParser/SubtargetFeature.h\"\n";
OS << "#include <assert.h>\n";
OS << '\n';
OS << "namespace llvm {\n\n";
diff --git a/llvm/utils/TableGen/DirectiveEmitter.cpp b/llvm/utils/TableGen/DirectiveEmitter.cpp
index f32fbe3e25cd..67033c6290ca 100644
--- a/llvm/utils/TableGen/DirectiveEmitter.cpp
+++ b/llvm/utils/TableGen/DirectiveEmitter.cpp
@@ -18,6 +18,7 @@
#include "llvm/ADT/StringSwitch.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
using namespace llvm;
@@ -36,14 +37,12 @@ private:
StringRef Name;
raw_ostream &OS;
};
-} // end anonymous namespace
-
-namespace llvm {
+} // namespace
// Generate enum class
-void GenerateEnumClass(const std::vector<Record *> &Records, raw_ostream &OS,
- StringRef Enum, StringRef Prefix,
- const DirectiveLanguage &DirLang) {
+static void GenerateEnumClass(const std::vector<Record *> &Records,
+ raw_ostream &OS, StringRef Enum, StringRef Prefix,
+ const DirectiveLanguage &DirLang) {
OS << "\n";
OS << "enum class " << Enum << " {\n";
for (const auto &R : Records) {
@@ -73,9 +72,10 @@ void GenerateEnumClass(const std::vector<Record *> &Records, raw_ostream &OS,
// Generate enums for values that clauses can take.
// Also generate function declarations for get<Enum>Name(StringRef Str).
-void GenerateEnumClauseVal(const std::vector<Record *> &Records,
- raw_ostream &OS, const DirectiveLanguage &DirLang,
- std::string &EnumHelperFuncs) {
+static void GenerateEnumClauseVal(const std::vector<Record *> &Records,
+ raw_ostream &OS,
+ const DirectiveLanguage &DirLang,
+ std::string &EnumHelperFuncs) {
for (const auto &R : Records) {
Clause C{R};
const auto &ClauseVals = C.getClauseVals();
@@ -117,9 +117,9 @@ void GenerateEnumClauseVal(const std::vector<Record *> &Records,
}
}
-bool HasDuplicateClauses(const std::vector<Record *> &Clauses,
- const Directive &Directive,
- llvm::StringSet<> &CrtClauses) {
+static bool HasDuplicateClauses(const std::vector<Record *> &Clauses,
+ const Directive &Directive,
+ llvm::StringSet<> &CrtClauses) {
bool HasError = false;
for (const auto &C : Clauses) {
VersionedClause VerClause{C};
@@ -136,7 +136,8 @@ bool HasDuplicateClauses(const std::vector<Record *> &Clauses,
// Check for duplicate clauses in lists. Clauses cannot appear twice in the
// three allowed list. Also, since required implies allowed, clauses cannot
// appear in both the allowedClauses and requiredClauses lists.
-bool HasDuplicateClausesInDirectives(const std::vector<Record *> &Directives) {
+static bool
+HasDuplicateClausesInDirectives(const std::vector<Record *> &Directives) {
bool HasDuplicate = false;
for (const auto &D : Directives) {
Directive Dir{D};
@@ -175,7 +176,7 @@ bool DirectiveLanguage::HasValidityErrors() const {
// Generate the declaration section for the enumeration in the directive
// language
-void EmitDirectivesDecl(RecordKeeper &Records, raw_ostream &OS) {
+static void EmitDirectivesDecl(RecordKeeper &Records, raw_ostream &OS) {
const auto DirLang = DirectiveLanguage{Records};
if (DirLang.HasValidityErrors())
return;
@@ -245,9 +246,10 @@ void EmitDirectivesDecl(RecordKeeper &Records, raw_ostream &OS) {
}
// Generate function implementation for get<Enum>Name(StringRef Str)
-void GenerateGetName(const std::vector<Record *> &Records, raw_ostream &OS,
- StringRef Enum, const DirectiveLanguage &DirLang,
- StringRef Prefix) {
+static void GenerateGetName(const std::vector<Record *> &Records,
+ raw_ostream &OS, StringRef Enum,
+ const DirectiveLanguage &DirLang,
+ StringRef Prefix) {
OS << "\n";
OS << "llvm::StringRef llvm::" << DirLang.getCppNamespace() << "::get"
<< DirLang.getName() << Enum << "Name(" << Enum << " Kind) {\n";
@@ -269,9 +271,10 @@ void GenerateGetName(const std::vector<Record *> &Records, raw_ostream &OS,
}
// Generate function implementation for get<Enum>Kind(StringRef Str)
-void GenerateGetKind(const std::vector<Record *> &Records, raw_ostream &OS,
- StringRef Enum, const DirectiveLanguage &DirLang,
- StringRef Prefix, bool ImplicitAsUnknown) {
+static void GenerateGetKind(const std::vector<Record *> &Records,
+ raw_ostream &OS, StringRef Enum,
+ const DirectiveLanguage &DirLang, StringRef Prefix,
+ bool ImplicitAsUnknown) {
auto DefaultIt = llvm::find_if(
Records, [](Record *R) { return R->getValueAsBit("isDefault") == true; });
@@ -303,8 +306,8 @@ void GenerateGetKind(const std::vector<Record *> &Records, raw_ostream &OS,
}
// Generate function implementation for get<ClauseVal>Kind(StringRef Str)
-void GenerateGetKindClauseVal(const DirectiveLanguage &DirLang,
- raw_ostream &OS) {
+static void GenerateGetKindClauseVal(const DirectiveLanguage &DirLang,
+ raw_ostream &OS) {
for (const auto &R : DirLang.getClauses()) {
Clause C{R};
const auto &ClauseVals = C.getClauseVals();
@@ -359,10 +362,11 @@ void GenerateGetKindClauseVal(const DirectiveLanguage &DirLang,
}
}
-void GenerateCaseForVersionedClauses(const std::vector<Record *> &Clauses,
- raw_ostream &OS, StringRef DirectiveName,
- const DirectiveLanguage &DirLang,
- llvm::StringSet<> &Cases) {
+static void
+GenerateCaseForVersionedClauses(const std::vector<Record *> &Clauses,
+ raw_ostream &OS, StringRef DirectiveName,
+ const DirectiveLanguage &DirLang,
+ llvm::StringSet<> &Cases) {
for (const auto &C : Clauses) {
VersionedClause VerClause{C};
@@ -378,8 +382,8 @@ void GenerateCaseForVersionedClauses(const std::vector<Record *> &Clauses,
}
// Generate the isAllowedClauseForDirective function implementation.
-void GenerateIsAllowedClause(const DirectiveLanguage &DirLang,
- raw_ostream &OS) {
+static void GenerateIsAllowedClause(const DirectiveLanguage &DirLang,
+ raw_ostream &OS) {
OS << "\n";
OS << "bool llvm::" << DirLang.getCppNamespace()
<< "::isAllowedClauseForDirective("
@@ -432,9 +436,10 @@ void GenerateIsAllowedClause(const DirectiveLanguage &DirLang,
}
// Generate a simple enum set with the give clauses.
-void GenerateClauseSet(const std::vector<Record *> &Clauses, raw_ostream &OS,
- StringRef ClauseSetPrefix, Directive &Dir,
- const DirectiveLanguage &DirLang) {
+static void GenerateClauseSet(const std::vector<Record *> &Clauses,
+ raw_ostream &OS, StringRef ClauseSetPrefix,
+ Directive &Dir,
+ const DirectiveLanguage &DirLang) {
OS << "\n";
OS << " static " << DirLang.getClauseEnumSetClass() << " " << ClauseSetPrefix
@@ -450,8 +455,8 @@ void GenerateClauseSet(const std::vector<Record *> &Clauses, raw_ostream &OS,
}
// Generate an enum set for the 4 kinds of clauses linked to a directive.
-void GenerateDirectiveClauseSets(const DirectiveLanguage &DirLang,
- raw_ostream &OS) {
+static void GenerateDirectiveClauseSets(const DirectiveLanguage &DirLang,
+ raw_ostream &OS) {
IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_SETS", OS);
@@ -490,8 +495,8 @@ void GenerateDirectiveClauseSets(const DirectiveLanguage &DirLang,
// Generate a map of directive (key) with DirectiveClauses struct as values.
// The struct holds the 4 sets of enumeration for the 4 kinds of clauses
// allowances (allowed, allowed once, allowed exclusive and required).
-void GenerateDirectiveClauseMap(const DirectiveLanguage &DirLang,
- raw_ostream &OS) {
+static void GenerateDirectiveClauseMap(const DirectiveLanguage &DirLang,
+ raw_ostream &OS) {
IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_MAP", OS);
@@ -525,8 +530,8 @@ void GenerateDirectiveClauseMap(const DirectiveLanguage &DirLang,
// If the clause does not hold a value, an EMPTY_CLASS is used.
// If the clause class is generic then a WRAPPER_CLASS is used. When the value
// is optional, the value class is wrapped into a std::optional.
-void GenerateFlangClauseParserClass(const DirectiveLanguage &DirLang,
- raw_ostream &OS) {
+static void GenerateFlangClauseParserClass(const DirectiveLanguage &DirLang,
+ raw_ostream &OS) {
IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES", OS);
@@ -553,8 +558,8 @@ void GenerateFlangClauseParserClass(const DirectiveLanguage &DirLang,
}
// Generate a list of the different clause classes for Flang.
-void GenerateFlangClauseParserClassList(const DirectiveLanguage &DirLang,
- raw_ostream &OS) {
+static void GenerateFlangClauseParserClassList(const DirectiveLanguage &DirLang,
+ raw_ostream &OS) {
IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES_LIST", OS);
@@ -566,8 +571,8 @@ void GenerateFlangClauseParserClassList(const DirectiveLanguage &DirLang,
}
// Generate dump node list for the clauses holding a generic class name.
-void GenerateFlangClauseDump(const DirectiveLanguage &DirLang,
- raw_ostream &OS) {
+static void GenerateFlangClauseDump(const DirectiveLanguage &DirLang,
+ raw_ostream &OS) {
IfDefScope Scope("GEN_FLANG_DUMP_PARSE_TREE_CLAUSES", OS);
@@ -581,8 +586,8 @@ void GenerateFlangClauseDump(const DirectiveLanguage &DirLang,
// Generate Unparse functions for clauses classes in the Flang parse-tree
// If the clause is a non-generic class, no entry is generated.
-void GenerateFlangClauseUnparse(const DirectiveLanguage &DirLang,
- raw_ostream &OS) {
+static void GenerateFlangClauseUnparse(const DirectiveLanguage &DirLang,
+ raw_ostream &OS) {
IfDefScope Scope("GEN_FLANG_CLAUSE_UNPARSE", OS);
@@ -633,8 +638,8 @@ void GenerateFlangClauseUnparse(const DirectiveLanguage &DirLang,
}
// Generate check in the Enter functions for clauses classes.
-void GenerateFlangClauseCheckPrototypes(const DirectiveLanguage &DirLang,
- raw_ostream &OS) {
+static void GenerateFlangClauseCheckPrototypes(const DirectiveLanguage &DirLang,
+ raw_ostream &OS) {
IfDefScope Scope("GEN_FLANG_CLAUSE_CHECK_ENTER", OS);
@@ -648,8 +653,8 @@ void GenerateFlangClauseCheckPrototypes(const DirectiveLanguage &DirLang,
// Generate the mapping for clauses between the parser class and the
// corresponding clause Kind
-void GenerateFlangClauseParserKindMap(const DirectiveLanguage &DirLang,
- raw_ostream &OS) {
+static void GenerateFlangClauseParserKindMap(const DirectiveLanguage &DirLang,
+ raw_ostream &OS) {
IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_KIND_MAP", OS);
@@ -669,15 +674,15 @@ void GenerateFlangClauseParserKindMap(const DirectiveLanguage &DirLang,
<< " Parser clause\");\n";
}
-bool compareClauseName(Record *R1, Record *R2) {
+static bool compareClauseName(Record *R1, Record *R2) {
Clause C1{R1};
Clause C2{R2};
return (C1.getName() > C2.getName());
}
// Generate the parser for the clauses.
-void GenerateFlangClausesParser(const DirectiveLanguage &DirLang,
- raw_ostream &OS) {
+static void GenerateFlangClausesParser(const DirectiveLanguage &DirLang,
+ raw_ostream &OS) {
std::vector<Record *> Clauses = DirLang.getClauses();
// Sort clauses in reverse alphabetical order so with clauses with same
// beginning, the longer option is tried before.
@@ -715,6 +720,8 @@ void GenerateFlangClausesParser(const DirectiveLanguage &DirLang,
if (Clause.isValueOptional())
OS << "maybe(";
OS << "parenthesized(";
+ if (Clause.isValueList())
+ OS << "nonemptyList(";
if (!Clause.getPrefix().empty())
OS << "\"" << Clause.getPrefix() << ":\" >> ";
@@ -735,6 +742,8 @@ void GenerateFlangClausesParser(const DirectiveLanguage &DirLang,
OS << Parser;
if (!Clause.getPrefix().empty() && Clause.isPrefixOptional())
OS << " || " << Parser;
+ if (Clause.isValueList()) // close nonemptyList(.
+ OS << ")";
OS << ")"; // close parenthesized(.
if (Clause.isValueOptional()) // close maybe(.
@@ -750,8 +759,8 @@ void GenerateFlangClausesParser(const DirectiveLanguage &DirLang,
// Generate the implementation section for the enumeration in the directive
// language
-void EmitDirectivesFlangImpl(const DirectiveLanguage &DirLang,
- raw_ostream &OS) {
+static void EmitDirectivesFlangImpl(const DirectiveLanguage &DirLang,
+ raw_ostream &OS) {
GenerateDirectiveClauseSets(DirLang, OS);
@@ -772,8 +781,8 @@ void EmitDirectivesFlangImpl(const DirectiveLanguage &DirLang,
GenerateFlangClausesParser(DirLang, OS);
}
-void GenerateClauseClassMacro(const DirectiveLanguage &DirLang,
- raw_ostream &OS) {
+static void GenerateClauseClassMacro(const DirectiveLanguage &DirLang,
+ raw_ostream &OS) {
// Generate macros style information for legacy code in clang
IfDefScope Scope("GEN_CLANG_CLAUSE_CLASS", OS);
@@ -870,7 +879,7 @@ void EmitDirectivesBasicImpl(const DirectiveLanguage &DirLang,
// Generate the implemenation section for the enumeration in the directive
// language.
-void EmitDirectivesImpl(RecordKeeper &Records, raw_ostream &OS) {
+static void EmitDirectivesImpl(RecordKeeper &Records, raw_ostream &OS) {
const auto DirLang = DirectiveLanguage{Records};
if (DirLang.HasValidityErrors())
return;
@@ -882,4 +891,10 @@ void EmitDirectivesImpl(RecordKeeper &Records, raw_ostream &OS) {
EmitDirectivesBasicImpl(DirLang, OS);
}
-} // namespace llvm
+static TableGen::Emitter::Opt
+ X("gen-directive-decl", EmitDirectivesDecl,
+ "Generate directive related declaration code (header file)");
+
+static TableGen::Emitter::Opt
+ Y("gen-directive-impl", EmitDirectivesImpl,
+ "Generate directive related implementation code");
diff --git a/llvm/utils/TableGen/DisassemblerEmitter.cpp b/llvm/utils/TableGen/DisassemblerEmitter.cpp
index dfa4b30ee569..92f3721507e5 100644
--- a/llvm/utils/TableGen/DisassemblerEmitter.cpp
+++ b/llvm/utils/TableGen/DisassemblerEmitter.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "CodeGenTarget.h"
+#include "TableGenBackends.h"
#include "WebAssemblyDisassemblerEmitter.h"
#include "X86DisassemblerTables.h"
#include "X86RecognizableInstr.h"
@@ -93,12 +94,7 @@ using namespace llvm::X86Disassembler;
/// X86RecognizableInstr.cpp contains the implementation for a single
/// instruction.
-namespace llvm {
-
-extern void EmitDecoder(RecordKeeper &RK, raw_ostream &OS,
- const std::string &PredicateNamespace);
-
-void EmitDisassembler(RecordKeeper &Records, raw_ostream &OS) {
+static void EmitDisassembler(RecordKeeper &Records, raw_ostream &OS) {
CodeGenTarget Target(Records);
emitSourceFileHeader(" * " + Target.getName().str() + " Disassembler", OS);
@@ -135,4 +131,5 @@ void EmitDisassembler(RecordKeeper &Records, raw_ostream &OS) {
EmitDecoder(Records, OS, PredicateNamespace);
}
-} // end namespace llvm
+static TableGen::Emitter::Opt X("gen-disassembler", EmitDisassembler,
+ "Generate disassembler");
diff --git a/llvm/utils/TableGen/ExegesisEmitter.cpp b/llvm/utils/TableGen/ExegesisEmitter.cpp
index bc8ccdac557b..736f1220be14 100644
--- a/llvm/utils/TableGen/ExegesisEmitter.cpp
+++ b/llvm/utils/TableGen/ExegesisEmitter.cpp
@@ -202,10 +202,5 @@ void ExegesisEmitter::run(raw_ostream &OS) const {
} // end anonymous namespace
-namespace llvm {
-
-void EmitExegesis(RecordKeeper &RK, raw_ostream &OS) {
- ExegesisEmitter(RK).run(OS);
-}
-
-} // end namespace llvm
+static TableGen::Emitter::OptClass<ExegesisEmitter>
+ X("gen-exegesis", "Generate llvm-exegesis tables");
diff --git a/llvm/utils/TableGen/FastISelEmitter.cpp b/llvm/utils/TableGen/FastISelEmitter.cpp
index 0a88f67be168..3f3a63de0c0c 100644
--- a/llvm/utils/TableGen/FastISelEmitter.cpp
+++ b/llvm/utils/TableGen/FastISelEmitter.cpp
@@ -18,6 +18,9 @@
#include "CodeGenDAGPatterns.h"
#include "CodeGenInstruction.h"
+#include "CodeGenRegisters.h"
+#include "CodeGenTarget.h"
+#include "InfoByHwMode.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/TableGen/Error.h"
@@ -854,9 +857,7 @@ void FastISelMap::printFunctionDefinitions(raw_ostream &OS) {
// TODO: SignaturesWithConstantForms should be empty here.
}
-namespace llvm {
-
-void EmitFastISel(RecordKeeper &RK, raw_ostream &OS) {
+static void EmitFastISel(RecordKeeper &RK, raw_ostream &OS) {
CodeGenDAGPatterns CGP(RK);
const CodeGenTarget &Target = CGP.getTargetInfo();
emitSourceFileHeader("\"Fast\" Instruction Selector for the " +
@@ -872,4 +873,5 @@ void EmitFastISel(RecordKeeper &RK, raw_ostream &OS) {
F.printFunctionDefinitions(OS);
}
-} // End llvm namespace
+static TableGen::Emitter::Opt X("gen-fast-isel", EmitFastISel,
+ "Generate a \"fast\" instruction selector");
diff --git a/llvm/utils/TableGen/GICombinerEmitter.cpp b/llvm/utils/TableGen/GICombinerEmitter.cpp
index 2ae313081a6f..ec26024b6518 100644
--- a/llvm/utils/TableGen/GICombinerEmitter.cpp
+++ b/llvm/utils/TableGen/GICombinerEmitter.cpp
@@ -14,7 +14,11 @@
#include "CodeGenTarget.h"
#include "GlobalISel/CodeExpander.h"
#include "GlobalISel/CodeExpansions.h"
+#include "GlobalISel/CombinerUtils.h"
#include "GlobalISel/GIMatchDag.h"
+#include "GlobalISel/GIMatchDagEdge.h"
+#include "GlobalISel/GIMatchDagInstr.h"
+#include "GlobalISel/GIMatchDagOperands.h"
#include "GlobalISel/GIMatchDagPredicate.h"
#include "GlobalISel/GIMatchTree.h"
#include "llvm/ADT/SmallSet.h"
@@ -24,6 +28,7 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/TableGen/Error.h"
+#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/StringMatcher.h"
#include "llvm/TableGen/TableGenBackend.h"
#include <cstdint>
@@ -38,14 +43,14 @@ STATISTIC(NumPatternTotalStatistic, "Total number of patterns");
cl::OptionCategory
GICombinerEmitterCat("Options for -gen-global-isel-combiner");
-static cl::list<std::string>
+cl::list<std::string>
SelectedCombiners("combiners", cl::desc("Emit the specified combiners"),
cl::cat(GICombinerEmitterCat), cl::CommaSeparated);
static cl::opt<bool> ShowExpansions(
"gicombiner-show-expansions",
cl::desc("Use C++ comments to indicate occurence of code expansion"),
cl::cat(GICombinerEmitterCat));
-static cl::opt<bool> StopAfterParse(
+cl::opt<bool> StopAfterParse(
"gicombiner-stop-after-parse",
cl::desc("Stop processing after parsing rules and dump state"),
cl::cat(GICombinerEmitterCat));
@@ -277,55 +282,6 @@ public:
}
};
-/// A convenience function to check that an Init refers to a specific def. This
-/// is primarily useful for testing for defs and similar in DagInit's since
-/// DagInit's support any type inside them.
-static bool isSpecificDef(const Init &N, StringRef Def) {
- if (const DefInit *OpI = dyn_cast<DefInit>(&N))
- if (OpI->getDef()->getName() == Def)
- return true;
- return false;
-}
-
-/// A convenience function to check that an Init refers to a def that is a
-/// subclass of the given class and coerce it to a def if it is. This is
-/// primarily useful for testing for subclasses of GIMatchKind and similar in
-/// DagInit's since DagInit's support any type inside them.
-static Record *getDefOfSubClass(const Init &N, StringRef Cls) {
- if (const DefInit *OpI = dyn_cast<DefInit>(&N))
- if (OpI->getDef()->isSubClassOf(Cls))
- return OpI->getDef();
- return nullptr;
-}
-
-/// A convenience function to check that an Init refers to a dag whose operator
-/// is a specific def and coerce it to a dag if it is. This is primarily useful
-/// for testing for subclasses of GIMatchKind and similar in DagInit's since
-/// DagInit's support any type inside them.
-static const DagInit *getDagWithSpecificOperator(const Init &N,
- StringRef Name) {
- if (const DagInit *I = dyn_cast<DagInit>(&N))
- if (I->getNumArgs() > 0)
- if (const DefInit *OpI = dyn_cast<DefInit>(I->getOperator()))
- if (OpI->getDef()->getName() == Name)
- return I;
- return nullptr;
-}
-
-/// A convenience function to check that an Init refers to a dag whose operator
-/// is a def that is a subclass of the given class and coerce it to a dag if it
-/// is. This is primarily useful for testing for subclasses of GIMatchKind and
-/// similar in DagInit's since DagInit's support any type inside them.
-static const DagInit *getDagWithOperatorOfSubClass(const Init &N,
- StringRef Cls) {
- if (const DagInit *I = dyn_cast<DagInit>(&N))
- if (I->getNumArgs() > 0)
- if (const DefInit *OpI = dyn_cast<DefInit>(I->getOperator()))
- if (OpI->getDef()->isSubClassOf(Cls))
- return I;
- return nullptr;
-}
-
StringRef makeNameForAnonInstr(CombineRule &Rule) {
return insertStrTab(to_string(
format("__anon%" PRIu64 "_%u", Rule.getID(), Rule.allocUID())));
@@ -1062,8 +1018,14 @@ void GICombinerEmitter::run(raw_ostream &OS) {
//===----------------------------------------------------------------------===//
-namespace llvm {
-void EmitGICombiner(RecordKeeper &RK, raw_ostream &OS) {
+static void EmitGICombiner(RecordKeeper &RK, raw_ostream &OS) {
+ PrintWarning(
+ "'-gen-global-isel-combiner' is deprecated and will be removed soon; "
+ "please use '-gen-global-isel-combiner-match-table' instead");
+ PrintNote(
+ "See "
+ "https://discourse.llvm.org/t/rfc-matchtable-based-globalisel-combiners");
+
CodeGenTarget Target(RK);
emitSourceFileHeader("Global Combiner", OS);
@@ -1078,4 +1040,5 @@ void EmitGICombiner(RecordKeeper &RK, raw_ostream &OS) {
NumPatternTotalStatistic = NumPatternTotal;
}
-} // namespace llvm
+static TableGen::Emitter::Opt X("gen-global-isel-combiner", EmitGICombiner,
+ "Generate GlobalISel combiner");
diff --git a/llvm/utils/TableGen/GlobalISel/CodeExpander.h b/llvm/utils/TableGen/GlobalISel/CodeExpander.h
index 1291eb1ad940..0b1e6ceab52c 100644
--- a/llvm/utils/TableGen/GlobalISel/CodeExpander.h
+++ b/llvm/utils/TableGen/GlobalISel/CodeExpander.h
@@ -1,4 +1,4 @@
-//===- CodeExpander.h - Expand variables in a string ----------------------===//
+//===- CodeExpander.h - Expand variables in a string ------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/llvm/utils/TableGen/GlobalISel/CombinerUtils.h b/llvm/utils/TableGen/GlobalISel/CombinerUtils.h
new file mode 100644
index 000000000000..394c43e3fa83
--- /dev/null
+++ b/llvm/utils/TableGen/GlobalISel/CombinerUtils.h
@@ -0,0 +1,72 @@
+//===- CombinerUtils.h ----------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file Utility functions used by both Combiner backends.
+/// TODO: Can remove when MatchDAG-based backend is removed.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_UTILS_TABLEGEN_COMBINERUTILS_H
+#define LLVM_UTILS_TABLEGEN_COMBINERUTILS_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/TableGen/Record.h"
+
+namespace llvm {
+
+/// A convenience function to check that an Init refers to a specific def. This
+/// is primarily useful for testing for defs and similar in DagInit's since
+/// DagInit's support any type inside them.
+inline bool isSpecificDef(const Init &N, StringRef Def) {
+ if (const DefInit *OpI = dyn_cast<DefInit>(&N))
+ if (OpI->getDef()->getName() == Def)
+ return true;
+ return false;
+}
+
+/// A convenience function to check that an Init refers to a def that is a
+/// subclass of the given class and coerce it to a def if it is. This is
+/// primarily useful for testing for subclasses of GIMatchKind and similar in
+/// DagInit's since DagInit's support any type inside them.
+inline Record *getDefOfSubClass(const Init &N, StringRef Cls) {
+ if (const DefInit *OpI = dyn_cast<DefInit>(&N))
+ if (OpI->getDef()->isSubClassOf(Cls))
+ return OpI->getDef();
+ return nullptr;
+}
+
+/// A convenience function to check that an Init refers to a dag whose operator
+/// is a specific def and coerce it to a dag if it is. This is primarily useful
+/// for testing for subclasses of GIMatchKind and similar in DagInit's since
+/// DagInit's support any type inside them.
+inline const DagInit *getDagWithSpecificOperator(const Init &N,
+ StringRef Name) {
+ if (const DagInit *I = dyn_cast<DagInit>(&N))
+ if (I->getNumArgs() > 0)
+ if (const DefInit *OpI = dyn_cast<DefInit>(I->getOperator()))
+ if (OpI->getDef()->getName() == Name)
+ return I;
+ return nullptr;
+}
+
+/// A convenience function to check that an Init refers to a dag whose operator
+/// is a def that is a subclass of the given class and coerce it to a dag if it
+/// is. This is primarily useful for testing for subclasses of GIMatchKind and
+/// similar in DagInit's since DagInit's support any type inside them.
+inline const DagInit *getDagWithOperatorOfSubClass(const Init &N,
+ StringRef Cls) {
+ if (const DagInit *I = dyn_cast<DagInit>(&N))
+ if (I->getNumArgs() > 0)
+ if (const DefInit *OpI = dyn_cast<DefInit>(I->getOperator()))
+ if (OpI->getDef()->isSubClassOf(Cls))
+ return I;
+ return nullptr;
+}
+} // namespace llvm
+
+#endif
diff --git a/llvm/utils/TableGen/GlobalISel/GIMatchDag.h b/llvm/utils/TableGen/GlobalISel/GIMatchDag.h
index 4c3c610aff74..c566dd73f709 100644
--- a/llvm/utils/TableGen/GlobalISel/GIMatchDag.h
+++ b/llvm/utils/TableGen/GlobalISel/GIMatchDag.h
@@ -1,4 +1,4 @@
-//===- GIMatchDag.h - Represent a DAG to be matched -----------------------===//
+//===- GIMatchDag.h - Represent a DAG to be matched -------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/llvm/utils/TableGen/GlobalISel/GIMatchDagEdge.h b/llvm/utils/TableGen/GlobalISel/GIMatchDagEdge.h
index 8e845ff0a51e..e76ef1b4a3aa 100644
--- a/llvm/utils/TableGen/GlobalISel/GIMatchDagEdge.h
+++ b/llvm/utils/TableGen/GlobalISel/GIMatchDagEdge.h
@@ -1,4 +1,4 @@
-//===- GIMatchDagEdge.h - Represent a shared operand list for nodes -------===//
+//===- GIMatchDagEdge.h - Represent node shared operand lists ---*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/llvm/utils/TableGen/GlobalISel/GIMatchDagInstr.h b/llvm/utils/TableGen/GlobalISel/GIMatchDagInstr.h
index 5e60448b30c1..d2c746dda9e9 100644
--- a/llvm/utils/TableGen/GlobalISel/GIMatchDagInstr.h
+++ b/llvm/utils/TableGen/GlobalISel/GIMatchDagInstr.h
@@ -1,4 +1,4 @@
-//===- GIMatchDagInstr.h - Represent a instruction to be matched ----------===//
+//===- GIMatchDagInstr.h - Represent instruction to be matched --*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/llvm/utils/TableGen/GlobalISel/GIMatchDagOperands.h b/llvm/utils/TableGen/GlobalISel/GIMatchDagOperands.h
index c2d30574231d..ae7190cb7296 100644
--- a/llvm/utils/TableGen/GlobalISel/GIMatchDagOperands.h
+++ b/llvm/utils/TableGen/GlobalISel/GIMatchDagOperands.h
@@ -1,4 +1,4 @@
-//===- GIMatchDagOperands.h - Represent a shared operand list for nodes ---===//
+//===- GIMatchDagOperands.h - Represent operand lists for nodes -*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/llvm/utils/TableGen/GlobalISel/GIMatchDagPredicate.h b/llvm/utils/TableGen/GlobalISel/GIMatchDagPredicate.h
index 96fef21b7627..952cbdb24f54 100644
--- a/llvm/utils/TableGen/GlobalISel/GIMatchDagPredicate.h
+++ b/llvm/utils/TableGen/GlobalISel/GIMatchDagPredicate.h
@@ -1,4 +1,4 @@
-//===- GIMatchDagPredicate - Represent a predicate to check ---------------===//
+//===- GIMatchDagPredicate - Represent a predicate to check -----*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/llvm/utils/TableGen/GlobalISel/GIMatchTree.cpp b/llvm/utils/TableGen/GlobalISel/GIMatchTree.cpp
index d98884493e84..23697fd9e2e2 100644
--- a/llvm/utils/TableGen/GlobalISel/GIMatchTree.cpp
+++ b/llvm/utils/TableGen/GlobalISel/GIMatchTree.cpp
@@ -89,20 +89,20 @@ GIMatchTreeBuilderLeafInfo::GIMatchTreeBuilderLeafInfo(
TraversableEdges(MatchDag.getNumEdges()),
TestablePredicates(MatchDag.getNumPredicates()) {
// Number all the predicates in this DAG
- for (auto &P : enumerate(MatchDag.predicates())) {
- PredicateIDs.insert(std::make_pair(P.value(), P.index()));
+ for (const auto &[Idx, P] : enumerate(MatchDag.predicates())) {
+ PredicateIDs.insert(std::make_pair(P, Idx));
}
// Number all the predicate dependencies in this DAG and set up a bitvector
// for each predicate indicating the unsatisfied dependencies.
- for (auto &Dep : enumerate(MatchDag.predicate_edges())) {
- PredicateDepIDs.insert(std::make_pair(Dep.value(), Dep.index()));
+ for (const auto &[Idx, Dep] : enumerate(MatchDag.predicate_edges())) {
+ PredicateDepIDs.insert(std::make_pair(Dep, Idx));
}
UnsatisfiedPredDepsForPred.resize(MatchDag.getNumPredicates(),
BitVector(PredicateDepIDs.size()));
- for (auto &Dep : enumerate(MatchDag.predicate_edges())) {
- unsigned ID = PredicateIDs.lookup(Dep.value()->getPredicate());
- UnsatisfiedPredDepsForPred[ID].set(Dep.index());
+ for (const auto &[Idx, Dep] : enumerate(MatchDag.predicate_edges())) {
+ unsigned ID = PredicateIDs.lookup(Dep->getPredicate());
+ UnsatisfiedPredDepsForPred[ID].set(Idx);
}
}
@@ -134,10 +134,10 @@ void GIMatchTreeBuilderLeafInfo::declareInstr(const GIMatchDagInstr *Instr, unsi
// Mark the dependencies that are now satisfied as a result of this
// instruction and mark any predicates whose dependencies are fully
// satisfied.
- for (auto &Dep : enumerate(MatchDag.predicate_edges())) {
+ for (const auto &Dep : enumerate(MatchDag.predicate_edges())) {
if (Dep.value()->getRequiredMI() == Instr &&
Dep.value()->getRequiredMO() == nullptr) {
- for (auto &DepsFor : enumerate(UnsatisfiedPredDepsForPred)) {
+ for (const auto &DepsFor : enumerate(UnsatisfiedPredDepsForPred)) {
DepsFor.value().reset(Dep.index());
if (DepsFor.value().none())
TestablePredicates.set(DepsFor.index());
@@ -157,10 +157,9 @@ void GIMatchTreeBuilderLeafInfo::declareOperand(unsigned InstrID,
// When an operand becomes reachable, we potentially activate some traversals.
// Record the edges that can now be followed as a result of this
// instruction.
- for (auto &E : enumerate(MatchDag.edges())) {
- if (E.value()->getFromMI() == Instr &&
- E.value()->getFromMO()->getIdx() == OpIdx) {
- TraversableEdges.set(E.index());
+ for (const auto &[Idx, E] : enumerate(MatchDag.edges())) {
+ if (E->getFromMI() == Instr && E->getFromMO()->getIdx() == OpIdx) {
+ TraversableEdges.set(Idx);
}
}
@@ -168,10 +167,10 @@ void GIMatchTreeBuilderLeafInfo::declareOperand(unsigned InstrID,
// Clear the dependencies that are now satisfied as a result of this
// operand and activate any predicates whose dependencies are fully
// satisfied.
- for (auto &Dep : enumerate(MatchDag.predicate_edges())) {
+ for (const auto &Dep : enumerate(MatchDag.predicate_edges())) {
if (Dep.value()->getRequiredMI() == Instr && Dep.value()->getRequiredMO() &&
Dep.value()->getRequiredMO()->getIdx() == OpIdx) {
- for (auto &DepsFor : enumerate(UnsatisfiedPredDepsForPred)) {
+ for (const auto &DepsFor : enumerate(UnsatisfiedPredDepsForPred)) {
DepsFor.value().reset(Dep.index());
if (DepsFor.value().none())
TestablePredicates.set(DepsFor.index());
@@ -231,25 +230,6 @@ void GIMatchTreeBuilder::runStep() {
dbgs() << "\n");
#endif // ifndef NDEBUG
- // Check for unreachable rules. Rules are unreachable if they are preceeded by
- // a fully tested rule.
- // Note: This is only true for the current algorithm, if we allow the
- // algorithm to compare equally valid rules then they will become
- // reachable.
- {
- auto FullyTestedLeafI = Leaves.end();
- for (auto LeafI = Leaves.begin(), LeafE = Leaves.end();
- LeafI != LeafE; ++LeafI) {
- if (LeafI->isFullyTraversed() && LeafI->isFullyTested())
- FullyTestedLeafI = LeafI;
- else if (FullyTestedLeafI != Leaves.end()) {
- PrintError("Leaf " + LeafI->getName() + " is unreachable");
- PrintNote("Leaf " + FullyTestedLeafI->getName() +
- " will have already matched");
- }
- }
- }
-
LLVM_DEBUG(dbgs() << " Eliminating redundant partitioners:\n");
filterRedundantPartitioners();
LLVM_DEBUG(dbgs() << " Partitioners remaining:\n");
@@ -339,9 +319,9 @@ void GIMatchTreeBuilder::runStep() {
"Must always partition into at least one partition");
TreeNode->setNumChildren(Partitioner->getNumPartitions());
- for (auto &C : enumerate(TreeNode->children())) {
- SubtreeBuilders.emplace_back(&C.value(), NextInstrID);
- Partitioner->applyForPartition(C.index(), *this, SubtreeBuilders.back());
+ for (const auto &[Idx, Child] : enumerate(TreeNode->children())) {
+ SubtreeBuilders.emplace_back(&Child, NextInstrID);
+ Partitioner->applyForPartition(Idx, *this, SubtreeBuilders.back());
}
TreeNode->setPartitioner(std::move(Partitioner));
@@ -536,22 +516,22 @@ void GIMatchTreeOpcodePartitioner::applyForPartition(
BitVector PossibleLeaves = getPossibleLeavesForPartition(PartitionIdx);
// Consume any predicates we handled.
- for (auto &EnumeratedLeaf : enumerate(Builder.getPossibleLeaves())) {
- if (!PossibleLeaves[EnumeratedLeaf.index()])
+ for (const auto &[Index, EnumeratedLeaf] :
+ enumerate(Builder.getPossibleLeaves())) {
+ if (!PossibleLeaves[Index])
continue;
- auto &Leaf = EnumeratedLeaf.value();
- const auto &TestedPredicatesForLeaf =
- TestedPredicates[EnumeratedLeaf.index()];
+ const auto &TestedPredicatesForLeaf = TestedPredicates[Index];
for (unsigned PredIdx : TestedPredicatesForLeaf.set_bits()) {
- LLVM_DEBUG(dbgs() << " " << Leaf.getName() << " tested predicate #"
- << PredIdx << " of " << TestedPredicatesForLeaf.size()
- << " " << *Leaf.getPredicate(PredIdx) << "\n");
- Leaf.RemainingPredicates.reset(PredIdx);
- Leaf.TestablePredicates.reset(PredIdx);
+ LLVM_DEBUG(dbgs() << " " << EnumeratedLeaf.getName()
+ << " tested predicate #" << PredIdx << " of "
+ << TestedPredicatesForLeaf.size() << " "
+ << *EnumeratedLeaf.getPredicate(PredIdx) << "\n");
+ EnumeratedLeaf.RemainingPredicates.reset(PredIdx);
+ EnumeratedLeaf.TestablePredicates.reset(PredIdx);
}
- SubBuilder.addLeaf(Leaf);
+ SubBuilder.addLeaf(EnumeratedLeaf);
}
// Nothing to do, we don't know anything about this instruction as a result
@@ -571,11 +551,11 @@ void GIMatchTreeOpcodePartitioner::applyForPartition(
if (!InstrInfo)
continue;
const GIMatchDagInstr *Instr = InstrInfo->getInstrNode();
- for (auto &E : enumerate(Leaf.getMatchDag().edges())) {
- if (E.value()->getFromMI() == Instr &&
- E.value()->getFromMO()->getIdx() < CGI->Operands.size()) {
- ReferencedOperands.resize(E.value()->getFromMO()->getIdx() + 1);
- ReferencedOperands.set(E.value()->getFromMO()->getIdx());
+ for (const auto &E : Leaf.getMatchDag().edges()) {
+ if (E->getFromMI() == Instr &&
+ E->getFromMO()->getIdx() < CGI->Operands.size()) {
+ ReferencedOperands.resize(E->getFromMO()->getIdx() + 1);
+ ReferencedOperands.set(E->getFromMO()->getIdx());
}
}
}
@@ -682,12 +662,7 @@ void GIMatchTreeVRegDefPartitioner::repartition(
WantsEdge = true;
}
- bool isNotReg = false;
- if (!WantsEdge && isNotReg) {
- // If this leaf doesn't have an edge and we _don't_ want a register,
- // then add it to partition 0.
- addToPartition(false, Leaf.index());
- } else if (!WantsEdge) {
+ if (!WantsEdge) {
// If this leaf doesn't have an edge and we don't know what we want,
// then add it to partition 0 and 1.
addToPartition(false, Leaf.index());
@@ -715,16 +690,16 @@ void GIMatchTreeVRegDefPartitioner::applyForPartition(
std::vector<BitVector> TraversedEdgesByNewLeaves;
// Consume any edges we handled.
- for (auto &EnumeratedLeaf : enumerate(Builder.getPossibleLeaves())) {
- if (!PossibleLeaves[EnumeratedLeaf.index()])
+ for (const auto &[Index, EnumeratedLeaf] :
+ enumerate(Builder.getPossibleLeaves())) {
+ if (!PossibleLeaves[Index])
continue;
- auto &Leaf = EnumeratedLeaf.value();
- const auto &TraversedEdgesForLeaf = TraversedEdges[EnumeratedLeaf.index()];
+ const auto &TraversedEdgesForLeaf = TraversedEdges[Index];
TraversedEdgesByNewLeaves.push_back(TraversedEdgesForLeaf);
- Leaf.RemainingEdges.reset(TraversedEdgesForLeaf);
- Leaf.TraversableEdges.reset(TraversedEdgesForLeaf);
- SubBuilder.addLeaf(Leaf);
+ EnumeratedLeaf.RemainingEdges.reset(TraversedEdgesForLeaf);
+ EnumeratedLeaf.TraversableEdges.reset(TraversedEdgesForLeaf);
+ SubBuilder.addLeaf(EnumeratedLeaf);
}
// Nothing to do. The only thing we know is that it isn't a vreg-def.
@@ -734,7 +709,7 @@ void GIMatchTreeVRegDefPartitioner::applyForPartition(
NewInstrID = SubBuilder.allocInstrID();
GIMatchTreeBuilder::LeafVec &NewLeaves = SubBuilder.getPossibleLeaves();
- for (const auto I : zip(NewLeaves, TraversedEdgesByNewLeaves)) {
+ for (const auto &I : zip(NewLeaves, TraversedEdgesByNewLeaves)) {
auto &Leaf = std::get<0>(I);
auto &TraversedEdgesForLeaf = std::get<1>(I);
GIMatchTreeInstrInfo *InstrInfo = Leaf.getInstrInfo(InstrID);
diff --git a/llvm/utils/TableGen/GlobalISel/GIMatchTree.h b/llvm/utils/TableGen/GlobalISel/GIMatchTree.h
index 0ce4060fe7b4..c65423ddacdb 100644
--- a/llvm/utils/TableGen/GlobalISel/GIMatchTree.h
+++ b/llvm/utils/TableGen/GlobalISel/GIMatchTree.h
@@ -390,7 +390,7 @@ protected:
/// The leaves that the resulting decision tree will distinguish.
LeafVec Leaves;
/// The tree node being constructed.
- GIMatchTree *TreeNode;
+ GIMatchTree *TreeNode = nullptr;
/// The builders for each subtree resulting from the current decision.
std::vector<GIMatchTreeBuilder> SubtreeBuilders;
/// The possible partitioners we could apply right now.
diff --git a/llvm/utils/TableGen/GlobalISelCombinerMatchTableEmitter.cpp b/llvm/utils/TableGen/GlobalISelCombinerMatchTableEmitter.cpp
new file mode 100644
index 000000000000..3ae66ed01b3a
--- /dev/null
+++ b/llvm/utils/TableGen/GlobalISelCombinerMatchTableEmitter.cpp
@@ -0,0 +1,1575 @@
+//===- GlobalISelCombinerMatchTableEmitter.cpp - --------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file Generate a combiner implementation for GlobalISel from a declarative
+/// syntax using GlobalISelMatchTable.
+///
+//===----------------------------------------------------------------------===//
+
+#include "CodeGenInstruction.h"
+#include "CodeGenTarget.h"
+#include "GlobalISel/CodeExpander.h"
+#include "GlobalISel/CodeExpansions.h"
+#include "GlobalISel/CombinerUtils.h"
+#include "GlobalISelMatchTable.h"
+#include "GlobalISelMatchTableExecutorEmitter.h"
+#include "SubtargetFeatureInfo.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/TableGen/Error.h"
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/StringMatcher.h"
+#include "llvm/TableGen/TableGenBackend.h"
+#include <cstdint>
+
+using namespace llvm;
+using namespace llvm::gi;
+
+#define DEBUG_TYPE "gicombiner-matchtable-emitter"
+
+extern cl::list<std::string> SelectedCombiners;
+extern cl::opt<bool> StopAfterParse;
+
+namespace {
+constexpr StringLiteral CXXApplyPrefix = "GICXXCustomAction_CombineApply";
+constexpr StringLiteral CXXPredPrefix = "GICXXPred_MI_Predicate_";
+
+std::string getIsEnabledPredicateEnumName(unsigned CombinerRuleID) {
+ return "GICXXPred_Simple_IsRule" + to_string(CombinerRuleID) + "Enabled";
+}
+
+void declareInstExpansion(CodeExpansions &CE, const InstructionMatcher &IM,
+ StringRef Name) {
+ CE.declare(Name, "State.MIs[" + to_string(IM.getInsnVarID()) + "]");
+}
+
+void declareOperandExpansion(CodeExpansions &CE, const OperandMatcher &OM,
+ StringRef Name) {
+ CE.declare(Name, "State.MIs[" + to_string(OM.getInsnVarID()) +
+ "]->getOperand(" + to_string(OM.getOpIdx()) + ")");
+}
+
+//===- MatchData Handling -------------------------------------------------===//
+
+/// Represents MatchData defined by the match stage and required by the apply
+/// stage.
+///
+/// This allows the plumbing of arbitrary data from C++ predicates between the
+/// stages.
+///
+/// When this class is initially created, it only has a pattern symbol and a
+/// type. When all of the MatchDatas declarations of a given pattern have been
+/// parsed, `AssignVariables` must be called to assign storage variable names to
+/// each MatchDataInfo.
+class MatchDataInfo {
+ StringRef PatternSymbol;
+ StringRef Type;
+ std::string VarName;
+
+public:
+ static constexpr StringLiteral StructTypeName = "MatchInfosTy";
+ static constexpr StringLiteral StructName = "MatchInfos";
+
+ MatchDataInfo(StringRef PatternSymbol, StringRef Type)
+ : PatternSymbol(PatternSymbol), Type(Type.trim()) {}
+
+ StringRef getPatternSymbol() const { return PatternSymbol; };
+ StringRef getType() const { return Type; };
+
+ bool hasVariableName() const { return !VarName.empty(); }
+ void setVariableName(StringRef Name) { VarName = Name; }
+ StringRef getVariableName() const;
+
+ std::string getQualifiedVariableName() const {
+ return StructName.str() + "." + getVariableName().str();
+ }
+
+ void print(raw_ostream &OS) const;
+ void dump() const { print(dbgs()); }
+};
+
+StringRef MatchDataInfo::getVariableName() const {
+ assert(hasVariableName());
+ return VarName;
+}
+
+void MatchDataInfo::print(raw_ostream &OS) const {
+ OS << "(MatchDataInfo pattern_symbol:" << PatternSymbol << " type:'" << Type
+ << "' var_name:" << (VarName.empty() ? "<unassigned>" : VarName) << ")";
+}
+
+/// Pool of type -> variables used to emit MatchData variables declarations.
+///
+/// e.g. if the map contains "int64_t" -> ["MD0", "MD1"], then two variable
+/// declarations must be emitted: `int64_t MD0` and `int64_t MD1`.
+///
+/// This has a static lifetime and will outlive all the `MatchDataInfo` objects
+/// by design. It needs to persist after all `CombineRuleBuilder` objects died
+/// so we can emit the variable declarations.
+StringMap<std::vector<std::string>> AllMatchDataVars;
+
+// Assign variable names to all MatchDatas used by a pattern. This must be
+// called after all MatchData decls have been parsed inside a rule.
+//
+// Requires an array of MatchDataInfo so we can handle cases where a pattern
+// uses multiple instances of the same MatchData type.
+void AssignMatchDataVariables(MutableArrayRef<MatchDataInfo> Infos) {
+ static unsigned NextVarID = 0;
+
+ StringMap<unsigned> SeenTypes;
+ for (auto &I : Infos) {
+ unsigned &NumSeen = SeenTypes[I.getType()];
+ auto &ExistingVars = AllMatchDataVars[I.getType()];
+
+ if (NumSeen == ExistingVars.size())
+ ExistingVars.push_back("MDInfo" + to_string(NextVarID++));
+
+ I.setVariableName(ExistingVars[NumSeen++]);
+ }
+}
+
+//===- C++ Predicates Handling --------------------------------------------===//
+
+/// Entry into the static pool of all CXX Predicate code. This contains the
+/// fully expanded C++ code.
+///
+/// Each CXXPattern creates a new entry in the pool to store its data, even
+/// after the pattern is destroyed.
+///
+/// Note that CXXPattern trims C++ code, so the Code is already expected to be
+/// free of leading/trailing whitespace.
+struct CXXPredicateCode {
+ CXXPredicateCode(std::string Code, unsigned ID)
+ : Code(Code), ID(ID), BaseEnumName("GICombiner" + to_string(ID)) {
+ assert(StringRef(Code).trim() == Code &&
+ "Code was expected to be trimmed!");
+ }
+
+ const std::string Code;
+ const unsigned ID;
+ const std::string BaseEnumName;
+
+ bool needsUnreachable() const {
+ return !StringRef(Code).starts_with("return");
+ }
+
+ std::string getEnumNameWithPrefix(StringRef Prefix) const {
+ return Prefix.str() + BaseEnumName;
+ }
+};
+
+using CXXPredicateCodePool =
+ DenseMap<hash_code, std::unique_ptr<CXXPredicateCode>>;
+CXXPredicateCodePool AllCXXMatchCode;
+CXXPredicateCodePool AllCXXApplyCode;
+
+/// Gets an instance of `CXXPredicateCode` for \p Code, or returns an already
+/// existing one.
+const CXXPredicateCode &getOrInsert(CXXPredicateCodePool &Pool,
+ std::string Code) {
+ // Check if we already have an identical piece of code, if not, create an
+ // entry in the pool.
+ const auto CodeHash = hash_value(Code);
+ if (auto It = Pool.find(CodeHash); It != Pool.end())
+ return *It->second;
+
+ const auto ID = Pool.size();
+ auto OwnedData = std::make_unique<CXXPredicateCode>(std::move(Code), ID);
+ const auto &DataRef = *OwnedData;
+ Pool[CodeHash] = std::move(OwnedData);
+ return DataRef;
+}
+
+/// Sorts a `CXXPredicateCodePool` by their IDs and returns it.
+std::vector<const CXXPredicateCode *>
+getSorted(const CXXPredicateCodePool &Pool) {
+ std::vector<const CXXPredicateCode *> Out;
+ std::transform(Pool.begin(), Pool.end(), std::back_inserter(Out),
+ [&](auto &Elt) { return Elt.second.get(); });
+ sort(Out, [](const auto *A, const auto *B) { return A->ID < B->ID; });
+ return Out;
+}
+
+//===- Pattern Base Class -------------------------------------------------===//
+
+// An abstract pattern found in a combine rule. This can be an apply or match
+// pattern.
+class Pattern {
+public:
+ enum {
+ K_AnyOpcode,
+ K_Inst,
+ K_CXX,
+ };
+
+ virtual ~Pattern() = default;
+
+ unsigned getKind() const { return Kind; }
+ const char *getKindName() const;
+
+ bool hasName() const { return !Name.empty(); }
+ StringRef getName() const { return Name; }
+
+ virtual void print(raw_ostream &OS, bool PrintName = true) const = 0;
+ void dump() const { return print(dbgs()); }
+
+protected:
+ Pattern(unsigned Kind, StringRef Name) : Kind(Kind), Name(Name.str()) {
+ assert(!Name.empty() && "unnamed pattern!");
+ }
+
+ void printImpl(raw_ostream &OS, bool PrintName,
+ function_ref<void()> ContentPrinter) const;
+
+private:
+ unsigned Kind;
+
+ // Note: if this ever changes to a StringRef (e.g. allocated in a pool or
+ // something), CombineRuleBuilder::verify() needs to be updated as well.
+ // It currently checks that the StringRef in the PatternMap references this.
+ std::string Name;
+};
+
+const char *Pattern::getKindName() const {
+ switch (Kind) {
+ case K_AnyOpcode:
+ return "AnyOpcodePattern";
+ case K_Inst:
+ return "InstructionPattern";
+ case K_CXX:
+ return "CXXPattern";
+ }
+
+ llvm_unreachable("unknown pattern kind!");
+}
+
+void Pattern::printImpl(raw_ostream &OS, bool PrintName,
+ function_ref<void()> ContentPrinter) const {
+ OS << "(" << getKindName() << " ";
+ if (PrintName)
+ OS << "name:" << getName() << " ";
+ ContentPrinter();
+ OS << ")";
+}
+
+//===- AnyOpcodePattern ---------------------------------------------------===//
+
+/// `wip_match_opcode` patterns.
+/// This matches one or more opcodes, and does not check any operands
+/// whatsoever.
+class AnyOpcodePattern : public Pattern {
+public:
+ AnyOpcodePattern(StringRef Name) : Pattern(K_AnyOpcode, Name) {}
+
+ static bool classof(const Pattern *P) { return P->getKind() == K_AnyOpcode; }
+
+ void addOpcode(const CodeGenInstruction *I) { Insts.push_back(I); }
+ const auto &insts() const { return Insts; }
+
+ void print(raw_ostream &OS, bool PrintName = true) const override;
+
+private:
+ SmallVector<const CodeGenInstruction *, 4> Insts;
+};
+
+void AnyOpcodePattern::print(raw_ostream &OS, bool PrintName) const {
+ printImpl(OS, PrintName, [&OS, this]() {
+ OS << "["
+ << join(map_range(Insts,
+ [](const auto *I) { return I->TheDef->getName(); }),
+ ", ")
+ << "]";
+ });
+}
+
+//===- InstructionPattern -------------------------------------------------===//
+
+/// Matches an instruction, e.g. `G_ADD $x, $y, $z`.
+///
+/// This pattern is simply CodeGenInstruction + a list of operands.
+class InstructionPattern : public Pattern {
+public:
+ struct Operand {
+ std::string Name;
+ bool IsDef = false;
+ };
+
+ InstructionPattern(const CodeGenInstruction &I, StringRef Name)
+ : Pattern(K_Inst, Name), I(I) {}
+
+ static bool classof(const Pattern *P) { return P->getKind() == K_Inst; }
+
+ const auto &operands() const { return Operands; }
+ void addOperand(StringRef Name);
+ unsigned getNumDefs() const { return I.Operands.NumDefs; }
+
+ const CodeGenInstruction &getInst() const { return I; }
+ StringRef getInstName() const { return I.TheDef->getName(); }
+
+ void reportUnreachable(ArrayRef<SMLoc> Locs) const;
+ bool checkSemantics(ArrayRef<SMLoc> Loc) const;
+
+ void print(raw_ostream &OS, bool PrintName = true) const override;
+
+private:
+ const CodeGenInstruction &I;
+ SmallVector<Operand, 4> Operands;
+};
+
+void InstructionPattern::addOperand(StringRef Name) {
+ const bool IsDef = Operands.size() < getNumDefs();
+ Operands.emplace_back(Operand{Name.str(), IsDef});
+}
+
+void InstructionPattern::reportUnreachable(ArrayRef<SMLoc> Locs) const {
+ PrintError(Locs, "Instruction pattern '" + getName() +
+ "' is unreachable from the pattern root!");
+}
+
+bool InstructionPattern::checkSemantics(ArrayRef<SMLoc> Loc) const {
+ unsigned NumExpectedOperands = I.Operands.size();
+ if (NumExpectedOperands != Operands.size()) {
+
+ PrintError(Loc, "'" + getInstName() + "' expected " +
+ Twine(NumExpectedOperands) + " operands, got " +
+ Twine(Operands.size()));
+ return false;
+ }
+ return true;
+}
+
+void InstructionPattern::print(raw_ostream &OS, bool PrintName) const {
+ printImpl(OS, PrintName, [&OS, this]() {
+ OS << "inst:" << I.TheDef->getName() << " operands:["
+ << join(map_range(Operands,
+ [](const auto &O) {
+ return (O.IsDef ? "<def>" : "") + O.Name;
+ }),
+ ", ")
+ << "]";
+ });
+}
+
+//===- CXXPattern ---------------------------------------------------------===//
+
+/// Raw C++ code which may need some expansions.
+///
+/// e.g. [{ return isFooBux(${src}.getReg()); }]
+///
+/// For the expanded code, \see CXXPredicateCode. CXXPredicateCode objects are
+/// created through `expandCode`.
+///
+/// \see CodeExpander and \see CodeExpansions for more information on code
+/// expansions.
+///
+/// This object has two purposes:
+/// - Represent C++ code as a pattern entry.
+/// - Be a factory for expanded C++ code.
+/// - It's immutable and only holds the raw code so we can expand the same
+/// CXX pattern multiple times if we need to.
+///
+/// Note that the code is always trimmed in the constructor, so leading and
+/// trailing whitespaces are removed. This removes bloat in the output, avoids
+/// formatting issues, but also allows us to check things like
+/// `.startswith("return")` trivially without worrying about spaces.
+class CXXPattern : public Pattern {
+public:
+ CXXPattern(const StringInit &Code, StringRef Name, bool IsApply)
+ : CXXPattern(Code.getAsUnquotedString(), Name, IsApply) {}
+
+ CXXPattern(StringRef Code, StringRef Name, bool IsApply)
+ : Pattern(K_CXX, Name), IsApply(IsApply), RawCode(Code.trim().str()) {}
+
+ static bool classof(const Pattern *P) { return P->getKind() == K_CXX; }
+
+ bool isApply() const { return IsApply; }
+ StringRef getRawCode() const { return RawCode; }
+
+ /// Expands raw code, replacing things such as `${foo}` with their
+ /// substitution in \p CE.
+ ///
+ /// \param CE Map of Code Expansions
+ /// \param Locs SMLocs for the Code Expander, in case it needs to emit
+ /// diagnostics.
+ /// \return A CXXPredicateCode object that contains the expanded code. Note
+ /// that this may or may not insert a new object. All CXXPredicateCode objects
+ /// are held in a set to avoid emitting duplicate C++ code.
+ const CXXPredicateCode &expandCode(const CodeExpansions &CE,
+ ArrayRef<SMLoc> Locs) const;
+
+ void print(raw_ostream &OS, bool PrintName = true) const override;
+
+private:
+ bool IsApply;
+ std::string RawCode;
+};
+
+const CXXPredicateCode &CXXPattern::expandCode(const CodeExpansions &CE,
+ ArrayRef<SMLoc> Locs) const {
+ std::string Result;
+ raw_string_ostream OS(Result);
+ CodeExpander Expander(RawCode, CE, Locs, /*ShowExpansions*/ false);
+ Expander.emit(OS);
+ return getOrInsert(IsApply ? AllCXXApplyCode : AllCXXMatchCode,
+ std::move(Result));
+}
+
+void CXXPattern::print(raw_ostream &OS, bool PrintName) const {
+ printImpl(OS, PrintName, [&OS, this] {
+ OS << (IsApply ? "apply" : "match") << " code:\"";
+ printEscapedString(getRawCode(), OS);
+ OS << "\"";
+ });
+}
+
+//===- CombineRuleBuilder -------------------------------------------------===//
+
+/// Helper for CombineRuleBuilder.
+///
+/// Represents information about an operand.
+/// Operands with no MatchPat are considered live-in to the pattern.
+struct OperandTableEntry {
+ // The matcher pattern that defines this operand.
+ // null for live-ins.
+ InstructionPattern *MatchPat = nullptr;
+ // The apply pattern that (re)defines this operand.
+ // This can only be non-null if MatchPat is.
+ InstructionPattern *ApplyPat = nullptr;
+
+ bool isLiveIn() const { return !MatchPat; }
+};
+
+/// Parses combine rule and builds a small intermediate representation to tie
+/// patterns together and emit RuleMatchers to match them. This may emit more
+/// than one RuleMatcher, e.g. for `wip_match_opcode`.
+///
+/// Memory management for `Pattern` objects is done through `std::unique_ptr`.
+/// In most cases, there are two stages to a pattern's lifetime:
+/// - Creation in a `parse` function
+/// - The unique_ptr is stored in a variable, and may be destroyed if the
+/// pattern is found to be semantically invalid.
+/// - Ownership transfer into a `PatternMap`
+/// - Once a pattern is moved into either the map of Match or Apply
+/// patterns, it is known to be valid and it never moves back.
+class CombineRuleBuilder {
+public:
+ using PatternMap = MapVector<StringRef, std::unique_ptr<Pattern>>;
+
+ CombineRuleBuilder(const CodeGenTarget &CGT,
+ SubtargetFeatureInfoMap &SubtargetFeatures,
+ Record &RuleDef, unsigned ID,
+ std::vector<RuleMatcher> &OutRMs)
+ : CGT(CGT), SubtargetFeatures(SubtargetFeatures), RuleDef(RuleDef),
+ RuleID(ID), OutRMs(OutRMs) {}
+
+ /// Parses all fields in the RuleDef record.
+ bool parseAll();
+
+ /// Emits all RuleMatchers into the vector of RuleMatchers passed in the
+ /// constructor.
+ bool emitRuleMatchers();
+
+ void print(raw_ostream &OS) const;
+ void dump() const { print(dbgs()); }
+
+ /// Debug-only verification of invariants.
+ void verify() const;
+
+private:
+ void PrintError(Twine Msg) const { ::PrintError(RuleDef.getLoc(), Msg); }
+
+ /// Adds the expansions from \see MatchDatas to \p CE.
+ void declareAllMatchDatasExpansions(CodeExpansions &CE) const;
+
+ /// Adds \p P to \p IM, expanding its code using \p CE.
+ void addCXXPredicate(InstructionMatcher &IM, const CodeExpansions &CE,
+ const CXXPattern &P);
+
+ /// Generates a name for anonymous patterns.
+ ///
+ /// e.g. (G_ADD $x, $y, $z):$foo is a pattern named "foo", but if ":$foo" is
+ /// absent, then the pattern is anonymous and this is used to assign it a
+ /// name.
+ std::string makeAnonPatName(StringRef Prefix) const;
+ mutable unsigned AnonIDCnt = 0;
+
+ /// Creates a new RuleMatcher with some boilerplate
+ /// settings/actions/predicates, and and adds it to \p OutRMs.
+ /// \see addFeaturePredicates too.
+ ///
+ /// \param AdditionalComment Comment string to be added to the
+ /// `DebugCommentAction`.
+ RuleMatcher &addRuleMatcher(Twine AdditionalComment = "");
+ bool addFeaturePredicates(RuleMatcher &M);
+
+ bool findRoots();
+ bool buildOperandsTable();
+
+ bool parseDefs(DagInit &Def);
+ bool parseMatch(DagInit &Match);
+ bool parseApply(DagInit &Apply);
+
+ std::unique_ptr<Pattern> parseInstructionMatcher(const Init &Arg,
+ StringRef PatName);
+ std::unique_ptr<Pattern> parseWipMatchOpcodeMatcher(const Init &Arg,
+ StringRef PatName);
+
+ bool emitMatchPattern(CodeExpansions &CE, const InstructionPattern &IP);
+ bool emitMatchPattern(CodeExpansions &CE, const AnyOpcodePattern &AOP);
+
+ bool emitApplyPatterns(CodeExpansions &CE, RuleMatcher &M);
+
+ // Recursively visits InstructionPattern from P to build up the
+ // RuleMatcher/InstructionMatcher. May create new InstructionMatchers as
+ // needed.
+ bool emitInstructionMatchPattern(CodeExpansions &CE, RuleMatcher &M,
+ InstructionMatcher &IM,
+ const InstructionPattern &P,
+ DenseSet<const Pattern *> &SeenPats);
+
+ const CodeGenTarget &CGT;
+ SubtargetFeatureInfoMap &SubtargetFeatures;
+ Record &RuleDef;
+ const unsigned RuleID;
+ std::vector<RuleMatcher> &OutRMs;
+
+ // For InstructionMatcher::addOperand
+ unsigned AllocatedTemporariesBaseID = 0;
+
+ /// The root of the pattern.
+ StringRef RootName;
+
+ /// These maps have ownership of the actual Pattern objects.
+ /// They both map a Pattern's name to the Pattern instance.
+ PatternMap MatchPats;
+ PatternMap ApplyPats;
+
+ /// Set by findRoots.
+ Pattern *MatchRoot = nullptr;
+
+ MapVector<StringRef, OperandTableEntry> OperandTable;
+ SmallVector<MatchDataInfo, 2> MatchDatas;
+};
+
+bool CombineRuleBuilder::parseAll() {
+ if (!parseDefs(*RuleDef.getValueAsDag("Defs")))
+ return false;
+ if (!parseMatch(*RuleDef.getValueAsDag("Match")))
+ return false;
+ if (!parseApply(*RuleDef.getValueAsDag("Apply")))
+ return false;
+ if (!buildOperandsTable())
+ return false;
+ if (!findRoots())
+ return false;
+ LLVM_DEBUG(verify());
+ return true;
+}
+
+bool CombineRuleBuilder::emitRuleMatchers() {
+ assert(MatchRoot);
+ CodeExpansions CE;
+ declareAllMatchDatasExpansions(CE);
+
+ switch (MatchRoot->getKind()) {
+ case Pattern::K_AnyOpcode: {
+ if (!emitMatchPattern(CE, *cast<AnyOpcodePattern>(MatchRoot)))
+ return false;
+ break;
+ }
+ case Pattern::K_Inst:
+ if (!emitMatchPattern(CE, *cast<InstructionPattern>(MatchRoot)))
+ return false;
+ break;
+ case Pattern::K_CXX:
+ PrintError("C++ code cannot be the root of a pattern!");
+ return false;
+ default:
+ llvm_unreachable("unknown pattern kind!");
+ }
+
+ return true;
+}
+
+void CombineRuleBuilder::print(raw_ostream &OS) const {
+ OS << "(CombineRule name:" << RuleDef.getName() << " id:" << RuleID
+ << " root:" << RootName << "\n";
+
+ OS << " (MatchDatas ";
+ if (MatchDatas.empty())
+ OS << "<empty>)\n";
+ else {
+ OS << "\n";
+ for (const auto &MD : MatchDatas) {
+ OS << " ";
+ MD.print(OS);
+ OS << "\n";
+ }
+ OS << " )\n";
+ }
+
+ const auto DumpPats = [&](StringRef Name, const PatternMap &Pats) {
+ OS << " (" << Name << " ";
+ if (Pats.empty()) {
+ OS << "<empty>)\n";
+ return;
+ }
+
+ OS << "\n";
+ for (const auto &[Name, Pat] : Pats) {
+ OS << " ";
+ if (Pat.get() == MatchRoot)
+ OS << "<root>";
+ OS << Name << ":";
+ Pat->print(OS, /*PrintName=*/false);
+ OS << "\n";
+ }
+ OS << " )\n";
+ };
+
+ DumpPats("MatchPats", MatchPats);
+ DumpPats("ApplyPats", ApplyPats);
+
+ OS << " (OperandTable ";
+ if (OperandTable.empty())
+ OS << "<empty>)\n";
+ else {
+ OS << "\n";
+ for (const auto &[Key, Val] : OperandTable) {
+ OS << " [" << Key;
+ if (const auto *P = Val.MatchPat)
+ OS << " match_pat:" << P->getName();
+ if (const auto *P = Val.ApplyPat)
+ OS << " apply_pat:" << P->getName();
+ if (Val.isLiveIn())
+ OS << " live-in";
+ OS << "]\n";
+ }
+ OS << " )\n";
+ }
+
+ OS << ")\n";
+}
+
+void CombineRuleBuilder::verify() const {
+ const auto VerifyPats = [&](const PatternMap &Pats) {
+ for (const auto &[Name, Pat] : Pats) {
+ if (!Pat)
+ PrintFatalError("null pattern in pattern map!");
+
+ if (Name != Pat->getName()) {
+ Pat->dump();
+ PrintFatalError("Pattern name mismatch! Map name: " + Name +
+ ", Pat name: " + Pat->getName());
+ }
+
+ // As an optimization, the PatternMaps don't re-allocate the PatternName
+ // string. They simply reference the std::string inside Pattern. Ensure
+ // this is the case to avoid memory issues.
+ if (Name.data() != Pat->getName().data()) {
+ dbgs() << "Map StringRef: '" << Name << "' @ "
+ << (const void *)Name.data() << "\n";
+ dbgs() << "Pat String: '" << Pat->getName() << "' @ "
+ << (const void *)Pat->getName().data() << "\n";
+ PrintFatalError("StringRef stored in the PatternMap is not referencing "
+ "the same string as its Pattern!");
+ }
+ }
+ };
+
+ VerifyPats(MatchPats);
+ VerifyPats(ApplyPats);
+
+ for (const auto &[Name, Op] : OperandTable) {
+ if (Op.ApplyPat && !Op.MatchPat) {
+ dump();
+ PrintFatalError("Operand " + Name +
+ " has an apply pattern, but no match pattern!");
+ }
+ }
+}
+
+bool CombineRuleBuilder::addFeaturePredicates(RuleMatcher &M) {
+ if (!RuleDef.getValue("Predicates"))
+ return true;
+
+ ListInit *Preds = RuleDef.getValueAsListInit("Predicates");
+ for (Init *I : Preds->getValues()) {
+ if (DefInit *Pred = dyn_cast<DefInit>(I)) {
+ Record *Def = Pred->getDef();
+ if (!Def->isSubClassOf("Predicate")) {
+ ::PrintError(Def->getLoc(), "Unknown 'Predicate' Type");
+ return false;
+ }
+
+ if (Def->getValueAsString("CondString").empty())
+ continue;
+
+ if (SubtargetFeatures.count(Def) == 0) {
+ SubtargetFeatures.emplace(
+ Def, SubtargetFeatureInfo(Def, SubtargetFeatures.size()));
+ }
+
+ M.addRequiredFeature(Def);
+ }
+ }
+
+ return true;
+}
+
+void CombineRuleBuilder::declareAllMatchDatasExpansions(
+ CodeExpansions &CE) const {
+ for (const auto &MD : MatchDatas)
+ CE.declare(MD.getPatternSymbol(), MD.getQualifiedVariableName());
+}
+
+void CombineRuleBuilder::addCXXPredicate(InstructionMatcher &IM,
+ const CodeExpansions &CE,
+ const CXXPattern &P) {
+ const auto &ExpandedCode = P.expandCode(CE, RuleDef.getLoc());
+ IM.addPredicate<GenericInstructionPredicateMatcher>(
+ ExpandedCode.getEnumNameWithPrefix(CXXPredPrefix));
+}
+
+std::string CombineRuleBuilder::makeAnonPatName(StringRef Prefix) const {
+ return to_string("__anon_pat_" + Prefix + "_" + to_string(RuleID) + "_" +
+ to_string(AnonIDCnt++));
+}
+
+RuleMatcher &CombineRuleBuilder::addRuleMatcher(Twine AdditionalComment) {
+ auto &RM = OutRMs.emplace_back(RuleDef.getLoc());
+ addFeaturePredicates(RM);
+ RM.addRequiredSimplePredicate(getIsEnabledPredicateEnumName(RuleID));
+ const std::string AdditionalCommentStr = AdditionalComment.str();
+ RM.addAction<DebugCommentAction>(
+ "Combiner Rule #" + to_string(RuleID) + ": " + RuleDef.getName().str() +
+ (AdditionalCommentStr.empty() ? "" : "; " + AdditionalCommentStr));
+ return RM;
+}
+
+bool CombineRuleBuilder::findRoots() {
+ // Look by pattern name, e.g.
+ // (G_FNEG $x, $y):$root
+ if (auto It = MatchPats.find(RootName); It != MatchPats.end()) {
+ MatchRoot = It->second.get();
+ return true;
+ }
+
+ // Look by def:
+ // (G_FNEG $root, $y)
+ auto It = OperandTable.find(RootName);
+ if (It == OperandTable.end()) {
+ PrintError("Cannot find root '" + RootName + "' in match patterns!");
+ return false;
+ }
+
+ if (!It->second.MatchPat) {
+ PrintError("Cannot use live-in operand '" + RootName +
+ "' as match pattern root!");
+ return false;
+ }
+
+ MatchRoot = It->second.MatchPat;
+ return true;
+}
+
+bool CombineRuleBuilder::buildOperandsTable() {
+ // Walk each instruction pattern
+ for (auto &[_, P] : MatchPats) {
+ auto *IP = dyn_cast<InstructionPattern>(P.get());
+ if (!IP)
+ continue;
+ for (const auto &Operand : IP->operands()) {
+ // Create an entry, no matter if it's a use or a def.
+ auto &Entry = OperandTable[Operand.Name];
+
+ // We only need to do additional checking on defs, though.
+ if (!Operand.IsDef)
+ continue;
+
+ if (Entry.MatchPat) {
+ PrintError("Operand '" + Operand.Name +
+ "' is defined multiple times in the 'match' patterns");
+ return false;
+ }
+ Entry.MatchPat = IP;
+ }
+ }
+
+ for (auto &[_, P] : ApplyPats) {
+ auto *IP = dyn_cast<InstructionPattern>(P.get());
+ if (!IP)
+ continue;
+ for (const auto &Operand : IP->operands()) {
+ // Create an entry, no matter if it's a use or a def.
+ auto &Entry = OperandTable[Operand.Name];
+
+ // We only need to do additional checking on defs, though.
+ if (!Operand.IsDef)
+ continue;
+
+ if (!Entry.MatchPat) {
+ PrintError("Cannot define live-in operand '" + Operand.Name +
+ "' in the 'apply' pattern");
+ return false;
+ }
+ if (Entry.ApplyPat) {
+ PrintError("Operand '" + Operand.Name +
+ "' is defined multiple times in the 'apply' patterns");
+ return false;
+ }
+ Entry.ApplyPat = IP;
+ }
+ }
+
+ return true;
+}
+
+bool CombineRuleBuilder::parseDefs(DagInit &Def) {
+ if (Def.getOperatorAsDef(RuleDef.getLoc())->getName() != "defs") {
+ PrintError("Expected defs operator");
+ return false;
+ }
+
+ SmallVector<StringRef> Roots;
+ for (unsigned I = 0, E = Def.getNumArgs(); I < E; ++I) {
+ if (isSpecificDef(*Def.getArg(I), "root")) {
+ Roots.emplace_back(Def.getArgNameStr(I));
+ continue;
+ }
+
+ // Subclasses of GIDefMatchData should declare that this rule needs to pass
+ // data from the match stage to the apply stage, and ensure that the
+ // generated matcher has a suitable variable for it to do so.
+ if (Record *MatchDataRec =
+ getDefOfSubClass(*Def.getArg(I), "GIDefMatchData")) {
+ MatchDatas.emplace_back(Def.getArgNameStr(I),
+ MatchDataRec->getValueAsString("Type"));
+ continue;
+ }
+
+ // Otherwise emit an appropriate error message.
+ if (getDefOfSubClass(*Def.getArg(I), "GIDefKind"))
+ PrintError("This GIDefKind not implemented in tablegen");
+ else if (getDefOfSubClass(*Def.getArg(I), "GIDefKindWithArgs"))
+ PrintError("This GIDefKindWithArgs not implemented in tablegen");
+ else
+ PrintError("Expected a subclass of GIDefKind or a sub-dag whose "
+ "operator is of type GIDefKindWithArgs");
+ return false;
+ }
+
+ if (Roots.size() != 1) {
+ PrintError("Combine rules must have exactly one root");
+ return false;
+ }
+
+ RootName = Roots.front();
+
+ // Assign variables to all MatchDatas.
+ AssignMatchDataVariables(MatchDatas);
+ return true;
+}
+
+bool CombineRuleBuilder::parseMatch(DagInit &Match) {
+ if (Match.getOperatorAsDef(RuleDef.getLoc())->getName() != "match") {
+ PrintError("Expected match operator");
+ return false;
+ }
+
+ if (Match.getNumArgs() == 0) {
+ PrintError("Matcher is empty");
+ return false;
+ }
+
+ // The match section consists of a list of matchers and predicates. Parse each
+ // one and add the equivalent GIMatchDag nodes, predicates, and edges.
+ bool HasOpcodeMatcher = false;
+ for (unsigned I = 0; I < Match.getNumArgs(); ++I) {
+ Init *Arg = Match.getArg(I);
+ std::string Name = Match.getArgName(I)
+ ? Match.getArgName(I)->getValue().str()
+ : makeAnonPatName("match");
+
+ if (MatchPats.contains(Name)) {
+ PrintError("'" + Name + "' match pattern defined more than once!");
+ return false;
+ }
+
+ if (auto Pat = parseInstructionMatcher(*Arg, Name)) {
+ MatchPats[Pat->getName()] = std::move(Pat);
+ continue;
+ }
+
+ if (auto Pat = parseWipMatchOpcodeMatcher(*Arg, Name)) {
+ if (HasOpcodeMatcher) {
+ PrintError("wip_opcode_match can only be present once");
+ return false;
+ }
+ HasOpcodeMatcher = true;
+ MatchPats[Pat->getName()] = std::move(Pat);
+ continue;
+ }
+
+ // Parse arbitrary C++ code
+ if (const auto *StringI = dyn_cast<StringInit>(Arg)) {
+ auto CXXPat =
+ std::make_unique<CXXPattern>(*StringI, Name, /*IsApply*/ false);
+ if (!CXXPat->getRawCode().contains("return ")) {
+ PrintWarning(RuleDef.getLoc(),
+ "'match' C++ code does not seem to return!");
+ }
+ MatchPats[CXXPat->getName()] = std::move(CXXPat);
+ continue;
+ }
+
+ // TODO: don't print this on, e.g. bad operand count in inst pat
+ PrintError("Expected a subclass of GIMatchKind or a sub-dag whose "
+ "operator is either of a GIMatchKindWithArgs or Instruction");
+ PrintNote("Pattern was `" + Arg->getAsString() + "'");
+ return false;
+ }
+
+ return true;
+}
+
+bool CombineRuleBuilder::parseApply(DagInit &Apply) {
+ // Currently we only support C++ :(
+ if (Apply.getOperatorAsDef(RuleDef.getLoc())->getName() != "apply") {
+ PrintError("Expected 'apply' operator in Apply DAG");
+ return false;
+ }
+
+ if (Apply.getNumArgs() != 1) {
+ PrintError("Expected exactly 1 argument in 'apply'");
+ return false;
+ }
+
+ const StringInit *Code = dyn_cast<StringInit>(Apply.getArg(0));
+ auto Pat = std::make_unique<CXXPattern>(*Code, makeAnonPatName("apply"),
+ /*IsApply*/ true);
+ ApplyPats[Pat->getName()] = std::move(Pat);
+ return true;
+}
+
+std::unique_ptr<Pattern>
+CombineRuleBuilder::parseInstructionMatcher(const Init &Arg, StringRef Name) {
+ const DagInit *Matcher = getDagWithOperatorOfSubClass(Arg, "Instruction");
+ if (!Matcher)
+ return nullptr;
+
+ auto &Instr = CGT.getInstruction(Matcher->getOperatorAsDef(RuleDef.getLoc()));
+ auto Pat = std::make_unique<InstructionPattern>(Instr, Name);
+
+ for (const auto &NameInit : Matcher->getArgNames())
+ Pat->addOperand(NameInit->getAsUnquotedString());
+
+ if (!Pat->checkSemantics(RuleDef.getLoc()))
+ return nullptr;
+
+ return std::move(Pat);
+}
+
+std::unique_ptr<Pattern>
+CombineRuleBuilder::parseWipMatchOpcodeMatcher(const Init &Arg,
+ StringRef Name) {
+ const DagInit *Matcher = getDagWithSpecificOperator(Arg, "wip_match_opcode");
+ if (!Matcher)
+ return nullptr;
+
+ if (Matcher->getNumArgs() == 0) {
+ PrintError("Empty wip_match_opcode");
+ return nullptr;
+ }
+
+ // Each argument is an opcode that can match.
+ auto Result = std::make_unique<AnyOpcodePattern>(Name);
+ for (const auto &Arg : Matcher->getArgs()) {
+ Record *OpcodeDef = getDefOfSubClass(*Arg, "Instruction");
+ if (OpcodeDef) {
+ Result->addOpcode(&CGT.getInstruction(OpcodeDef));
+ continue;
+ }
+
+ PrintError("Arguments to wip_match_opcode must be instructions");
+ return nullptr;
+ }
+
+ return std::move(Result);
+}
+
+bool CombineRuleBuilder::emitMatchPattern(CodeExpansions &CE,
+ const InstructionPattern &IP) {
+ auto &M = addRuleMatcher();
+ InstructionMatcher &IM = M.addInstructionMatcher("root");
+ declareInstExpansion(CE, IM, IP.getName());
+
+ DenseSet<const Pattern *> SeenPats;
+ if (!emitInstructionMatchPattern(CE, M, IM, IP, SeenPats))
+ return false;
+
+ // Emit remaining patterns
+ for (auto &[_, Pat] : MatchPats) {
+ if (SeenPats.contains(Pat.get()))
+ continue;
+
+ switch (Pat->getKind()) {
+ case Pattern::K_AnyOpcode:
+ PrintError("wip_match_opcode can not be used with instruction patterns!");
+ return false;
+ case Pattern::K_Inst:
+ cast<InstructionPattern>(Pat.get())->reportUnreachable(RuleDef.getLoc());
+ return false;
+ case Pattern::K_CXX: {
+ addCXXPredicate(IM, CE, *cast<CXXPattern>(Pat.get()));
+ continue;
+ }
+ default:
+ llvm_unreachable("unknown pattern kind!");
+ }
+ }
+
+ return emitApplyPatterns(CE, M);
+}
+
+bool CombineRuleBuilder::emitMatchPattern(CodeExpansions &CE,
+ const AnyOpcodePattern &AOP) {
+
+ for (const CodeGenInstruction *CGI : AOP.insts()) {
+ auto &M = addRuleMatcher("wip_match_opcode alternative '" +
+ CGI->TheDef->getName() + "'");
+
+ InstructionMatcher &IM = M.addInstructionMatcher(AOP.getName());
+ declareInstExpansion(CE, IM, AOP.getName());
+ // declareInstExpansion needs to be identical, otherwise we need to create a
+ // CodeExpansions object here instead.
+ assert(IM.getInsnVarID() == 0);
+
+ IM.addPredicate<InstructionOpcodeMatcher>(CGI);
+
+ // Emit remaining patterns.
+ for (auto &[_, Pat] : MatchPats) {
+ if (Pat.get() == &AOP)
+ continue;
+
+ switch (Pat->getKind()) {
+ case Pattern::K_AnyOpcode:
+ PrintError("wip_match_opcode can only be present once!");
+ return false;
+ case Pattern::K_Inst:
+ cast<InstructionPattern>(Pat.get())->reportUnreachable(
+ RuleDef.getLoc());
+ return false;
+ case Pattern::K_CXX: {
+ addCXXPredicate(IM, CE, *cast<CXXPattern>(Pat.get()));
+ break;
+ }
+ default:
+ llvm_unreachable("unknown pattern kind!");
+ }
+ }
+
+ if (!emitApplyPatterns(CE, M))
+ return false;
+ }
+
+ return true;
+}
+
+bool CombineRuleBuilder::emitApplyPatterns(CodeExpansions &CE, RuleMatcher &M) {
+ for (auto &[_, Pat] : ApplyPats) {
+ switch (Pat->getKind()) {
+ case Pattern::K_AnyOpcode:
+ case Pattern::K_Inst:
+ llvm_unreachable("Unsupported pattern kind in output pattern!");
+ case Pattern::K_CXX: {
+ CXXPattern *CXXPat = cast<CXXPattern>(Pat.get());
+ const auto &ExpandedCode = CXXPat->expandCode(CE, RuleDef.getLoc());
+ M.addAction<CustomCXXAction>(
+ ExpandedCode.getEnumNameWithPrefix(CXXApplyPrefix));
+ continue;
+ }
+ default:
+ llvm_unreachable("Unknown pattern kind!");
+ }
+ }
+
+ return true;
+}
+
+bool CombineRuleBuilder::emitInstructionMatchPattern(
+ CodeExpansions &CE, RuleMatcher &M, InstructionMatcher &IM,
+ const InstructionPattern &P, DenseSet<const Pattern *> &SeenPats) {
+ if (SeenPats.contains(&P))
+ return true;
+
+ SeenPats.insert(&P);
+
+ IM.addPredicate<InstructionOpcodeMatcher>(&P.getInst());
+ declareInstExpansion(CE, IM, P.getName());
+
+ unsigned OpIdx = 0;
+ for (auto &O : P.operands()) {
+ auto &OpTableEntry = OperandTable.find(O.Name)->second;
+
+ OperandMatcher &OM =
+ IM.addOperand(OpIdx++, O.Name, AllocatedTemporariesBaseID++);
+ declareOperandExpansion(CE, OM, O.Name);
+
+ if (O.IsDef)
+ continue;
+
+ if (InstructionPattern *DefPat = OpTableEntry.MatchPat) {
+ auto InstOpM = OM.addPredicate<InstructionOperandMatcher>(M, O.Name);
+ if (!InstOpM) {
+ // TODO: copy-pasted from GlobalISelEmitter.cpp. Is it still relevant
+ // here?
+ PrintError("Nested instruction '" + DefPat->getName() +
+ "' cannot be the same as another operand '" + O.Name + "'");
+ return false;
+ }
+
+ if (!emitInstructionMatchPattern(CE, M, (*InstOpM)->getInsnMatcher(),
+ *DefPat, SeenPats))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+//===- GICombinerEmitter --------------------------------------------------===//
+
+/// This class is essentially the driver. It fetches all TableGen records, calls
+/// CombineRuleBuilder to build the MatchTable's RuleMatchers, then creates the
+/// MatchTable & emits it. It also handles emitting all the supporting code such
+/// as the list of LLTs, the CXXPredicates, etc.
+class GICombinerEmitter final : public GlobalISelMatchTableExecutorEmitter {
+ RecordKeeper &Records;
+ StringRef Name;
+ const CodeGenTarget &Target;
+ Record *Combiner;
+ unsigned NextRuleID = 0;
+
+ // List all combine rules (ID, name) imported.
+ // Note that the combiner rule ID is different from the RuleMatcher ID. The
+ // latter is internal to the MatchTable, the former is the canonical ID of the
+ // combine rule used to disable/enable it.
+ std::vector<std::pair<unsigned, std::string>> AllCombineRules;
+
+ MatchTable buildMatchTable(MutableArrayRef<RuleMatcher> Rules);
+
+ void emitRuleConfigImpl(raw_ostream &OS);
+
+ void emitAdditionalImpl(raw_ostream &OS) override;
+
+ void emitMIPredicateFns(raw_ostream &OS) override;
+ void emitI64ImmPredicateFns(raw_ostream &OS) override;
+ void emitAPFloatImmPredicateFns(raw_ostream &OS) override;
+ void emitAPIntImmPredicateFns(raw_ostream &OS) override;
+ void emitTestSimplePredicate(raw_ostream &OS) override;
+ void emitRunCustomAction(raw_ostream &OS) override;
+
+ void emitAdditionalTemporariesDecl(raw_ostream &OS,
+ StringRef Indent) override;
+
+ const CodeGenTarget &getTarget() const override { return Target; }
+ StringRef getClassName() const override {
+ return Combiner->getValueAsString("Classname");
+ }
+
+ std::string getRuleConfigClassName() const {
+ return getClassName().str() + "RuleConfig";
+ }
+
+ void gatherRules(std::vector<RuleMatcher> &Rules,
+ const std::vector<Record *> &&RulesAndGroups);
+
+public:
+ explicit GICombinerEmitter(RecordKeeper &RK, const CodeGenTarget &Target,
+ StringRef Name, Record *Combiner);
+ ~GICombinerEmitter() {}
+
+ void run(raw_ostream &OS);
+};
+
+void GICombinerEmitter::emitRuleConfigImpl(raw_ostream &OS) {
+ OS << "struct " << getRuleConfigClassName() << " {\n"
+ << " SparseBitVector<> DisabledRules;\n\n"
+ << " bool isRuleEnabled(unsigned RuleID) const;\n"
+ << " bool parseCommandLineOption();\n"
+ << " bool setRuleEnabled(StringRef RuleIdentifier);\n"
+ << " bool setRuleDisabled(StringRef RuleIdentifier);\n"
+ << "};\n\n";
+
+ std::vector<std::pair<std::string, std::string>> Cases;
+ Cases.reserve(AllCombineRules.size());
+
+ for (const auto &[ID, Name] : AllCombineRules)
+ Cases.emplace_back(Name, "return " + to_string(ID) + ";\n");
+
+ OS << "static std::optional<uint64_t> getRuleIdxForIdentifier(StringRef "
+ "RuleIdentifier) {\n"
+ << " uint64_t I;\n"
+ << " // getAtInteger(...) returns false on success\n"
+ << " bool Parsed = !RuleIdentifier.getAsInteger(0, I);\n"
+ << " if (Parsed)\n"
+ << " return I;\n\n"
+ << "#ifndef NDEBUG\n";
+ StringMatcher Matcher("RuleIdentifier", Cases, OS);
+ Matcher.Emit();
+ OS << "#endif // ifndef NDEBUG\n\n"
+ << " return std::nullopt;\n"
+ << "}\n";
+
+ OS << "static std::optional<std::pair<uint64_t, uint64_t>> "
+ "getRuleRangeForIdentifier(StringRef RuleIdentifier) {\n"
+ << " std::pair<StringRef, StringRef> RangePair = "
+ "RuleIdentifier.split('-');\n"
+ << " if (!RangePair.second.empty()) {\n"
+ << " const auto First = "
+ "getRuleIdxForIdentifier(RangePair.first);\n"
+ << " const auto Last = "
+ "getRuleIdxForIdentifier(RangePair.second);\n"
+ << " if (!First || !Last)\n"
+ << " return std::nullopt;\n"
+ << " if (First >= Last)\n"
+ << " report_fatal_error(\"Beginning of range should be before "
+ "end of range\");\n"
+ << " return {{*First, *Last + 1}};\n"
+ << " }\n"
+ << " if (RangePair.first == \"*\") {\n"
+ << " return {{0, " << AllCombineRules.size() << "}};\n"
+ << " }\n"
+ << " const auto I = getRuleIdxForIdentifier(RangePair.first);\n"
+ << " if (!I)\n"
+ << " return std::nullopt;\n"
+ << " return {{*I, *I + 1}};\n"
+ << "}\n\n";
+
+ for (bool Enabled : {true, false}) {
+ OS << "bool " << getRuleConfigClassName() << "::setRule"
+ << (Enabled ? "Enabled" : "Disabled") << "(StringRef RuleIdentifier) {\n"
+ << " auto MaybeRange = getRuleRangeForIdentifier(RuleIdentifier);\n"
+ << " if (!MaybeRange)\n"
+ << " return false;\n"
+ << " for (auto I = MaybeRange->first; I < MaybeRange->second; ++I)\n"
+ << " DisabledRules." << (Enabled ? "reset" : "set") << "(I);\n"
+ << " return true;\n"
+ << "}\n\n";
+ }
+
+ OS << "static std::vector<std::string> " << Name << "Option;\n"
+ << "static cl::list<std::string> " << Name << "DisableOption(\n"
+ << " \"" << Name.lower() << "-disable-rule\",\n"
+ << " cl::desc(\"Disable one or more combiner rules temporarily in "
+ << "the " << Name << " pass\"),\n"
+ << " cl::CommaSeparated,\n"
+ << " cl::Hidden,\n"
+ << " cl::cat(GICombinerOptionCategory),\n"
+ << " cl::callback([](const std::string &Str) {\n"
+ << " " << Name << "Option.push_back(Str);\n"
+ << " }));\n"
+ << "static cl::list<std::string> " << Name << "OnlyEnableOption(\n"
+ << " \"" << Name.lower() << "-only-enable-rule\",\n"
+ << " cl::desc(\"Disable all rules in the " << Name
+ << " pass then re-enable the specified ones\"),\n"
+ << " cl::Hidden,\n"
+ << " cl::cat(GICombinerOptionCategory),\n"
+ << " cl::callback([](const std::string &CommaSeparatedArg) {\n"
+ << " StringRef Str = CommaSeparatedArg;\n"
+ << " " << Name << "Option.push_back(\"*\");\n"
+ << " do {\n"
+ << " auto X = Str.split(\",\");\n"
+ << " " << Name << "Option.push_back((\"!\" + X.first).str());\n"
+ << " Str = X.second;\n"
+ << " } while (!Str.empty());\n"
+ << " }));\n"
+ << "\n\n"
+ << "bool " << getRuleConfigClassName()
+ << "::isRuleEnabled(unsigned RuleID) const {\n"
+ << " return !DisabledRules.test(RuleID);\n"
+ << "}\n"
+ << "bool " << getRuleConfigClassName() << "::parseCommandLineOption() {\n"
+ << " for (StringRef Identifier : " << Name << "Option) {\n"
+ << " bool Enabled = Identifier.consume_front(\"!\");\n"
+ << " if (Enabled && !setRuleEnabled(Identifier))\n"
+ << " return false;\n"
+ << " if (!Enabled && !setRuleDisabled(Identifier))\n"
+ << " return false;\n"
+ << " }\n"
+ << " return true;\n"
+ << "}\n\n";
+}
+
+void GICombinerEmitter::emitAdditionalImpl(raw_ostream &OS) {
+ OS << "bool " << getClassName()
+ << "::tryCombineAll(MachineInstr &I) const {\n"
+ << " const TargetSubtargetInfo &ST = MF.getSubtarget();\n"
+ << " const PredicateBitset AvailableFeatures = "
+ "getAvailableFeatures();\n"
+ << " NewMIVector OutMIs;\n"
+ << " State.MIs.clear();\n"
+ << " State.MIs.push_back(&I);\n"
+ << " " << MatchDataInfo::StructName << " = "
+ << MatchDataInfo::StructTypeName << "();\n\n"
+ << " if (executeMatchTable(*this, OutMIs, State, ExecInfo"
+ << ", getMatchTable(), *ST.getInstrInfo(), MRI, "
+ "*MRI.getTargetRegisterInfo(), *ST.getRegBankInfo(), AvailableFeatures"
+ << ", /*CoverageInfo*/ nullptr)) {\n"
+ << " return true;\n"
+ << " }\n\n"
+ << " return false;\n"
+ << "}\n\n";
+}
+
+void GICombinerEmitter::emitMIPredicateFns(raw_ostream &OS) {
+ auto MatchCode = getSorted(AllCXXMatchCode);
+ emitMIPredicateFnsImpl<const CXXPredicateCode *>(
+ OS, "", ArrayRef<const CXXPredicateCode *>(MatchCode),
+ [](const CXXPredicateCode *C) -> StringRef { return C->BaseEnumName; },
+ [](const CXXPredicateCode *C) -> StringRef { return C->Code; });
+}
+
+void GICombinerEmitter::emitI64ImmPredicateFns(raw_ostream &OS) {
+ // Unused, but still needs to be called.
+ emitImmPredicateFnsImpl<unsigned>(
+ OS, "I64", "int64_t", {}, [](unsigned) { return ""; },
+ [](unsigned) { return ""; });
+}
+
+void GICombinerEmitter::emitAPFloatImmPredicateFns(raw_ostream &OS) {
+ // Unused, but still needs to be called.
+ emitImmPredicateFnsImpl<unsigned>(
+ OS, "APFloat", "const APFloat &", {}, [](unsigned) { return ""; },
+ [](unsigned) { return ""; });
+}
+
+void GICombinerEmitter::emitAPIntImmPredicateFns(raw_ostream &OS) {
+ // Unused, but still needs to be called.
+ emitImmPredicateFnsImpl<unsigned>(
+ OS, "APInt", "const APInt &", {}, [](unsigned) { return ""; },
+ [](unsigned) { return ""; });
+}
+
+void GICombinerEmitter::emitTestSimplePredicate(raw_ostream &OS) {
+ if (!AllCombineRules.empty()) {
+ OS << "enum {\n";
+ std::string EnumeratorSeparator = " = GICXXPred_Invalid + 1,\n";
+ // To avoid emitting a switch, we expect that all those rules are in order.
+ // That way we can just get the RuleID from the enum by subtracting
+ // (GICXXPred_Invalid + 1).
+ unsigned ExpectedID = 0;
+ (void)ExpectedID;
+ for (const auto &[ID, _] : AllCombineRules) {
+ assert(ExpectedID++ == ID && "combine rules are not ordered!");
+ OS << " " << getIsEnabledPredicateEnumName(ID) << EnumeratorSeparator;
+ EnumeratorSeparator = ",\n";
+ }
+ OS << "};\n\n";
+ }
+
+ OS << "bool " << getClassName()
+ << "::testSimplePredicate(unsigned Predicate) const {\n"
+ << " return RuleConfig.isRuleEnabled(Predicate - "
+ "GICXXPred_Invalid - "
+ "1);\n"
+ << "}\n";
+}
+
+void GICombinerEmitter::emitRunCustomAction(raw_ostream &OS) {
+ const auto ApplyCode = getSorted(AllCXXApplyCode);
+
+ if (!ApplyCode.empty()) {
+ OS << "enum {\n";
+ std::string EnumeratorSeparator = " = GICXXCustomAction_Invalid + 1,\n";
+ for (const auto &Apply : ApplyCode) {
+ OS << " " << Apply->getEnumNameWithPrefix(CXXApplyPrefix)
+ << EnumeratorSeparator;
+ EnumeratorSeparator = ",\n";
+ }
+ OS << "};\n";
+ }
+
+ OS << "void " << getClassName()
+ << "::runCustomAction(unsigned ApplyID, const MatcherState &State) const "
+ "{\n";
+ if (!ApplyCode.empty()) {
+ OS << " switch(ApplyID) {\n";
+ for (const auto &Apply : ApplyCode) {
+ OS << " case " << Apply->getEnumNameWithPrefix(CXXApplyPrefix) << ":{\n"
+ << " " << Apply->Code << "\n"
+ << " return;\n";
+ OS << " }\n";
+ }
+ OS << "}\n";
+ }
+ OS << " llvm_unreachable(\"Unknown Apply Action\");\n"
+ << "}\n";
+}
+
+void GICombinerEmitter::emitAdditionalTemporariesDecl(raw_ostream &OS,
+ StringRef Indent) {
+ OS << Indent << "struct " << MatchDataInfo::StructTypeName << " {\n";
+ for (const auto &[Type, VarNames] : AllMatchDataVars) {
+ assert(!VarNames.empty() && "Cannot have no vars for this type!");
+ OS << Indent << " " << Type << " " << join(VarNames, ", ") << ";\n";
+ }
+ OS << Indent << "};\n"
+ << Indent << "mutable " << MatchDataInfo::StructTypeName << " "
+ << MatchDataInfo::StructName << ";\n\n";
+}
+
+GICombinerEmitter::GICombinerEmitter(RecordKeeper &RK,
+ const CodeGenTarget &Target,
+ StringRef Name, Record *Combiner)
+ : Records(RK), Name(Name), Target(Target), Combiner(Combiner) {}
+
+MatchTable
+GICombinerEmitter::buildMatchTable(MutableArrayRef<RuleMatcher> Rules) {
+ std::vector<Matcher *> InputRules;
+ for (Matcher &Rule : Rules)
+ InputRules.push_back(&Rule);
+
+ unsigned CurrentOrdering = 0;
+ StringMap<unsigned> OpcodeOrder;
+ for (RuleMatcher &Rule : Rules) {
+ const StringRef Opcode = Rule.getOpcode();
+ assert(!Opcode.empty() && "Didn't expect an undefined opcode");
+ if (OpcodeOrder.count(Opcode) == 0)
+ OpcodeOrder[Opcode] = CurrentOrdering++;
+ }
+
+ llvm::stable_sort(InputRules, [&OpcodeOrder](const Matcher *A,
+ const Matcher *B) {
+ auto *L = static_cast<const RuleMatcher *>(A);
+ auto *R = static_cast<const RuleMatcher *>(B);
+ return std::make_tuple(OpcodeOrder[L->getOpcode()], L->getNumOperands()) <
+ std::make_tuple(OpcodeOrder[R->getOpcode()], R->getNumOperands());
+ });
+
+ for (Matcher *Rule : InputRules)
+ Rule->optimize();
+
+ std::vector<std::unique_ptr<Matcher>> MatcherStorage;
+ std::vector<Matcher *> OptRules =
+ optimizeRules<GroupMatcher>(InputRules, MatcherStorage);
+
+ for (Matcher *Rule : OptRules)
+ Rule->optimize();
+
+ OptRules = optimizeRules<SwitchMatcher>(OptRules, MatcherStorage);
+
+ return MatchTable::buildTable(OptRules, /*WithCoverage*/ false,
+ /*IsCombiner*/ true);
+}
+
+/// Recurse into GICombineGroup's and flatten the ruleset into a simple list.
+void GICombinerEmitter::gatherRules(
+ std::vector<RuleMatcher> &ActiveRules,
+ const std::vector<Record *> &&RulesAndGroups) {
+ for (Record *R : RulesAndGroups) {
+ if (R->isValueUnset("Rules")) {
+ AllCombineRules.emplace_back(NextRuleID, R->getName().str());
+ CombineRuleBuilder CRB(Target, SubtargetFeatures, *R, NextRuleID++,
+ ActiveRules);
+
+ if (!CRB.parseAll())
+ continue;
+
+ if (StopAfterParse) {
+ CRB.print(outs());
+ continue;
+ }
+
+ if (!CRB.emitRuleMatchers())
+ continue;
+ } else
+ gatherRules(ActiveRules, R->getValueAsListOfDefs("Rules"));
+ }
+}
+
+void GICombinerEmitter::run(raw_ostream &OS) {
+ Records.startTimer("Gather rules");
+ std::vector<RuleMatcher> Rules;
+ gatherRules(Rules, Combiner->getValueAsListOfDefs("Rules"));
+ if (ErrorsPrinted)
+ PrintFatalError(Combiner->getLoc(), "Failed to parse one or more rules");
+
+ Records.startTimer("Creating Match Table");
+ unsigned MaxTemporaries = 0;
+ for (const auto &Rule : Rules)
+ MaxTemporaries = std::max(MaxTemporaries, Rule.countRendererFns());
+
+ const MatchTable Table = buildMatchTable(Rules);
+
+ Records.startTimer("Emit combiner");
+
+ emitSourceFileHeader(getClassName().str() + " Combiner Match Table", OS);
+
+ // Unused
+ std::vector<StringRef> CustomRendererFns;
+ // Unused, but hack to avoid empty declarator
+ std::vector<LLTCodeGen> TypeObjects = {LLTCodeGen(LLT::scalar(1))};
+ // Unused
+ std::vector<Record *> ComplexPredicates;
+
+ // GET_GICOMBINER_DEPS, which pulls in extra dependencies.
+ OS << "#ifdef GET_GICOMBINER_DEPS\n"
+ << "#include \"llvm/ADT/SparseBitVector.h\"\n"
+ << "namespace llvm {\n"
+ << "extern cl::OptionCategory GICombinerOptionCategory;\n"
+ << "} // end namespace llvm\n"
+ << "#endif // ifdef GET_GICOMBINER_DEPS\n\n";
+
+ // GET_GICOMBINER_TYPES, which needs to be included before the declaration of
+ // the class.
+ OS << "#ifdef GET_GICOMBINER_TYPES\n";
+ emitRuleConfigImpl(OS);
+ OS << "#endif // ifdef GET_GICOMBINER_TYPES\n\n";
+ emitPredicateBitset(OS, "GET_GICOMBINER_TYPES");
+
+ // GET_GICOMBINER_CLASS_MEMBERS, which need to be included inside the class.
+ emitPredicatesDecl(OS, "GET_GICOMBINER_CLASS_MEMBERS");
+ emitTemporariesDecl(OS, "GET_GICOMBINER_CLASS_MEMBERS");
+
+ // GET_GICOMBINER_IMPL, which needs to be included outside the class.
+ emitExecutorImpl(OS, Table, TypeObjects, Rules, ComplexPredicates,
+ CustomRendererFns, "GET_GICOMBINER_IMPL");
+
+ // GET_GICOMBINER_CONSTRUCTOR_INITS, which are in the constructor's
+ // initializer list.
+ emitPredicatesInit(OS, "GET_GICOMBINER_CONSTRUCTOR_INITS");
+ emitTemporariesInit(OS, MaxTemporaries, "GET_GICOMBINER_CONSTRUCTOR_INITS");
+}
+
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+
+static void EmitGICombiner(RecordKeeper &RK, raw_ostream &OS) {
+ CodeGenTarget Target(RK);
+
+ if (SelectedCombiners.empty())
+ PrintFatalError("No combiners selected with -combiners");
+ for (const auto &Combiner : SelectedCombiners) {
+ Record *CombinerDef = RK.getDef(Combiner);
+ if (!CombinerDef)
+ PrintFatalError("Could not find " + Combiner);
+ GICombinerEmitter(RK, Target, Combiner, CombinerDef).run(OS);
+ }
+}
+
+static TableGen::Emitter::Opt X("gen-global-isel-combiner-matchtable",
+ EmitGICombiner,
+ "Generate GlobalISel combiner Match Table");
diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp
index c79c79948a80..3bdcfec06e24 100644
--- a/llvm/utils/TableGen/GlobalISelEmitter.cpp
+++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp
@@ -8,7 +8,7 @@
//
/// \file
/// This tablegen backend emits code for use by the GlobalISel instruction
-/// selector. See include/llvm/CodeGen/TargetGlobalISel.td.
+/// selector. See include/llvm/Target/GlobalISel/Target.td.
///
/// This file analyzes the patterns recognized by the SelectionDAGISel tablegen
/// backend, filters out the ones that are unsupported, maps
@@ -31,28 +31,39 @@
#include "CodeGenDAGPatterns.h"
#include "CodeGenInstruction.h"
+#include "CodeGenIntrinsics.h"
+#include "CodeGenRegisters.h"
+#include "CodeGenTarget.h"
+#include "GlobalISelMatchTable.h"
+#include "GlobalISelMatchTableExecutorEmitter.h"
+#include "InfoByHwMode.h"
#include "SubtargetFeatureInfo.h"
#include "llvm/ADT/Statistic.h"
+#include "llvm/CodeGen/LowLevelType.h"
+#include "llvm/CodeGen/MachineValueType.h"
#include "llvm/Support/CodeGenCoverage.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Error.h"
-#include "llvm/Support/LowLevelTypeImpl.h"
-#include "llvm/Support/MachineValueType.h"
+#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
#include <numeric>
#include <string>
+
using namespace llvm;
+using namespace llvm::gi;
+
+using action_iterator = RuleMatcher::action_iterator;
#define DEBUG_TYPE "gisel-emitter"
STATISTIC(NumPatternTotal, "Total number of patterns");
STATISTIC(NumPatternImported, "Number of patterns imported from SelectionDAG");
STATISTIC(NumPatternImportsSkipped, "Number of SelectionDAG imports skipped");
-STATISTIC(NumPatternsTested, "Number of patterns executed according to coverage information");
-STATISTIC(NumPatternEmitted, "Number of patterns emitted");
+STATISTIC(NumPatternsTested,
+ "Number of patterns executed according to coverage information");
cl::OptionCategory GlobalISelEmitterCat("Options for -gen-global-isel");
@@ -78,140 +89,6 @@ static cl::opt<bool> OptimizeMatchTable(
cl::init(true), cl::cat(GlobalISelEmitterCat));
namespace {
-//===- Helper functions ---------------------------------------------------===//
-
-/// Get the name of the enum value used to number the predicate function.
-std::string getEnumNameForPredicate(const TreePredicateFn &Predicate) {
- if (Predicate.hasGISelPredicateCode())
- return "GIPFP_MI_" + Predicate.getFnName();
- return "GIPFP_" + Predicate.getImmTypeIdentifier().str() + "_" +
- Predicate.getFnName();
-}
-
-/// Get the opcode used to check this predicate.
-std::string getMatchOpcodeForImmPredicate(const TreePredicateFn &Predicate) {
- return "GIM_Check" + Predicate.getImmTypeIdentifier().str() + "ImmPredicate";
-}
-
-/// This class stands in for LLT wherever we want to tablegen-erate an
-/// equivalent at compiler run-time.
-class LLTCodeGen {
-private:
- LLT Ty;
-
-public:
- LLTCodeGen() = default;
- LLTCodeGen(const LLT &Ty) : Ty(Ty) {}
-
- std::string getCxxEnumValue() const {
- std::string Str;
- raw_string_ostream OS(Str);
-
- emitCxxEnumValue(OS);
- return Str;
- }
-
- void emitCxxEnumValue(raw_ostream &OS) const {
- if (Ty.isScalar()) {
- OS << "GILLT_s" << Ty.getSizeInBits();
- return;
- }
- if (Ty.isVector()) {
- OS << (Ty.isScalable() ? "GILLT_nxv" : "GILLT_v")
- << Ty.getElementCount().getKnownMinValue() << "s"
- << Ty.getScalarSizeInBits();
- return;
- }
- if (Ty.isPointer()) {
- OS << "GILLT_p" << Ty.getAddressSpace();
- if (Ty.getSizeInBits() > 0)
- OS << "s" << Ty.getSizeInBits();
- return;
- }
- llvm_unreachable("Unhandled LLT");
- }
-
- void emitCxxConstructorCall(raw_ostream &OS) const {
- if (Ty.isScalar()) {
- OS << "LLT::scalar(" << Ty.getSizeInBits() << ")";
- return;
- }
- if (Ty.isVector()) {
- OS << "LLT::vector("
- << (Ty.isScalable() ? "ElementCount::getScalable("
- : "ElementCount::getFixed(")
- << Ty.getElementCount().getKnownMinValue() << "), "
- << Ty.getScalarSizeInBits() << ")";
- return;
- }
- if (Ty.isPointer() && Ty.getSizeInBits() > 0) {
- OS << "LLT::pointer(" << Ty.getAddressSpace() << ", "
- << Ty.getSizeInBits() << ")";
- return;
- }
- llvm_unreachable("Unhandled LLT");
- }
-
- const LLT &get() const { return Ty; }
-
- /// This ordering is used for std::unique() and llvm::sort(). There's no
- /// particular logic behind the order but either A < B or B < A must be
- /// true if A != B.
- bool operator<(const LLTCodeGen &Other) const {
- if (Ty.isValid() != Other.Ty.isValid())
- return Ty.isValid() < Other.Ty.isValid();
- if (!Ty.isValid())
- return false;
-
- if (Ty.isVector() != Other.Ty.isVector())
- return Ty.isVector() < Other.Ty.isVector();
- if (Ty.isScalar() != Other.Ty.isScalar())
- return Ty.isScalar() < Other.Ty.isScalar();
- if (Ty.isPointer() != Other.Ty.isPointer())
- return Ty.isPointer() < Other.Ty.isPointer();
-
- if (Ty.isPointer() && Ty.getAddressSpace() != Other.Ty.getAddressSpace())
- return Ty.getAddressSpace() < Other.Ty.getAddressSpace();
-
- if (Ty.isVector() && Ty.getElementCount() != Other.Ty.getElementCount())
- return std::make_tuple(Ty.isScalable(),
- Ty.getElementCount().getKnownMinValue()) <
- std::make_tuple(Other.Ty.isScalable(),
- Other.Ty.getElementCount().getKnownMinValue());
-
- assert((!Ty.isVector() || Ty.isScalable() == Other.Ty.isScalable()) &&
- "Unexpected mismatch of scalable property");
- return Ty.isVector()
- ? std::make_tuple(Ty.isScalable(),
- Ty.getSizeInBits().getKnownMinValue()) <
- std::make_tuple(
- Other.Ty.isScalable(),
- Other.Ty.getSizeInBits().getKnownMinValue())
- : Ty.getSizeInBits().getFixedValue() <
- Other.Ty.getSizeInBits().getFixedValue();
- }
-
- bool operator==(const LLTCodeGen &B) const { return Ty == B.Ty; }
-};
-
-// Track all types that are used so we can emit the corresponding enum.
-std::set<LLTCodeGen> KnownTypes;
-
-class InstructionMatcher;
-/// Convert an MVT to an equivalent LLT if possible, or the invalid LLT() for
-/// MVTs that don't map cleanly to an LLT (e.g., iPTR, *any, ...).
-static std::optional<LLTCodeGen> MVTToLLT(MVT::SimpleValueType SVT) {
- MVT VT(SVT);
-
- if (VT.isVector() && !VT.getVectorElementCount().isScalar())
- return LLTCodeGen(
- LLT::vector(VT.getVectorElementCount(), VT.getScalarSizeInBits()));
-
- if (VT.isInteger() || VT.isFloatingPoint())
- return LLTCodeGen(LLT::scalar(VT.getSizeInBits()));
-
- return std::nullopt;
-}
static std::string explainPredicates(const TreePatternNode *N) {
std::string Explanation;
@@ -401,3150 +278,10 @@ static Record *getInitValueAsRegClass(Init *V) {
return nullptr;
}
-std::string
-getNameForFeatureBitset(const std::vector<Record *> &FeatureBitset) {
- std::string Name = "GIFBS";
- for (const auto &Feature : FeatureBitset)
- Name += ("_" + Feature->getName()).str();
- return Name;
-}
-
static std::string getScopedName(unsigned Scope, const std::string &Name) {
return ("pred:" + Twine(Scope) + ":" + Name).str();
}
-//===- MatchTable Helpers -------------------------------------------------===//
-
-class MatchTable;
-
-/// A record to be stored in a MatchTable.
-///
-/// This class represents any and all output that may be required to emit the
-/// MatchTable. Instances are most often configured to represent an opcode or
-/// value that will be emitted to the table with some formatting but it can also
-/// represent commas, comments, and other formatting instructions.
-struct MatchTableRecord {
- enum RecordFlagsBits {
- MTRF_None = 0x0,
- /// Causes EmitStr to be formatted as comment when emitted.
- MTRF_Comment = 0x1,
- /// Causes the record value to be followed by a comma when emitted.
- MTRF_CommaFollows = 0x2,
- /// Causes the record value to be followed by a line break when emitted.
- MTRF_LineBreakFollows = 0x4,
- /// Indicates that the record defines a label and causes an additional
- /// comment to be emitted containing the index of the label.
- MTRF_Label = 0x8,
- /// Causes the record to be emitted as the index of the label specified by
- /// LabelID along with a comment indicating where that label is.
- MTRF_JumpTarget = 0x10,
- /// Causes the formatter to add a level of indentation before emitting the
- /// record.
- MTRF_Indent = 0x20,
- /// Causes the formatter to remove a level of indentation after emitting the
- /// record.
- MTRF_Outdent = 0x40,
- };
-
- /// When MTRF_Label or MTRF_JumpTarget is used, indicates a label id to
- /// reference or define.
- unsigned LabelID;
- /// The string to emit. Depending on the MTRF_* flags it may be a comment, a
- /// value, a label name.
- std::string EmitStr;
-
-private:
- /// The number of MatchTable elements described by this record. Comments are 0
- /// while values are typically 1. Values >1 may occur when we need to emit
- /// values that exceed the size of a MatchTable element.
- unsigned NumElements;
-
-public:
- /// A bitfield of RecordFlagsBits flags.
- unsigned Flags;
-
- /// The actual run-time value, if known
- int64_t RawValue;
-
- MatchTableRecord(std::optional<unsigned> LabelID_, StringRef EmitStr,
- unsigned NumElements, unsigned Flags,
- int64_t RawValue = std::numeric_limits<int64_t>::min())
- : LabelID(LabelID_.value_or(~0u)), EmitStr(EmitStr),
- NumElements(NumElements), Flags(Flags), RawValue(RawValue) {
- assert((!LabelID_ || LabelID != ~0u) &&
- "This value is reserved for non-labels");
- }
- MatchTableRecord(const MatchTableRecord &Other) = default;
- MatchTableRecord(MatchTableRecord &&Other) = default;
-
- /// Useful if a Match Table Record gets optimized out
- void turnIntoComment() {
- Flags |= MTRF_Comment;
- Flags &= ~MTRF_CommaFollows;
- NumElements = 0;
- }
-
- /// For Jump Table generation purposes
- bool operator<(const MatchTableRecord &Other) const {
- return RawValue < Other.RawValue;
- }
- int64_t getRawValue() const { return RawValue; }
-
- void emit(raw_ostream &OS, bool LineBreakNextAfterThis,
- const MatchTable &Table) const;
- unsigned size() const { return NumElements; }
-};
-
-class Matcher;
-
-/// Holds the contents of a generated MatchTable to enable formatting and the
-/// necessary index tracking needed to support GIM_Try.
-class MatchTable {
- /// An unique identifier for the table. The generated table will be named
- /// MatchTable${ID}.
- unsigned ID;
- /// The records that make up the table. Also includes comments describing the
- /// values being emitted and line breaks to format it.
- std::vector<MatchTableRecord> Contents;
- /// The currently defined labels.
- DenseMap<unsigned, unsigned> LabelMap;
- /// Tracks the sum of MatchTableRecord::NumElements as the table is built.
- unsigned CurrentSize = 0;
- /// A unique identifier for a MatchTable label.
- unsigned CurrentLabelID = 0;
- /// Determines if the table should be instrumented for rule coverage tracking.
- bool IsWithCoverage;
-
-public:
- static MatchTableRecord LineBreak;
- static MatchTableRecord Comment(StringRef Comment) {
- return MatchTableRecord(std::nullopt, Comment, 0,
- MatchTableRecord::MTRF_Comment);
- }
- static MatchTableRecord Opcode(StringRef Opcode, int IndentAdjust = 0) {
- unsigned ExtraFlags = 0;
- if (IndentAdjust > 0)
- ExtraFlags |= MatchTableRecord::MTRF_Indent;
- if (IndentAdjust < 0)
- ExtraFlags |= MatchTableRecord::MTRF_Outdent;
-
- return MatchTableRecord(std::nullopt, Opcode, 1,
- MatchTableRecord::MTRF_CommaFollows | ExtraFlags);
- }
- static MatchTableRecord NamedValue(StringRef NamedValue) {
- return MatchTableRecord(std::nullopt, NamedValue, 1,
- MatchTableRecord::MTRF_CommaFollows);
- }
- static MatchTableRecord NamedValue(StringRef NamedValue, int64_t RawValue) {
- return MatchTableRecord(std::nullopt, NamedValue, 1,
- MatchTableRecord::MTRF_CommaFollows, RawValue);
- }
- static MatchTableRecord NamedValue(StringRef Namespace,
- StringRef NamedValue) {
- return MatchTableRecord(std::nullopt, (Namespace + "::" + NamedValue).str(),
- 1, MatchTableRecord::MTRF_CommaFollows);
- }
- static MatchTableRecord NamedValue(StringRef Namespace, StringRef NamedValue,
- int64_t RawValue) {
- return MatchTableRecord(std::nullopt, (Namespace + "::" + NamedValue).str(),
- 1, MatchTableRecord::MTRF_CommaFollows, RawValue);
- }
- static MatchTableRecord IntValue(int64_t IntValue) {
- return MatchTableRecord(std::nullopt, llvm::to_string(IntValue), 1,
- MatchTableRecord::MTRF_CommaFollows);
- }
- static MatchTableRecord Label(unsigned LabelID) {
- return MatchTableRecord(LabelID, "Label " + llvm::to_string(LabelID), 0,
- MatchTableRecord::MTRF_Label |
- MatchTableRecord::MTRF_Comment |
- MatchTableRecord::MTRF_LineBreakFollows);
- }
- static MatchTableRecord JumpTarget(unsigned LabelID) {
- return MatchTableRecord(LabelID, "Label " + llvm::to_string(LabelID), 1,
- MatchTableRecord::MTRF_JumpTarget |
- MatchTableRecord::MTRF_Comment |
- MatchTableRecord::MTRF_CommaFollows);
- }
-
- static MatchTable buildTable(ArrayRef<Matcher *> Rules, bool WithCoverage);
-
- MatchTable(bool WithCoverage, unsigned ID = 0)
- : ID(ID), IsWithCoverage(WithCoverage) {}
-
- bool isWithCoverage() const { return IsWithCoverage; }
-
- void push_back(const MatchTableRecord &Value) {
- if (Value.Flags & MatchTableRecord::MTRF_Label)
- defineLabel(Value.LabelID);
- Contents.push_back(Value);
- CurrentSize += Value.size();
- }
-
- unsigned allocateLabelID() { return CurrentLabelID++; }
-
- void defineLabel(unsigned LabelID) {
- LabelMap.insert(std::make_pair(LabelID, CurrentSize));
- }
-
- unsigned getLabelIndex(unsigned LabelID) const {
- const auto I = LabelMap.find(LabelID);
- assert(I != LabelMap.end() && "Use of undeclared label");
- return I->second;
- }
-
- void emitUse(raw_ostream &OS) const { OS << "MatchTable" << ID; }
-
- void emitDeclaration(raw_ostream &OS) const {
- unsigned Indentation = 4;
- OS << " constexpr static int64_t MatchTable" << ID << "[] = {";
- LineBreak.emit(OS, true, *this);
- OS << std::string(Indentation, ' ');
-
- for (auto I = Contents.begin(), E = Contents.end(); I != E;
- ++I) {
- bool LineBreakIsNext = false;
- const auto &NextI = std::next(I);
-
- if (NextI != E) {
- if (NextI->EmitStr == "" &&
- NextI->Flags == MatchTableRecord::MTRF_LineBreakFollows)
- LineBreakIsNext = true;
- }
-
- if (I->Flags & MatchTableRecord::MTRF_Indent)
- Indentation += 2;
-
- I->emit(OS, LineBreakIsNext, *this);
- if (I->Flags & MatchTableRecord::MTRF_LineBreakFollows)
- OS << std::string(Indentation, ' ');
-
- if (I->Flags & MatchTableRecord::MTRF_Outdent)
- Indentation -= 2;
- }
- OS << "};\n";
- }
-};
-
-MatchTableRecord MatchTable::LineBreak = {
- std::nullopt, "" /* Emit String */, 0 /* Elements */,
- MatchTableRecord::MTRF_LineBreakFollows};
-
-void MatchTableRecord::emit(raw_ostream &OS, bool LineBreakIsNextAfterThis,
- const MatchTable &Table) const {
- bool UseLineComment =
- LineBreakIsNextAfterThis || (Flags & MTRF_LineBreakFollows);
- if (Flags & (MTRF_JumpTarget | MTRF_CommaFollows))
- UseLineComment = false;
-
- if (Flags & MTRF_Comment)
- OS << (UseLineComment ? "// " : "/*");
-
- OS << EmitStr;
- if (Flags & MTRF_Label)
- OS << ": @" << Table.getLabelIndex(LabelID);
-
- if ((Flags & MTRF_Comment) && !UseLineComment)
- OS << "*/";
-
- if (Flags & MTRF_JumpTarget) {
- if (Flags & MTRF_Comment)
- OS << " ";
- OS << Table.getLabelIndex(LabelID);
- }
-
- if (Flags & MTRF_CommaFollows) {
- OS << ",";
- if (!LineBreakIsNextAfterThis && !(Flags & MTRF_LineBreakFollows))
- OS << " ";
- }
-
- if (Flags & MTRF_LineBreakFollows)
- OS << "\n";
-}
-
-MatchTable &operator<<(MatchTable &Table, const MatchTableRecord &Value) {
- Table.push_back(Value);
- return Table;
-}
-
-//===- Matchers -----------------------------------------------------------===//
-
-class OperandMatcher;
-class MatchAction;
-class PredicateMatcher;
-
-class Matcher {
-public:
- virtual ~Matcher() = default;
- virtual void optimize() {}
- virtual void emit(MatchTable &Table) = 0;
-
- virtual bool hasFirstCondition() const = 0;
- virtual const PredicateMatcher &getFirstCondition() const = 0;
- virtual std::unique_ptr<PredicateMatcher> popFirstCondition() = 0;
-};
-
-MatchTable MatchTable::buildTable(ArrayRef<Matcher *> Rules,
- bool WithCoverage) {
- MatchTable Table(WithCoverage);
- for (Matcher *Rule : Rules)
- Rule->emit(Table);
-
- return Table << MatchTable::Opcode("GIM_Reject") << MatchTable::LineBreak;
-}
-
-class GroupMatcher final : public Matcher {
- /// Conditions that form a common prefix of all the matchers contained.
- SmallVector<std::unique_ptr<PredicateMatcher>, 1> Conditions;
-
- /// All the nested matchers, sharing a common prefix.
- std::vector<Matcher *> Matchers;
-
- /// An owning collection for any auxiliary matchers created while optimizing
- /// nested matchers contained.
- std::vector<std::unique_ptr<Matcher>> MatcherStorage;
-
-public:
- /// Add a matcher to the collection of nested matchers if it meets the
- /// requirements, and return true. If it doesn't, do nothing and return false.
- ///
- /// Expected to preserve its argument, so it could be moved out later on.
- bool addMatcher(Matcher &Candidate);
-
- /// Mark the matcher as fully-built and ensure any invariants expected by both
- /// optimize() and emit(...) methods. Generally, both sequences of calls
- /// are expected to lead to a sensible result:
- ///
- /// addMatcher(...)*; finalize(); optimize(); emit(...); and
- /// addMatcher(...)*; finalize(); emit(...);
- ///
- /// or generally
- ///
- /// addMatcher(...)*; finalize(); { optimize()*; emit(...); }*
- ///
- /// Multiple calls to optimize() are expected to be handled gracefully, though
- /// optimize() is not expected to be idempotent. Multiple calls to finalize()
- /// aren't generally supported. emit(...) is expected to be non-mutating and
- /// producing the exact same results upon repeated calls.
- ///
- /// addMatcher() calls after the finalize() call are not supported.
- ///
- /// finalize() and optimize() are both allowed to mutate the contained
- /// matchers, so moving them out after finalize() is not supported.
- void finalize();
- void optimize() override;
- void emit(MatchTable &Table) override;
-
- /// Could be used to move out the matchers added previously, unless finalize()
- /// has been already called. If any of the matchers are moved out, the group
- /// becomes safe to destroy, but not safe to re-use for anything else.
- iterator_range<std::vector<Matcher *>::iterator> matchers() {
- return make_range(Matchers.begin(), Matchers.end());
- }
- size_t size() const { return Matchers.size(); }
- bool empty() const { return Matchers.empty(); }
-
- std::unique_ptr<PredicateMatcher> popFirstCondition() override {
- assert(!Conditions.empty() &&
- "Trying to pop a condition from a condition-less group");
- std::unique_ptr<PredicateMatcher> P = std::move(Conditions.front());
- Conditions.erase(Conditions.begin());
- return P;
- }
- const PredicateMatcher &getFirstCondition() const override {
- assert(!Conditions.empty() &&
- "Trying to get a condition from a condition-less group");
- return *Conditions.front();
- }
- bool hasFirstCondition() const override { return !Conditions.empty(); }
-
-private:
- /// See if a candidate matcher could be added to this group solely by
- /// analyzing its first condition.
- bool candidateConditionMatches(const PredicateMatcher &Predicate) const;
-};
-
-class SwitchMatcher : public Matcher {
- /// All the nested matchers, representing distinct switch-cases. The first
- /// conditions (as Matcher::getFirstCondition() reports) of all the nested
- /// matchers must share the same type and path to a value they check, in other
- /// words, be isIdenticalDownToValue, but have different values they check
- /// against.
- std::vector<Matcher *> Matchers;
-
- /// The representative condition, with a type and a path (InsnVarID and OpIdx
- /// in most cases) shared by all the matchers contained.
- std::unique_ptr<PredicateMatcher> Condition = nullptr;
-
- /// Temporary set used to check that the case values don't repeat within the
- /// same switch.
- std::set<MatchTableRecord> Values;
-
- /// An owning collection for any auxiliary matchers created while optimizing
- /// nested matchers contained.
- std::vector<std::unique_ptr<Matcher>> MatcherStorage;
-
-public:
- bool addMatcher(Matcher &Candidate);
-
- void finalize();
- void emit(MatchTable &Table) override;
-
- iterator_range<std::vector<Matcher *>::iterator> matchers() {
- return make_range(Matchers.begin(), Matchers.end());
- }
- size_t size() const { return Matchers.size(); }
- bool empty() const { return Matchers.empty(); }
-
- std::unique_ptr<PredicateMatcher> popFirstCondition() override {
- // SwitchMatcher doesn't have a common first condition for its cases, as all
- // the cases only share a kind of a value (a type and a path to it) they
- // match, but deliberately differ in the actual value they match.
- llvm_unreachable("Trying to pop a condition from a condition-less group");
- }
- const PredicateMatcher &getFirstCondition() const override {
- llvm_unreachable("Trying to pop a condition from a condition-less group");
- }
- bool hasFirstCondition() const override { return false; }
-
-private:
- /// See if the predicate type has a Switch-implementation for it.
- static bool isSupportedPredicateType(const PredicateMatcher &Predicate);
-
- bool candidateConditionMatches(const PredicateMatcher &Predicate) const;
-
- /// emit()-helper
- static void emitPredicateSpecificOpcodes(const PredicateMatcher &P,
- MatchTable &Table);
-};
-
-/// Generates code to check that a match rule matches.
-class RuleMatcher : public Matcher {
-public:
- using ActionList = std::list<std::unique_ptr<MatchAction>>;
- using action_iterator = ActionList::iterator;
-
-protected:
- /// A list of matchers that all need to succeed for the current rule to match.
- /// FIXME: This currently supports a single match position but could be
- /// extended to support multiple positions to support div/rem fusion or
- /// load-multiple instructions.
- using MatchersTy = std::vector<std::unique_ptr<InstructionMatcher>> ;
- MatchersTy Matchers;
-
- /// A list of actions that need to be taken when all predicates in this rule
- /// have succeeded.
- ActionList Actions;
-
- using DefinedInsnVariablesMap = std::map<InstructionMatcher *, unsigned>;
-
- /// A map of instruction matchers to the local variables
- DefinedInsnVariablesMap InsnVariableIDs;
-
- using MutatableInsnSet = SmallPtrSet<InstructionMatcher *, 4>;
-
- // The set of instruction matchers that have not yet been claimed for mutation
- // by a BuildMI.
- MutatableInsnSet MutatableInsns;
-
- /// A map of named operands defined by the matchers that may be referenced by
- /// the renderers.
- StringMap<OperandMatcher *> DefinedOperands;
-
- /// A map of anonymous physical register operands defined by the matchers that
- /// may be referenced by the renderers.
- DenseMap<Record *, OperandMatcher *> PhysRegOperands;
-
- /// ID for the next instruction variable defined with implicitlyDefineInsnVar()
- unsigned NextInsnVarID;
-
- /// ID for the next output instruction allocated with allocateOutputInsnID()
- unsigned NextOutputInsnID;
-
- /// ID for the next temporary register ID allocated with allocateTempRegID()
- unsigned NextTempRegID;
-
- std::vector<Record *> RequiredFeatures;
- std::vector<std::unique_ptr<PredicateMatcher>> EpilogueMatchers;
-
- ArrayRef<SMLoc> SrcLoc;
-
- typedef std::tuple<Record *, unsigned, unsigned>
- DefinedComplexPatternSubOperand;
- typedef StringMap<DefinedComplexPatternSubOperand>
- DefinedComplexPatternSubOperandMap;
- /// A map of Symbolic Names to ComplexPattern sub-operands.
- DefinedComplexPatternSubOperandMap ComplexSubOperands;
- /// A map used to for multiple referenced error check of ComplexSubOperand.
- /// ComplexSubOperand can't be referenced multiple from different operands,
- /// however multiple references from same operand are allowed since that is
- /// how 'same operand checks' are generated.
- StringMap<std::string> ComplexSubOperandsParentName;
-
- uint64_t RuleID;
- static uint64_t NextRuleID;
-
-public:
- RuleMatcher(ArrayRef<SMLoc> SrcLoc)
- : NextInsnVarID(0), NextOutputInsnID(0), NextTempRegID(0), SrcLoc(SrcLoc),
- RuleID(NextRuleID++) {}
- RuleMatcher(RuleMatcher &&Other) = default;
- RuleMatcher &operator=(RuleMatcher &&Other) = default;
-
- uint64_t getRuleID() const { return RuleID; }
-
- InstructionMatcher &addInstructionMatcher(StringRef SymbolicName);
- void addRequiredFeature(Record *Feature);
- const std::vector<Record *> &getRequiredFeatures() const;
-
- template <class Kind, class... Args> Kind &addAction(Args &&... args);
- template <class Kind, class... Args>
- action_iterator insertAction(action_iterator InsertPt, Args &&... args);
-
- /// Define an instruction without emitting any code to do so.
- unsigned implicitlyDefineInsnVar(InstructionMatcher &Matcher);
-
- unsigned getInsnVarID(InstructionMatcher &InsnMatcher) const;
- DefinedInsnVariablesMap::const_iterator defined_insn_vars_begin() const {
- return InsnVariableIDs.begin();
- }
- DefinedInsnVariablesMap::const_iterator defined_insn_vars_end() const {
- return InsnVariableIDs.end();
- }
- iterator_range<typename DefinedInsnVariablesMap::const_iterator>
- defined_insn_vars() const {
- return make_range(defined_insn_vars_begin(), defined_insn_vars_end());
- }
-
- MutatableInsnSet::const_iterator mutatable_insns_begin() const {
- return MutatableInsns.begin();
- }
- MutatableInsnSet::const_iterator mutatable_insns_end() const {
- return MutatableInsns.end();
- }
- iterator_range<typename MutatableInsnSet::const_iterator>
- mutatable_insns() const {
- return make_range(mutatable_insns_begin(), mutatable_insns_end());
- }
- void reserveInsnMatcherForMutation(InstructionMatcher *InsnMatcher) {
- bool R = MutatableInsns.erase(InsnMatcher);
- assert(R && "Reserving a mutatable insn that isn't available");
- (void)R;
- }
-
- action_iterator actions_begin() { return Actions.begin(); }
- action_iterator actions_end() { return Actions.end(); }
- iterator_range<action_iterator> actions() {
- return make_range(actions_begin(), actions_end());
- }
-
- void defineOperand(StringRef SymbolicName, OperandMatcher &OM);
-
- void definePhysRegOperand(Record *Reg, OperandMatcher &OM);
-
- Error defineComplexSubOperand(StringRef SymbolicName, Record *ComplexPattern,
- unsigned RendererID, unsigned SubOperandID,
- StringRef ParentSymbolicName) {
- std::string ParentName(ParentSymbolicName);
- if (ComplexSubOperands.count(SymbolicName)) {
- const std::string &RecordedParentName =
- ComplexSubOperandsParentName[SymbolicName];
- if (RecordedParentName != ParentName)
- return failedImport("Error: Complex suboperand " + SymbolicName +
- " referenced by different operands: " +
- RecordedParentName + " and " + ParentName + ".");
- // Complex suboperand referenced more than once from same the operand is
- // used to generate 'same operand check'. Emitting of
- // GIR_ComplexSubOperandRenderer for them is already handled.
- return Error::success();
- }
-
- ComplexSubOperands[SymbolicName] =
- std::make_tuple(ComplexPattern, RendererID, SubOperandID);
- ComplexSubOperandsParentName[SymbolicName] = ParentName;
-
- return Error::success();
- }
-
- std::optional<DefinedComplexPatternSubOperand>
- getComplexSubOperand(StringRef SymbolicName) const {
- const auto &I = ComplexSubOperands.find(SymbolicName);
- if (I == ComplexSubOperands.end())
- return std::nullopt;
- return I->second;
- }
-
- InstructionMatcher &getInstructionMatcher(StringRef SymbolicName) const;
- const OperandMatcher &getOperandMatcher(StringRef Name) const;
- const OperandMatcher &getPhysRegOperandMatcher(Record *) const;
-
- void optimize() override;
- void emit(MatchTable &Table) override;
-
- /// Compare the priority of this object and B.
- ///
- /// Returns true if this object is more important than B.
- bool isHigherPriorityThan(const RuleMatcher &B) const;
-
- /// Report the maximum number of temporary operands needed by the rule
- /// matcher.
- unsigned countRendererFns() const;
-
- std::unique_ptr<PredicateMatcher> popFirstCondition() override;
- const PredicateMatcher &getFirstCondition() const override;
- LLTCodeGen getFirstConditionAsRootType();
- bool hasFirstCondition() const override;
- unsigned getNumOperands() const;
- StringRef getOpcode() const;
-
- // FIXME: Remove this as soon as possible
- InstructionMatcher &insnmatchers_front() const { return *Matchers.front(); }
-
- unsigned allocateOutputInsnID() { return NextOutputInsnID++; }
- unsigned allocateTempRegID() { return NextTempRegID++; }
-
- iterator_range<MatchersTy::iterator> insnmatchers() {
- return make_range(Matchers.begin(), Matchers.end());
- }
- bool insnmatchers_empty() const { return Matchers.empty(); }
- void insnmatchers_pop_front() { Matchers.erase(Matchers.begin()); }
-};
-
-uint64_t RuleMatcher::NextRuleID = 0;
-
-using action_iterator = RuleMatcher::action_iterator;
-
-template <class PredicateTy> class PredicateListMatcher {
-private:
- /// Template instantiations should specialize this to return a string to use
- /// for the comment emitted when there are no predicates.
- std::string getNoPredicateComment() const;
-
-protected:
- using PredicatesTy = std::deque<std::unique_ptr<PredicateTy>>;
- PredicatesTy Predicates;
-
- /// Track if the list of predicates was manipulated by one of the optimization
- /// methods.
- bool Optimized = false;
-
-public:
- typename PredicatesTy::iterator predicates_begin() {
- return Predicates.begin();
- }
- typename PredicatesTy::iterator predicates_end() {
- return Predicates.end();
- }
- iterator_range<typename PredicatesTy::iterator> predicates() {
- return make_range(predicates_begin(), predicates_end());
- }
- typename PredicatesTy::size_type predicates_size() const {
- return Predicates.size();
- }
- bool predicates_empty() const { return Predicates.empty(); }
-
- std::unique_ptr<PredicateTy> predicates_pop_front() {
- std::unique_ptr<PredicateTy> Front = std::move(Predicates.front());
- Predicates.pop_front();
- Optimized = true;
- return Front;
- }
-
- void prependPredicate(std::unique_ptr<PredicateTy> &&Predicate) {
- Predicates.push_front(std::move(Predicate));
- }
-
- void eraseNullPredicates() {
- const auto NewEnd =
- std::stable_partition(Predicates.begin(), Predicates.end(),
- std::logical_not<std::unique_ptr<PredicateTy>>());
- if (NewEnd != Predicates.begin()) {
- Predicates.erase(Predicates.begin(), NewEnd);
- Optimized = true;
- }
- }
-
- /// Emit MatchTable opcodes that tests whether all the predicates are met.
- template <class... Args>
- void emitPredicateListOpcodes(MatchTable &Table, Args &&... args) {
- if (Predicates.empty() && !Optimized) {
- Table << MatchTable::Comment(getNoPredicateComment())
- << MatchTable::LineBreak;
- return;
- }
-
- for (const auto &Predicate : predicates())
- Predicate->emitPredicateOpcodes(Table, std::forward<Args>(args)...);
- }
-
- /// Provide a function to avoid emitting certain predicates. This is used to
- /// defer some predicate checks until after others
- using PredicateFilterFunc = std::function<bool(const PredicateTy&)>;
-
- /// Emit MatchTable opcodes for predicates which satisfy \p
- /// ShouldEmitPredicate. This should be called multiple times to ensure all
- /// predicates are eventually added to the match table.
- template <class... Args>
- void emitFilteredPredicateListOpcodes(PredicateFilterFunc ShouldEmitPredicate,
- MatchTable &Table, Args &&... args) {
- if (Predicates.empty() && !Optimized) {
- Table << MatchTable::Comment(getNoPredicateComment())
- << MatchTable::LineBreak;
- return;
- }
-
- for (const auto &Predicate : predicates()) {
- if (ShouldEmitPredicate(*Predicate))
- Predicate->emitPredicateOpcodes(Table, std::forward<Args>(args)...);
- }
- }
-};
-
-class PredicateMatcher {
-public:
- /// This enum is used for RTTI and also defines the priority that is given to
- /// the predicate when generating the matcher code. Kinds with higher priority
- /// must be tested first.
- ///
- /// The relative priority of OPM_LLT, OPM_RegBank, and OPM_MBB do not matter
- /// but OPM_Int must have priority over OPM_RegBank since constant integers
- /// are represented by a virtual register defined by a G_CONSTANT instruction.
- ///
- /// Note: The relative priority between IPM_ and OPM_ does not matter, they
- /// are currently not compared between each other.
- enum PredicateKind {
- IPM_Opcode,
- IPM_NumOperands,
- IPM_ImmPredicate,
- IPM_Imm,
- IPM_AtomicOrderingMMO,
- IPM_MemoryLLTSize,
- IPM_MemoryVsLLTSize,
- IPM_MemoryAddressSpace,
- IPM_MemoryAlignment,
- IPM_VectorSplatImm,
- IPM_NoUse,
- IPM_GenericPredicate,
- OPM_SameOperand,
- OPM_ComplexPattern,
- OPM_IntrinsicID,
- OPM_CmpPredicate,
- OPM_Instruction,
- OPM_Int,
- OPM_LiteralInt,
- OPM_LLT,
- OPM_PointerToAny,
- OPM_RegBank,
- OPM_MBB,
- OPM_RecordNamedOperand,
- };
-
-protected:
- PredicateKind Kind;
- unsigned InsnVarID;
- unsigned OpIdx;
-
-public:
- PredicateMatcher(PredicateKind Kind, unsigned InsnVarID, unsigned OpIdx = ~0)
- : Kind(Kind), InsnVarID(InsnVarID), OpIdx(OpIdx) {}
-
- unsigned getInsnVarID() const { return InsnVarID; }
- unsigned getOpIdx() const { return OpIdx; }
-
- virtual ~PredicateMatcher() = default;
- /// Emit MatchTable opcodes that check the predicate for the given operand.
- virtual void emitPredicateOpcodes(MatchTable &Table,
- RuleMatcher &Rule) const = 0;
-
- PredicateKind getKind() const { return Kind; }
-
- bool dependsOnOperands() const {
- // Custom predicates really depend on the context pattern of the
- // instruction, not just the individual instruction. This therefore
- // implicitly depends on all other pattern constraints.
- return Kind == IPM_GenericPredicate;
- }
-
- virtual bool isIdentical(const PredicateMatcher &B) const {
- return B.getKind() == getKind() && InsnVarID == B.InsnVarID &&
- OpIdx == B.OpIdx;
- }
-
- virtual bool isIdenticalDownToValue(const PredicateMatcher &B) const {
- return hasValue() && PredicateMatcher::isIdentical(B);
- }
-
- virtual MatchTableRecord getValue() const {
- assert(hasValue() && "Can not get a value of a value-less predicate!");
- llvm_unreachable("Not implemented yet");
- }
- virtual bool hasValue() const { return false; }
-
- /// Report the maximum number of temporary operands needed by the predicate
- /// matcher.
- virtual unsigned countRendererFns() const { return 0; }
-};
-
-/// Generates code to check a predicate of an operand.
-///
-/// Typical predicates include:
-/// * Operand is a particular register.
-/// * Operand is assigned a particular register bank.
-/// * Operand is an MBB.
-class OperandPredicateMatcher : public PredicateMatcher {
-public:
- OperandPredicateMatcher(PredicateKind Kind, unsigned InsnVarID,
- unsigned OpIdx)
- : PredicateMatcher(Kind, InsnVarID, OpIdx) {}
- virtual ~OperandPredicateMatcher() {}
-
- /// Compare the priority of this object and B.
- ///
- /// Returns true if this object is more important than B.
- virtual bool isHigherPriorityThan(const OperandPredicateMatcher &B) const;
-};
-
-template <>
-std::string
-PredicateListMatcher<OperandPredicateMatcher>::getNoPredicateComment() const {
- return "No operand predicates";
-}
-
-/// Generates code to check that a register operand is defined by the same exact
-/// one as another.
-class SameOperandMatcher : public OperandPredicateMatcher {
- std::string MatchingName;
- unsigned OrigOpIdx;
-
-public:
- SameOperandMatcher(unsigned InsnVarID, unsigned OpIdx, StringRef MatchingName,
- unsigned OrigOpIdx)
- : OperandPredicateMatcher(OPM_SameOperand, InsnVarID, OpIdx),
- MatchingName(MatchingName), OrigOpIdx(OrigOpIdx) {}
-
- static bool classof(const PredicateMatcher *P) {
- return P->getKind() == OPM_SameOperand;
- }
-
- void emitPredicateOpcodes(MatchTable &Table,
- RuleMatcher &Rule) const override;
-
- bool isIdentical(const PredicateMatcher &B) const override {
- return OperandPredicateMatcher::isIdentical(B) &&
- OrigOpIdx == cast<SameOperandMatcher>(&B)->OrigOpIdx &&
- MatchingName == cast<SameOperandMatcher>(&B)->MatchingName;
- }
-};
-
-/// Generates code to check that an operand is a particular LLT.
-class LLTOperandMatcher : public OperandPredicateMatcher {
-protected:
- LLTCodeGen Ty;
-
-public:
- static std::map<LLTCodeGen, unsigned> TypeIDValues;
-
- static void initTypeIDValuesMap() {
- TypeIDValues.clear();
-
- unsigned ID = 0;
- for (const LLTCodeGen &LLTy : KnownTypes)
- TypeIDValues[LLTy] = ID++;
- }
-
- LLTOperandMatcher(unsigned InsnVarID, unsigned OpIdx, const LLTCodeGen &Ty)
- : OperandPredicateMatcher(OPM_LLT, InsnVarID, OpIdx), Ty(Ty) {
- KnownTypes.insert(Ty);
- }
-
- static bool classof(const PredicateMatcher *P) {
- return P->getKind() == OPM_LLT;
- }
- bool isIdentical(const PredicateMatcher &B) const override {
- return OperandPredicateMatcher::isIdentical(B) &&
- Ty == cast<LLTOperandMatcher>(&B)->Ty;
- }
- MatchTableRecord getValue() const override {
- const auto VI = TypeIDValues.find(Ty);
- if (VI == TypeIDValues.end())
- return MatchTable::NamedValue(getTy().getCxxEnumValue());
- return MatchTable::NamedValue(getTy().getCxxEnumValue(), VI->second);
- }
- bool hasValue() const override {
- if (TypeIDValues.size() != KnownTypes.size())
- initTypeIDValuesMap();
- return TypeIDValues.count(Ty);
- }
-
- LLTCodeGen getTy() const { return Ty; }
-
- void emitPredicateOpcodes(MatchTable &Table,
- RuleMatcher &Rule) const override {
- Table << MatchTable::Opcode("GIM_CheckType") << MatchTable::Comment("MI")
- << MatchTable::IntValue(InsnVarID) << MatchTable::Comment("Op")
- << MatchTable::IntValue(OpIdx) << MatchTable::Comment("Type")
- << getValue() << MatchTable::LineBreak;
- }
-};
-
-std::map<LLTCodeGen, unsigned> LLTOperandMatcher::TypeIDValues;
-
-/// Generates code to check that an operand is a pointer to any address space.
-///
-/// In SelectionDAG, the types did not describe pointers or address spaces. As a
-/// result, iN is used to describe a pointer of N bits to any address space and
-/// PatFrag predicates are typically used to constrain the address space. There's
-/// no reliable means to derive the missing type information from the pattern so
-/// imported rules must test the components of a pointer separately.
-///
-/// If SizeInBits is zero, then the pointer size will be obtained from the
-/// subtarget.
-class PointerToAnyOperandMatcher : public OperandPredicateMatcher {
-protected:
- unsigned SizeInBits;
-
-public:
- PointerToAnyOperandMatcher(unsigned InsnVarID, unsigned OpIdx,
- unsigned SizeInBits)
- : OperandPredicateMatcher(OPM_PointerToAny, InsnVarID, OpIdx),
- SizeInBits(SizeInBits) {}
-
- static bool classof(const PredicateMatcher *P) {
- return P->getKind() == OPM_PointerToAny;
- }
-
- bool isIdentical(const PredicateMatcher &B) const override {
- return OperandPredicateMatcher::isIdentical(B) &&
- SizeInBits == cast<PointerToAnyOperandMatcher>(&B)->SizeInBits;
- }
-
- void emitPredicateOpcodes(MatchTable &Table,
- RuleMatcher &Rule) const override {
- Table << MatchTable::Opcode("GIM_CheckPointerToAny")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx)
- << MatchTable::Comment("SizeInBits")
- << MatchTable::IntValue(SizeInBits) << MatchTable::LineBreak;
- }
-};
-
-/// Generates code to record named operand in RecordedOperands list at StoreIdx.
-/// Predicates with 'let PredicateCodeUsesOperands = 1' get RecordedOperands as
-/// an argument to predicate's c++ code once all operands have been matched.
-class RecordNamedOperandMatcher : public OperandPredicateMatcher {
-protected:
- unsigned StoreIdx;
- std::string Name;
-
-public:
- RecordNamedOperandMatcher(unsigned InsnVarID, unsigned OpIdx,
- unsigned StoreIdx, StringRef Name)
- : OperandPredicateMatcher(OPM_RecordNamedOperand, InsnVarID, OpIdx),
- StoreIdx(StoreIdx), Name(Name) {}
-
- static bool classof(const PredicateMatcher *P) {
- return P->getKind() == OPM_RecordNamedOperand;
- }
-
- bool isIdentical(const PredicateMatcher &B) const override {
- return OperandPredicateMatcher::isIdentical(B) &&
- StoreIdx == cast<RecordNamedOperandMatcher>(&B)->StoreIdx &&
- Name == cast<RecordNamedOperandMatcher>(&B)->Name;
- }
-
- void emitPredicateOpcodes(MatchTable &Table,
- RuleMatcher &Rule) const override {
- Table << MatchTable::Opcode("GIM_RecordNamedOperand")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx)
- << MatchTable::Comment("StoreIdx") << MatchTable::IntValue(StoreIdx)
- << MatchTable::Comment("Name : " + Name) << MatchTable::LineBreak;
- }
-};
-
-/// Generates code to check that an operand is a particular target constant.
-class ComplexPatternOperandMatcher : public OperandPredicateMatcher {
-protected:
- const OperandMatcher &Operand;
- const Record &TheDef;
-
- unsigned getAllocatedTemporariesBaseID() const;
-
-public:
- bool isIdentical(const PredicateMatcher &B) const override { return false; }
-
- ComplexPatternOperandMatcher(unsigned InsnVarID, unsigned OpIdx,
- const OperandMatcher &Operand,
- const Record &TheDef)
- : OperandPredicateMatcher(OPM_ComplexPattern, InsnVarID, OpIdx),
- Operand(Operand), TheDef(TheDef) {}
-
- static bool classof(const PredicateMatcher *P) {
- return P->getKind() == OPM_ComplexPattern;
- }
-
- void emitPredicateOpcodes(MatchTable &Table,
- RuleMatcher &Rule) const override {
- unsigned ID = getAllocatedTemporariesBaseID();
- Table << MatchTable::Opcode("GIM_CheckComplexPattern")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx)
- << MatchTable::Comment("Renderer") << MatchTable::IntValue(ID)
- << MatchTable::NamedValue(("GICP_" + TheDef.getName()).str())
- << MatchTable::LineBreak;
- }
-
- unsigned countRendererFns() const override {
- return 1;
- }
-};
-
-/// Generates code to check that an operand is in a particular register bank.
-class RegisterBankOperandMatcher : public OperandPredicateMatcher {
-protected:
- const CodeGenRegisterClass &RC;
-
-public:
- RegisterBankOperandMatcher(unsigned InsnVarID, unsigned OpIdx,
- const CodeGenRegisterClass &RC)
- : OperandPredicateMatcher(OPM_RegBank, InsnVarID, OpIdx), RC(RC) {}
-
- bool isIdentical(const PredicateMatcher &B) const override {
- return OperandPredicateMatcher::isIdentical(B) &&
- RC.getDef() == cast<RegisterBankOperandMatcher>(&B)->RC.getDef();
- }
-
- static bool classof(const PredicateMatcher *P) {
- return P->getKind() == OPM_RegBank;
- }
-
- void emitPredicateOpcodes(MatchTable &Table,
- RuleMatcher &Rule) const override {
- Table << MatchTable::Opcode("GIM_CheckRegBankForClass")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx)
- << MatchTable::Comment("RC")
- << MatchTable::NamedValue(RC.getQualifiedName() + "RegClassID")
- << MatchTable::LineBreak;
- }
-};
-
-/// Generates code to check that an operand is a basic block.
-class MBBOperandMatcher : public OperandPredicateMatcher {
-public:
- MBBOperandMatcher(unsigned InsnVarID, unsigned OpIdx)
- : OperandPredicateMatcher(OPM_MBB, InsnVarID, OpIdx) {}
-
- static bool classof(const PredicateMatcher *P) {
- return P->getKind() == OPM_MBB;
- }
-
- void emitPredicateOpcodes(MatchTable &Table,
- RuleMatcher &Rule) const override {
- Table << MatchTable::Opcode("GIM_CheckIsMBB") << MatchTable::Comment("MI")
- << MatchTable::IntValue(InsnVarID) << MatchTable::Comment("Op")
- << MatchTable::IntValue(OpIdx) << MatchTable::LineBreak;
- }
-};
-
-class ImmOperandMatcher : public OperandPredicateMatcher {
-public:
- ImmOperandMatcher(unsigned InsnVarID, unsigned OpIdx)
- : OperandPredicateMatcher(IPM_Imm, InsnVarID, OpIdx) {}
-
- static bool classof(const PredicateMatcher *P) {
- return P->getKind() == IPM_Imm;
- }
-
- void emitPredicateOpcodes(MatchTable &Table,
- RuleMatcher &Rule) const override {
- Table << MatchTable::Opcode("GIM_CheckIsImm") << MatchTable::Comment("MI")
- << MatchTable::IntValue(InsnVarID) << MatchTable::Comment("Op")
- << MatchTable::IntValue(OpIdx) << MatchTable::LineBreak;
- }
-};
-
-/// Generates code to check that an operand is a G_CONSTANT with a particular
-/// int.
-class ConstantIntOperandMatcher : public OperandPredicateMatcher {
-protected:
- int64_t Value;
-
-public:
- ConstantIntOperandMatcher(unsigned InsnVarID, unsigned OpIdx, int64_t Value)
- : OperandPredicateMatcher(OPM_Int, InsnVarID, OpIdx), Value(Value) {}
-
- bool isIdentical(const PredicateMatcher &B) const override {
- return OperandPredicateMatcher::isIdentical(B) &&
- Value == cast<ConstantIntOperandMatcher>(&B)->Value;
- }
-
- static bool classof(const PredicateMatcher *P) {
- return P->getKind() == OPM_Int;
- }
-
- void emitPredicateOpcodes(MatchTable &Table,
- RuleMatcher &Rule) const override {
- Table << MatchTable::Opcode("GIM_CheckConstantInt")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx)
- << MatchTable::IntValue(Value) << MatchTable::LineBreak;
- }
-};
-
-/// Generates code to check that an operand is a raw int (where MO.isImm() or
-/// MO.isCImm() is true).
-class LiteralIntOperandMatcher : public OperandPredicateMatcher {
-protected:
- int64_t Value;
-
-public:
- LiteralIntOperandMatcher(unsigned InsnVarID, unsigned OpIdx, int64_t Value)
- : OperandPredicateMatcher(OPM_LiteralInt, InsnVarID, OpIdx),
- Value(Value) {}
-
- bool isIdentical(const PredicateMatcher &B) const override {
- return OperandPredicateMatcher::isIdentical(B) &&
- Value == cast<LiteralIntOperandMatcher>(&B)->Value;
- }
-
- static bool classof(const PredicateMatcher *P) {
- return P->getKind() == OPM_LiteralInt;
- }
-
- void emitPredicateOpcodes(MatchTable &Table,
- RuleMatcher &Rule) const override {
- Table << MatchTable::Opcode("GIM_CheckLiteralInt")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx)
- << MatchTable::IntValue(Value) << MatchTable::LineBreak;
- }
-};
-
-/// Generates code to check that an operand is an CmpInst predicate
-class CmpPredicateOperandMatcher : public OperandPredicateMatcher {
-protected:
- std::string PredName;
-
-public:
- CmpPredicateOperandMatcher(unsigned InsnVarID, unsigned OpIdx,
- std::string P)
- : OperandPredicateMatcher(OPM_CmpPredicate, InsnVarID, OpIdx), PredName(P) {}
-
- bool isIdentical(const PredicateMatcher &B) const override {
- return OperandPredicateMatcher::isIdentical(B) &&
- PredName == cast<CmpPredicateOperandMatcher>(&B)->PredName;
- }
-
- static bool classof(const PredicateMatcher *P) {
- return P->getKind() == OPM_CmpPredicate;
- }
-
- void emitPredicateOpcodes(MatchTable &Table,
- RuleMatcher &Rule) const override {
- Table << MatchTable::Opcode("GIM_CheckCmpPredicate")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx)
- << MatchTable::Comment("Predicate")
- << MatchTable::NamedValue("CmpInst", PredName)
- << MatchTable::LineBreak;
- }
-};
-
-/// Generates code to check that an operand is an intrinsic ID.
-class IntrinsicIDOperandMatcher : public OperandPredicateMatcher {
-protected:
- const CodeGenIntrinsic *II;
-
-public:
- IntrinsicIDOperandMatcher(unsigned InsnVarID, unsigned OpIdx,
- const CodeGenIntrinsic *II)
- : OperandPredicateMatcher(OPM_IntrinsicID, InsnVarID, OpIdx), II(II) {}
-
- bool isIdentical(const PredicateMatcher &B) const override {
- return OperandPredicateMatcher::isIdentical(B) &&
- II == cast<IntrinsicIDOperandMatcher>(&B)->II;
- }
-
- static bool classof(const PredicateMatcher *P) {
- return P->getKind() == OPM_IntrinsicID;
- }
-
- void emitPredicateOpcodes(MatchTable &Table,
- RuleMatcher &Rule) const override {
- Table << MatchTable::Opcode("GIM_CheckIntrinsicID")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx)
- << MatchTable::NamedValue("Intrinsic::" + II->EnumName)
- << MatchTable::LineBreak;
- }
-};
-
-/// Generates code to check that this operand is an immediate whose value meets
-/// an immediate predicate.
-class OperandImmPredicateMatcher : public OperandPredicateMatcher {
-protected:
- TreePredicateFn Predicate;
-
-public:
- OperandImmPredicateMatcher(unsigned InsnVarID, unsigned OpIdx,
- const TreePredicateFn &Predicate)
- : OperandPredicateMatcher(IPM_ImmPredicate, InsnVarID, OpIdx),
- Predicate(Predicate) {}
-
- bool isIdentical(const PredicateMatcher &B) const override {
- return OperandPredicateMatcher::isIdentical(B) &&
- Predicate.getOrigPatFragRecord() ==
- cast<OperandImmPredicateMatcher>(&B)
- ->Predicate.getOrigPatFragRecord();
- }
-
- static bool classof(const PredicateMatcher *P) {
- return P->getKind() == IPM_ImmPredicate;
- }
-
- void emitPredicateOpcodes(MatchTable &Table,
- RuleMatcher &Rule) const override {
- Table << MatchTable::Opcode("GIM_CheckImmOperandPredicate")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::Comment("MO") << MatchTable::IntValue(OpIdx)
- << MatchTable::Comment("Predicate")
- << MatchTable::NamedValue(getEnumNameForPredicate(Predicate))
- << MatchTable::LineBreak;
- }
-};
-
-/// Generates code to check that a set of predicates match for a particular
-/// operand.
-class OperandMatcher : public PredicateListMatcher<OperandPredicateMatcher> {
-protected:
- InstructionMatcher &Insn;
- unsigned OpIdx;
- std::string SymbolicName;
-
- /// The index of the first temporary variable allocated to this operand. The
- /// number of allocated temporaries can be found with
- /// countRendererFns().
- unsigned AllocatedTemporariesBaseID;
-
-public:
- OperandMatcher(InstructionMatcher &Insn, unsigned OpIdx,
- const std::string &SymbolicName,
- unsigned AllocatedTemporariesBaseID)
- : Insn(Insn), OpIdx(OpIdx), SymbolicName(SymbolicName),
- AllocatedTemporariesBaseID(AllocatedTemporariesBaseID) {}
-
- bool hasSymbolicName() const { return !SymbolicName.empty(); }
- StringRef getSymbolicName() const { return SymbolicName; }
- void setSymbolicName(StringRef Name) {
- assert(SymbolicName.empty() && "Operand already has a symbolic name");
- SymbolicName = std::string(Name);
- }
-
- /// Construct a new operand predicate and add it to the matcher.
- template <class Kind, class... Args>
- std::optional<Kind *> addPredicate(Args &&...args) {
- if (isSameAsAnotherOperand())
- return std::nullopt;
- Predicates.emplace_back(std::make_unique<Kind>(
- getInsnVarID(), getOpIdx(), std::forward<Args>(args)...));
- return static_cast<Kind *>(Predicates.back().get());
- }
-
- unsigned getOpIdx() const { return OpIdx; }
- unsigned getInsnVarID() const;
-
- std::string getOperandExpr(unsigned InsnVarID) const {
- return "State.MIs[" + llvm::to_string(InsnVarID) + "]->getOperand(" +
- llvm::to_string(OpIdx) + ")";
- }
-
- InstructionMatcher &getInstructionMatcher() const { return Insn; }
-
- Error addTypeCheckPredicate(const TypeSetByHwMode &VTy,
- bool OperandIsAPointer);
-
- /// Emit MatchTable opcodes that test whether the instruction named in
- /// InsnVarID matches all the predicates and all the operands.
- void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule) {
- if (!Optimized) {
- std::string Comment;
- raw_string_ostream CommentOS(Comment);
- CommentOS << "MIs[" << getInsnVarID() << "] ";
- if (SymbolicName.empty())
- CommentOS << "Operand " << OpIdx;
- else
- CommentOS << SymbolicName;
- Table << MatchTable::Comment(Comment) << MatchTable::LineBreak;
- }
-
- emitPredicateListOpcodes(Table, Rule);
- }
-
- /// Compare the priority of this object and B.
- ///
- /// Returns true if this object is more important than B.
- bool isHigherPriorityThan(OperandMatcher &B) {
- // Operand matchers involving more predicates have higher priority.
- if (predicates_size() > B.predicates_size())
- return true;
- if (predicates_size() < B.predicates_size())
- return false;
-
- // This assumes that predicates are added in a consistent order.
- for (auto &&Predicate : zip(predicates(), B.predicates())) {
- if (std::get<0>(Predicate)->isHigherPriorityThan(*std::get<1>(Predicate)))
- return true;
- if (std::get<1>(Predicate)->isHigherPriorityThan(*std::get<0>(Predicate)))
- return false;
- }
-
- return false;
- };
-
- /// Report the maximum number of temporary operands needed by the operand
- /// matcher.
- unsigned countRendererFns() {
- return std::accumulate(
- predicates().begin(), predicates().end(), 0,
- [](unsigned A,
- const std::unique_ptr<OperandPredicateMatcher> &Predicate) {
- return A + Predicate->countRendererFns();
- });
- }
-
- unsigned getAllocatedTemporariesBaseID() const {
- return AllocatedTemporariesBaseID;
- }
-
- bool isSameAsAnotherOperand() {
- for (const auto &Predicate : predicates())
- if (isa<SameOperandMatcher>(Predicate))
- return true;
- return false;
- }
-};
-
-Error OperandMatcher::addTypeCheckPredicate(const TypeSetByHwMode &VTy,
- bool OperandIsAPointer) {
- if (!VTy.isMachineValueType())
- return failedImport("unsupported typeset");
-
- if (VTy.getMachineValueType() == MVT::iPTR && OperandIsAPointer) {
- addPredicate<PointerToAnyOperandMatcher>(0);
- return Error::success();
- }
-
- auto OpTyOrNone = MVTToLLT(VTy.getMachineValueType().SimpleTy);
- if (!OpTyOrNone)
- return failedImport("unsupported type");
-
- if (OperandIsAPointer)
- addPredicate<PointerToAnyOperandMatcher>(OpTyOrNone->get().getSizeInBits());
- else if (VTy.isPointer())
- addPredicate<LLTOperandMatcher>(LLT::pointer(VTy.getPtrAddrSpace(),
- OpTyOrNone->get().getSizeInBits()));
- else
- addPredicate<LLTOperandMatcher>(*OpTyOrNone);
- return Error::success();
-}
-
-unsigned ComplexPatternOperandMatcher::getAllocatedTemporariesBaseID() const {
- return Operand.getAllocatedTemporariesBaseID();
-}
-
-/// Generates code to check a predicate on an instruction.
-///
-/// Typical predicates include:
-/// * The opcode of the instruction is a particular value.
-/// * The nsw/nuw flag is/isn't set.
-class InstructionPredicateMatcher : public PredicateMatcher {
-public:
- InstructionPredicateMatcher(PredicateKind Kind, unsigned InsnVarID)
- : PredicateMatcher(Kind, InsnVarID) {}
- virtual ~InstructionPredicateMatcher() {}
-
- /// Compare the priority of this object and B.
- ///
- /// Returns true if this object is more important than B.
- virtual bool
- isHigherPriorityThan(const InstructionPredicateMatcher &B) const {
- return Kind < B.Kind;
- };
-};
-
-template <>
-std::string
-PredicateListMatcher<PredicateMatcher>::getNoPredicateComment() const {
- return "No instruction predicates";
-}
-
-/// Generates code to check the opcode of an instruction.
-class InstructionOpcodeMatcher : public InstructionPredicateMatcher {
-protected:
- // Allow matching one to several, similar opcodes that share properties. This
- // is to handle patterns where one SelectionDAG operation maps to multiple
- // GlobalISel ones (e.g. G_BUILD_VECTOR and G_BUILD_VECTOR_TRUNC). The first
- // is treated as the canonical opcode.
- SmallVector<const CodeGenInstruction *, 2> Insts;
-
- static DenseMap<const CodeGenInstruction *, unsigned> OpcodeValues;
-
-
- MatchTableRecord getInstValue(const CodeGenInstruction *I) const {
- const auto VI = OpcodeValues.find(I);
- if (VI != OpcodeValues.end())
- return MatchTable::NamedValue(I->Namespace, I->TheDef->getName(),
- VI->second);
- return MatchTable::NamedValue(I->Namespace, I->TheDef->getName());
- }
-
-public:
- static void initOpcodeValuesMap(const CodeGenTarget &Target) {
- OpcodeValues.clear();
-
- unsigned OpcodeValue = 0;
- for (const CodeGenInstruction *I : Target.getInstructionsByEnumValue())
- OpcodeValues[I] = OpcodeValue++;
- }
-
- InstructionOpcodeMatcher(unsigned InsnVarID,
- ArrayRef<const CodeGenInstruction *> I)
- : InstructionPredicateMatcher(IPM_Opcode, InsnVarID),
- Insts(I.begin(), I.end()) {
- assert((Insts.size() == 1 || Insts.size() == 2) &&
- "unexpected number of opcode alternatives");
- }
-
- static bool classof(const PredicateMatcher *P) {
- return P->getKind() == IPM_Opcode;
- }
-
- bool isIdentical(const PredicateMatcher &B) const override {
- return InstructionPredicateMatcher::isIdentical(B) &&
- Insts == cast<InstructionOpcodeMatcher>(&B)->Insts;
- }
-
- bool hasValue() const override {
- return Insts.size() == 1 && OpcodeValues.count(Insts[0]);
- }
-
- // TODO: This is used for the SwitchMatcher optimization. We should be able to
- // return a list of the opcodes to match.
- MatchTableRecord getValue() const override {
- assert(Insts.size() == 1);
-
- const CodeGenInstruction *I = Insts[0];
- const auto VI = OpcodeValues.find(I);
- if (VI != OpcodeValues.end())
- return MatchTable::NamedValue(I->Namespace, I->TheDef->getName(),
- VI->second);
- return MatchTable::NamedValue(I->Namespace, I->TheDef->getName());
- }
-
- void emitPredicateOpcodes(MatchTable &Table,
- RuleMatcher &Rule) const override {
- StringRef CheckType = Insts.size() == 1 ?
- "GIM_CheckOpcode" : "GIM_CheckOpcodeIsEither";
- Table << MatchTable::Opcode(CheckType) << MatchTable::Comment("MI")
- << MatchTable::IntValue(InsnVarID);
-
- for (const CodeGenInstruction *I : Insts)
- Table << getInstValue(I);
- Table << MatchTable::LineBreak;
- }
-
- /// Compare the priority of this object and B.
- ///
- /// Returns true if this object is more important than B.
- bool
- isHigherPriorityThan(const InstructionPredicateMatcher &B) const override {
- if (InstructionPredicateMatcher::isHigherPriorityThan(B))
- return true;
- if (B.InstructionPredicateMatcher::isHigherPriorityThan(*this))
- return false;
-
- // Prioritize opcodes for cosmetic reasons in the generated source. Although
- // this is cosmetic at the moment, we may want to drive a similar ordering
- // using instruction frequency information to improve compile time.
- if (const InstructionOpcodeMatcher *BO =
- dyn_cast<InstructionOpcodeMatcher>(&B))
- return Insts[0]->TheDef->getName() < BO->Insts[0]->TheDef->getName();
-
- return false;
- };
-
- bool isConstantInstruction() const {
- return Insts.size() == 1 && Insts[0]->TheDef->getName() == "G_CONSTANT";
- }
-
- // The first opcode is the canonical opcode, and later are alternatives.
- StringRef getOpcode() const {
- return Insts[0]->TheDef->getName();
- }
-
- ArrayRef<const CodeGenInstruction *> getAlternativeOpcodes() {
- return Insts;
- }
-
- bool isVariadicNumOperands() const {
- // If one is variadic, they all should be.
- return Insts[0]->Operands.isVariadic;
- }
-
- StringRef getOperandType(unsigned OpIdx) const {
- // Types expected to be uniform for all alternatives.
- return Insts[0]->Operands[OpIdx].OperandType;
- }
-};
-
-DenseMap<const CodeGenInstruction *, unsigned>
- InstructionOpcodeMatcher::OpcodeValues;
-
-class InstructionNumOperandsMatcher final : public InstructionPredicateMatcher {
- unsigned NumOperands = 0;
-
-public:
- InstructionNumOperandsMatcher(unsigned InsnVarID, unsigned NumOperands)
- : InstructionPredicateMatcher(IPM_NumOperands, InsnVarID),
- NumOperands(NumOperands) {}
-
- static bool classof(const PredicateMatcher *P) {
- return P->getKind() == IPM_NumOperands;
- }
-
- bool isIdentical(const PredicateMatcher &B) const override {
- return InstructionPredicateMatcher::isIdentical(B) &&
- NumOperands == cast<InstructionNumOperandsMatcher>(&B)->NumOperands;
- }
-
- void emitPredicateOpcodes(MatchTable &Table,
- RuleMatcher &Rule) const override {
- Table << MatchTable::Opcode("GIM_CheckNumOperands")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::Comment("Expected")
- << MatchTable::IntValue(NumOperands) << MatchTable::LineBreak;
- }
-};
-
-/// Generates code to check that this instruction is a constant whose value
-/// meets an immediate predicate.
-///
-/// Immediates are slightly odd since they are typically used like an operand
-/// but are represented as an operator internally. We typically write simm8:$src
-/// in a tablegen pattern, but this is just syntactic sugar for
-/// (imm:i32)<<P:Predicate_simm8>>:$imm which more directly describes the nodes
-/// that will be matched and the predicate (which is attached to the imm
-/// operator) that will be tested. In SelectionDAG this describes a
-/// ConstantSDNode whose internal value will be tested using the simm8 predicate.
-///
-/// The corresponding GlobalISel representation is %1 = G_CONSTANT iN Value. In
-/// this representation, the immediate could be tested with an
-/// InstructionMatcher, InstructionOpcodeMatcher, OperandMatcher, and a
-/// OperandPredicateMatcher-subclass to check the Value meets the predicate but
-/// there are two implementation issues with producing that matcher
-/// configuration from the SelectionDAG pattern:
-/// * ImmLeaf is a PatFrag whose root is an InstructionMatcher. This means that
-/// were we to sink the immediate predicate to the operand we would have to
-/// have two partial implementations of PatFrag support, one for immediates
-/// and one for non-immediates.
-/// * At the point we handle the predicate, the OperandMatcher hasn't been
-/// created yet. If we were to sink the predicate to the OperandMatcher we
-/// would also have to complicate (or duplicate) the code that descends and
-/// creates matchers for the subtree.
-/// Overall, it's simpler to handle it in the place it was found.
-class InstructionImmPredicateMatcher : public InstructionPredicateMatcher {
-protected:
- TreePredicateFn Predicate;
-
-public:
- InstructionImmPredicateMatcher(unsigned InsnVarID,
- const TreePredicateFn &Predicate)
- : InstructionPredicateMatcher(IPM_ImmPredicate, InsnVarID),
- Predicate(Predicate) {}
-
- bool isIdentical(const PredicateMatcher &B) const override {
- return InstructionPredicateMatcher::isIdentical(B) &&
- Predicate.getOrigPatFragRecord() ==
- cast<InstructionImmPredicateMatcher>(&B)
- ->Predicate.getOrigPatFragRecord();
- }
-
- static bool classof(const PredicateMatcher *P) {
- return P->getKind() == IPM_ImmPredicate;
- }
-
- void emitPredicateOpcodes(MatchTable &Table,
- RuleMatcher &Rule) const override {
- Table << MatchTable::Opcode(getMatchOpcodeForImmPredicate(Predicate))
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::Comment("Predicate")
- << MatchTable::NamedValue(getEnumNameForPredicate(Predicate))
- << MatchTable::LineBreak;
- }
-};
-
-/// Generates code to check that a memory instruction has a atomic ordering
-/// MachineMemoryOperand.
-class AtomicOrderingMMOPredicateMatcher : public InstructionPredicateMatcher {
-public:
- enum AOComparator {
- AO_Exactly,
- AO_OrStronger,
- AO_WeakerThan,
- };
-
-protected:
- StringRef Order;
- AOComparator Comparator;
-
-public:
- AtomicOrderingMMOPredicateMatcher(unsigned InsnVarID, StringRef Order,
- AOComparator Comparator = AO_Exactly)
- : InstructionPredicateMatcher(IPM_AtomicOrderingMMO, InsnVarID),
- Order(Order), Comparator(Comparator) {}
-
- static bool classof(const PredicateMatcher *P) {
- return P->getKind() == IPM_AtomicOrderingMMO;
- }
-
- bool isIdentical(const PredicateMatcher &B) const override {
- if (!InstructionPredicateMatcher::isIdentical(B))
- return false;
- const auto &R = *cast<AtomicOrderingMMOPredicateMatcher>(&B);
- return Order == R.Order && Comparator == R.Comparator;
- }
-
- void emitPredicateOpcodes(MatchTable &Table,
- RuleMatcher &Rule) const override {
- StringRef Opcode = "GIM_CheckAtomicOrdering";
-
- if (Comparator == AO_OrStronger)
- Opcode = "GIM_CheckAtomicOrderingOrStrongerThan";
- if (Comparator == AO_WeakerThan)
- Opcode = "GIM_CheckAtomicOrderingWeakerThan";
-
- Table << MatchTable::Opcode(Opcode) << MatchTable::Comment("MI")
- << MatchTable::IntValue(InsnVarID) << MatchTable::Comment("Order")
- << MatchTable::NamedValue(("(int64_t)AtomicOrdering::" + Order).str())
- << MatchTable::LineBreak;
- }
-};
-
-/// Generates code to check that the size of an MMO is exactly N bytes.
-class MemorySizePredicateMatcher : public InstructionPredicateMatcher {
-protected:
- unsigned MMOIdx;
- uint64_t Size;
-
-public:
- MemorySizePredicateMatcher(unsigned InsnVarID, unsigned MMOIdx, unsigned Size)
- : InstructionPredicateMatcher(IPM_MemoryLLTSize, InsnVarID),
- MMOIdx(MMOIdx), Size(Size) {}
-
- static bool classof(const PredicateMatcher *P) {
- return P->getKind() == IPM_MemoryLLTSize;
- }
- bool isIdentical(const PredicateMatcher &B) const override {
- return InstructionPredicateMatcher::isIdentical(B) &&
- MMOIdx == cast<MemorySizePredicateMatcher>(&B)->MMOIdx &&
- Size == cast<MemorySizePredicateMatcher>(&B)->Size;
- }
-
- void emitPredicateOpcodes(MatchTable &Table,
- RuleMatcher &Rule) const override {
- Table << MatchTable::Opcode("GIM_CheckMemorySizeEqualTo")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::Comment("MMO") << MatchTable::IntValue(MMOIdx)
- << MatchTable::Comment("Size") << MatchTable::IntValue(Size)
- << MatchTable::LineBreak;
- }
-};
-
-class MemoryAddressSpacePredicateMatcher : public InstructionPredicateMatcher {
-protected:
- unsigned MMOIdx;
- SmallVector<unsigned, 4> AddrSpaces;
-
-public:
- MemoryAddressSpacePredicateMatcher(unsigned InsnVarID, unsigned MMOIdx,
- ArrayRef<unsigned> AddrSpaces)
- : InstructionPredicateMatcher(IPM_MemoryAddressSpace, InsnVarID),
- MMOIdx(MMOIdx), AddrSpaces(AddrSpaces.begin(), AddrSpaces.end()) {}
-
- static bool classof(const PredicateMatcher *P) {
- return P->getKind() == IPM_MemoryAddressSpace;
- }
- bool isIdentical(const PredicateMatcher &B) const override {
- if (!InstructionPredicateMatcher::isIdentical(B))
- return false;
- auto *Other = cast<MemoryAddressSpacePredicateMatcher>(&B);
- return MMOIdx == Other->MMOIdx && AddrSpaces == Other->AddrSpaces;
- }
-
- void emitPredicateOpcodes(MatchTable &Table,
- RuleMatcher &Rule) const override {
- Table << MatchTable::Opcode("GIM_CheckMemoryAddressSpace")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::Comment("MMO") << MatchTable::IntValue(MMOIdx)
- // Encode number of address spaces to expect.
- << MatchTable::Comment("NumAddrSpace")
- << MatchTable::IntValue(AddrSpaces.size());
- for (unsigned AS : AddrSpaces)
- Table << MatchTable::Comment("AddrSpace") << MatchTable::IntValue(AS);
-
- Table << MatchTable::LineBreak;
- }
-};
-
-class MemoryAlignmentPredicateMatcher : public InstructionPredicateMatcher {
-protected:
- unsigned MMOIdx;
- int MinAlign;
-
-public:
- MemoryAlignmentPredicateMatcher(unsigned InsnVarID, unsigned MMOIdx,
- int MinAlign)
- : InstructionPredicateMatcher(IPM_MemoryAlignment, InsnVarID),
- MMOIdx(MMOIdx), MinAlign(MinAlign) {
- assert(MinAlign > 0);
- }
-
- static bool classof(const PredicateMatcher *P) {
- return P->getKind() == IPM_MemoryAlignment;
- }
-
- bool isIdentical(const PredicateMatcher &B) const override {
- if (!InstructionPredicateMatcher::isIdentical(B))
- return false;
- auto *Other = cast<MemoryAlignmentPredicateMatcher>(&B);
- return MMOIdx == Other->MMOIdx && MinAlign == Other->MinAlign;
- }
-
- void emitPredicateOpcodes(MatchTable &Table,
- RuleMatcher &Rule) const override {
- Table << MatchTable::Opcode("GIM_CheckMemoryAlignment")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::Comment("MMO") << MatchTable::IntValue(MMOIdx)
- << MatchTable::Comment("MinAlign") << MatchTable::IntValue(MinAlign)
- << MatchTable::LineBreak;
- }
-};
-
-/// Generates code to check that the size of an MMO is less-than, equal-to, or
-/// greater than a given LLT.
-class MemoryVsLLTSizePredicateMatcher : public InstructionPredicateMatcher {
-public:
- enum RelationKind {
- GreaterThan,
- EqualTo,
- LessThan,
- };
-
-protected:
- unsigned MMOIdx;
- RelationKind Relation;
- unsigned OpIdx;
-
-public:
- MemoryVsLLTSizePredicateMatcher(unsigned InsnVarID, unsigned MMOIdx,
- enum RelationKind Relation,
- unsigned OpIdx)
- : InstructionPredicateMatcher(IPM_MemoryVsLLTSize, InsnVarID),
- MMOIdx(MMOIdx), Relation(Relation), OpIdx(OpIdx) {}
-
- static bool classof(const PredicateMatcher *P) {
- return P->getKind() == IPM_MemoryVsLLTSize;
- }
- bool isIdentical(const PredicateMatcher &B) const override {
- return InstructionPredicateMatcher::isIdentical(B) &&
- MMOIdx == cast<MemoryVsLLTSizePredicateMatcher>(&B)->MMOIdx &&
- Relation == cast<MemoryVsLLTSizePredicateMatcher>(&B)->Relation &&
- OpIdx == cast<MemoryVsLLTSizePredicateMatcher>(&B)->OpIdx;
- }
-
- void emitPredicateOpcodes(MatchTable &Table,
- RuleMatcher &Rule) const override {
- Table << MatchTable::Opcode(Relation == EqualTo
- ? "GIM_CheckMemorySizeEqualToLLT"
- : Relation == GreaterThan
- ? "GIM_CheckMemorySizeGreaterThanLLT"
- : "GIM_CheckMemorySizeLessThanLLT")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::Comment("MMO") << MatchTable::IntValue(MMOIdx)
- << MatchTable::Comment("OpIdx") << MatchTable::IntValue(OpIdx)
- << MatchTable::LineBreak;
- }
-};
-
-// Matcher for immAllOnesV/immAllZerosV
-class VectorSplatImmPredicateMatcher : public InstructionPredicateMatcher {
-public:
- enum SplatKind {
- AllZeros,
- AllOnes
- };
-
-private:
- SplatKind Kind;
-
-public:
- VectorSplatImmPredicateMatcher(unsigned InsnVarID, SplatKind K)
- : InstructionPredicateMatcher(IPM_VectorSplatImm, InsnVarID), Kind(K) {}
-
- static bool classof(const PredicateMatcher *P) {
- return P->getKind() == IPM_VectorSplatImm;
- }
-
- bool isIdentical(const PredicateMatcher &B) const override {
- return InstructionPredicateMatcher::isIdentical(B) &&
- Kind == static_cast<const VectorSplatImmPredicateMatcher &>(B).Kind;
- }
-
- void emitPredicateOpcodes(MatchTable &Table,
- RuleMatcher &Rule) const override {
- if (Kind == AllOnes)
- Table << MatchTable::Opcode("GIM_CheckIsBuildVectorAllOnes");
- else
- Table << MatchTable::Opcode("GIM_CheckIsBuildVectorAllZeros");
-
- Table << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID);
- Table << MatchTable::LineBreak;
- }
-};
-
-/// Generates code to check an arbitrary C++ instruction predicate.
-class GenericInstructionPredicateMatcher : public InstructionPredicateMatcher {
-protected:
- TreePredicateFn Predicate;
-
-public:
- GenericInstructionPredicateMatcher(unsigned InsnVarID,
- TreePredicateFn Predicate)
- : InstructionPredicateMatcher(IPM_GenericPredicate, InsnVarID),
- Predicate(Predicate) {}
-
- static bool classof(const InstructionPredicateMatcher *P) {
- return P->getKind() == IPM_GenericPredicate;
- }
- bool isIdentical(const PredicateMatcher &B) const override {
- return InstructionPredicateMatcher::isIdentical(B) &&
- Predicate ==
- static_cast<const GenericInstructionPredicateMatcher &>(B)
- .Predicate;
- }
- void emitPredicateOpcodes(MatchTable &Table,
- RuleMatcher &Rule) const override {
- Table << MatchTable::Opcode("GIM_CheckCxxInsnPredicate")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::Comment("FnId")
- << MatchTable::NamedValue(getEnumNameForPredicate(Predicate))
- << MatchTable::LineBreak;
- }
-};
-
-/// Generates code to check for the absence of use of the result.
-// TODO? Generalize this to support checking for one use.
-class NoUsePredicateMatcher : public InstructionPredicateMatcher {
-public:
- NoUsePredicateMatcher(unsigned InsnVarID)
- : InstructionPredicateMatcher(IPM_NoUse, InsnVarID) {}
-
- static bool classof(const PredicateMatcher *P) {
- return P->getKind() == IPM_NoUse;
- }
-
- bool isIdentical(const PredicateMatcher &B) const override {
- return InstructionPredicateMatcher::isIdentical(B);
- }
-
- void emitPredicateOpcodes(MatchTable &Table,
- RuleMatcher &Rule) const override {
- Table << MatchTable::Opcode("GIM_CheckHasNoUse")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::LineBreak;
- }
-};
-
-/// Generates code to check that a set of predicates and operands match for a
-/// particular instruction.
-///
-/// Typical predicates include:
-/// * Has a specific opcode.
-/// * Has an nsw/nuw flag or doesn't.
-class InstructionMatcher final : public PredicateListMatcher<PredicateMatcher> {
-protected:
- typedef std::vector<std::unique_ptr<OperandMatcher>> OperandVec;
-
- RuleMatcher &Rule;
-
- /// The operands to match. All rendered operands must be present even if the
- /// condition is always true.
- OperandVec Operands;
- bool NumOperandsCheck = true;
-
- std::string SymbolicName;
- unsigned InsnVarID;
-
- /// PhysRegInputs - List list has an entry for each explicitly specified
- /// physreg input to the pattern. The first elt is the Register node, the
- /// second is the recorded slot number the input pattern match saved it in.
- SmallVector<std::pair<Record *, unsigned>, 2> PhysRegInputs;
-
-public:
- InstructionMatcher(RuleMatcher &Rule, StringRef SymbolicName,
- bool NumOpsCheck = true)
- : Rule(Rule), NumOperandsCheck(NumOpsCheck), SymbolicName(SymbolicName) {
- // We create a new instruction matcher.
- // Get a new ID for that instruction.
- InsnVarID = Rule.implicitlyDefineInsnVar(*this);
- }
-
- /// Construct a new instruction predicate and add it to the matcher.
- template <class Kind, class... Args>
- std::optional<Kind *> addPredicate(Args &&...args) {
- Predicates.emplace_back(
- std::make_unique<Kind>(getInsnVarID(), std::forward<Args>(args)...));
- return static_cast<Kind *>(Predicates.back().get());
- }
-
- RuleMatcher &getRuleMatcher() const { return Rule; }
-
- unsigned getInsnVarID() const { return InsnVarID; }
-
- /// Add an operand to the matcher.
- OperandMatcher &addOperand(unsigned OpIdx, const std::string &SymbolicName,
- unsigned AllocatedTemporariesBaseID) {
- Operands.emplace_back(new OperandMatcher(*this, OpIdx, SymbolicName,
- AllocatedTemporariesBaseID));
- if (!SymbolicName.empty())
- Rule.defineOperand(SymbolicName, *Operands.back());
-
- return *Operands.back();
- }
-
- OperandMatcher &getOperand(unsigned OpIdx) {
- auto I = llvm::find_if(Operands,
- [&OpIdx](const std::unique_ptr<OperandMatcher> &X) {
- return X->getOpIdx() == OpIdx;
- });
- if (I != Operands.end())
- return **I;
- llvm_unreachable("Failed to lookup operand");
- }
-
- OperandMatcher &addPhysRegInput(Record *Reg, unsigned OpIdx,
- unsigned TempOpIdx) {
- assert(SymbolicName.empty());
- OperandMatcher *OM = new OperandMatcher(*this, OpIdx, "", TempOpIdx);
- Operands.emplace_back(OM);
- Rule.definePhysRegOperand(Reg, *OM);
- PhysRegInputs.emplace_back(Reg, OpIdx);
- return *OM;
- }
-
- ArrayRef<std::pair<Record *, unsigned>> getPhysRegInputs() const {
- return PhysRegInputs;
- }
-
- StringRef getSymbolicName() const { return SymbolicName; }
- unsigned getNumOperands() const { return Operands.size(); }
- OperandVec::iterator operands_begin() { return Operands.begin(); }
- OperandVec::iterator operands_end() { return Operands.end(); }
- iterator_range<OperandVec::iterator> operands() {
- return make_range(operands_begin(), operands_end());
- }
- OperandVec::const_iterator operands_begin() const { return Operands.begin(); }
- OperandVec::const_iterator operands_end() const { return Operands.end(); }
- iterator_range<OperandVec::const_iterator> operands() const {
- return make_range(operands_begin(), operands_end());
- }
- bool operands_empty() const { return Operands.empty(); }
-
- void pop_front() { Operands.erase(Operands.begin()); }
-
- void optimize();
-
- /// Emit MatchTable opcodes that test whether the instruction named in
- /// InsnVarName matches all the predicates and all the operands.
- void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule) {
- if (NumOperandsCheck)
- InstructionNumOperandsMatcher(InsnVarID, getNumOperands())
- .emitPredicateOpcodes(Table, Rule);
-
- // First emit all instruction level predicates need to be verified before we
- // can verify operands.
- emitFilteredPredicateListOpcodes(
- [](const PredicateMatcher &P) {
- return !P.dependsOnOperands();
- }, Table, Rule);
-
- // Emit all operand constraints.
- for (const auto &Operand : Operands)
- Operand->emitPredicateOpcodes(Table, Rule);
-
- // All of the tablegen defined predicates should now be matched. Now emit
- // any custom predicates that rely on all generated checks.
- emitFilteredPredicateListOpcodes(
- [](const PredicateMatcher &P) {
- return P.dependsOnOperands();
- }, Table, Rule);
- }
-
- /// Compare the priority of this object and B.
- ///
- /// Returns true if this object is more important than B.
- bool isHigherPriorityThan(InstructionMatcher &B) {
- // Instruction matchers involving more operands have higher priority.
- if (Operands.size() > B.Operands.size())
- return true;
- if (Operands.size() < B.Operands.size())
- return false;
-
- for (auto &&P : zip(predicates(), B.predicates())) {
- auto L = static_cast<InstructionPredicateMatcher *>(std::get<0>(P).get());
- auto R = static_cast<InstructionPredicateMatcher *>(std::get<1>(P).get());
- if (L->isHigherPriorityThan(*R))
- return true;
- if (R->isHigherPriorityThan(*L))
- return false;
- }
-
- for (auto Operand : zip(Operands, B.Operands)) {
- if (std::get<0>(Operand)->isHigherPriorityThan(*std::get<1>(Operand)))
- return true;
- if (std::get<1>(Operand)->isHigherPriorityThan(*std::get<0>(Operand)))
- return false;
- }
-
- return false;
- };
-
- /// Report the maximum number of temporary operands needed by the instruction
- /// matcher.
- unsigned countRendererFns() {
- return std::accumulate(
- predicates().begin(), predicates().end(), 0,
- [](unsigned A,
- const std::unique_ptr<PredicateMatcher> &Predicate) {
- return A + Predicate->countRendererFns();
- }) +
- std::accumulate(
- Operands.begin(), Operands.end(), 0,
- [](unsigned A, const std::unique_ptr<OperandMatcher> &Operand) {
- return A + Operand->countRendererFns();
- });
- }
-
- InstructionOpcodeMatcher &getOpcodeMatcher() {
- for (auto &P : predicates())
- if (auto *OpMatcher = dyn_cast<InstructionOpcodeMatcher>(P.get()))
- return *OpMatcher;
- llvm_unreachable("Didn't find an opcode matcher");
- }
-
- bool isConstantInstruction() {
- return getOpcodeMatcher().isConstantInstruction();
- }
-
- StringRef getOpcode() { return getOpcodeMatcher().getOpcode(); }
-};
-
-StringRef RuleMatcher::getOpcode() const {
- return Matchers.front()->getOpcode();
-}
-
-unsigned RuleMatcher::getNumOperands() const {
- return Matchers.front()->getNumOperands();
-}
-
-LLTCodeGen RuleMatcher::getFirstConditionAsRootType() {
- InstructionMatcher &InsnMatcher = *Matchers.front();
- if (!InsnMatcher.predicates_empty())
- if (const auto *TM =
- dyn_cast<LLTOperandMatcher>(&**InsnMatcher.predicates_begin()))
- if (TM->getInsnVarID() == 0 && TM->getOpIdx() == 0)
- return TM->getTy();
- return {};
-}
-
-/// Generates code to check that the operand is a register defined by an
-/// instruction that matches the given instruction matcher.
-///
-/// For example, the pattern:
-/// (set $dst, (G_MUL (G_ADD $src1, $src2), $src3))
-/// would use an InstructionOperandMatcher for operand 1 of the G_MUL to match
-/// the:
-/// (G_ADD $src1, $src2)
-/// subpattern.
-class InstructionOperandMatcher : public OperandPredicateMatcher {
-protected:
- std::unique_ptr<InstructionMatcher> InsnMatcher;
-
-public:
- InstructionOperandMatcher(unsigned InsnVarID, unsigned OpIdx,
- RuleMatcher &Rule, StringRef SymbolicName,
- bool NumOpsCheck = true)
- : OperandPredicateMatcher(OPM_Instruction, InsnVarID, OpIdx),
- InsnMatcher(new InstructionMatcher(Rule, SymbolicName, NumOpsCheck)) {}
-
- static bool classof(const PredicateMatcher *P) {
- return P->getKind() == OPM_Instruction;
- }
-
- InstructionMatcher &getInsnMatcher() const { return *InsnMatcher; }
-
- void emitCaptureOpcodes(MatchTable &Table, RuleMatcher &Rule) const {
- const unsigned NewInsnVarID = InsnMatcher->getInsnVarID();
- Table << MatchTable::Opcode("GIM_RecordInsn")
- << MatchTable::Comment("DefineMI")
- << MatchTable::IntValue(NewInsnVarID) << MatchTable::Comment("MI")
- << MatchTable::IntValue(getInsnVarID())
- << MatchTable::Comment("OpIdx") << MatchTable::IntValue(getOpIdx())
- << MatchTable::Comment("MIs[" + llvm::to_string(NewInsnVarID) + "]")
- << MatchTable::LineBreak;
- }
-
- void emitPredicateOpcodes(MatchTable &Table,
- RuleMatcher &Rule) const override {
- emitCaptureOpcodes(Table, Rule);
- InsnMatcher->emitPredicateOpcodes(Table, Rule);
- }
-
- bool isHigherPriorityThan(const OperandPredicateMatcher &B) const override {
- if (OperandPredicateMatcher::isHigherPriorityThan(B))
- return true;
- if (B.OperandPredicateMatcher::isHigherPriorityThan(*this))
- return false;
-
- if (const InstructionOperandMatcher *BP =
- dyn_cast<InstructionOperandMatcher>(&B))
- if (InsnMatcher->isHigherPriorityThan(*BP->InsnMatcher))
- return true;
- return false;
- }
-
- /// Report the maximum number of temporary operands needed by the predicate
- /// matcher.
- unsigned countRendererFns() const override {
- return InsnMatcher->countRendererFns();
- }
-};
-
-void InstructionMatcher::optimize() {
- SmallVector<std::unique_ptr<PredicateMatcher>, 8> Stash;
- const auto &OpcMatcher = getOpcodeMatcher();
-
- Stash.push_back(predicates_pop_front());
- if (Stash.back().get() == &OpcMatcher) {
- if (NumOperandsCheck && OpcMatcher.isVariadicNumOperands())
- Stash.emplace_back(
- new InstructionNumOperandsMatcher(InsnVarID, getNumOperands()));
- NumOperandsCheck = false;
-
- for (auto &OM : Operands)
- for (auto &OP : OM->predicates())
- if (isa<IntrinsicIDOperandMatcher>(OP)) {
- Stash.push_back(std::move(OP));
- OM->eraseNullPredicates();
- break;
- }
- }
-
- if (InsnVarID > 0) {
- assert(!Operands.empty() && "Nested instruction is expected to def a vreg");
- for (auto &OP : Operands[0]->predicates())
- OP.reset();
- Operands[0]->eraseNullPredicates();
- }
- for (auto &OM : Operands) {
- for (auto &OP : OM->predicates())
- if (isa<LLTOperandMatcher>(OP))
- Stash.push_back(std::move(OP));
- OM->eraseNullPredicates();
- }
- while (!Stash.empty())
- prependPredicate(Stash.pop_back_val());
-}
-
-//===- Actions ------------------------------------------------------------===//
-class OperandRenderer {
-public:
- enum RendererKind {
- OR_Copy,
- OR_CopyOrAddZeroReg,
- OR_CopySubReg,
- OR_CopyPhysReg,
- OR_CopyConstantAsImm,
- OR_CopyFConstantAsFPImm,
- OR_Imm,
- OR_SubRegIndex,
- OR_Register,
- OR_TempRegister,
- OR_ComplexPattern,
- OR_Custom,
- OR_CustomOperand
- };
-
-protected:
- RendererKind Kind;
-
-public:
- OperandRenderer(RendererKind Kind) : Kind(Kind) {}
- virtual ~OperandRenderer() {}
-
- RendererKind getKind() const { return Kind; }
-
- virtual void emitRenderOpcodes(MatchTable &Table,
- RuleMatcher &Rule) const = 0;
-};
-
-/// A CopyRenderer emits code to copy a single operand from an existing
-/// instruction to the one being built.
-class CopyRenderer : public OperandRenderer {
-protected:
- unsigned NewInsnID;
- /// The name of the operand.
- const StringRef SymbolicName;
-
-public:
- CopyRenderer(unsigned NewInsnID, StringRef SymbolicName)
- : OperandRenderer(OR_Copy), NewInsnID(NewInsnID),
- SymbolicName(SymbolicName) {
- assert(!SymbolicName.empty() && "Cannot copy from an unspecified source");
- }
-
- static bool classof(const OperandRenderer *R) {
- return R->getKind() == OR_Copy;
- }
-
- StringRef getSymbolicName() const { return SymbolicName; }
-
- void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
- const OperandMatcher &Operand = Rule.getOperandMatcher(SymbolicName);
- unsigned OldInsnVarID = Rule.getInsnVarID(Operand.getInstructionMatcher());
- Table << MatchTable::Opcode("GIR_Copy") << MatchTable::Comment("NewInsnID")
- << MatchTable::IntValue(NewInsnID) << MatchTable::Comment("OldInsnID")
- << MatchTable::IntValue(OldInsnVarID) << MatchTable::Comment("OpIdx")
- << MatchTable::IntValue(Operand.getOpIdx())
- << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
- }
-};
-
-/// A CopyRenderer emits code to copy a virtual register to a specific physical
-/// register.
-class CopyPhysRegRenderer : public OperandRenderer {
-protected:
- unsigned NewInsnID;
- Record *PhysReg;
-
-public:
- CopyPhysRegRenderer(unsigned NewInsnID, Record *Reg)
- : OperandRenderer(OR_CopyPhysReg), NewInsnID(NewInsnID),
- PhysReg(Reg) {
- assert(PhysReg);
- }
-
- static bool classof(const OperandRenderer *R) {
- return R->getKind() == OR_CopyPhysReg;
- }
-
- Record *getPhysReg() const { return PhysReg; }
-
- void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
- const OperandMatcher &Operand = Rule.getPhysRegOperandMatcher(PhysReg);
- unsigned OldInsnVarID = Rule.getInsnVarID(Operand.getInstructionMatcher());
- Table << MatchTable::Opcode("GIR_Copy") << MatchTable::Comment("NewInsnID")
- << MatchTable::IntValue(NewInsnID) << MatchTable::Comment("OldInsnID")
- << MatchTable::IntValue(OldInsnVarID) << MatchTable::Comment("OpIdx")
- << MatchTable::IntValue(Operand.getOpIdx())
- << MatchTable::Comment(PhysReg->getName())
- << MatchTable::LineBreak;
- }
-};
-
-/// A CopyOrAddZeroRegRenderer emits code to copy a single operand from an
-/// existing instruction to the one being built. If the operand turns out to be
-/// a 'G_CONSTANT 0' then it replaces the operand with a zero register.
-class CopyOrAddZeroRegRenderer : public OperandRenderer {
-protected:
- unsigned NewInsnID;
- /// The name of the operand.
- const StringRef SymbolicName;
- const Record *ZeroRegisterDef;
-
-public:
- CopyOrAddZeroRegRenderer(unsigned NewInsnID,
- StringRef SymbolicName, Record *ZeroRegisterDef)
- : OperandRenderer(OR_CopyOrAddZeroReg), NewInsnID(NewInsnID),
- SymbolicName(SymbolicName), ZeroRegisterDef(ZeroRegisterDef) {
- assert(!SymbolicName.empty() && "Cannot copy from an unspecified source");
- }
-
- static bool classof(const OperandRenderer *R) {
- return R->getKind() == OR_CopyOrAddZeroReg;
- }
-
- StringRef getSymbolicName() const { return SymbolicName; }
-
- void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
- const OperandMatcher &Operand = Rule.getOperandMatcher(SymbolicName);
- unsigned OldInsnVarID = Rule.getInsnVarID(Operand.getInstructionMatcher());
- Table << MatchTable::Opcode("GIR_CopyOrAddZeroReg")
- << MatchTable::Comment("NewInsnID") << MatchTable::IntValue(NewInsnID)
- << MatchTable::Comment("OldInsnID")
- << MatchTable::IntValue(OldInsnVarID) << MatchTable::Comment("OpIdx")
- << MatchTable::IntValue(Operand.getOpIdx())
- << MatchTable::NamedValue(
- (ZeroRegisterDef->getValue("Namespace")
- ? ZeroRegisterDef->getValueAsString("Namespace")
- : ""),
- ZeroRegisterDef->getName())
- << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
- }
-};
-
-/// A CopyConstantAsImmRenderer emits code to render a G_CONSTANT instruction to
-/// an extended immediate operand.
-class CopyConstantAsImmRenderer : public OperandRenderer {
-protected:
- unsigned NewInsnID;
- /// The name of the operand.
- const std::string SymbolicName;
- bool Signed;
-
-public:
- CopyConstantAsImmRenderer(unsigned NewInsnID, StringRef SymbolicName)
- : OperandRenderer(OR_CopyConstantAsImm), NewInsnID(NewInsnID),
- SymbolicName(SymbolicName), Signed(true) {}
-
- static bool classof(const OperandRenderer *R) {
- return R->getKind() == OR_CopyConstantAsImm;
- }
-
- StringRef getSymbolicName() const { return SymbolicName; }
-
- void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
- InstructionMatcher &InsnMatcher = Rule.getInstructionMatcher(SymbolicName);
- unsigned OldInsnVarID = Rule.getInsnVarID(InsnMatcher);
- Table << MatchTable::Opcode(Signed ? "GIR_CopyConstantAsSImm"
- : "GIR_CopyConstantAsUImm")
- << MatchTable::Comment("NewInsnID") << MatchTable::IntValue(NewInsnID)
- << MatchTable::Comment("OldInsnID")
- << MatchTable::IntValue(OldInsnVarID)
- << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
- }
-};
-
-/// A CopyFConstantAsFPImmRenderer emits code to render a G_FCONSTANT
-/// instruction to an extended immediate operand.
-class CopyFConstantAsFPImmRenderer : public OperandRenderer {
-protected:
- unsigned NewInsnID;
- /// The name of the operand.
- const std::string SymbolicName;
-
-public:
- CopyFConstantAsFPImmRenderer(unsigned NewInsnID, StringRef SymbolicName)
- : OperandRenderer(OR_CopyFConstantAsFPImm), NewInsnID(NewInsnID),
- SymbolicName(SymbolicName) {}
-
- static bool classof(const OperandRenderer *R) {
- return R->getKind() == OR_CopyFConstantAsFPImm;
- }
-
- StringRef getSymbolicName() const { return SymbolicName; }
-
- void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
- InstructionMatcher &InsnMatcher = Rule.getInstructionMatcher(SymbolicName);
- unsigned OldInsnVarID = Rule.getInsnVarID(InsnMatcher);
- Table << MatchTable::Opcode("GIR_CopyFConstantAsFPImm")
- << MatchTable::Comment("NewInsnID") << MatchTable::IntValue(NewInsnID)
- << MatchTable::Comment("OldInsnID")
- << MatchTable::IntValue(OldInsnVarID)
- << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
- }
-};
-
-/// A CopySubRegRenderer emits code to copy a single register operand from an
-/// existing instruction to the one being built and indicate that only a
-/// subregister should be copied.
-class CopySubRegRenderer : public OperandRenderer {
-protected:
- unsigned NewInsnID;
- /// The name of the operand.
- const StringRef SymbolicName;
- /// The subregister to extract.
- const CodeGenSubRegIndex *SubReg;
-
-public:
- CopySubRegRenderer(unsigned NewInsnID, StringRef SymbolicName,
- const CodeGenSubRegIndex *SubReg)
- : OperandRenderer(OR_CopySubReg), NewInsnID(NewInsnID),
- SymbolicName(SymbolicName), SubReg(SubReg) {}
-
- static bool classof(const OperandRenderer *R) {
- return R->getKind() == OR_CopySubReg;
- }
-
- StringRef getSymbolicName() const { return SymbolicName; }
-
- void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
- const OperandMatcher &Operand = Rule.getOperandMatcher(SymbolicName);
- unsigned OldInsnVarID = Rule.getInsnVarID(Operand.getInstructionMatcher());
- Table << MatchTable::Opcode("GIR_CopySubReg")
- << MatchTable::Comment("NewInsnID") << MatchTable::IntValue(NewInsnID)
- << MatchTable::Comment("OldInsnID")
- << MatchTable::IntValue(OldInsnVarID) << MatchTable::Comment("OpIdx")
- << MatchTable::IntValue(Operand.getOpIdx())
- << MatchTable::Comment("SubRegIdx")
- << MatchTable::IntValue(SubReg->EnumValue)
- << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
- }
-};
-
-/// Adds a specific physical register to the instruction being built.
-/// This is typically useful for WZR/XZR on AArch64.
-class AddRegisterRenderer : public OperandRenderer {
-protected:
- unsigned InsnID;
- const Record *RegisterDef;
- bool IsDef;
- const CodeGenTarget &Target;
-
-public:
- AddRegisterRenderer(unsigned InsnID, const CodeGenTarget &Target,
- const Record *RegisterDef, bool IsDef = false)
- : OperandRenderer(OR_Register), InsnID(InsnID), RegisterDef(RegisterDef),
- IsDef(IsDef), Target(Target) {}
-
- static bool classof(const OperandRenderer *R) {
- return R->getKind() == OR_Register;
- }
-
- void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
- Table << MatchTable::Opcode("GIR_AddRegister")
- << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID);
- if (RegisterDef->getName() != "zero_reg") {
- Table << MatchTable::NamedValue(
- (RegisterDef->getValue("Namespace")
- ? RegisterDef->getValueAsString("Namespace")
- : ""),
- RegisterDef->getName());
- } else {
- Table << MatchTable::NamedValue(Target.getRegNamespace(), "NoRegister");
- }
- Table << MatchTable::Comment("AddRegisterRegFlags");
-
- // TODO: This is encoded as a 64-bit element, but only 16 or 32-bits are
- // really needed for a physical register reference. We can pack the
- // register and flags in a single field.
- if (IsDef)
- Table << MatchTable::NamedValue("RegState::Define");
- else
- Table << MatchTable::IntValue(0);
- Table << MatchTable::LineBreak;
- }
-};
-
-/// Adds a specific temporary virtual register to the instruction being built.
-/// This is used to chain instructions together when emitting multiple
-/// instructions.
-class TempRegRenderer : public OperandRenderer {
-protected:
- unsigned InsnID;
- unsigned TempRegID;
- const CodeGenSubRegIndex *SubRegIdx;
- bool IsDef;
- bool IsDead;
-
-public:
- TempRegRenderer(unsigned InsnID, unsigned TempRegID, bool IsDef = false,
- const CodeGenSubRegIndex *SubReg = nullptr,
- bool IsDead = false)
- : OperandRenderer(OR_Register), InsnID(InsnID), TempRegID(TempRegID),
- SubRegIdx(SubReg), IsDef(IsDef), IsDead(IsDead) {}
-
- static bool classof(const OperandRenderer *R) {
- return R->getKind() == OR_TempRegister;
- }
-
- void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
- if (SubRegIdx) {
- assert(!IsDef);
- Table << MatchTable::Opcode("GIR_AddTempSubRegister");
- } else
- Table << MatchTable::Opcode("GIR_AddTempRegister");
-
- Table << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
- << MatchTable::Comment("TempRegID") << MatchTable::IntValue(TempRegID)
- << MatchTable::Comment("TempRegFlags");
-
- if (IsDef) {
- SmallString<32> RegFlags;
- RegFlags += "RegState::Define";
- if (IsDead)
- RegFlags += "|RegState::Dead";
- Table << MatchTable::NamedValue(RegFlags);
- } else
- Table << MatchTable::IntValue(0);
-
- if (SubRegIdx)
- Table << MatchTable::NamedValue(SubRegIdx->getQualifiedName());
- Table << MatchTable::LineBreak;
- }
-};
-
-/// Adds a specific immediate to the instruction being built.
-class ImmRenderer : public OperandRenderer {
-protected:
- unsigned InsnID;
- int64_t Imm;
-
-public:
- ImmRenderer(unsigned InsnID, int64_t Imm)
- : OperandRenderer(OR_Imm), InsnID(InsnID), Imm(Imm) {}
-
- static bool classof(const OperandRenderer *R) {
- return R->getKind() == OR_Imm;
- }
-
- void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
- Table << MatchTable::Opcode("GIR_AddImm") << MatchTable::Comment("InsnID")
- << MatchTable::IntValue(InsnID) << MatchTable::Comment("Imm")
- << MatchTable::IntValue(Imm) << MatchTable::LineBreak;
- }
-};
-
-/// Adds an enum value for a subreg index to the instruction being built.
-class SubRegIndexRenderer : public OperandRenderer {
-protected:
- unsigned InsnID;
- const CodeGenSubRegIndex *SubRegIdx;
-
-public:
- SubRegIndexRenderer(unsigned InsnID, const CodeGenSubRegIndex *SRI)
- : OperandRenderer(OR_SubRegIndex), InsnID(InsnID), SubRegIdx(SRI) {}
-
- static bool classof(const OperandRenderer *R) {
- return R->getKind() == OR_SubRegIndex;
- }
-
- void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
- Table << MatchTable::Opcode("GIR_AddImm") << MatchTable::Comment("InsnID")
- << MatchTable::IntValue(InsnID) << MatchTable::Comment("SubRegIndex")
- << MatchTable::IntValue(SubRegIdx->EnumValue)
- << MatchTable::LineBreak;
- }
-};
-
-/// Adds operands by calling a renderer function supplied by the ComplexPattern
-/// matcher function.
-class RenderComplexPatternOperand : public OperandRenderer {
-private:
- unsigned InsnID;
- const Record &TheDef;
- /// The name of the operand.
- const StringRef SymbolicName;
- /// The renderer number. This must be unique within a rule since it's used to
- /// identify a temporary variable to hold the renderer function.
- unsigned RendererID;
- /// When provided, this is the suboperand of the ComplexPattern operand to
- /// render. Otherwise all the suboperands will be rendered.
- std::optional<unsigned> SubOperand;
-
- unsigned getNumOperands() const {
- return TheDef.getValueAsDag("Operands")->getNumArgs();
- }
-
-public:
- RenderComplexPatternOperand(unsigned InsnID, const Record &TheDef,
- StringRef SymbolicName, unsigned RendererID,
- std::optional<unsigned> SubOperand = std::nullopt)
- : OperandRenderer(OR_ComplexPattern), InsnID(InsnID), TheDef(TheDef),
- SymbolicName(SymbolicName), RendererID(RendererID),
- SubOperand(SubOperand) {}
-
- static bool classof(const OperandRenderer *R) {
- return R->getKind() == OR_ComplexPattern;
- }
-
- void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
- Table << MatchTable::Opcode(SubOperand ? "GIR_ComplexSubOperandRenderer"
- : "GIR_ComplexRenderer")
- << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
- << MatchTable::Comment("RendererID")
- << MatchTable::IntValue(RendererID);
- if (SubOperand)
- Table << MatchTable::Comment("SubOperand")
- << MatchTable::IntValue(*SubOperand);
- Table << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
- }
-};
-
-class CustomRenderer : public OperandRenderer {
-protected:
- unsigned InsnID;
- const Record &Renderer;
- /// The name of the operand.
- const std::string SymbolicName;
-
-public:
- CustomRenderer(unsigned InsnID, const Record &Renderer,
- StringRef SymbolicName)
- : OperandRenderer(OR_Custom), InsnID(InsnID), Renderer(Renderer),
- SymbolicName(SymbolicName) {}
-
- static bool classof(const OperandRenderer *R) {
- return R->getKind() == OR_Custom;
- }
-
- void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
- InstructionMatcher &InsnMatcher = Rule.getInstructionMatcher(SymbolicName);
- unsigned OldInsnVarID = Rule.getInsnVarID(InsnMatcher);
- Table << MatchTable::Opcode("GIR_CustomRenderer")
- << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
- << MatchTable::Comment("OldInsnID")
- << MatchTable::IntValue(OldInsnVarID)
- << MatchTable::Comment("Renderer")
- << MatchTable::NamedValue(
- "GICR_" + Renderer.getValueAsString("RendererFn").str())
- << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
- }
-};
-
-class CustomOperandRenderer : public OperandRenderer {
-protected:
- unsigned InsnID;
- const Record &Renderer;
- /// The name of the operand.
- const std::string SymbolicName;
-
-public:
- CustomOperandRenderer(unsigned InsnID, const Record &Renderer,
- StringRef SymbolicName)
- : OperandRenderer(OR_CustomOperand), InsnID(InsnID), Renderer(Renderer),
- SymbolicName(SymbolicName) {}
-
- static bool classof(const OperandRenderer *R) {
- return R->getKind() == OR_CustomOperand;
- }
-
- void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
- const OperandMatcher &OpdMatcher = Rule.getOperandMatcher(SymbolicName);
- Table << MatchTable::Opcode("GIR_CustomOperandRenderer")
- << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
- << MatchTable::Comment("OldInsnID")
- << MatchTable::IntValue(OpdMatcher.getInsnVarID())
- << MatchTable::Comment("OpIdx")
- << MatchTable::IntValue(OpdMatcher.getOpIdx())
- << MatchTable::Comment("OperandRenderer")
- << MatchTable::NamedValue(
- "GICR_" + Renderer.getValueAsString("RendererFn").str())
- << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
- }
-};
-
-/// An action taken when all Matcher predicates succeeded for a parent rule.
-///
-/// Typical actions include:
-/// * Changing the opcode of an instruction.
-/// * Adding an operand to an instruction.
-class MatchAction {
-public:
- virtual ~MatchAction() {}
-
- /// Emit the MatchTable opcodes to implement the action.
- virtual void emitActionOpcodes(MatchTable &Table,
- RuleMatcher &Rule) const = 0;
-};
-
-/// Generates a comment describing the matched rule being acted upon.
-class DebugCommentAction : public MatchAction {
-private:
- std::string S;
-
-public:
- DebugCommentAction(StringRef S) : S(std::string(S)) {}
-
- void emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
- Table << MatchTable::Comment(S) << MatchTable::LineBreak;
- }
-};
-
-/// Generates code to build an instruction or mutate an existing instruction
-/// into the desired instruction when this is possible.
-class BuildMIAction : public MatchAction {
-private:
- unsigned InsnID;
- const CodeGenInstruction *I;
- InstructionMatcher *Matched;
- std::vector<std::unique_ptr<OperandRenderer>> OperandRenderers;
-
- /// True if the instruction can be built solely by mutating the opcode.
- bool canMutate(RuleMatcher &Rule, const InstructionMatcher *Insn) const {
- if (!Insn)
- return false;
-
- if (OperandRenderers.size() != Insn->getNumOperands())
- return false;
-
- for (const auto &Renderer : enumerate(OperandRenderers)) {
- if (const auto *Copy = dyn_cast<CopyRenderer>(&*Renderer.value())) {
- const OperandMatcher &OM = Rule.getOperandMatcher(Copy->getSymbolicName());
- if (Insn != &OM.getInstructionMatcher() ||
- OM.getOpIdx() != Renderer.index())
- return false;
- } else
- return false;
- }
-
- return true;
- }
-
-public:
- BuildMIAction(unsigned InsnID, const CodeGenInstruction *I)
- : InsnID(InsnID), I(I), Matched(nullptr) {}
-
- unsigned getInsnID() const { return InsnID; }
- const CodeGenInstruction *getCGI() const { return I; }
-
- void chooseInsnToMutate(RuleMatcher &Rule) {
- for (auto *MutateCandidate : Rule.mutatable_insns()) {
- if (canMutate(Rule, MutateCandidate)) {
- // Take the first one we're offered that we're able to mutate.
- Rule.reserveInsnMatcherForMutation(MutateCandidate);
- Matched = MutateCandidate;
- return;
- }
- }
- }
-
- template <class Kind, class... Args>
- Kind &addRenderer(Args&&... args) {
- OperandRenderers.emplace_back(
- std::make_unique<Kind>(InsnID, std::forward<Args>(args)...));
- return *static_cast<Kind *>(OperandRenderers.back().get());
- }
-
- void emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
- if (Matched) {
- assert(canMutate(Rule, Matched) &&
- "Arranged to mutate an insn that isn't mutatable");
-
- unsigned RecycleInsnID = Rule.getInsnVarID(*Matched);
- Table << MatchTable::Opcode("GIR_MutateOpcode")
- << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
- << MatchTable::Comment("RecycleInsnID")
- << MatchTable::IntValue(RecycleInsnID)
- << MatchTable::Comment("Opcode")
- << MatchTable::NamedValue(I->Namespace, I->TheDef->getName())
- << MatchTable::LineBreak;
-
- if (!I->ImplicitDefs.empty() || !I->ImplicitUses.empty()) {
- for (auto *Def : I->ImplicitDefs) {
- auto Namespace = Def->getValue("Namespace")
- ? Def->getValueAsString("Namespace")
- : "";
- Table << MatchTable::Opcode("GIR_AddImplicitDef")
- << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
- << MatchTable::NamedValue(Namespace, Def->getName())
- << MatchTable::LineBreak;
- }
- for (auto *Use : I->ImplicitUses) {
- auto Namespace = Use->getValue("Namespace")
- ? Use->getValueAsString("Namespace")
- : "";
- Table << MatchTable::Opcode("GIR_AddImplicitUse")
- << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
- << MatchTable::NamedValue(Namespace, Use->getName())
- << MatchTable::LineBreak;
- }
- }
- return;
- }
-
- // TODO: Simple permutation looks like it could be almost as common as
- // mutation due to commutative operations.
-
- Table << MatchTable::Opcode("GIR_BuildMI") << MatchTable::Comment("InsnID")
- << MatchTable::IntValue(InsnID) << MatchTable::Comment("Opcode")
- << MatchTable::NamedValue(I->Namespace, I->TheDef->getName())
- << MatchTable::LineBreak;
- for (const auto &Renderer : OperandRenderers)
- Renderer->emitRenderOpcodes(Table, Rule);
-
- if (I->mayLoad || I->mayStore) {
- Table << MatchTable::Opcode("GIR_MergeMemOperands")
- << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
- << MatchTable::Comment("MergeInsnID's");
- // Emit the ID's for all the instructions that are matched by this rule.
- // TODO: Limit this to matched instructions that mayLoad/mayStore or have
- // some other means of having a memoperand. Also limit this to
- // emitted instructions that expect to have a memoperand too. For
- // example, (G_SEXT (G_LOAD x)) that results in separate load and
- // sign-extend instructions shouldn't put the memoperand on the
- // sign-extend since it has no effect there.
- std::vector<unsigned> MergeInsnIDs;
- for (const auto &IDMatcherPair : Rule.defined_insn_vars())
- MergeInsnIDs.push_back(IDMatcherPair.second);
- llvm::sort(MergeInsnIDs);
- for (const auto &MergeInsnID : MergeInsnIDs)
- Table << MatchTable::IntValue(MergeInsnID);
- Table << MatchTable::NamedValue("GIU_MergeMemOperands_EndOfList")
- << MatchTable::LineBreak;
- }
-
- // FIXME: This is a hack but it's sufficient for ISel. We'll need to do
- // better for combines. Particularly when there are multiple match
- // roots.
- if (InsnID == 0)
- Table << MatchTable::Opcode("GIR_EraseFromParent")
- << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
- << MatchTable::LineBreak;
- }
-};
-
-/// Generates code to constrain the operands of an output instruction to the
-/// register classes specified by the definition of that instruction.
-class ConstrainOperandsToDefinitionAction : public MatchAction {
- unsigned InsnID;
-
-public:
- ConstrainOperandsToDefinitionAction(unsigned InsnID) : InsnID(InsnID) {}
-
- void emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
- Table << MatchTable::Opcode("GIR_ConstrainSelectedInstOperands")
- << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
- << MatchTable::LineBreak;
- }
-};
-
-/// Generates code to constrain the specified operand of an output instruction
-/// to the specified register class.
-class ConstrainOperandToRegClassAction : public MatchAction {
- unsigned InsnID;
- unsigned OpIdx;
- const CodeGenRegisterClass &RC;
-
-public:
- ConstrainOperandToRegClassAction(unsigned InsnID, unsigned OpIdx,
- const CodeGenRegisterClass &RC)
- : InsnID(InsnID), OpIdx(OpIdx), RC(RC) {}
-
- void emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
- Table << MatchTable::Opcode("GIR_ConstrainOperandRC")
- << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
- << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx)
- << MatchTable::NamedValue(RC.getQualifiedName() + "RegClassID")
- << MatchTable::LineBreak;
- }
-};
-
-/// Generates code to create a temporary register which can be used to chain
-/// instructions together.
-class MakeTempRegisterAction : public MatchAction {
-private:
- LLTCodeGen Ty;
- unsigned TempRegID;
-
-public:
- MakeTempRegisterAction(const LLTCodeGen &Ty, unsigned TempRegID)
- : Ty(Ty), TempRegID(TempRegID) {
- KnownTypes.insert(Ty);
- }
-
- void emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
- Table << MatchTable::Opcode("GIR_MakeTempReg")
- << MatchTable::Comment("TempRegID") << MatchTable::IntValue(TempRegID)
- << MatchTable::Comment("TypeID")
- << MatchTable::NamedValue(Ty.getCxxEnumValue())
- << MatchTable::LineBreak;
- }
-};
-
-InstructionMatcher &RuleMatcher::addInstructionMatcher(StringRef SymbolicName) {
- Matchers.emplace_back(new InstructionMatcher(*this, SymbolicName));
- MutatableInsns.insert(Matchers.back().get());
- return *Matchers.back();
-}
-
-void RuleMatcher::addRequiredFeature(Record *Feature) {
- RequiredFeatures.push_back(Feature);
-}
-
-const std::vector<Record *> &RuleMatcher::getRequiredFeatures() const {
- return RequiredFeatures;
-}
-
-// Emplaces an action of the specified Kind at the end of the action list.
-//
-// Returns a reference to the newly created action.
-//
-// Like std::vector::emplace_back(), may invalidate all iterators if the new
-// size exceeds the capacity. Otherwise, only invalidates the past-the-end
-// iterator.
-template <class Kind, class... Args>
-Kind &RuleMatcher::addAction(Args &&... args) {
- Actions.emplace_back(std::make_unique<Kind>(std::forward<Args>(args)...));
- return *static_cast<Kind *>(Actions.back().get());
-}
-
-// Emplaces an action of the specified Kind before the given insertion point.
-//
-// Returns an iterator pointing at the newly created instruction.
-//
-// Like std::vector::insert(), may invalidate all iterators if the new size
-// exceeds the capacity. Otherwise, only invalidates the iterators from the
-// insertion point onwards.
-template <class Kind, class... Args>
-action_iterator RuleMatcher::insertAction(action_iterator InsertPt,
- Args &&... args) {
- return Actions.emplace(InsertPt,
- std::make_unique<Kind>(std::forward<Args>(args)...));
-}
-
-unsigned RuleMatcher::implicitlyDefineInsnVar(InstructionMatcher &Matcher) {
- unsigned NewInsnVarID = NextInsnVarID++;
- InsnVariableIDs[&Matcher] = NewInsnVarID;
- return NewInsnVarID;
-}
-
-unsigned RuleMatcher::getInsnVarID(InstructionMatcher &InsnMatcher) const {
- const auto &I = InsnVariableIDs.find(&InsnMatcher);
- if (I != InsnVariableIDs.end())
- return I->second;
- llvm_unreachable("Matched Insn was not captured in a local variable");
-}
-
-void RuleMatcher::defineOperand(StringRef SymbolicName, OperandMatcher &OM) {
- if (DefinedOperands.find(SymbolicName) == DefinedOperands.end()) {
- DefinedOperands[SymbolicName] = &OM;
- return;
- }
-
- // If the operand is already defined, then we must ensure both references in
- // the matcher have the exact same node.
- OM.addPredicate<SameOperandMatcher>(
- OM.getSymbolicName(), getOperandMatcher(OM.getSymbolicName()).getOpIdx());
-}
-
-void RuleMatcher::definePhysRegOperand(Record *Reg, OperandMatcher &OM) {
- if (PhysRegOperands.find(Reg) == PhysRegOperands.end()) {
- PhysRegOperands[Reg] = &OM;
- return;
- }
-}
-
-InstructionMatcher &
-RuleMatcher::getInstructionMatcher(StringRef SymbolicName) const {
- for (const auto &I : InsnVariableIDs)
- if (I.first->getSymbolicName() == SymbolicName)
- return *I.first;
- llvm_unreachable(
- ("Failed to lookup instruction " + SymbolicName).str().c_str());
-}
-
-const OperandMatcher &
-RuleMatcher::getPhysRegOperandMatcher(Record *Reg) const {
- const auto &I = PhysRegOperands.find(Reg);
-
- if (I == PhysRegOperands.end()) {
- PrintFatalError(SrcLoc, "Register " + Reg->getName() +
- " was not declared in matcher");
- }
-
- return *I->second;
-}
-
-const OperandMatcher &
-RuleMatcher::getOperandMatcher(StringRef Name) const {
- const auto &I = DefinedOperands.find(Name);
-
- if (I == DefinedOperands.end())
- PrintFatalError(SrcLoc, "Operand " + Name + " was not declared in matcher");
-
- return *I->second;
-}
-
-void RuleMatcher::emit(MatchTable &Table) {
- if (Matchers.empty())
- llvm_unreachable("Unexpected empty matcher!");
-
- // The representation supports rules that require multiple roots such as:
- // %ptr(p0) = ...
- // %elt0(s32) = G_LOAD %ptr
- // %1(p0) = G_ADD %ptr, 4
- // %elt1(s32) = G_LOAD p0 %1
- // which could be usefully folded into:
- // %ptr(p0) = ...
- // %elt0(s32), %elt1(s32) = TGT_LOAD_PAIR %ptr
- // on some targets but we don't need to make use of that yet.
- assert(Matchers.size() == 1 && "Cannot handle multi-root matchers yet");
-
- unsigned LabelID = Table.allocateLabelID();
- Table << MatchTable::Opcode("GIM_Try", +1)
- << MatchTable::Comment("On fail goto")
- << MatchTable::JumpTarget(LabelID)
- << MatchTable::Comment(("Rule ID " + Twine(RuleID) + " //").str())
- << MatchTable::LineBreak;
-
- if (!RequiredFeatures.empty()) {
- Table << MatchTable::Opcode("GIM_CheckFeatures")
- << MatchTable::NamedValue(getNameForFeatureBitset(RequiredFeatures))
- << MatchTable::LineBreak;
- }
-
- Matchers.front()->emitPredicateOpcodes(Table, *this);
-
- // We must also check if it's safe to fold the matched instructions.
- if (InsnVariableIDs.size() >= 2) {
- // Invert the map to create stable ordering (by var names)
- SmallVector<unsigned, 2> InsnIDs;
- for (const auto &Pair : InsnVariableIDs) {
- // Skip the root node since it isn't moving anywhere. Everything else is
- // sinking to meet it.
- if (Pair.first == Matchers.front().get())
- continue;
-
- InsnIDs.push_back(Pair.second);
- }
- llvm::sort(InsnIDs);
-
- for (const auto &InsnID : InsnIDs) {
- // Reject the difficult cases until we have a more accurate check.
- Table << MatchTable::Opcode("GIM_CheckIsSafeToFold")
- << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
- << MatchTable::LineBreak;
-
- // FIXME: Emit checks to determine it's _actually_ safe to fold and/or
- // account for unsafe cases.
- //
- // Example:
- // MI1--> %0 = ...
- // %1 = ... %0
- // MI0--> %2 = ... %0
- // It's not safe to erase MI1. We currently handle this by not
- // erasing %0 (even when it's dead).
- //
- // Example:
- // MI1--> %0 = load volatile @a
- // %1 = load volatile @a
- // MI0--> %2 = ... %0
- // It's not safe to sink %0's def past %1. We currently handle
- // this by rejecting all loads.
- //
- // Example:
- // MI1--> %0 = load @a
- // %1 = store @a
- // MI0--> %2 = ... %0
- // It's not safe to sink %0's def past %1. We currently handle
- // this by rejecting all loads.
- //
- // Example:
- // G_CONDBR %cond, @BB1
- // BB0:
- // MI1--> %0 = load @a
- // G_BR @BB1
- // BB1:
- // MI0--> %2 = ... %0
- // It's not always safe to sink %0 across control flow. In this
- // case it may introduce a memory fault. We currentl handle this
- // by rejecting all loads.
- }
- }
-
- for (const auto &PM : EpilogueMatchers)
- PM->emitPredicateOpcodes(Table, *this);
-
- for (const auto &MA : Actions)
- MA->emitActionOpcodes(Table, *this);
-
- if (Table.isWithCoverage())
- Table << MatchTable::Opcode("GIR_Coverage") << MatchTable::IntValue(RuleID)
- << MatchTable::LineBreak;
- else
- Table << MatchTable::Comment(("GIR_Coverage, " + Twine(RuleID) + ",").str())
- << MatchTable::LineBreak;
-
- Table << MatchTable::Opcode("GIR_Done", -1) << MatchTable::LineBreak
- << MatchTable::Label(LabelID);
- ++NumPatternEmitted;
-}
-
-bool RuleMatcher::isHigherPriorityThan(const RuleMatcher &B) const {
- // Rules involving more match roots have higher priority.
- if (Matchers.size() > B.Matchers.size())
- return true;
- if (Matchers.size() < B.Matchers.size())
- return false;
-
- for (auto Matcher : zip(Matchers, B.Matchers)) {
- if (std::get<0>(Matcher)->isHigherPriorityThan(*std::get<1>(Matcher)))
- return true;
- if (std::get<1>(Matcher)->isHigherPriorityThan(*std::get<0>(Matcher)))
- return false;
- }
-
- return false;
-}
-
-unsigned RuleMatcher::countRendererFns() const {
- return std::accumulate(
- Matchers.begin(), Matchers.end(), 0,
- [](unsigned A, const std::unique_ptr<InstructionMatcher> &Matcher) {
- return A + Matcher->countRendererFns();
- });
-}
-
-bool OperandPredicateMatcher::isHigherPriorityThan(
- const OperandPredicateMatcher &B) const {
- // Generally speaking, an instruction is more important than an Int or a
- // LiteralInt because it can cover more nodes but theres an exception to
- // this. G_CONSTANT's are less important than either of those two because they
- // are more permissive.
-
- const InstructionOperandMatcher *AOM =
- dyn_cast<InstructionOperandMatcher>(this);
- const InstructionOperandMatcher *BOM =
- dyn_cast<InstructionOperandMatcher>(&B);
- bool AIsConstantInsn = AOM && AOM->getInsnMatcher().isConstantInstruction();
- bool BIsConstantInsn = BOM && BOM->getInsnMatcher().isConstantInstruction();
-
- if (AOM && BOM) {
- // The relative priorities between a G_CONSTANT and any other instruction
- // don't actually matter but this code is needed to ensure a strict weak
- // ordering. This is particularly important on Windows where the rules will
- // be incorrectly sorted without it.
- if (AIsConstantInsn != BIsConstantInsn)
- return AIsConstantInsn < BIsConstantInsn;
- return false;
- }
-
- if (AOM && AIsConstantInsn && (B.Kind == OPM_Int || B.Kind == OPM_LiteralInt))
- return false;
- if (BOM && BIsConstantInsn && (Kind == OPM_Int || Kind == OPM_LiteralInt))
- return true;
-
- return Kind < B.Kind;
-}
-
-void SameOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
- RuleMatcher &Rule) const {
- const OperandMatcher &OtherOM = Rule.getOperandMatcher(MatchingName);
- unsigned OtherInsnVarID = Rule.getInsnVarID(OtherOM.getInstructionMatcher());
- assert(OtherInsnVarID == OtherOM.getInstructionMatcher().getInsnVarID());
-
- Table << MatchTable::Opcode("GIM_CheckIsSameOperand")
- << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
- << MatchTable::Comment("OpIdx") << MatchTable::IntValue(OpIdx)
- << MatchTable::Comment("OtherMI")
- << MatchTable::IntValue(OtherInsnVarID)
- << MatchTable::Comment("OtherOpIdx")
- << MatchTable::IntValue(OtherOM.getOpIdx())
- << MatchTable::LineBreak;
-}
-
//===- GlobalISelEmitter class --------------------------------------------===//
static Expected<LLTCodeGen> getInstResultType(const TreePatternNode *Dst) {
@@ -3554,8 +291,7 @@ static Expected<LLTCodeGen> getInstResultType(const TreePatternNode *Dst) {
std::optional<LLTCodeGen> MaybeOpTy;
if (ChildTypes.front().isMachineValueType()) {
- MaybeOpTy =
- MVTToLLT(ChildTypes.front().getMachineValueType().SimpleTy);
+ MaybeOpTy = MVTToLLT(ChildTypes.front().getMachineValueType().SimpleTy);
}
if (!MaybeOpTy)
@@ -3563,17 +299,34 @@ static Expected<LLTCodeGen> getInstResultType(const TreePatternNode *Dst) {
return *MaybeOpTy;
}
-class GlobalISelEmitter {
+class GlobalISelEmitter final : public GlobalISelMatchTableExecutorEmitter {
public:
explicit GlobalISelEmitter(RecordKeeper &RK);
+
+ void emitAdditionalImpl(raw_ostream &OS) override;
+
+ void emitMIPredicateFns(raw_ostream &OS) override;
+ void emitI64ImmPredicateFns(raw_ostream &OS) override;
+ void emitAPFloatImmPredicateFns(raw_ostream &OS) override;
+ void emitAPIntImmPredicateFns(raw_ostream &OS) override;
+ void emitTestSimplePredicate(raw_ostream &OS) override;
+ void emitRunCustomAction(raw_ostream &OS) override;
+
+ const CodeGenTarget &getTarget() const override { return Target; }
+ StringRef getClassName() const override { return ClassName; }
+
void run(raw_ostream &OS);
private:
+ std::string ClassName;
+
const RecordKeeper &RK;
const CodeGenDAGPatterns CGP;
const CodeGenTarget &Target;
CodeGenRegBank &CGRegs;
+ std::vector<Record *> AllPatFrags;
+
/// Keep track of the equivalence between SDNodes and Instruction by mapping
/// SDNodes to the GINodeEquiv mapping. We need to map to the GINodeEquiv to
/// check for attributes on the relation such as CheckMMOIsNonAtomic.
@@ -3594,9 +347,6 @@ private:
/// This adds compatibility for RuleMatchers to use this for ordering rules.
DenseMap<uint64_t, int> RuleMatcherScores;
- // Map of predicates to their subtarget features.
- SubtargetFeatureInfoMap SubtargetFeatures;
-
// Rule coverage information.
std::optional<CodeGenCoverage> RuleCoverage;
@@ -3635,24 +385,21 @@ private:
const TreePatternNode *Src, const TreePatternNode *Dst);
Expected<action_iterator> createAndImportSubInstructionRenderer(
action_iterator InsertPt, RuleMatcher &M, const TreePatternNode *Dst,
- unsigned TempReg);
+ const TreePatternNode *Src, unsigned TempReg);
Expected<action_iterator>
createInstructionRenderer(action_iterator InsertPt, RuleMatcher &M,
const TreePatternNode *Dst);
- Expected<action_iterator>
- importExplicitDefRenderers(action_iterator InsertPt, RuleMatcher &M,
- BuildMIAction &DstMIBuilder,
- const TreePatternNode *Dst);
+ Expected<action_iterator> importExplicitDefRenderers(
+ action_iterator InsertPt, RuleMatcher &M, BuildMIAction &DstMIBuilder,
+ const TreePatternNode *Src, const TreePatternNode *Dst);
- Expected<action_iterator>
- importExplicitUseRenderers(action_iterator InsertPt, RuleMatcher &M,
- BuildMIAction &DstMIBuilder,
- const llvm::TreePatternNode *Dst);
- Expected<action_iterator>
- importExplicitUseRenderer(action_iterator InsertPt, RuleMatcher &Rule,
- BuildMIAction &DstMIBuilder,
- TreePatternNode *DstChild);
+ Expected<action_iterator> importExplicitUseRenderers(
+ action_iterator InsertPt, RuleMatcher &M, BuildMIAction &DstMIBuilder,
+ const llvm::TreePatternNode *Dst, const TreePatternNode *Src);
+ Expected<action_iterator> importExplicitUseRenderer(
+ action_iterator InsertPt, RuleMatcher &Rule, BuildMIAction &DstMIBuilder,
+ const TreePatternNode *DstChild, const TreePatternNode *Src);
Error importDefaultOperandRenderers(action_iterator InsertPt, RuleMatcher &M,
BuildMIAction &DstMIBuilder,
DagInit *DefaultOps) const;
@@ -3660,16 +407,6 @@ private:
importImplicitDefRenderers(BuildMIAction &DstMIBuilder,
const std::vector<Record *> &ImplicitDefs) const;
- void emitCxxPredicateFns(raw_ostream &OS, StringRef CodeFieldName,
- StringRef TypeIdentifier, StringRef ArgType,
- StringRef ArgName, StringRef AdditionalArgs,
- StringRef AdditionalDeclarations,
- std::function<bool(const Record *R)> Filter);
- void emitImmPredicateFns(raw_ostream &OS, StringRef TypeIdentifier,
- StringRef ArgType,
- std::function<bool(const Record *R)> Filter);
- void emitMIPredicateFns(raw_ostream &OS);
-
/// Analyze pattern \p P, returning a matcher for it if possible.
/// Otherwise, return an Error explaining why we don't support it.
Expected<RuleMatcher> runOnPattern(const PatternToMatch &P);
@@ -3685,25 +422,25 @@ private:
/// If no register class is found, return std::nullopt.
std::optional<const CodeGenRegisterClass *>
inferSuperRegisterClassForNode(const TypeSetByHwMode &Ty,
- TreePatternNode *SuperRegNode,
- TreePatternNode *SubRegIdxNode);
+ const TreePatternNode *SuperRegNode,
+ const TreePatternNode *SubRegIdxNode);
std::optional<CodeGenSubRegIndex *>
- inferSubRegIndexForNode(TreePatternNode *SubRegIdxNode);
+ inferSubRegIndexForNode(const TreePatternNode *SubRegIdxNode);
/// Infer a CodeGenRegisterClass which suppoorts \p Ty and \p SubRegIdxNode.
/// Return std::nullopt if no such class exists.
std::optional<const CodeGenRegisterClass *>
inferSuperRegisterClass(const TypeSetByHwMode &Ty,
- TreePatternNode *SubRegIdxNode);
+ const TreePatternNode *SubRegIdxNode);
/// Return the CodeGenRegisterClass associated with \p Leaf if it has one.
std::optional<const CodeGenRegisterClass *>
- getRegClassFromLeaf(TreePatternNode *Leaf);
+ getRegClassFromLeaf(const TreePatternNode *Leaf);
/// Return a CodeGenRegisterClass for \p N if one can be found. Return
/// std::nullopt otherwise.
std::optional<const CodeGenRegisterClass *>
- inferRegClassFromPattern(TreePatternNode *N);
+ inferRegClassFromPattern(const TreePatternNode *N);
/// Return the size of the MemoryVT in this predicate, if possible.
std::optional<unsigned>
@@ -3714,39 +451,10 @@ private:
addBuiltinPredicates(const Record *SrcGIEquivOrNull,
const TreePredicateFn &Predicate,
InstructionMatcher &InsnMatcher, bool &HasAddedMatcher);
-
-public:
- /// Takes a sequence of \p Rules and group them based on the predicates
- /// they share. \p MatcherStorage is used as a memory container
- /// for the group that are created as part of this process.
- ///
- /// What this optimization does looks like if GroupT = GroupMatcher:
- /// Output without optimization:
- /// \verbatim
- /// # R1
- /// # predicate A
- /// # predicate B
- /// ...
- /// # R2
- /// # predicate A // <-- effectively this is going to be checked twice.
- /// // Once in R1 and once in R2.
- /// # predicate C
- /// \endverbatim
- /// Output with optimization:
- /// \verbatim
- /// # Group1_2
- /// # predicate A // <-- Check is now shared.
- /// # R1
- /// # predicate B
- /// # R2
- /// # predicate C
- /// \endverbatim
- template <class GroupT>
- static std::vector<Matcher *> optimizeRules(
- ArrayRef<Matcher *> Rules,
- std::vector<std::unique_ptr<Matcher>> &MatcherStorage);
};
+StringRef getPatFragPredicateEnumName(Record *R) { return R->getName(); }
+
void GlobalISelEmitter::gatherOpcodeValues() {
InstructionOpcodeMatcher::initOpcodeValuesMap(Target);
}
@@ -3766,15 +474,15 @@ void GlobalISelEmitter::gatherNodeEquivs() {
if (!SelDAGEquiv)
continue;
ComplexPatternEquivs[SelDAGEquiv] = Equiv;
- }
+ }
- assert(SDNodeXFormEquivs.empty());
- for (Record *Equiv : RK.getAllDerivedDefinitions("GISDNodeXFormEquiv")) {
- Record *SelDAGEquiv = Equiv->getValueAsDef("SelDAGEquivalent");
- if (!SelDAGEquiv)
- continue;
- SDNodeXFormEquivs[SelDAGEquiv] = Equiv;
- }
+ assert(SDNodeXFormEquivs.empty());
+ for (Record *Equiv : RK.getAllDerivedDefinitions("GISDNodeXFormEquiv")) {
+ Record *SelDAGEquiv = Equiv->getValueAsDef("SelDAGEquivalent");
+ if (!SelDAGEquiv)
+ continue;
+ SDNodeXFormEquivs[SelDAGEquiv] = Equiv;
+ }
}
Record *GlobalISelEmitter::findNodeEquiv(Record *N) const {
@@ -3806,8 +514,10 @@ GlobalISelEmitter::getEquivNode(Record &Equiv, const TreePatternNode *N) const {
}
GlobalISelEmitter::GlobalISelEmitter(RecordKeeper &RK)
- : RK(RK), CGP(RK), Target(CGP.getTargetInfo()),
- CGRegs(Target.getRegBank()) {}
+ : GlobalISelMatchTableExecutorEmitter(), RK(RK), CGP(RK),
+ Target(CGP.getTargetInfo()), CGRegs(Target.getRegBank()) {
+ ClassName = Target.getName().str() + "InstructionSelector";
+}
//===- Emitter ------------------------------------------------------------===//
@@ -3900,6 +610,7 @@ Expected<InstructionMatcher &> GlobalISelEmitter::addBuiltinPredicates(
}
}
+ assert(SrcGIEquivOrNull != nullptr && "Invalid SrcGIEquivOrNull value");
// No check required. We already did it by swapping the opcode.
if (!SrcGIEquivOrNull->isValueUnset("IfSignExtend") &&
Predicate.isSignExtLoad())
@@ -3985,13 +696,12 @@ Expected<InstructionMatcher &> GlobalISelEmitter::addBuiltinPredicates(
Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
RuleMatcher &Rule, InstructionMatcher &InsnMatcher,
const TreePatternNode *Src, unsigned &TempOpIdx) {
+ const auto SavedFlags = Rule.setGISelFlags(Src->getGISelFlagsRecord());
+
Record *SrcGIEquivOrNull = nullptr;
const CodeGenInstruction *SrcGIOrNull = nullptr;
// Start with the defined operands (i.e., the results of the root operator).
- if (Src->getExtTypes().size() > 1)
- return failedImport("Src pattern has multiple results");
-
if (Src->isLeaf()) {
Init *SrcInit = Src->getLeafValue();
if (isa<IntInit>(SrcInit)) {
@@ -4070,12 +780,14 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
}
bool IsAtomic = false;
- if (SrcGIEquivOrNull && SrcGIEquivOrNull->getValueAsBit("CheckMMOIsNonAtomic"))
+ if (SrcGIEquivOrNull &&
+ SrcGIEquivOrNull->getValueAsBit("CheckMMOIsNonAtomic"))
InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>("NotAtomic");
- else if (SrcGIEquivOrNull && SrcGIEquivOrNull->getValueAsBit("CheckMMOIsAtomic")) {
+ else if (SrcGIEquivOrNull &&
+ SrcGIEquivOrNull->getValueAsBit("CheckMMOIsAtomic")) {
IsAtomic = true;
InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>(
- "Unordered", AtomicOrderingMMOPredicateMatcher::AO_OrStronger);
+ "Unordered", AtomicOrderingMMOPredicateMatcher::AO_OrStronger);
}
if (Src->isLeaf()) {
@@ -4107,7 +819,7 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
bool IsFCmp = SrcGIOrNull->TheDef->getName() == "G_FCMP";
if (IsFCmp || SrcGIOrNull->TheDef->getName() == "G_ICMP") {
- TreePatternNode *SrcChild = Src->getChild(NumChildren - 1);
+ const TreePatternNode *SrcChild = Src->getChild(NumChildren - 1);
if (SrcChild->isLeaf()) {
DefInit *DI = dyn_cast<DefInit>(SrcChild->getLeafValue());
Record *CCDef = DI ? DI->getDef() : nullptr;
@@ -4115,9 +827,9 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
return failedImport("Unable to handle CondCode");
OperandMatcher &OM =
- InsnMatcher.addOperand(OpIdx++, SrcChild->getName(), TempOpIdx);
- StringRef PredType = IsFCmp ? CCDef->getValueAsString("FCmpPredicate") :
- CCDef->getValueAsString("ICmpPredicate");
+ InsnMatcher.addOperand(OpIdx++, SrcChild->getName(), TempOpIdx);
+ StringRef PredType = IsFCmp ? CCDef->getValueAsString("FCmpPredicate")
+ : CCDef->getValueAsString("ICmpPredicate");
if (!PredType.empty()) {
OM.addPredicate<CmpPredicateOperandMatcher>(std::string(PredType));
@@ -4135,8 +847,8 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
if (IsAtomic && SrcGIOrNull->TheDef->getName() == "G_STORE") {
assert(NumChildren == 2 && "wrong operands for atomic store");
- TreePatternNode *PtrChild = Src->getChild(0);
- TreePatternNode *ValueChild = Src->getChild(1);
+ const TreePatternNode *PtrChild = Src->getChild(0);
+ const TreePatternNode *ValueChild = Src->getChild(1);
if (auto Error = importChildMatcher(Rule, InsnMatcher, PtrChild, true,
false, 1, TempOpIdx))
@@ -4157,7 +869,7 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
return failedImport("Expected IntInit containing intrinsic ID)");
for (unsigned i = 0; i != NumChildren; ++i) {
- TreePatternNode *SrcChild = Src->getChild(i);
+ const TreePatternNode *SrcChild = Src->getChild(i);
// We need to determine the meaning of a literal integer based on the
// context. If this is a field required to be an immediate (such as an
@@ -4169,8 +881,9 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
bool OperandIsImmArg = SrcGIOrNull->isInOperandImmArg(i);
// SelectionDAG allows pointers to be represented with iN since it doesn't
- // distinguish between pointers and integers but they are different types in GlobalISel.
- // Coerce integers to pointers to address space 0 if the context indicates a pointer.
+ // distinguish between pointers and integers but they are different types
+ // in GlobalISel. Coerce integers to pointers to address space 0 if the
+ // context indicates a pointer.
//
bool OperandIsAPointer = SrcGIOrNull->isInOperandAPointer(i);
@@ -4327,7 +1040,8 @@ Error GlobalISelEmitter::importChildMatcher(
// 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.
- return failedImport("Nested instruction cannot be the same as another operand");
+ return failedImport(
+ "Nested instruction cannot be the same as another operand");
}
// Map the node to a gMIR instruction.
@@ -4377,11 +1091,11 @@ Error GlobalISelEmitter::importChildMatcher(
if (ChildRec->isSubClassOf("Register")) {
// This just be emitted as a copy to the specific register.
ValueTypeByHwMode VT = ChildTypes.front().getValueTypeByHwMode();
- const CodeGenRegisterClass *RC
- = CGRegs.getMinimalPhysRegClass(ChildRec, &VT);
+ const CodeGenRegisterClass *RC =
+ CGRegs.getMinimalPhysRegClass(ChildRec, &VT);
if (!RC) {
return failedImport(
- "Could not determine physical register class of pattern source");
+ "Could not determine physical register class of pattern source");
}
OM.addPredicate<RegisterBankOperandMatcher>(*RC);
@@ -4416,10 +1130,10 @@ Error GlobalISelEmitter::importChildMatcher(
ValueTypeByHwMode VTy = ChildTypes.front().getValueTypeByHwMode();
- const CodeGenInstruction &BuildVector
- = Target.getInstruction(RK.getDef("G_BUILD_VECTOR"));
- const CodeGenInstruction &BuildVectorTrunc
- = Target.getInstruction(RK.getDef("G_BUILD_VECTOR_TRUNC"));
+ const CodeGenInstruction &BuildVector =
+ Target.getInstruction(RK.getDef("G_BUILD_VECTOR"));
+ const CodeGenInstruction &BuildVectorTrunc =
+ Target.getInstruction(RK.getDef("G_BUILD_VECTOR_TRUNC"));
// Treat G_BUILD_VECTOR as the canonical opcode, and G_BUILD_VECTOR_TRUNC
// as an alternative.
@@ -4451,7 +1165,7 @@ Error GlobalISelEmitter::importChildMatcher(
Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderer(
action_iterator InsertPt, RuleMatcher &Rule, BuildMIAction &DstMIBuilder,
- TreePatternNode *DstChild) {
+ const TreePatternNode *DstChild, const TreePatternNode *Src) {
const auto &SubOperand = Rule.getComplexSubOperand(DstChild->getName());
if (SubOperand) {
@@ -4516,18 +1230,19 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderer(
return OpTy.takeError();
unsigned TempRegID = Rule.allocateTempRegID();
- InsertPt = Rule.insertAction<MakeTempRegisterAction>(
- InsertPt, *OpTy, TempRegID);
+ InsertPt =
+ Rule.insertAction<MakeTempRegisterAction>(InsertPt, *OpTy, TempRegID);
DstMIBuilder.addRenderer<TempRegRenderer>(TempRegID);
auto InsertPtOrError = createAndImportSubInstructionRenderer(
- ++InsertPt, Rule, DstChild, TempRegID);
+ ++InsertPt, Rule, DstChild, Src, TempRegID);
if (auto Error = InsertPtOrError.takeError())
return std::move(Error);
return InsertPtOrError.get();
}
- return failedImport("Dst pattern child isn't a leaf node or an MBB" + llvm::to_string(*DstChild));
+ return failedImport("Dst pattern child isn't a leaf node or an MBB" +
+ llvm::to_string(*DstChild));
}
// It could be a specific immediate in which case we should just check for
@@ -4593,6 +1308,16 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderer(
return failedImport(
"Dst pattern child def is an unsupported tablegen class");
}
+
+ // Handle the case where the MVT/register class is omitted in the dest pattern
+ // but MVT exists in the source pattern.
+ if (isa<UnsetInit>(DstChild->getLeafValue())) {
+ for (unsigned NumOp = 0; NumOp < Src->getNumChildren(); NumOp++)
+ if (Src->getChild(NumOp)->getName() == DstChild->getName()) {
+ DstMIBuilder.addRenderer<CopyRenderer>(Src->getChild(NumOp)->getName());
+ return InsertPt;
+ }
+ }
return failedImport("Dst pattern child is an unsupported kind");
}
@@ -4612,18 +1337,19 @@ Expected<BuildMIAction &> GlobalISelEmitter::createAndImportInstructionRenderer(
&Target.getInstruction(RK.getDef("COPY")));
BuildMIAction &CopyToPhysRegMIBuilder =
*static_cast<BuildMIAction *>(InsertPt->get());
- CopyToPhysRegMIBuilder.addRenderer<AddRegisterRenderer>(Target,
- PhysInput.first,
- true);
+ CopyToPhysRegMIBuilder.addRenderer<AddRegisterRenderer>(
+ Target, PhysInput.first, true);
CopyToPhysRegMIBuilder.addRenderer<CopyPhysRegRenderer>(PhysInput.first);
}
- if (auto Error = importExplicitDefRenderers(InsertPt, M, DstMIBuilder, Dst)
- .takeError())
+ if (auto Error =
+ importExplicitDefRenderers(InsertPt, M, DstMIBuilder, Src, Dst)
+ .takeError())
return std::move(Error);
- if (auto Error = importExplicitUseRenderers(InsertPt, M, DstMIBuilder, Dst)
- .takeError())
+ if (auto Error =
+ importExplicitUseRenderers(InsertPt, M, DstMIBuilder, Dst, Src)
+ .takeError())
return std::move(Error);
return DstMIBuilder;
@@ -4632,7 +1358,7 @@ Expected<BuildMIAction &> GlobalISelEmitter::createAndImportInstructionRenderer(
Expected<action_iterator>
GlobalISelEmitter::createAndImportSubInstructionRenderer(
const action_iterator InsertPt, RuleMatcher &M, const TreePatternNode *Dst,
- unsigned TempRegID) {
+ const TreePatternNode *Src, unsigned TempRegID) {
auto InsertPtOrError = createInstructionRenderer(InsertPt, M, Dst);
// TODO: Assert there's exactly one result.
@@ -4646,8 +1372,8 @@ GlobalISelEmitter::createAndImportSubInstructionRenderer(
// Assign the result to TempReg.
DstMIBuilder.addRenderer<TempRegRenderer>(TempRegID, true);
- InsertPtOrError =
- importExplicitUseRenderers(InsertPtOrError.get(), M, DstMIBuilder, Dst);
+ InsertPtOrError = importExplicitUseRenderers(InsertPtOrError.get(), M,
+ DstMIBuilder, Dst, Src);
if (auto Error = InsertPtOrError.takeError())
return std::move(Error);
@@ -4685,19 +1411,19 @@ GlobalISelEmitter::createAndImportSubInstructionRenderer(
auto SuperClass = inferRegClassFromPattern(Dst->getChild(0));
if (!SuperClass)
return failedImport(
- "Cannot infer register class from EXTRACT_SUBREG operand #0");
+ "Cannot infer register class from EXTRACT_SUBREG operand #0");
auto SubIdx = inferSubRegIndexForNode(Dst->getChild(1));
if (!SubIdx)
return failedImport("EXTRACT_SUBREG child #1 is not a subreg index");
const auto SrcRCDstRCPair =
- (*SuperClass)->getMatchingSubClassWithSubRegs(CGRegs, *SubIdx);
+ (*SuperClass)->getMatchingSubClassWithSubRegs(CGRegs, *SubIdx);
assert(SrcRCDstRCPair->second && "Couldn't find a matching subclass");
M.insertAction<ConstrainOperandToRegClassAction>(
- InsertPt, DstMIBuilder.getInsnID(), 0, *SrcRCDstRCPair->second);
+ InsertPt, DstMIBuilder.getInsnID(), 0, *SrcRCDstRCPair->second);
M.insertAction<ConstrainOperandToRegClassAction>(
- InsertPt, DstMIBuilder.getInsnID(), 1, *SrcRCDstRCPair->first);
+ InsertPt, DstMIBuilder.getInsnID(), 1, *SrcRCDstRCPair->first);
// We're done with this pattern! It's eligible for GISel emission; return
// it.
@@ -4710,37 +1436,37 @@ GlobalISelEmitter::createAndImportSubInstructionRenderer(
auto SubClass = inferRegClassFromPattern(Dst->getChild(1));
if (!SubClass)
return failedImport(
- "Cannot infer register class from SUBREG_TO_REG child #1");
- auto SuperClass = inferSuperRegisterClass(Dst->getExtType(0),
- Dst->getChild(2));
+ "Cannot infer register class from SUBREG_TO_REG child #1");
+ auto SuperClass =
+ inferSuperRegisterClass(Dst->getExtType(0), Dst->getChild(2));
if (!SuperClass)
return failedImport(
- "Cannot infer register class for SUBREG_TO_REG operand #0");
+ "Cannot infer register class for SUBREG_TO_REG operand #0");
M.insertAction<ConstrainOperandToRegClassAction>(
- InsertPt, DstMIBuilder.getInsnID(), 0, **SuperClass);
+ InsertPt, DstMIBuilder.getInsnID(), 0, **SuperClass);
M.insertAction<ConstrainOperandToRegClassAction>(
- InsertPt, DstMIBuilder.getInsnID(), 2, **SubClass);
+ InsertPt, DstMIBuilder.getInsnID(), 2, **SubClass);
return InsertPtOrError.get();
}
if (OpName == "REG_SEQUENCE") {
auto SuperClass = inferRegClassFromPattern(Dst->getChild(0));
M.insertAction<ConstrainOperandToRegClassAction>(
- InsertPt, DstMIBuilder.getInsnID(), 0, **SuperClass);
+ InsertPt, DstMIBuilder.getInsnID(), 0, **SuperClass);
unsigned Num = Dst->getNumChildren();
for (unsigned I = 1; I != Num; I += 2) {
- TreePatternNode *SubRegChild = Dst->getChild(I + 1);
+ const TreePatternNode *SubRegChild = Dst->getChild(I + 1);
auto SubIdx = inferSubRegIndexForNode(SubRegChild);
if (!SubIdx)
return failedImport("REG_SEQUENCE child is not a subreg index");
const auto SrcRCDstRCPair =
- (*SuperClass)->getMatchingSubClassWithSubRegs(CGRegs, *SubIdx);
+ (*SuperClass)->getMatchingSubClassWithSubRegs(CGRegs, *SubIdx);
assert(SrcRCDstRCPair->second && "Couldn't find a matching subclass");
M.insertAction<ConstrainOperandToRegClassAction>(
- InsertPt, DstMIBuilder.getInsnID(), I, *SrcRCDstRCPair->second);
+ InsertPt, DstMIBuilder.getInsnID(), I, *SrcRCDstRCPair->second);
}
return InsertPtOrError.get();
@@ -4774,22 +1500,22 @@ Expected<action_iterator> GlobalISelEmitter::createInstructionRenderer(
Expected<action_iterator> GlobalISelEmitter::importExplicitDefRenderers(
action_iterator InsertPt, RuleMatcher &M, BuildMIAction &DstMIBuilder,
- const TreePatternNode *Dst) {
+ const TreePatternNode *Src, const TreePatternNode *Dst) {
const CodeGenInstruction *DstI = DstMIBuilder.getCGI();
- const unsigned NumDefs = DstI->Operands.NumDefs;
- if (NumDefs == 0)
+ const unsigned SrcNumDefs = Src->getExtTypes().size();
+ const unsigned DstNumDefs = DstI->Operands.NumDefs;
+ if (DstNumDefs == 0)
return InsertPt;
- DstMIBuilder.addRenderer<CopyRenderer>(DstI->Operands[0].Name);
+ for (unsigned I = 0; I < SrcNumDefs; ++I)
+ DstMIBuilder.addRenderer<CopyRenderer>(DstI->Operands[I].Name);
// Some instructions have multiple defs, but are missing a type entry
// (e.g. s_cc_out operands).
- if (Dst->getExtTypes().size() < NumDefs)
+ if (Dst->getExtTypes().size() < DstNumDefs)
return failedImport("unhandled discarded def");
- // Patterns only handle a single result, so any result after the first is an
- // implicitly dead def.
- for (unsigned I = 1; I < NumDefs; ++I) {
+ for (unsigned I = SrcNumDefs; I < DstNumDefs; ++I) {
const TypeSetByHwMode &ExtTy = Dst->getExtType(I);
if (!ExtTy.isMachineValueType())
return failedImport("unsupported typeset");
@@ -4800,7 +1526,7 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitDefRenderers(
unsigned TempRegID = M.allocateTempRegID();
InsertPt =
- M.insertAction<MakeTempRegisterAction>(InsertPt, *OpTy, TempRegID);
+ M.insertAction<MakeTempRegisterAction>(InsertPt, *OpTy, TempRegID);
DstMIBuilder.addRenderer<TempRegRenderer>(TempRegID, true, nullptr, true);
}
@@ -4809,7 +1535,7 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitDefRenderers(
Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderers(
action_iterator InsertPt, RuleMatcher &M, BuildMIAction &DstMIBuilder,
- const llvm::TreePatternNode *Dst) {
+ const llvm::TreePatternNode *Dst, const llvm::TreePatternNode *Src) {
const CodeGenInstruction *DstI = DstMIBuilder.getCGI();
CodeGenInstruction *OrigDstI = &Target.getInstruction(Dst->getOperator());
@@ -4825,7 +1551,7 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderers(
return failedImport("EXTRACT_SUBREG child #1 is not a subreg index");
CodeGenSubRegIndex *SubIdx = CGRegs.getSubRegIdx(SubRegInit->getDef());
- TreePatternNode *ValChild = Dst->getChild(0);
+ const TreePatternNode *ValChild = Dst->getChild(0);
if (!ValChild->isLeaf()) {
// We really have to handle the source instruction, and then insert a
// copy from the subregister.
@@ -4834,11 +1560,11 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderers(
return ExtractSrcTy.takeError();
unsigned TempRegID = M.allocateTempRegID();
- InsertPt = M.insertAction<MakeTempRegisterAction>(
- InsertPt, *ExtractSrcTy, TempRegID);
+ InsertPt = M.insertAction<MakeTempRegisterAction>(InsertPt, *ExtractSrcTy,
+ TempRegID);
auto InsertPtOrError = createAndImportSubInstructionRenderer(
- ++InsertPt, M, ValChild, TempRegID);
+ ++InsertPt, M, ValChild, Src, TempRegID);
if (auto Error = InsertPtOrError.takeError())
return std::move(Error);
@@ -4855,15 +1581,22 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderers(
CodeGenRegisterClass *RC = CGRegs.getRegClass(RCDef);
const auto SrcRCDstRCPair =
- RC->getMatchingSubClassWithSubRegs(CGRegs, SubIdx);
+ RC->getMatchingSubClassWithSubRegs(CGRegs, SubIdx);
if (SrcRCDstRCPair) {
assert(SrcRCDstRCPair->second && "Couldn't find a matching subclass");
if (SrcRCDstRCPair->first != RC)
return failedImport("EXTRACT_SUBREG requires an additional COPY");
}
- DstMIBuilder.addRenderer<CopySubRegRenderer>(Dst->getChild(0)->getName(),
- SubIdx);
+ StringRef RegOperandName = Dst->getChild(0)->getName();
+ if (const auto &SubOperand = M.getComplexSubOperand(RegOperandName)) {
+ DstMIBuilder.addRenderer<RenderComplexPatternOperand>(
+ *std::get<0>(*SubOperand), RegOperandName, std::get<1>(*SubOperand),
+ std::get<2>(*SubOperand), SubIdx);
+ return InsertPt;
+ }
+
+ DstMIBuilder.addRenderer<CopySubRegRenderer>(RegOperandName, SubIdx);
return InsertPt;
}
@@ -4880,15 +1613,15 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderers(
return failedImport("Malformed REG_SEQUENCE");
for (unsigned I = 1; I != ExpectedDstINumUses; I += 2) {
- TreePatternNode *ValChild = Dst->getChild(I);
- TreePatternNode *SubRegChild = Dst->getChild(I + 1);
+ const TreePatternNode *ValChild = Dst->getChild(I);
+ const TreePatternNode *SubRegChild = Dst->getChild(I + 1);
if (DefInit *SubRegInit =
dyn_cast<DefInit>(SubRegChild->getLeafValue())) {
CodeGenSubRegIndex *SubIdx = CGRegs.getSubRegIdx(SubRegInit->getDef());
auto InsertPtOrError =
- importExplicitUseRenderer(InsertPt, M, DstMIBuilder, ValChild);
+ importExplicitUseRenderer(InsertPt, M, DstMIBuilder, ValChild, Src);
if (auto Error = InsertPtOrError.takeError())
return std::move(Error);
InsertPt = InsertPtOrError.get();
@@ -4949,15 +1682,15 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderers(
const CGIOperandList::OperandInfo &DstIOperand = DstI->Operands[InstOpNo];
DagInit *DefaultOps = DstIOperand.Rec->getValueAsDag("DefaultOps");
- if (auto Error = importDefaultOperandRenderers(
- InsertPt, M, DstMIBuilder, DefaultOps))
+ if (auto Error = importDefaultOperandRenderers(InsertPt, M, DstMIBuilder,
+ DefaultOps))
return std::move(Error);
++NumDefaultOps;
continue;
}
auto InsertPtOrError = importExplicitUseRenderer(InsertPt, M, DstMIBuilder,
- Dst->getChild(Child));
+ Dst->getChild(Child), Src);
if (auto Error = InsertPtOrError.takeError())
return std::move(Error);
InsertPt = InsertPtOrError.get();
@@ -4985,8 +1718,7 @@ Error GlobalISelEmitter::importDefaultOperandRenderers(
if (const DefInit *DefaultDagOperator =
dyn_cast<DefInit>(DefaultDagOp->getOperator())) {
if (DefaultDagOperator->getDef()->isSubClassOf("ValueType")) {
- OpTyOrNone = MVTToLLT(getValueType(
- DefaultDagOperator->getDef()));
+ OpTyOrNone = MVTToLLT(getValueType(DefaultDagOperator->getDef()));
DefaultOp = DefaultDagOp->getArg(0);
}
}
@@ -4999,10 +1731,10 @@ Error GlobalISelEmitter::importDefaultOperandRenderers(
M.insertAction<MakeTempRegisterAction>(InsertPt, *OpTyOrNone,
TempRegID);
InsertPt = M.insertAction<BuildMIAction>(
- InsertPt, M.allocateOutputInsnID(),
- &Target.getInstruction(RK.getDef("IMPLICIT_DEF")));
- BuildMIAction &IDMIBuilder = *static_cast<BuildMIAction *>(
- InsertPt->get());
+ InsertPt, M.allocateOutputInsnID(),
+ &Target.getInstruction(RK.getDef("IMPLICIT_DEF")));
+ BuildMIAction &IDMIBuilder =
+ *static_cast<BuildMIAction *>(InsertPt->get());
IDMIBuilder.addRenderer<TempRegRenderer>(TempRegID);
DstMIBuilder.addRenderer<TempRegRenderer>(TempRegID);
} else {
@@ -5031,7 +1763,7 @@ Error GlobalISelEmitter::importImplicitDefRenderers(
}
std::optional<const CodeGenRegisterClass *>
-GlobalISelEmitter::getRegClassFromLeaf(TreePatternNode *Leaf) {
+GlobalISelEmitter::getRegClassFromLeaf(const TreePatternNode *Leaf) {
assert(Leaf && "Expected node?");
assert(Leaf->isLeaf() && "Expected leaf?");
Record *RCRec = getInitValueAsRegClass(Leaf->getLeafValue());
@@ -5044,7 +1776,7 @@ GlobalISelEmitter::getRegClassFromLeaf(TreePatternNode *Leaf) {
}
std::optional<const CodeGenRegisterClass *>
-GlobalISelEmitter::inferRegClassFromPattern(TreePatternNode *N) {
+GlobalISelEmitter::inferRegClassFromPattern(const TreePatternNode *N) {
if (!N)
return std::nullopt;
@@ -5076,13 +1808,13 @@ GlobalISelEmitter::inferRegClassFromPattern(TreePatternNode *N) {
if (IsRegSequence || InstName == "COPY_TO_REGCLASS") {
// If we have a COPY_TO_REGCLASS, then we need to handle it specially. It
// has the desired register class as the first child.
- TreePatternNode *RCChild = N->getChild(IsRegSequence ? 0 : 1);
+ const TreePatternNode *RCChild = N->getChild(IsRegSequence ? 0 : 1);
if (!RCChild->isLeaf())
return std::nullopt;
return getRegClassFromLeaf(RCChild);
}
if (InstName == "INSERT_SUBREG") {
- TreePatternNode *Child0 = N->getChild(0);
+ const TreePatternNode *Child0 = N->getChild(0);
assert(Child0->getNumTypes() == 1 && "Unexpected number of types!");
const TypeSetByHwMode &VTy = Child0->getExtType(0);
return inferSuperRegisterClassForNode(VTy, Child0, N->getChild(2));
@@ -5112,8 +1844,8 @@ GlobalISelEmitter::inferRegClassFromPattern(TreePatternNode *N) {
}
std::optional<const CodeGenRegisterClass *>
-GlobalISelEmitter::inferSuperRegisterClass(const TypeSetByHwMode &Ty,
- TreePatternNode *SubRegIdxNode) {
+GlobalISelEmitter::inferSuperRegisterClass(
+ const TypeSetByHwMode &Ty, const TreePatternNode *SubRegIdxNode) {
assert(SubRegIdxNode && "Expected subregister index node!");
// We need a ValueTypeByHwMode for getSuperRegForSubReg.
if (!Ty.isValueTypeByHwMode(false))
@@ -5137,8 +1869,8 @@ GlobalISelEmitter::inferSuperRegisterClass(const TypeSetByHwMode &Ty,
std::optional<const CodeGenRegisterClass *>
GlobalISelEmitter::inferSuperRegisterClassForNode(
- const TypeSetByHwMode &Ty, TreePatternNode *SuperRegNode,
- TreePatternNode *SubRegIdxNode) {
+ const TypeSetByHwMode &Ty, const TreePatternNode *SuperRegNode,
+ const TreePatternNode *SubRegIdxNode) {
assert(SuperRegNode && "Expected super register node!");
// Check if we already have a defined register class for the super register
// node. If we do, then we should preserve that rather than inferring anything
@@ -5151,8 +1883,8 @@ GlobalISelEmitter::inferSuperRegisterClassForNode(
return inferSuperRegisterClass(Ty, SubRegIdxNode);
}
-std::optional<CodeGenSubRegIndex *>
-GlobalISelEmitter::inferSubRegIndexForNode(TreePatternNode *SubRegIdxNode) {
+std::optional<CodeGenSubRegIndex *> GlobalISelEmitter::inferSubRegIndexForNode(
+ const TreePatternNode *SubRegIdxNode) {
if (!SubRegIdxNode->isLeaf())
return std::nullopt;
@@ -5211,6 +1943,9 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
// before their first use.)
InstructionMatcher &InsnMatcherTemp = M.addInstructionMatcher(Src->getName());
unsigned TempOpIdx = 0;
+
+ const auto SavedFlags = M.setGISelFlags(P.getSrcRecord());
+
auto InsnMatcherOrError =
createAndImportSelDAGMatcher(M, InsnMatcherTemp, Src, TempOpIdx);
if (auto Error = InsnMatcherOrError.takeError())
@@ -5297,7 +2032,8 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
} else if (DstIName == "EXTRACT_SUBREG") {
auto InferredClass = inferRegClassFromPattern(Dst->getChild(0));
if (!InferredClass)
- return failedImport("Could not infer class for EXTRACT_SUBREG operand #0");
+ return failedImport(
+ "Could not infer class for EXTRACT_SUBREG operand #0");
// We can assume that a subregister is in the same bank as it's super
// register.
@@ -5379,7 +2115,7 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
auto SuperClass = inferRegClassFromPattern(Dst->getChild(0));
if (!SuperClass)
return failedImport(
- "Cannot infer register class from EXTRACT_SUBREG operand #0");
+ "Cannot infer register class from EXTRACT_SUBREG operand #0");
auto SubIdx = inferSubRegIndexForNode(Dst->getChild(1));
if (!SubIdx)
@@ -5392,17 +2128,18 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
// FIXME: This may introduce an extra copy if the chosen class doesn't
// actually contain the subregisters.
assert(Src->getExtTypes().size() == 1 &&
- "Expected Src of EXTRACT_SUBREG to have one result type");
+ "Expected Src of EXTRACT_SUBREG to have one result type");
const auto SrcRCDstRCPair =
- (*SuperClass)->getMatchingSubClassWithSubRegs(CGRegs, *SubIdx);
+ (*SuperClass)->getMatchingSubClassWithSubRegs(CGRegs, *SubIdx);
if (!SrcRCDstRCPair) {
return failedImport("subreg index is incompatible "
"with inferred reg class");
}
assert(SrcRCDstRCPair->second && "Couldn't find a matching subclass");
- M.addAction<ConstrainOperandToRegClassAction>(0, 0, *SrcRCDstRCPair->second);
+ M.addAction<ConstrainOperandToRegClassAction>(0, 0,
+ *SrcRCDstRCPair->second);
M.addAction<ConstrainOperandToRegClassAction>(0, 1, *SrcRCDstRCPair->first);
// We're done with this pattern! It's eligible for GISel emission; return
@@ -5470,7 +2207,7 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
return failedImport("REG_SEQUENCE child is not a subreg index");
const auto SrcRCDstRCPair =
- (*SuperClass)->getMatchingSubClassWithSubRegs(CGRegs, *SubIdx);
+ (*SuperClass)->getMatchingSubClassWithSubRegs(CGRegs, *SubIdx);
M.addAction<ConstrainOperandToRegClassAction>(0, I,
*SrcRCDstRCPair->second);
@@ -5487,126 +2224,6 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
return std::move(M);
}
-// Emit imm predicate table and an enum to reference them with.
-// The 'Predicate_' part of the name is redundant but eliminating it is more
-// trouble than it's worth.
-void GlobalISelEmitter::emitCxxPredicateFns(
- raw_ostream &OS, StringRef CodeFieldName, StringRef TypeIdentifier,
- StringRef ArgType, StringRef ArgName, StringRef AdditionalArgs,
- StringRef AdditionalDeclarations,
- std::function<bool(const Record *R)> Filter) {
- std::vector<const Record *> MatchedRecords;
- const auto &Defs = RK.getAllDerivedDefinitions("PatFrags");
- std::copy_if(Defs.begin(), Defs.end(), std::back_inserter(MatchedRecords),
- [&](Record *Record) {
- return !Record->getValueAsString(CodeFieldName).empty() &&
- Filter(Record);
- });
-
- if (!MatchedRecords.empty()) {
- OS << "// PatFrag predicates.\n"
- << "enum {\n";
- std::string EnumeratorSeparator =
- (" = GIPFP_" + TypeIdentifier + "_Invalid + 1,\n").str();
- for (const auto *Record : MatchedRecords) {
- OS << " GIPFP_" << TypeIdentifier << "_Predicate_" << Record->getName()
- << EnumeratorSeparator;
- EnumeratorSeparator = ",\n";
- }
- OS << "};\n";
- }
-
- OS << "bool " << Target.getName() << "InstructionSelector::test" << ArgName
- << "Predicate_" << TypeIdentifier << "(unsigned PredicateID, " << ArgType << " "
- << ArgName << AdditionalArgs <<") const {\n"
- << AdditionalDeclarations;
- if (!AdditionalDeclarations.empty())
- OS << "\n";
- if (!MatchedRecords.empty())
- OS << " switch (PredicateID) {\n";
- for (const auto *Record : MatchedRecords) {
- OS << " case GIPFP_" << TypeIdentifier << "_Predicate_"
- << Record->getName() << ": {\n"
- << " " << Record->getValueAsString(CodeFieldName) << "\n"
- << " llvm_unreachable(\"" << CodeFieldName
- << " should have returned\");\n"
- << " return false;\n"
- << " }\n";
- }
- if (!MatchedRecords.empty())
- OS << " }\n";
- OS << " llvm_unreachable(\"Unknown predicate\");\n"
- << " return false;\n"
- << "}\n";
-}
-
-void GlobalISelEmitter::emitImmPredicateFns(
- raw_ostream &OS, StringRef TypeIdentifier, StringRef ArgType,
- std::function<bool(const Record *R)> Filter) {
- return emitCxxPredicateFns(OS, "ImmediateCode", TypeIdentifier, ArgType,
- "Imm", "", "", Filter);
-}
-
-void GlobalISelEmitter::emitMIPredicateFns(raw_ostream &OS) {
- return emitCxxPredicateFns(
- OS, "GISelPredicateCode", "MI", "const MachineInstr &", "MI",
- ", const std::array<const MachineOperand *, 3> &Operands",
- " const MachineFunction &MF = *MI.getParent()->getParent();\n"
- " const MachineRegisterInfo &MRI = MF.getRegInfo();\n"
- " (void)MRI;",
- [](const Record *R) { return true; });
-}
-
-template <class GroupT>
-std::vector<Matcher *> GlobalISelEmitter::optimizeRules(
- ArrayRef<Matcher *> Rules,
- std::vector<std::unique_ptr<Matcher>> &MatcherStorage) {
-
- std::vector<Matcher *> OptRules;
- std::unique_ptr<GroupT> CurrentGroup = std::make_unique<GroupT>();
- assert(CurrentGroup->empty() && "Newly created group isn't empty!");
- unsigned NumGroups = 0;
-
- auto ProcessCurrentGroup = [&]() {
- if (CurrentGroup->empty())
- // An empty group is good to be reused:
- return;
-
- // If the group isn't large enough to provide any benefit, move all the
- // added rules out of it and make sure to re-create the group to properly
- // re-initialize it:
- if (CurrentGroup->size() < 2)
- append_range(OptRules, CurrentGroup->matchers());
- else {
- CurrentGroup->finalize();
- OptRules.push_back(CurrentGroup.get());
- MatcherStorage.emplace_back(std::move(CurrentGroup));
- ++NumGroups;
- }
- CurrentGroup = std::make_unique<GroupT>();
- };
- for (Matcher *Rule : Rules) {
- // Greedily add as many matchers as possible to the current group:
- if (CurrentGroup->addMatcher(*Rule))
- continue;
-
- ProcessCurrentGroup();
- assert(CurrentGroup->empty() && "A group wasn't properly re-initialized");
-
- // Try to add the pending matcher to a newly created empty group:
- if (!CurrentGroup->addMatcher(*Rule))
- // If we couldn't add the matcher to an empty group, that group type
- // doesn't support that kind of matchers at all, so just skip it:
- OptRules.push_back(Rule);
- }
- ProcessCurrentGroup();
-
- LLVM_DEBUG(dbgs() << "NumGroups: " << NumGroups << "\n");
- (void) NumGroups;
- assert(CurrentGroup->empty() && "The last group wasn't properly processed");
- return OptRules;
-}
-
MatchTable
GlobalISelEmitter::buildMatchTable(MutableArrayRef<RuleMatcher> Rules,
bool Optimize, bool WithCoverage) {
@@ -5649,32 +2266,101 @@ GlobalISelEmitter::buildMatchTable(MutableArrayRef<RuleMatcher> Rules,
return MatchTable::buildTable(OptRules, WithCoverage);
}
-void GroupMatcher::optimize() {
- // Make sure we only sort by a specific predicate within a range of rules that
- // all have that predicate checked against a specific value (not a wildcard):
- auto F = Matchers.begin();
- auto T = F;
- auto E = Matchers.end();
- while (T != E) {
- while (T != E) {
- auto *R = static_cast<RuleMatcher *>(*T);
- if (!R->getFirstConditionAsRootType().get().isValid())
- break;
- ++T;
- }
- std::stable_sort(F, T, [](Matcher *A, Matcher *B) {
- auto *L = static_cast<RuleMatcher *>(A);
- auto *R = static_cast<RuleMatcher *>(B);
- return L->getFirstConditionAsRootType() <
- R->getFirstConditionAsRootType();
- });
- if (T != E)
- F = ++T;
- }
- GlobalISelEmitter::optimizeRules<GroupMatcher>(Matchers, MatcherStorage)
- .swap(Matchers);
- GlobalISelEmitter::optimizeRules<SwitchMatcher>(Matchers, MatcherStorage)
- .swap(Matchers);
+void GlobalISelEmitter::emitAdditionalImpl(raw_ostream &OS) {
+ OS << "bool " << getClassName()
+ << "::selectImpl(MachineInstr &I, CodeGenCoverage "
+ "&CoverageInfo) const {\n"
+ << " const PredicateBitset AvailableFeatures = "
+ "getAvailableFeatures();\n"
+ << " NewMIVector OutMIs;\n"
+ << " State.MIs.clear();\n"
+ << " State.MIs.push_back(&I);\n\n"
+ << " if (executeMatchTable(*this, OutMIs, State, ExecInfo"
+ << ", getMatchTable(), TII, MF->getRegInfo(), TRI, RBI, AvailableFeatures"
+ << ", &CoverageInfo)) {\n"
+ << " return true;\n"
+ << " }\n\n"
+ << " return false;\n"
+ << "}\n\n";
+}
+
+void GlobalISelEmitter::emitMIPredicateFns(raw_ostream &OS) {
+ std::vector<Record *> MatchedRecords;
+ std::copy_if(AllPatFrags.begin(), AllPatFrags.end(),
+ std::back_inserter(MatchedRecords), [&](Record *R) {
+ return !R->getValueAsString("GISelPredicateCode").empty();
+ });
+ emitMIPredicateFnsImpl<Record *>(
+ OS,
+ " const MachineFunction &MF = *MI.getParent()->getParent();\n"
+ " const MachineRegisterInfo &MRI = MF.getRegInfo();\n"
+ " const auto &Operands = State.RecordedOperands;\n"
+ " (void)Operands;\n"
+ " (void)MRI;",
+ ArrayRef<Record *>(MatchedRecords), &getPatFragPredicateEnumName,
+ [&](Record *R) { return R->getValueAsString("GISelPredicateCode"); },
+ "PatFrag predicates.");
+}
+
+void GlobalISelEmitter::emitI64ImmPredicateFns(raw_ostream &OS) {
+ std::vector<Record *> MatchedRecords;
+ std::copy_if(AllPatFrags.begin(), AllPatFrags.end(),
+ std::back_inserter(MatchedRecords), [&](Record *R) {
+ bool Unset;
+ return !R->getValueAsString("ImmediateCode").empty() &&
+ !R->getValueAsBitOrUnset("IsAPFloat", Unset) &&
+ !R->getValueAsBit("IsAPInt");
+ });
+ emitImmPredicateFnsImpl<Record *>(
+ OS, "I64", "int64_t", ArrayRef<Record *>(MatchedRecords),
+ &getPatFragPredicateEnumName,
+ [&](Record *R) { return R->getValueAsString("ImmediateCode"); },
+ "PatFrag predicates.");
+}
+
+void GlobalISelEmitter::emitAPFloatImmPredicateFns(raw_ostream &OS) {
+ std::vector<Record *> MatchedRecords;
+ std::copy_if(AllPatFrags.begin(), AllPatFrags.end(),
+ std::back_inserter(MatchedRecords), [&](Record *R) {
+ bool Unset;
+ return !R->getValueAsString("ImmediateCode").empty() &&
+ R->getValueAsBitOrUnset("IsAPFloat", Unset);
+ });
+ emitImmPredicateFnsImpl<Record *>(
+ OS, "APFloat", "const APFloat &", ArrayRef<Record *>(MatchedRecords),
+ &getPatFragPredicateEnumName,
+ [&](Record *R) { return R->getValueAsString("ImmediateCode"); },
+ "PatFrag predicates.");
+}
+
+void GlobalISelEmitter::emitAPIntImmPredicateFns(raw_ostream &OS) {
+ std::vector<Record *> MatchedRecords;
+ std::copy_if(AllPatFrags.begin(), AllPatFrags.end(),
+ std::back_inserter(MatchedRecords), [&](Record *R) {
+ return !R->getValueAsString("ImmediateCode").empty() &&
+ R->getValueAsBit("IsAPInt");
+ });
+ emitImmPredicateFnsImpl<Record *>(
+ OS, "APInt", "const APInt &", ArrayRef<Record *>(MatchedRecords),
+ &getPatFragPredicateEnumName,
+ [&](Record *R) { return R->getValueAsString("ImmediateCode"); },
+ "PatFrag predicates.");
+}
+
+void GlobalISelEmitter::emitTestSimplePredicate(raw_ostream &OS) {
+ OS << "bool " << getClassName() << "::testSimplePredicate(unsigned) const {\n"
+ << " llvm_unreachable(\"" + getClassName() +
+ " does not support simple predicates!\");\n"
+ << " return false;\n"
+ << "}\n";
+}
+
+void GlobalISelEmitter::emitRunCustomAction(raw_ostream &OS) {
+ OS << "void " << getClassName()
+ << "::runCustomAction(unsigned, const MatcherState&) const {\n"
+ << " llvm_unreachable(\"" + getClassName() +
+ " does not support custom C++ actions!\");\n"
+ << "}\n";
}
void GlobalISelEmitter::run(raw_ostream &OS) {
@@ -5700,8 +2386,12 @@ void GlobalISelEmitter::run(raw_ostream &OS) {
// Track the GINodeEquiv definitions.
gatherNodeEquivs();
- emitSourceFileHeader(("Global Instruction Selector for the " +
- Target.getName() + " target").str(), OS);
+ AllPatFrags = RK.getAllDerivedDefinitions("PatFrags");
+
+ emitSourceFileHeader(
+ ("Global Instruction Selector for the " + Target.getName() + " target")
+ .str(),
+ OS);
std::vector<RuleMatcher> Rules;
// Look through the SelectionDAG patterns we found, possibly emitting some.
for (const PatternToMatch &Pat : CGP.ptms()) {
@@ -5753,203 +2443,13 @@ void GlobalISelEmitter::run(raw_ostream &OS) {
std::unique(CustomRendererFns.begin(), CustomRendererFns.end()),
CustomRendererFns.end());
- unsigned MaxTemporaries = 0;
- for (const auto &Rule : Rules)
- MaxTemporaries = std::max(MaxTemporaries, Rule.countRendererFns());
-
- OS << "#ifdef GET_GLOBALISEL_PREDICATE_BITSET\n"
- << "const unsigned MAX_SUBTARGET_PREDICATES = " << SubtargetFeatures.size()
- << ";\n"
- << "using PredicateBitset = "
- "llvm::PredicateBitsetImpl<MAX_SUBTARGET_PREDICATES>;\n"
- << "#endif // ifdef GET_GLOBALISEL_PREDICATE_BITSET\n\n";
-
- OS << "#ifdef GET_GLOBALISEL_TEMPORARIES_DECL\n"
- << " mutable MatcherState State;\n"
- << " typedef "
- "ComplexRendererFns("
- << Target.getName()
- << "InstructionSelector::*ComplexMatcherMemFn)(MachineOperand &) const;\n"
-
- << " typedef void(" << Target.getName()
- << "InstructionSelector::*CustomRendererFn)(MachineInstrBuilder &, const "
- "MachineInstr &, int) "
- "const;\n"
- << " const ISelInfoTy<PredicateBitset, ComplexMatcherMemFn, "
- "CustomRendererFn> "
- "ISelInfo;\n";
- OS << " static " << Target.getName()
- << "InstructionSelector::ComplexMatcherMemFn ComplexPredicateFns[];\n"
- << " static " << Target.getName()
- << "InstructionSelector::CustomRendererFn CustomRenderers[];\n"
- << " bool testImmPredicate_I64(unsigned PredicateID, int64_t Imm) const "
- "override;\n"
- << " bool testImmPredicate_APInt(unsigned PredicateID, const APInt &Imm) "
- "const override;\n"
- << " bool testImmPredicate_APFloat(unsigned PredicateID, const APFloat "
- "&Imm) const override;\n"
- << " const int64_t *getMatchTable() const override;\n"
- << " bool testMIPredicate_MI(unsigned PredicateID, const MachineInstr &MI"
- ", const std::array<const MachineOperand *, 3> &Operands) "
- "const override;\n"
- << "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_DECL\n\n";
-
- OS << "#ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n"
- << ", State(" << MaxTemporaries << "),\n"
- << "ISelInfo(TypeObjects, NumTypeObjects, FeatureBitsets"
- << ", ComplexPredicateFns, CustomRenderers)\n"
- << "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n\n";
-
- OS << "#ifdef GET_GLOBALISEL_IMPL\n";
- SubtargetFeatureInfo::emitSubtargetFeatureBitEnumeration(SubtargetFeatures,
- OS);
-
- // Separate subtarget features by how often they must be recomputed.
- SubtargetFeatureInfoMap ModuleFeatures;
- std::copy_if(SubtargetFeatures.begin(), SubtargetFeatures.end(),
- std::inserter(ModuleFeatures, ModuleFeatures.end()),
- [](const SubtargetFeatureInfoMap::value_type &X) {
- return !X.second.mustRecomputePerFunction();
- });
- SubtargetFeatureInfoMap FunctionFeatures;
- std::copy_if(SubtargetFeatures.begin(), SubtargetFeatures.end(),
- std::inserter(FunctionFeatures, FunctionFeatures.end()),
- [](const SubtargetFeatureInfoMap::value_type &X) {
- return X.second.mustRecomputePerFunction();
- });
-
- SubtargetFeatureInfo::emitComputeAvailableFeatures(
- Target.getName(), "InstructionSelector", "computeAvailableModuleFeatures",
- ModuleFeatures, OS);
-
-
- OS << "void " << Target.getName() << "InstructionSelector"
- "::setupGeneratedPerFunctionState(MachineFunction &MF) {\n"
- " AvailableFunctionFeatures = computeAvailableFunctionFeatures("
- "(const " << Target.getName() << "Subtarget *)&MF.getSubtarget(), &MF);\n"
- "}\n";
-
- SubtargetFeatureInfo::emitComputeAvailableFeatures(
- Target.getName(), "InstructionSelector",
- "computeAvailableFunctionFeatures", FunctionFeatures, OS,
- "const MachineFunction *MF");
-
- // Emit a table containing the LLT objects needed by the matcher and an enum
+ // Create a table containing the LLT objects needed by the matcher and an enum
// for the matcher to reference them with.
std::vector<LLTCodeGen> TypeObjects;
append_range(TypeObjects, KnownTypes);
llvm::sort(TypeObjects);
- OS << "// LLT Objects.\n"
- << "enum {\n";
- for (const auto &TypeObject : TypeObjects) {
- OS << " ";
- TypeObject.emitCxxEnumValue(OS);
- OS << ",\n";
- }
- OS << "};\n";
- OS << "const static size_t NumTypeObjects = " << TypeObjects.size() << ";\n"
- << "const static LLT TypeObjects[] = {\n";
- for (const auto &TypeObject : TypeObjects) {
- OS << " ";
- TypeObject.emitCxxConstructorCall(OS);
- OS << ",\n";
- }
- OS << "};\n\n";
-
- // Emit a table containing the PredicateBitsets objects needed by the matcher
- // and an enum for the matcher to reference them with.
- std::vector<std::vector<Record *>> FeatureBitsets;
- FeatureBitsets.reserve(Rules.size());
- for (auto &Rule : Rules)
- FeatureBitsets.push_back(Rule.getRequiredFeatures());
- llvm::sort(FeatureBitsets, [&](const std::vector<Record *> &A,
- const std::vector<Record *> &B) {
- if (A.size() < B.size())
- return true;
- if (A.size() > B.size())
- return false;
- for (auto Pair : zip(A, B)) {
- if (std::get<0>(Pair)->getName() < std::get<1>(Pair)->getName())
- return true;
- if (std::get<0>(Pair)->getName() > std::get<1>(Pair)->getName())
- return false;
- }
- return false;
- });
- FeatureBitsets.erase(
- std::unique(FeatureBitsets.begin(), FeatureBitsets.end()),
- FeatureBitsets.end());
- OS << "// Feature bitsets.\n"
- << "enum {\n"
- << " GIFBS_Invalid,\n";
- for (const auto &FeatureBitset : FeatureBitsets) {
- if (FeatureBitset.empty())
- continue;
- OS << " " << getNameForFeatureBitset(FeatureBitset) << ",\n";
- }
- OS << "};\n"
- << "const static PredicateBitset FeatureBitsets[] {\n"
- << " {}, // GIFBS_Invalid\n";
- for (const auto &FeatureBitset : FeatureBitsets) {
- if (FeatureBitset.empty())
- continue;
- OS << " {";
- for (const auto &Feature : FeatureBitset) {
- const auto &I = SubtargetFeatures.find(Feature);
- assert(I != SubtargetFeatures.end() && "Didn't import predicate?");
- OS << I->second.getEnumBitName() << ", ";
- }
- OS << "},\n";
- }
- OS << "};\n\n";
-
- // Emit complex predicate table and an enum to reference them with.
- OS << "// ComplexPattern predicates.\n"
- << "enum {\n"
- << " GICP_Invalid,\n";
- for (const auto &Record : ComplexPredicates)
- OS << " GICP_" << Record->getName() << ",\n";
- OS << "};\n"
- << "// See constructor for table contents\n\n";
-
- emitImmPredicateFns(OS, "I64", "int64_t", [](const Record *R) {
- bool Unset;
- return !R->getValueAsBitOrUnset("IsAPFloat", Unset) &&
- !R->getValueAsBit("IsAPInt");
- });
- emitImmPredicateFns(OS, "APFloat", "const APFloat &", [](const Record *R) {
- bool Unset;
- return R->getValueAsBitOrUnset("IsAPFloat", Unset);
- });
- emitImmPredicateFns(OS, "APInt", "const APInt &", [](const Record *R) {
- return R->getValueAsBit("IsAPInt");
- });
- emitMIPredicateFns(OS);
- OS << "\n";
-
- OS << Target.getName() << "InstructionSelector::ComplexMatcherMemFn\n"
- << Target.getName() << "InstructionSelector::ComplexPredicateFns[] = {\n"
- << " nullptr, // GICP_Invalid\n";
- for (const auto &Record : ComplexPredicates)
- OS << " &" << Target.getName()
- << "InstructionSelector::" << Record->getValueAsString("MatcherFn")
- << ", // " << Record->getName() << "\n";
- OS << "};\n\n";
-
- OS << "// Custom renderers.\n"
- << "enum {\n"
- << " GICR_Invalid,\n";
- for (const auto &Fn : CustomRendererFns)
- OS << " GICR_" << Fn << ",\n";
- OS << "};\n";
-
- OS << Target.getName() << "InstructionSelector::CustomRendererFn\n"
- << Target.getName() << "InstructionSelector::CustomRenderers[] = {\n"
- << " nullptr, // GICR_Invalid\n";
- for (const auto &Fn : CustomRendererFns)
- OS << " &" << Target.getName() << "InstructionSelector::" << Fn << ",\n";
- OS << "};\n\n";
+ // Sort rules.
llvm::stable_sort(Rules, [&](const RuleMatcher &A, const RuleMatcher &B) {
int ScoreA = RuleMatcherScores[A.getRuleID()];
int ScoreB = RuleMatcherScores[B.getRuleID()];
@@ -5966,53 +2466,21 @@ void GlobalISelEmitter::run(raw_ostream &OS) {
return false;
});
- OS << "bool " << Target.getName()
- << "InstructionSelector::selectImpl(MachineInstr &I, CodeGenCoverage "
- "&CoverageInfo) const {\n"
- << " MachineFunction &MF = *I.getParent()->getParent();\n"
- << " MachineRegisterInfo &MRI = MF.getRegInfo();\n"
- << " const PredicateBitset AvailableFeatures = getAvailableFeatures();\n"
- << " NewMIVector OutMIs;\n"
- << " State.MIs.clear();\n"
- << " State.MIs.push_back(&I);\n\n"
- << " if (executeMatchTable(*this, OutMIs, State, ISelInfo"
- << ", getMatchTable(), TII, MRI, TRI, RBI, AvailableFeatures"
- << ", CoverageInfo)) {\n"
- << " return true;\n"
- << " }\n\n"
- << " return false;\n"
- << "}\n\n";
+ unsigned MaxTemporaries = 0;
+ for (const auto &Rule : Rules)
+ MaxTemporaries = std::max(MaxTemporaries, Rule.countRendererFns());
+ // Build match table
const MatchTable Table =
buildMatchTable(Rules, OptimizeMatchTable, GenerateCoverage);
- OS << "const int64_t *" << Target.getName()
- << "InstructionSelector::getMatchTable() const {\n";
- Table.emitDeclaration(OS);
- OS << " return ";
- Table.emitUse(OS);
- OS << ";\n}\n";
- OS << "#endif // ifdef GET_GLOBALISEL_IMPL\n";
- OS << "#ifdef GET_GLOBALISEL_PREDICATES_DECL\n"
- << "PredicateBitset AvailableModuleFeatures;\n"
- << "mutable PredicateBitset AvailableFunctionFeatures;\n"
- << "PredicateBitset getAvailableFeatures() const {\n"
- << " return AvailableModuleFeatures | AvailableFunctionFeatures;\n"
- << "}\n"
- << "PredicateBitset\n"
- << "computeAvailableModuleFeatures(const " << Target.getName()
- << "Subtarget *Subtarget) const;\n"
- << "PredicateBitset\n"
- << "computeAvailableFunctionFeatures(const " << Target.getName()
- << "Subtarget *Subtarget,\n"
- << " const MachineFunction *MF) const;\n"
- << "void setupGeneratedPerFunctionState(MachineFunction &MF) override;\n"
- << "#endif // ifdef GET_GLOBALISEL_PREDICATES_DECL\n";
-
- OS << "#ifdef GET_GLOBALISEL_PREDICATES_INIT\n"
- << "AvailableModuleFeatures(computeAvailableModuleFeatures(&STI)),\n"
- << "AvailableFunctionFeatures()\n"
- << "#endif // ifdef GET_GLOBALISEL_PREDICATES_INIT\n";
+ emitPredicateBitset(OS, "GET_GLOBALISEL_PREDICATE_BITSET");
+ emitTemporariesDecl(OS, "GET_GLOBALISEL_TEMPORARIES_DECL");
+ emitTemporariesInit(OS, MaxTemporaries, "GET_GLOBALISEL_TEMPORARIES_INIT");
+ emitExecutorImpl(OS, Table, TypeObjects, Rules, ComplexPredicates,
+ CustomRendererFns, "GET_GLOBALISEL_IMPL");
+ emitPredicatesDecl(OS, "GET_GLOBALISEL_PREDICATES_DECL");
+ emitPredicatesInit(OS, "GET_GLOBALISEL_PREDICATES_INIT");
}
void GlobalISelEmitter::declareSubtargetFeature(Record *Predicate) {
@@ -6021,294 +2489,9 @@ void GlobalISelEmitter::declareSubtargetFeature(Record *Predicate) {
Predicate, SubtargetFeatureInfo(Predicate, SubtargetFeatures.size()));
}
-void RuleMatcher::optimize() {
- for (auto &Item : InsnVariableIDs) {
- InstructionMatcher &InsnMatcher = *Item.first;
- for (auto &OM : InsnMatcher.operands()) {
- // Complex Patterns are usually expensive and they relatively rarely fail
- // on their own: more often we end up throwing away all the work done by a
- // matching part of a complex pattern because some other part of the
- // enclosing pattern didn't match. All of this makes it beneficial to
- // delay complex patterns until the very end of the rule matching,
- // especially for targets having lots of complex patterns.
- for (auto &OP : OM->predicates())
- if (isa<ComplexPatternOperandMatcher>(OP))
- EpilogueMatchers.emplace_back(std::move(OP));
- OM->eraseNullPredicates();
- }
- InsnMatcher.optimize();
- }
- llvm::sort(EpilogueMatchers, [](const std::unique_ptr<PredicateMatcher> &L,
- const std::unique_ptr<PredicateMatcher> &R) {
- return std::make_tuple(L->getKind(), L->getInsnVarID(), L->getOpIdx()) <
- std::make_tuple(R->getKind(), R->getInsnVarID(), R->getOpIdx());
- });
-}
-
-bool RuleMatcher::hasFirstCondition() const {
- if (insnmatchers_empty())
- return false;
- InstructionMatcher &Matcher = insnmatchers_front();
- if (!Matcher.predicates_empty())
- return true;
- for (auto &OM : Matcher.operands())
- for (auto &OP : OM->predicates())
- if (!isa<InstructionOperandMatcher>(OP))
- return true;
- return false;
-}
-
-const PredicateMatcher &RuleMatcher::getFirstCondition() const {
- assert(!insnmatchers_empty() &&
- "Trying to get a condition from an empty RuleMatcher");
-
- InstructionMatcher &Matcher = insnmatchers_front();
- if (!Matcher.predicates_empty())
- return **Matcher.predicates_begin();
- // If there is no more predicate on the instruction itself, look at its
- // operands.
- for (auto &OM : Matcher.operands())
- for (auto &OP : OM->predicates())
- if (!isa<InstructionOperandMatcher>(OP))
- return *OP;
-
- llvm_unreachable("Trying to get a condition from an InstructionMatcher with "
- "no conditions");
-}
-
-std::unique_ptr<PredicateMatcher> RuleMatcher::popFirstCondition() {
- assert(!insnmatchers_empty() &&
- "Trying to pop a condition from an empty RuleMatcher");
-
- InstructionMatcher &Matcher = insnmatchers_front();
- if (!Matcher.predicates_empty())
- return Matcher.predicates_pop_front();
- // If there is no more predicate on the instruction itself, look at its
- // operands.
- for (auto &OM : Matcher.operands())
- for (auto &OP : OM->predicates())
- if (!isa<InstructionOperandMatcher>(OP)) {
- std::unique_ptr<PredicateMatcher> Result = std::move(OP);
- OM->eraseNullPredicates();
- return Result;
- }
-
- llvm_unreachable("Trying to pop a condition from an InstructionMatcher with "
- "no conditions");
-}
-
-bool GroupMatcher::candidateConditionMatches(
- const PredicateMatcher &Predicate) const {
-
- if (empty()) {
- // Sharing predicates for nested instructions is not supported yet as we
- // currently don't hoist the GIM_RecordInsn's properly, therefore we can
- // only work on the original root instruction (InsnVarID == 0):
- if (Predicate.getInsnVarID() != 0)
- return false;
- // ... otherwise an empty group can handle any predicate with no specific
- // requirements:
- return true;
- }
-
- const Matcher &Representative = **Matchers.begin();
- const auto &RepresentativeCondition = Representative.getFirstCondition();
- // ... if not empty, the group can only accomodate matchers with the exact
- // same first condition:
- return Predicate.isIdentical(RepresentativeCondition);
-}
-
-bool GroupMatcher::addMatcher(Matcher &Candidate) {
- if (!Candidate.hasFirstCondition())
- return false;
-
- const PredicateMatcher &Predicate = Candidate.getFirstCondition();
- if (!candidateConditionMatches(Predicate))
- return false;
-
- Matchers.push_back(&Candidate);
- return true;
-}
-
-void GroupMatcher::finalize() {
- assert(Conditions.empty() && "Already finalized?");
- if (empty())
- return;
-
- Matcher &FirstRule = **Matchers.begin();
- for (;;) {
- // All the checks are expected to succeed during the first iteration:
- for (const auto &Rule : Matchers)
- if (!Rule->hasFirstCondition())
- return;
- const auto &FirstCondition = FirstRule.getFirstCondition();
- for (unsigned I = 1, E = Matchers.size(); I < E; ++I)
- if (!Matchers[I]->getFirstCondition().isIdentical(FirstCondition))
- return;
-
- Conditions.push_back(FirstRule.popFirstCondition());
- for (unsigned I = 1, E = Matchers.size(); I < E; ++I)
- Matchers[I]->popFirstCondition();
- }
-}
-
-void GroupMatcher::emit(MatchTable &Table) {
- unsigned LabelID = ~0U;
- if (!Conditions.empty()) {
- LabelID = Table.allocateLabelID();
- Table << MatchTable::Opcode("GIM_Try", +1)
- << MatchTable::Comment("On fail goto")
- << MatchTable::JumpTarget(LabelID) << MatchTable::LineBreak;
- }
- for (auto &Condition : Conditions)
- Condition->emitPredicateOpcodes(
- Table, *static_cast<RuleMatcher *>(*Matchers.begin()));
-
- for (const auto &M : Matchers)
- M->emit(Table);
-
- // Exit the group
- if (!Conditions.empty())
- Table << MatchTable::Opcode("GIM_Reject", -1) << MatchTable::LineBreak
- << MatchTable::Label(LabelID);
-}
-
-bool SwitchMatcher::isSupportedPredicateType(const PredicateMatcher &P) {
- return isa<InstructionOpcodeMatcher>(P) || isa<LLTOperandMatcher>(P);
-}
-
-bool SwitchMatcher::candidateConditionMatches(
- const PredicateMatcher &Predicate) const {
-
- if (empty()) {
- // Sharing predicates for nested instructions is not supported yet as we
- // currently don't hoist the GIM_RecordInsn's properly, therefore we can
- // only work on the original root instruction (InsnVarID == 0):
- if (Predicate.getInsnVarID() != 0)
- return false;
- // ... while an attempt to add even a root matcher to an empty SwitchMatcher
- // could fail as not all the types of conditions are supported:
- if (!isSupportedPredicateType(Predicate))
- return false;
- // ... or the condition might not have a proper implementation of
- // getValue() / isIdenticalDownToValue() yet:
- if (!Predicate.hasValue())
- return false;
- // ... otherwise an empty Switch can accomodate the condition with no
- // further requirements:
- return true;
- }
-
- const Matcher &CaseRepresentative = **Matchers.begin();
- const auto &RepresentativeCondition = CaseRepresentative.getFirstCondition();
- // Switch-cases must share the same kind of condition and path to the value it
- // checks:
- if (!Predicate.isIdenticalDownToValue(RepresentativeCondition))
- return false;
-
- const auto Value = Predicate.getValue();
- // ... but be unique with respect to the actual value they check:
- return Values.count(Value) == 0;
-}
-
-bool SwitchMatcher::addMatcher(Matcher &Candidate) {
- if (!Candidate.hasFirstCondition())
- return false;
-
- const PredicateMatcher &Predicate = Candidate.getFirstCondition();
- if (!candidateConditionMatches(Predicate))
- return false;
- const auto Value = Predicate.getValue();
- Values.insert(Value);
-
- Matchers.push_back(&Candidate);
- return true;
-}
-
-void SwitchMatcher::finalize() {
- assert(Condition == nullptr && "Already finalized");
- assert(Values.size() == Matchers.size() && "Broken SwitchMatcher");
- if (empty())
- return;
-
- llvm::stable_sort(Matchers, [](const Matcher *L, const Matcher *R) {
- return L->getFirstCondition().getValue() <
- R->getFirstCondition().getValue();
- });
- Condition = Matchers[0]->popFirstCondition();
- for (unsigned I = 1, E = Values.size(); I < E; ++I)
- Matchers[I]->popFirstCondition();
-}
-
-void SwitchMatcher::emitPredicateSpecificOpcodes(const PredicateMatcher &P,
- MatchTable &Table) {
- assert(isSupportedPredicateType(P) && "Predicate type is not supported");
-
- if (const auto *Condition = dyn_cast<InstructionOpcodeMatcher>(&P)) {
- Table << MatchTable::Opcode("GIM_SwitchOpcode") << MatchTable::Comment("MI")
- << MatchTable::IntValue(Condition->getInsnVarID());
- return;
- }
- if (const auto *Condition = dyn_cast<LLTOperandMatcher>(&P)) {
- Table << MatchTable::Opcode("GIM_SwitchType") << MatchTable::Comment("MI")
- << MatchTable::IntValue(Condition->getInsnVarID())
- << MatchTable::Comment("Op")
- << MatchTable::IntValue(Condition->getOpIdx());
- return;
- }
-
- llvm_unreachable("emitPredicateSpecificOpcodes is broken: can not handle a "
- "predicate type that is claimed to be supported");
-}
-
-void SwitchMatcher::emit(MatchTable &Table) {
- assert(Values.size() == Matchers.size() && "Broken SwitchMatcher");
- if (empty())
- return;
- assert(Condition != nullptr &&
- "Broken SwitchMatcher, hasn't been finalized?");
-
- std::vector<unsigned> LabelIDs(Values.size());
- std::generate(LabelIDs.begin(), LabelIDs.end(),
- [&Table]() { return Table.allocateLabelID(); });
- const unsigned Default = Table.allocateLabelID();
-
- const int64_t LowerBound = Values.begin()->getRawValue();
- const int64_t UpperBound = Values.rbegin()->getRawValue() + 1;
-
- emitPredicateSpecificOpcodes(*Condition, Table);
-
- Table << MatchTable::Comment("[") << MatchTable::IntValue(LowerBound)
- << MatchTable::IntValue(UpperBound) << MatchTable::Comment(")")
- << MatchTable::Comment("default:") << MatchTable::JumpTarget(Default);
-
- int64_t J = LowerBound;
- auto VI = Values.begin();
- for (unsigned I = 0, E = Values.size(); I < E; ++I) {
- auto V = *VI++;
- while (J++ < V.getRawValue())
- Table << MatchTable::IntValue(0);
- V.turnIntoComment();
- Table << MatchTable::LineBreak << V << MatchTable::JumpTarget(LabelIDs[I]);
- }
- Table << MatchTable::LineBreak;
-
- for (unsigned I = 0, E = Values.size(); I < E; ++I) {
- Table << MatchTable::Label(LabelIDs[I]);
- Matchers[I]->emit(Table);
- Table << MatchTable::Opcode("GIM_Reject") << MatchTable::LineBreak;
- }
- Table << MatchTable::Label(Default);
-}
-
-unsigned OperandMatcher::getInsnVarID() const { return Insn.getInsnVarID(); }
-
} // end anonymous namespace
//===----------------------------------------------------------------------===//
-namespace llvm {
-void EmitGlobalISel(RecordKeeper &RK, raw_ostream &OS) {
- GlobalISelEmitter(RK).run(OS);
-}
-} // End llvm namespace
+static TableGen::Emitter::OptClass<GlobalISelEmitter>
+ X("gen-global-isel", "Generate GlobalISel selector");
diff --git a/llvm/utils/TableGen/GlobalISelMatchTable.cpp b/llvm/utils/TableGen/GlobalISelMatchTable.cpp
new file mode 100644
index 000000000000..aab772f020a6
--- /dev/null
+++ b/llvm/utils/TableGen/GlobalISelMatchTable.cpp
@@ -0,0 +1,2019 @@
+//===- GlobalISelMatchTable.cpp -------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "GlobalISelMatchTable.h"
+#include "CodeGenInstruction.h"
+#include "CodeGenRegisters.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/TableGen/Error.h"
+
+#define DEBUG_TYPE "gi-match-table"
+
+STATISTIC(NumPatternEmitted, "Number of patterns emitted");
+
+namespace llvm {
+namespace gi {
+
+namespace {
+
+Error failUnsupported(const Twine &Reason) {
+ return make_error<StringError>(Reason, inconvertibleErrorCode());
+}
+
+/// Get the name of the enum value used to number the predicate function.
+std::string getEnumNameForPredicate(const TreePredicateFn &Predicate) {
+ if (Predicate.hasGISelPredicateCode())
+ return "GICXXPred_MI_" + Predicate.getFnName();
+ return "GICXXPred_" + Predicate.getImmTypeIdentifier().str() + "_" +
+ Predicate.getFnName();
+}
+
+std::string getMatchOpcodeForImmPredicate(const TreePredicateFn &Predicate) {
+ return "GIM_Check" + Predicate.getImmTypeIdentifier().str() + "ImmPredicate";
+}
+} // namespace
+
+//===- Helpers ------------------------------------------------------------===//
+
+std::string
+getNameForFeatureBitset(const std::vector<Record *> &FeatureBitset) {
+ std::string Name = "GIFBS";
+ for (const auto &Feature : FeatureBitset)
+ Name += ("_" + Feature->getName()).str();
+ return Name;
+}
+
+template <class GroupT>
+std::vector<Matcher *>
+optimizeRules(ArrayRef<Matcher *> Rules,
+ std::vector<std::unique_ptr<Matcher>> &MatcherStorage) {
+
+ std::vector<Matcher *> OptRules;
+ std::unique_ptr<GroupT> CurrentGroup = std::make_unique<GroupT>();
+ assert(CurrentGroup->empty() && "Newly created group isn't empty!");
+ unsigned NumGroups = 0;
+
+ auto ProcessCurrentGroup = [&]() {
+ if (CurrentGroup->empty())
+ // An empty group is good to be reused:
+ return;
+
+ // If the group isn't large enough to provide any benefit, move all the
+ // added rules out of it and make sure to re-create the group to properly
+ // re-initialize it:
+ if (CurrentGroup->size() < 2)
+ append_range(OptRules, CurrentGroup->matchers());
+ else {
+ CurrentGroup->finalize();
+ OptRules.push_back(CurrentGroup.get());
+ MatcherStorage.emplace_back(std::move(CurrentGroup));
+ ++NumGroups;
+ }
+ CurrentGroup = std::make_unique<GroupT>();
+ };
+ for (Matcher *Rule : Rules) {
+ // Greedily add as many matchers as possible to the current group:
+ if (CurrentGroup->addMatcher(*Rule))
+ continue;
+
+ ProcessCurrentGroup();
+ assert(CurrentGroup->empty() && "A group wasn't properly re-initialized");
+
+ // Try to add the pending matcher to a newly created empty group:
+ if (!CurrentGroup->addMatcher(*Rule))
+ // If we couldn't add the matcher to an empty group, that group type
+ // doesn't support that kind of matchers at all, so just skip it:
+ OptRules.push_back(Rule);
+ }
+ ProcessCurrentGroup();
+
+ LLVM_DEBUG(dbgs() << "NumGroups: " << NumGroups << "\n");
+ (void)NumGroups;
+ assert(CurrentGroup->empty() && "The last group wasn't properly processed");
+ return OptRules;
+}
+
+template std::vector<Matcher *> optimizeRules<GroupMatcher>(
+ ArrayRef<Matcher *> Rules,
+ std::vector<std::unique_ptr<Matcher>> &MatcherStorage);
+
+template std::vector<Matcher *> optimizeRules<SwitchMatcher>(
+ ArrayRef<Matcher *> Rules,
+ std::vector<std::unique_ptr<Matcher>> &MatcherStorage);
+
+//===- Global Data --------------------------------------------------------===//
+
+std::set<LLTCodeGen> KnownTypes;
+
+//===- MatchTableRecord ---------------------------------------------------===//
+
+void MatchTableRecord::emit(raw_ostream &OS, bool LineBreakIsNextAfterThis,
+ const MatchTable &Table) const {
+ bool UseLineComment =
+ LineBreakIsNextAfterThis || (Flags & MTRF_LineBreakFollows);
+ if (Flags & (MTRF_JumpTarget | MTRF_CommaFollows))
+ UseLineComment = false;
+
+ if (Flags & MTRF_Comment)
+ OS << (UseLineComment ? "// " : "/*");
+
+ OS << EmitStr;
+ if (Flags & MTRF_Label)
+ OS << ": @" << Table.getLabelIndex(LabelID);
+
+ if ((Flags & MTRF_Comment) && !UseLineComment)
+ OS << "*/";
+
+ if (Flags & MTRF_JumpTarget) {
+ if (Flags & MTRF_Comment)
+ OS << " ";
+ OS << Table.getLabelIndex(LabelID);
+ }
+
+ if (Flags & MTRF_CommaFollows) {
+ OS << ",";
+ if (!LineBreakIsNextAfterThis && !(Flags & MTRF_LineBreakFollows))
+ OS << " ";
+ }
+
+ if (Flags & MTRF_LineBreakFollows)
+ OS << "\n";
+}
+
+//===- MatchTable ---------------------------------------------------------===//
+
+MatchTableRecord MatchTable::LineBreak = {
+ std::nullopt, "" /* Emit String */, 0 /* Elements */,
+ MatchTableRecord::MTRF_LineBreakFollows};
+
+MatchTableRecord MatchTable::Comment(StringRef Comment) {
+ return MatchTableRecord(std::nullopt, Comment, 0,
+ MatchTableRecord::MTRF_Comment);
+}
+
+MatchTableRecord MatchTable::Opcode(StringRef Opcode, int IndentAdjust) {
+ unsigned ExtraFlags = 0;
+ if (IndentAdjust > 0)
+ ExtraFlags |= MatchTableRecord::MTRF_Indent;
+ if (IndentAdjust < 0)
+ ExtraFlags |= MatchTableRecord::MTRF_Outdent;
+
+ return MatchTableRecord(std::nullopt, Opcode, 1,
+ MatchTableRecord::MTRF_CommaFollows | ExtraFlags);
+}
+
+MatchTableRecord MatchTable::NamedValue(StringRef NamedValue) {
+ return MatchTableRecord(std::nullopt, NamedValue, 1,
+ MatchTableRecord::MTRF_CommaFollows);
+}
+
+MatchTableRecord MatchTable::NamedValue(StringRef NamedValue,
+ int64_t RawValue) {
+ return MatchTableRecord(std::nullopt, NamedValue, 1,
+ MatchTableRecord::MTRF_CommaFollows, RawValue);
+}
+
+MatchTableRecord MatchTable::NamedValue(StringRef Namespace,
+ StringRef NamedValue) {
+ return MatchTableRecord(std::nullopt, (Namespace + "::" + NamedValue).str(),
+ 1, MatchTableRecord::MTRF_CommaFollows);
+}
+
+MatchTableRecord MatchTable::NamedValue(StringRef Namespace,
+ StringRef NamedValue,
+ int64_t RawValue) {
+ return MatchTableRecord(std::nullopt, (Namespace + "::" + NamedValue).str(),
+ 1, MatchTableRecord::MTRF_CommaFollows, RawValue);
+}
+
+MatchTableRecord MatchTable::IntValue(int64_t IntValue) {
+ return MatchTableRecord(std::nullopt, llvm::to_string(IntValue), 1,
+ MatchTableRecord::MTRF_CommaFollows);
+}
+
+MatchTableRecord MatchTable::Label(unsigned LabelID) {
+ return MatchTableRecord(LabelID, "Label " + llvm::to_string(LabelID), 0,
+ MatchTableRecord::MTRF_Label |
+ MatchTableRecord::MTRF_Comment |
+ MatchTableRecord::MTRF_LineBreakFollows);
+}
+
+MatchTableRecord MatchTable::JumpTarget(unsigned LabelID) {
+ return MatchTableRecord(LabelID, "Label " + llvm::to_string(LabelID), 1,
+ MatchTableRecord::MTRF_JumpTarget |
+ MatchTableRecord::MTRF_Comment |
+ MatchTableRecord::MTRF_CommaFollows);
+}
+
+void MatchTable::emitUse(raw_ostream &OS) const { OS << "MatchTable" << ID; }
+
+void MatchTable::emitDeclaration(raw_ostream &OS) const {
+ unsigned Indentation = 4;
+ OS << " constexpr static int64_t MatchTable" << ID << "[] = {";
+ LineBreak.emit(OS, true, *this);
+ OS << std::string(Indentation, ' ');
+
+ for (auto I = Contents.begin(), E = Contents.end(); I != E; ++I) {
+ bool LineBreakIsNext = false;
+ const auto &NextI = std::next(I);
+
+ if (NextI != E) {
+ if (NextI->EmitStr == "" &&
+ NextI->Flags == MatchTableRecord::MTRF_LineBreakFollows)
+ LineBreakIsNext = true;
+ }
+
+ if (I->Flags & MatchTableRecord::MTRF_Indent)
+ Indentation += 2;
+
+ I->emit(OS, LineBreakIsNext, *this);
+ if (I->Flags & MatchTableRecord::MTRF_LineBreakFollows)
+ OS << std::string(Indentation, ' ');
+
+ if (I->Flags & MatchTableRecord::MTRF_Outdent)
+ Indentation -= 2;
+ }
+ OS << "};\n";
+}
+
+MatchTable MatchTable::buildTable(ArrayRef<Matcher *> Rules, bool WithCoverage,
+ bool IsCombiner) {
+ MatchTable Table(WithCoverage, IsCombiner);
+ for (Matcher *Rule : Rules)
+ Rule->emit(Table);
+
+ return Table << MatchTable::Opcode("GIM_Reject") << MatchTable::LineBreak;
+}
+
+//===- LLTCodeGen ---------------------------------------------------------===//
+
+std::string LLTCodeGen::getCxxEnumValue() const {
+ std::string Str;
+ raw_string_ostream OS(Str);
+
+ emitCxxEnumValue(OS);
+ return Str;
+}
+
+void LLTCodeGen::emitCxxEnumValue(raw_ostream &OS) const {
+ if (Ty.isScalar()) {
+ OS << "GILLT_s" << Ty.getSizeInBits();
+ return;
+ }
+ if (Ty.isVector()) {
+ OS << (Ty.isScalable() ? "GILLT_nxv" : "GILLT_v")
+ << Ty.getElementCount().getKnownMinValue() << "s"
+ << Ty.getScalarSizeInBits();
+ return;
+ }
+ if (Ty.isPointer()) {
+ OS << "GILLT_p" << Ty.getAddressSpace();
+ if (Ty.getSizeInBits() > 0)
+ OS << "s" << Ty.getSizeInBits();
+ return;
+ }
+ llvm_unreachable("Unhandled LLT");
+}
+
+void LLTCodeGen::emitCxxConstructorCall(raw_ostream &OS) const {
+ if (Ty.isScalar()) {
+ OS << "LLT::scalar(" << Ty.getSizeInBits() << ")";
+ return;
+ }
+ if (Ty.isVector()) {
+ OS << "LLT::vector("
+ << (Ty.isScalable() ? "ElementCount::getScalable("
+ : "ElementCount::getFixed(")
+ << Ty.getElementCount().getKnownMinValue() << "), "
+ << Ty.getScalarSizeInBits() << ")";
+ return;
+ }
+ if (Ty.isPointer() && Ty.getSizeInBits() > 0) {
+ OS << "LLT::pointer(" << Ty.getAddressSpace() << ", " << Ty.getSizeInBits()
+ << ")";
+ return;
+ }
+ llvm_unreachable("Unhandled LLT");
+}
+
+/// This ordering is used for std::unique() and llvm::sort(). There's no
+/// particular logic behind the order but either A < B or B < A must be
+/// true if A != B.
+bool LLTCodeGen::operator<(const LLTCodeGen &Other) const {
+ if (Ty.isValid() != Other.Ty.isValid())
+ return Ty.isValid() < Other.Ty.isValid();
+ if (!Ty.isValid())
+ return false;
+
+ if (Ty.isVector() != Other.Ty.isVector())
+ return Ty.isVector() < Other.Ty.isVector();
+ if (Ty.isScalar() != Other.Ty.isScalar())
+ return Ty.isScalar() < Other.Ty.isScalar();
+ if (Ty.isPointer() != Other.Ty.isPointer())
+ return Ty.isPointer() < Other.Ty.isPointer();
+
+ if (Ty.isPointer() && Ty.getAddressSpace() != Other.Ty.getAddressSpace())
+ return Ty.getAddressSpace() < Other.Ty.getAddressSpace();
+
+ if (Ty.isVector() && Ty.getElementCount() != Other.Ty.getElementCount())
+ return std::make_tuple(Ty.isScalable(),
+ Ty.getElementCount().getKnownMinValue()) <
+ std::make_tuple(Other.Ty.isScalable(),
+ Other.Ty.getElementCount().getKnownMinValue());
+
+ assert((!Ty.isVector() || Ty.isScalable() == Other.Ty.isScalable()) &&
+ "Unexpected mismatch of scalable property");
+ return Ty.isVector()
+ ? std::make_tuple(Ty.isScalable(),
+ Ty.getSizeInBits().getKnownMinValue()) <
+ std::make_tuple(Other.Ty.isScalable(),
+ Other.Ty.getSizeInBits().getKnownMinValue())
+ : Ty.getSizeInBits().getFixedValue() <
+ Other.Ty.getSizeInBits().getFixedValue();
+}
+
+//===- LLTCodeGen Helpers -------------------------------------------------===//
+
+std::optional<LLTCodeGen> MVTToLLT(MVT::SimpleValueType SVT) {
+ MVT VT(SVT);
+
+ if (VT.isVector() && !VT.getVectorElementCount().isScalar())
+ return LLTCodeGen(
+ LLT::vector(VT.getVectorElementCount(), VT.getScalarSizeInBits()));
+
+ if (VT.isInteger() || VT.isFloatingPoint())
+ return LLTCodeGen(LLT::scalar(VT.getSizeInBits()));
+
+ return std::nullopt;
+}
+
+//===- Matcher ------------------------------------------------------------===//
+
+void Matcher::optimize() {}
+
+Matcher::~Matcher() {}
+
+//===- GroupMatcher -------------------------------------------------------===//
+
+bool GroupMatcher::candidateConditionMatches(
+ const PredicateMatcher &Predicate) const {
+
+ if (empty()) {
+ // Sharing predicates for nested instructions is not supported yet as we
+ // currently don't hoist the GIM_RecordInsn's properly, therefore we can
+ // only work on the original root instruction (InsnVarID == 0):
+ if (Predicate.getInsnVarID() != 0)
+ return false;
+ // ... otherwise an empty group can handle any predicate with no specific
+ // requirements:
+ return true;
+ }
+
+ const Matcher &Representative = **Matchers.begin();
+ const auto &RepresentativeCondition = Representative.getFirstCondition();
+ // ... if not empty, the group can only accomodate matchers with the exact
+ // same first condition:
+ return Predicate.isIdentical(RepresentativeCondition);
+}
+
+bool GroupMatcher::addMatcher(Matcher &Candidate) {
+ if (!Candidate.hasFirstCondition())
+ return false;
+
+ const PredicateMatcher &Predicate = Candidate.getFirstCondition();
+ if (!candidateConditionMatches(Predicate))
+ return false;
+
+ Matchers.push_back(&Candidate);
+ return true;
+}
+
+void GroupMatcher::finalize() {
+ assert(Conditions.empty() && "Already finalized?");
+ if (empty())
+ return;
+
+ Matcher &FirstRule = **Matchers.begin();
+ for (;;) {
+ // All the checks are expected to succeed during the first iteration:
+ for (const auto &Rule : Matchers)
+ if (!Rule->hasFirstCondition())
+ return;
+ const auto &FirstCondition = FirstRule.getFirstCondition();
+ for (unsigned I = 1, E = Matchers.size(); I < E; ++I)
+ if (!Matchers[I]->getFirstCondition().isIdentical(FirstCondition))
+ return;
+
+ Conditions.push_back(FirstRule.popFirstCondition());
+ for (unsigned I = 1, E = Matchers.size(); I < E; ++I)
+ Matchers[I]->popFirstCondition();
+ }
+}
+
+void GroupMatcher::emit(MatchTable &Table) {
+ unsigned LabelID = ~0U;
+ if (!Conditions.empty()) {
+ LabelID = Table.allocateLabelID();
+ Table << MatchTable::Opcode("GIM_Try", +1)
+ << MatchTable::Comment("On fail goto")
+ << MatchTable::JumpTarget(LabelID) << MatchTable::LineBreak;
+ }
+ for (auto &Condition : Conditions)
+ Condition->emitPredicateOpcodes(
+ Table, *static_cast<RuleMatcher *>(*Matchers.begin()));
+
+ for (const auto &M : Matchers)
+ M->emit(Table);
+
+ // Exit the group
+ if (!Conditions.empty())
+ Table << MatchTable::Opcode("GIM_Reject", -1) << MatchTable::LineBreak
+ << MatchTable::Label(LabelID);
+}
+
+void GroupMatcher::optimize() {
+ // Make sure we only sort by a specific predicate within a range of rules that
+ // all have that predicate checked against a specific value (not a wildcard):
+ auto F = Matchers.begin();
+ auto T = F;
+ auto E = Matchers.end();
+ while (T != E) {
+ while (T != E) {
+ auto *R = static_cast<RuleMatcher *>(*T);
+ if (!R->getFirstConditionAsRootType().get().isValid())
+ break;
+ ++T;
+ }
+ std::stable_sort(F, T, [](Matcher *A, Matcher *B) {
+ auto *L = static_cast<RuleMatcher *>(A);
+ auto *R = static_cast<RuleMatcher *>(B);
+ return L->getFirstConditionAsRootType() <
+ R->getFirstConditionAsRootType();
+ });
+ if (T != E)
+ F = ++T;
+ }
+ optimizeRules<GroupMatcher>(Matchers, MatcherStorage).swap(Matchers);
+ optimizeRules<SwitchMatcher>(Matchers, MatcherStorage).swap(Matchers);
+}
+
+//===- SwitchMatcher ------------------------------------------------------===//
+
+bool SwitchMatcher::isSupportedPredicateType(const PredicateMatcher &P) {
+ return isa<InstructionOpcodeMatcher>(P) || isa<LLTOperandMatcher>(P);
+}
+
+bool SwitchMatcher::candidateConditionMatches(
+ const PredicateMatcher &Predicate) const {
+
+ if (empty()) {
+ // Sharing predicates for nested instructions is not supported yet as we
+ // currently don't hoist the GIM_RecordInsn's properly, therefore we can
+ // only work on the original root instruction (InsnVarID == 0):
+ if (Predicate.getInsnVarID() != 0)
+ return false;
+ // ... while an attempt to add even a root matcher to an empty SwitchMatcher
+ // could fail as not all the types of conditions are supported:
+ if (!isSupportedPredicateType(Predicate))
+ return false;
+ // ... or the condition might not have a proper implementation of
+ // getValue() / isIdenticalDownToValue() yet:
+ if (!Predicate.hasValue())
+ return false;
+ // ... otherwise an empty Switch can accomodate the condition with no
+ // further requirements:
+ return true;
+ }
+
+ const Matcher &CaseRepresentative = **Matchers.begin();
+ const auto &RepresentativeCondition = CaseRepresentative.getFirstCondition();
+ // Switch-cases must share the same kind of condition and path to the value it
+ // checks:
+ if (!Predicate.isIdenticalDownToValue(RepresentativeCondition))
+ return false;
+
+ const auto Value = Predicate.getValue();
+ // ... but be unique with respect to the actual value they check:
+ return Values.count(Value) == 0;
+}
+
+bool SwitchMatcher::addMatcher(Matcher &Candidate) {
+ if (!Candidate.hasFirstCondition())
+ return false;
+
+ const PredicateMatcher &Predicate = Candidate.getFirstCondition();
+ if (!candidateConditionMatches(Predicate))
+ return false;
+ const auto Value = Predicate.getValue();
+ Values.insert(Value);
+
+ Matchers.push_back(&Candidate);
+ return true;
+}
+
+void SwitchMatcher::finalize() {
+ assert(Condition == nullptr && "Already finalized");
+ assert(Values.size() == Matchers.size() && "Broken SwitchMatcher");
+ if (empty())
+ return;
+
+ llvm::stable_sort(Matchers, [](const Matcher *L, const Matcher *R) {
+ return L->getFirstCondition().getValue() <
+ R->getFirstCondition().getValue();
+ });
+ Condition = Matchers[0]->popFirstCondition();
+ for (unsigned I = 1, E = Values.size(); I < E; ++I)
+ Matchers[I]->popFirstCondition();
+}
+
+void SwitchMatcher::emitPredicateSpecificOpcodes(const PredicateMatcher &P,
+ MatchTable &Table) {
+ assert(isSupportedPredicateType(P) && "Predicate type is not supported");
+
+ if (const auto *Condition = dyn_cast<InstructionOpcodeMatcher>(&P)) {
+ Table << MatchTable::Opcode("GIM_SwitchOpcode") << MatchTable::Comment("MI")
+ << MatchTable::IntValue(Condition->getInsnVarID());
+ return;
+ }
+ if (const auto *Condition = dyn_cast<LLTOperandMatcher>(&P)) {
+ Table << MatchTable::Opcode("GIM_SwitchType") << MatchTable::Comment("MI")
+ << MatchTable::IntValue(Condition->getInsnVarID())
+ << MatchTable::Comment("Op")
+ << MatchTable::IntValue(Condition->getOpIdx());
+ return;
+ }
+
+ llvm_unreachable("emitPredicateSpecificOpcodes is broken: can not handle a "
+ "predicate type that is claimed to be supported");
+}
+
+void SwitchMatcher::emit(MatchTable &Table) {
+ assert(Values.size() == Matchers.size() && "Broken SwitchMatcher");
+ if (empty())
+ return;
+ assert(Condition != nullptr &&
+ "Broken SwitchMatcher, hasn't been finalized?");
+
+ std::vector<unsigned> LabelIDs(Values.size());
+ std::generate(LabelIDs.begin(), LabelIDs.end(),
+ [&Table]() { return Table.allocateLabelID(); });
+ const unsigned Default = Table.allocateLabelID();
+
+ const int64_t LowerBound = Values.begin()->getRawValue();
+ const int64_t UpperBound = Values.rbegin()->getRawValue() + 1;
+
+ emitPredicateSpecificOpcodes(*Condition, Table);
+
+ Table << MatchTable::Comment("[") << MatchTable::IntValue(LowerBound)
+ << MatchTable::IntValue(UpperBound) << MatchTable::Comment(")")
+ << MatchTable::Comment("default:") << MatchTable::JumpTarget(Default);
+
+ int64_t J = LowerBound;
+ auto VI = Values.begin();
+ for (unsigned I = 0, E = Values.size(); I < E; ++I) {
+ auto V = *VI++;
+ while (J++ < V.getRawValue())
+ Table << MatchTable::IntValue(0);
+ V.turnIntoComment();
+ Table << MatchTable::LineBreak << V << MatchTable::JumpTarget(LabelIDs[I]);
+ }
+ Table << MatchTable::LineBreak;
+
+ for (unsigned I = 0, E = Values.size(); I < E; ++I) {
+ Table << MatchTable::Label(LabelIDs[I]);
+ Matchers[I]->emit(Table);
+ Table << MatchTable::Opcode("GIM_Reject") << MatchTable::LineBreak;
+ }
+ Table << MatchTable::Label(Default);
+}
+
+//===- RuleMatcher --------------------------------------------------------===//
+
+uint64_t RuleMatcher::NextRuleID = 0;
+
+StringRef RuleMatcher::getOpcode() const {
+ return Matchers.front()->getOpcode();
+}
+
+unsigned RuleMatcher::getNumOperands() const {
+ return Matchers.front()->getNumOperands();
+}
+
+LLTCodeGen RuleMatcher::getFirstConditionAsRootType() {
+ InstructionMatcher &InsnMatcher = *Matchers.front();
+ if (!InsnMatcher.predicates_empty())
+ if (const auto *TM =
+ dyn_cast<LLTOperandMatcher>(&**InsnMatcher.predicates_begin()))
+ if (TM->getInsnVarID() == 0 && TM->getOpIdx() == 0)
+ return TM->getTy();
+ return {};
+}
+
+void RuleMatcher::optimize() {
+ for (auto &Item : InsnVariableIDs) {
+ InstructionMatcher &InsnMatcher = *Item.first;
+ for (auto &OM : InsnMatcher.operands()) {
+ // Complex Patterns are usually expensive and they relatively rarely fail
+ // on their own: more often we end up throwing away all the work done by a
+ // matching part of a complex pattern because some other part of the
+ // enclosing pattern didn't match. All of this makes it beneficial to
+ // delay complex patterns until the very end of the rule matching,
+ // especially for targets having lots of complex patterns.
+ for (auto &OP : OM->predicates())
+ if (isa<ComplexPatternOperandMatcher>(OP))
+ EpilogueMatchers.emplace_back(std::move(OP));
+ OM->eraseNullPredicates();
+ }
+ InsnMatcher.optimize();
+ }
+ llvm::sort(EpilogueMatchers, [](const std::unique_ptr<PredicateMatcher> &L,
+ const std::unique_ptr<PredicateMatcher> &R) {
+ return std::make_tuple(L->getKind(), L->getInsnVarID(), L->getOpIdx()) <
+ std::make_tuple(R->getKind(), R->getInsnVarID(), R->getOpIdx());
+ });
+}
+
+bool RuleMatcher::hasFirstCondition() const {
+ if (insnmatchers_empty())
+ return false;
+ InstructionMatcher &Matcher = insnmatchers_front();
+ if (!Matcher.predicates_empty())
+ return true;
+ for (auto &OM : Matcher.operands())
+ for (auto &OP : OM->predicates())
+ if (!isa<InstructionOperandMatcher>(OP))
+ return true;
+ return false;
+}
+
+const PredicateMatcher &RuleMatcher::getFirstCondition() const {
+ assert(!insnmatchers_empty() &&
+ "Trying to get a condition from an empty RuleMatcher");
+
+ InstructionMatcher &Matcher = insnmatchers_front();
+ if (!Matcher.predicates_empty())
+ return **Matcher.predicates_begin();
+ // If there is no more predicate on the instruction itself, look at its
+ // operands.
+ for (auto &OM : Matcher.operands())
+ for (auto &OP : OM->predicates())
+ if (!isa<InstructionOperandMatcher>(OP))
+ return *OP;
+
+ llvm_unreachable("Trying to get a condition from an InstructionMatcher with "
+ "no conditions");
+}
+
+std::unique_ptr<PredicateMatcher> RuleMatcher::popFirstCondition() {
+ assert(!insnmatchers_empty() &&
+ "Trying to pop a condition from an empty RuleMatcher");
+
+ InstructionMatcher &Matcher = insnmatchers_front();
+ if (!Matcher.predicates_empty())
+ return Matcher.predicates_pop_front();
+ // If there is no more predicate on the instruction itself, look at its
+ // operands.
+ for (auto &OM : Matcher.operands())
+ for (auto &OP : OM->predicates())
+ if (!isa<InstructionOperandMatcher>(OP)) {
+ std::unique_ptr<PredicateMatcher> Result = std::move(OP);
+ OM->eraseNullPredicates();
+ return Result;
+ }
+
+ llvm_unreachable("Trying to pop a condition from an InstructionMatcher with "
+ "no conditions");
+}
+
+GISelFlags RuleMatcher::updateGISelFlag(GISelFlags CurFlags, const Record *R,
+ StringRef FlagName,
+ GISelFlags FlagBit) {
+ // If the value of a flag is unset, ignore it.
+ // If it's set, it always takes precedence over the existing value so
+ // clear/set the corresponding bit.
+ bool Unset = false;
+ bool Value = R->getValueAsBitOrUnset("GIIgnoreCopies", Unset);
+ if (!Unset)
+ return Value ? (CurFlags | FlagBit) : (CurFlags & ~FlagBit);
+ return CurFlags;
+}
+
+SaveAndRestore<GISelFlags> RuleMatcher::setGISelFlags(const Record *R) {
+ if (!R || !R->isSubClassOf("GISelFlags"))
+ return {Flags, Flags};
+
+ assert((R->isSubClassOf("PatFrags") || R->isSubClassOf("Pattern")) &&
+ "GISelFlags is only expected on Pattern/PatFrags!");
+
+ GISelFlags NewFlags =
+ updateGISelFlag(Flags, R, "GIIgnoreCopies", GISF_IgnoreCopies);
+ return {Flags, NewFlags};
+}
+
+Error RuleMatcher::defineComplexSubOperand(StringRef SymbolicName,
+ Record *ComplexPattern,
+ unsigned RendererID,
+ unsigned SubOperandID,
+ StringRef ParentSymbolicName) {
+ std::string ParentName(ParentSymbolicName);
+ if (ComplexSubOperands.count(SymbolicName)) {
+ const std::string &RecordedParentName =
+ ComplexSubOperandsParentName[SymbolicName];
+ if (RecordedParentName != ParentName)
+ return failUnsupported("Error: Complex suboperand " + SymbolicName +
+ " referenced by different operands: " +
+ RecordedParentName + " and " + ParentName + ".");
+ // Complex suboperand referenced more than once from same the operand is
+ // used to generate 'same operand check'. Emitting of
+ // GIR_ComplexSubOperandRenderer for them is already handled.
+ return Error::success();
+ }
+
+ ComplexSubOperands[SymbolicName] =
+ std::make_tuple(ComplexPattern, RendererID, SubOperandID);
+ ComplexSubOperandsParentName[SymbolicName] = ParentName;
+
+ return Error::success();
+}
+
+InstructionMatcher &RuleMatcher::addInstructionMatcher(StringRef SymbolicName) {
+ Matchers.emplace_back(new InstructionMatcher(*this, SymbolicName));
+ MutatableInsns.insert(Matchers.back().get());
+ return *Matchers.back();
+}
+
+void RuleMatcher::addRequiredSimplePredicate(StringRef PredName) {
+ RequiredSimplePredicates.push_back(PredName.str());
+}
+
+const std::vector<std::string> &RuleMatcher::getRequiredSimplePredicates() {
+ return RequiredSimplePredicates;
+}
+
+void RuleMatcher::addRequiredFeature(Record *Feature) {
+ RequiredFeatures.push_back(Feature);
+}
+
+const std::vector<Record *> &RuleMatcher::getRequiredFeatures() const {
+ return RequiredFeatures;
+}
+
+unsigned RuleMatcher::implicitlyDefineInsnVar(InstructionMatcher &Matcher) {
+ unsigned NewInsnVarID = NextInsnVarID++;
+ InsnVariableIDs[&Matcher] = NewInsnVarID;
+ return NewInsnVarID;
+}
+
+unsigned RuleMatcher::getInsnVarID(InstructionMatcher &InsnMatcher) const {
+ const auto &I = InsnVariableIDs.find(&InsnMatcher);
+ if (I != InsnVariableIDs.end())
+ return I->second;
+ llvm_unreachable("Matched Insn was not captured in a local variable");
+}
+
+void RuleMatcher::defineOperand(StringRef SymbolicName, OperandMatcher &OM) {
+ if (!DefinedOperands.contains(SymbolicName)) {
+ DefinedOperands[SymbolicName] = &OM;
+ return;
+ }
+
+ // If the operand is already defined, then we must ensure both references in
+ // the matcher have the exact same node.
+ RuleMatcher &RM = OM.getInstructionMatcher().getRuleMatcher();
+ OM.addPredicate<SameOperandMatcher>(
+ OM.getSymbolicName(), getOperandMatcher(OM.getSymbolicName()).getOpIdx(),
+ RM.getGISelFlags());
+}
+
+void RuleMatcher::definePhysRegOperand(Record *Reg, OperandMatcher &OM) {
+ if (!PhysRegOperands.contains(Reg)) {
+ PhysRegOperands[Reg] = &OM;
+ return;
+ }
+}
+
+InstructionMatcher &
+RuleMatcher::getInstructionMatcher(StringRef SymbolicName) const {
+ for (const auto &I : InsnVariableIDs)
+ if (I.first->getSymbolicName() == SymbolicName)
+ return *I.first;
+ llvm_unreachable(
+ ("Failed to lookup instruction " + SymbolicName).str().c_str());
+}
+
+const OperandMatcher &RuleMatcher::getPhysRegOperandMatcher(Record *Reg) const {
+ const auto &I = PhysRegOperands.find(Reg);
+
+ if (I == PhysRegOperands.end()) {
+ PrintFatalError(SrcLoc, "Register " + Reg->getName() +
+ " was not declared in matcher");
+ }
+
+ return *I->second;
+}
+
+const OperandMatcher &RuleMatcher::getOperandMatcher(StringRef Name) const {
+ const auto &I = DefinedOperands.find(Name);
+
+ if (I == DefinedOperands.end())
+ PrintFatalError(SrcLoc, "Operand " + Name + " was not declared in matcher");
+
+ return *I->second;
+}
+
+void RuleMatcher::emit(MatchTable &Table) {
+ if (Matchers.empty())
+ llvm_unreachable("Unexpected empty matcher!");
+
+ // The representation supports rules that require multiple roots such as:
+ // %ptr(p0) = ...
+ // %elt0(s32) = G_LOAD %ptr
+ // %1(p0) = G_ADD %ptr, 4
+ // %elt1(s32) = G_LOAD p0 %1
+ // which could be usefully folded into:
+ // %ptr(p0) = ...
+ // %elt0(s32), %elt1(s32) = TGT_LOAD_PAIR %ptr
+ // on some targets but we don't need to make use of that yet.
+ assert(Matchers.size() == 1 && "Cannot handle multi-root matchers yet");
+
+ unsigned LabelID = Table.allocateLabelID();
+ Table << MatchTable::Opcode("GIM_Try", +1)
+ << MatchTable::Comment("On fail goto")
+ << MatchTable::JumpTarget(LabelID)
+ << MatchTable::Comment(("Rule ID " + Twine(RuleID) + " //").str())
+ << MatchTable::LineBreak;
+
+ if (!RequiredFeatures.empty()) {
+ Table << MatchTable::Opcode("GIM_CheckFeatures")
+ << MatchTable::NamedValue(getNameForFeatureBitset(RequiredFeatures))
+ << MatchTable::LineBreak;
+ }
+
+ if (!RequiredSimplePredicates.empty()) {
+ for (const auto &Pred : RequiredSimplePredicates) {
+ Table << MatchTable::Opcode("GIM_CheckSimplePredicate")
+ << MatchTable::NamedValue(Pred) << MatchTable::LineBreak;
+ }
+ }
+
+ Matchers.front()->emitPredicateOpcodes(Table, *this);
+
+ // We must also check if it's safe to fold the matched instructions.
+ if (InsnVariableIDs.size() >= 2) {
+ // Invert the map to create stable ordering (by var names)
+ SmallVector<unsigned, 2> InsnIDs;
+ for (const auto &Pair : InsnVariableIDs) {
+ // Skip the root node since it isn't moving anywhere. Everything else is
+ // sinking to meet it.
+ if (Pair.first == Matchers.front().get())
+ continue;
+
+ InsnIDs.push_back(Pair.second);
+ }
+ llvm::sort(InsnIDs);
+
+ for (const auto &InsnID : InsnIDs) {
+ // Reject the difficult cases until we have a more accurate check.
+ Table << MatchTable::Opcode("GIM_CheckIsSafeToFold")
+ << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
+ << MatchTable::LineBreak;
+
+ // FIXME: Emit checks to determine it's _actually_ safe to fold and/or
+ // account for unsafe cases.
+ //
+ // Example:
+ // MI1--> %0 = ...
+ // %1 = ... %0
+ // MI0--> %2 = ... %0
+ // It's not safe to erase MI1. We currently handle this by not
+ // erasing %0 (even when it's dead).
+ //
+ // Example:
+ // MI1--> %0 = load volatile @a
+ // %1 = load volatile @a
+ // MI0--> %2 = ... %0
+ // It's not safe to sink %0's def past %1. We currently handle
+ // this by rejecting all loads.
+ //
+ // Example:
+ // MI1--> %0 = load @a
+ // %1 = store @a
+ // MI0--> %2 = ... %0
+ // It's not safe to sink %0's def past %1. We currently handle
+ // this by rejecting all loads.
+ //
+ // Example:
+ // G_CONDBR %cond, @BB1
+ // BB0:
+ // MI1--> %0 = load @a
+ // G_BR @BB1
+ // BB1:
+ // MI0--> %2 = ... %0
+ // It's not always safe to sink %0 across control flow. In this
+ // case it may introduce a memory fault. We currentl handle
+ // this by rejecting all loads.
+ }
+ }
+
+ for (const auto &PM : EpilogueMatchers)
+ PM->emitPredicateOpcodes(Table, *this);
+
+ for (const auto &MA : Actions)
+ MA->emitActionOpcodes(Table, *this);
+
+ assert((Table.isWithCoverage() ? !Table.isCombiner() : true) &&
+ "Combiner tables don't support coverage!");
+ if (Table.isWithCoverage())
+ Table << MatchTable::Opcode("GIR_Coverage") << MatchTable::IntValue(RuleID)
+ << MatchTable::LineBreak;
+ else if (!Table.isCombiner())
+ Table << MatchTable::Comment(("GIR_Coverage, " + Twine(RuleID) + ",").str())
+ << MatchTable::LineBreak;
+
+ Table << MatchTable::Opcode("GIR_Done", -1) << MatchTable::LineBreak
+ << MatchTable::Label(LabelID);
+ ++NumPatternEmitted;
+}
+
+bool RuleMatcher::isHigherPriorityThan(const RuleMatcher &B) const {
+ // Rules involving more match roots have higher priority.
+ if (Matchers.size() > B.Matchers.size())
+ return true;
+ if (Matchers.size() < B.Matchers.size())
+ return false;
+
+ for (auto Matcher : zip(Matchers, B.Matchers)) {
+ if (std::get<0>(Matcher)->isHigherPriorityThan(*std::get<1>(Matcher)))
+ return true;
+ if (std::get<1>(Matcher)->isHigherPriorityThan(*std::get<0>(Matcher)))
+ return false;
+ }
+
+ return false;
+}
+
+unsigned RuleMatcher::countRendererFns() const {
+ return std::accumulate(
+ Matchers.begin(), Matchers.end(), 0,
+ [](unsigned A, const std::unique_ptr<InstructionMatcher> &Matcher) {
+ return A + Matcher->countRendererFns();
+ });
+}
+
+//===- PredicateMatcher ---------------------------------------------------===//
+
+PredicateMatcher::~PredicateMatcher() {}
+
+//===- OperandPredicateMatcher --------------------------------------------===//
+
+OperandPredicateMatcher::~OperandPredicateMatcher() {}
+
+bool OperandPredicateMatcher::isHigherPriorityThan(
+ const OperandPredicateMatcher &B) const {
+ // Generally speaking, an instruction is more important than an Int or a
+ // LiteralInt because it can cover more nodes but theres an exception to
+ // this. G_CONSTANT's are less important than either of those two because they
+ // are more permissive.
+
+ const InstructionOperandMatcher *AOM =
+ dyn_cast<InstructionOperandMatcher>(this);
+ const InstructionOperandMatcher *BOM =
+ dyn_cast<InstructionOperandMatcher>(&B);
+ bool AIsConstantInsn = AOM && AOM->getInsnMatcher().isConstantInstruction();
+ bool BIsConstantInsn = BOM && BOM->getInsnMatcher().isConstantInstruction();
+
+ if (AOM && BOM) {
+ // The relative priorities between a G_CONSTANT and any other instruction
+ // don't actually matter but this code is needed to ensure a strict weak
+ // ordering. This is particularly important on Windows where the rules will
+ // be incorrectly sorted without it.
+ if (AIsConstantInsn != BIsConstantInsn)
+ return AIsConstantInsn < BIsConstantInsn;
+ return false;
+ }
+
+ if (AOM && AIsConstantInsn && (B.Kind == OPM_Int || B.Kind == OPM_LiteralInt))
+ return false;
+ if (BOM && BIsConstantInsn && (Kind == OPM_Int || Kind == OPM_LiteralInt))
+ return true;
+
+ return Kind < B.Kind;
+}
+
+//===- SameOperandMatcher -------------------------------------------------===//
+
+void SameOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const {
+ const OperandMatcher &OtherOM = Rule.getOperandMatcher(MatchingName);
+ unsigned OtherInsnVarID = Rule.getInsnVarID(OtherOM.getInstructionMatcher());
+ assert(OtherInsnVarID == OtherOM.getInstructionMatcher().getInsnVarID());
+ const bool IgnoreCopies = Flags & GISF_IgnoreCopies;
+ Table << MatchTable::Opcode(IgnoreCopies
+ ? "GIM_CheckIsSameOperandIgnoreCopies"
+ : "GIM_CheckIsSameOperand")
+ << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
+ << MatchTable::Comment("OpIdx") << MatchTable::IntValue(OpIdx)
+ << MatchTable::Comment("OtherMI")
+ << MatchTable::IntValue(OtherInsnVarID)
+ << MatchTable::Comment("OtherOpIdx")
+ << MatchTable::IntValue(OtherOM.getOpIdx()) << MatchTable::LineBreak;
+}
+
+//===- LLTOperandMatcher --------------------------------------------------===//
+
+std::map<LLTCodeGen, unsigned> LLTOperandMatcher::TypeIDValues;
+
+MatchTableRecord LLTOperandMatcher::getValue() const {
+ const auto VI = TypeIDValues.find(Ty);
+ if (VI == TypeIDValues.end())
+ return MatchTable::NamedValue(getTy().getCxxEnumValue());
+ return MatchTable::NamedValue(getTy().getCxxEnumValue(), VI->second);
+}
+
+bool LLTOperandMatcher::hasValue() const {
+ if (TypeIDValues.size() != KnownTypes.size())
+ initTypeIDValuesMap();
+ return TypeIDValues.count(Ty);
+}
+
+void LLTOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const {
+ Table << MatchTable::Opcode("GIM_CheckType") << MatchTable::Comment("MI")
+ << MatchTable::IntValue(InsnVarID) << MatchTable::Comment("Op")
+ << MatchTable::IntValue(OpIdx) << MatchTable::Comment("Type")
+ << getValue() << MatchTable::LineBreak;
+}
+
+//===- PointerToAnyOperandMatcher -----------------------------------------===//
+
+void PointerToAnyOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const {
+ Table << MatchTable::Opcode("GIM_CheckPointerToAny")
+ << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
+ << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx)
+ << MatchTable::Comment("SizeInBits") << MatchTable::IntValue(SizeInBits)
+ << MatchTable::LineBreak;
+}
+
+//===- RecordNamedOperandMatcher ------------------------------------------===//
+
+void RecordNamedOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const {
+ Table << MatchTable::Opcode("GIM_RecordNamedOperand")
+ << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
+ << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx)
+ << MatchTable::Comment("StoreIdx") << MatchTable::IntValue(StoreIdx)
+ << MatchTable::Comment("Name : " + Name) << MatchTable::LineBreak;
+}
+
+//===- ComplexPatternOperandMatcher ---------------------------------------===//
+
+void ComplexPatternOperandMatcher::emitPredicateOpcodes(
+ MatchTable &Table, RuleMatcher &Rule) const {
+ unsigned ID = getAllocatedTemporariesBaseID();
+ Table << MatchTable::Opcode("GIM_CheckComplexPattern")
+ << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
+ << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx)
+ << MatchTable::Comment("Renderer") << MatchTable::IntValue(ID)
+ << MatchTable::NamedValue(("GICP_" + TheDef.getName()).str())
+ << MatchTable::LineBreak;
+}
+
+unsigned ComplexPatternOperandMatcher::getAllocatedTemporariesBaseID() const {
+ return Operand.getAllocatedTemporariesBaseID();
+}
+
+//===- RegisterBankOperandMatcher -----------------------------------------===//
+
+bool RegisterBankOperandMatcher::isIdentical(const PredicateMatcher &B) const {
+ return OperandPredicateMatcher::isIdentical(B) &&
+ RC.getDef() == cast<RegisterBankOperandMatcher>(&B)->RC.getDef();
+}
+
+void RegisterBankOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const {
+ Table << MatchTable::Opcode("GIM_CheckRegBankForClass")
+ << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
+ << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx)
+ << MatchTable::Comment("RC")
+ << MatchTable::NamedValue(RC.getQualifiedName() + "RegClassID")
+ << MatchTable::LineBreak;
+}
+
+//===- MBBOperandMatcher --------------------------------------------------===//
+
+void MBBOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const {
+ Table << MatchTable::Opcode("GIM_CheckIsMBB") << MatchTable::Comment("MI")
+ << MatchTable::IntValue(InsnVarID) << MatchTable::Comment("Op")
+ << MatchTable::IntValue(OpIdx) << MatchTable::LineBreak;
+}
+
+//===- ImmOperandMatcher --------------------------------------------------===//
+
+void ImmOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const {
+ Table << MatchTable::Opcode("GIM_CheckIsImm") << MatchTable::Comment("MI")
+ << MatchTable::IntValue(InsnVarID) << MatchTable::Comment("Op")
+ << MatchTable::IntValue(OpIdx) << MatchTable::LineBreak;
+}
+
+//===- ConstantIntOperandMatcher ------------------------------------------===//
+
+void ConstantIntOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const {
+ Table << MatchTable::Opcode("GIM_CheckConstantInt")
+ << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
+ << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx)
+ << MatchTable::IntValue(Value) << MatchTable::LineBreak;
+}
+
+//===- LiteralIntOperandMatcher -------------------------------------------===//
+
+void LiteralIntOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const {
+ Table << MatchTable::Opcode("GIM_CheckLiteralInt")
+ << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
+ << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx)
+ << MatchTable::IntValue(Value) << MatchTable::LineBreak;
+}
+
+//===- CmpPredicateOperandMatcher -----------------------------------------===//
+
+void CmpPredicateOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const {
+ Table << MatchTable::Opcode("GIM_CheckCmpPredicate")
+ << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
+ << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx)
+ << MatchTable::Comment("Predicate")
+ << MatchTable::NamedValue("CmpInst", PredName) << MatchTable::LineBreak;
+}
+
+//===- IntrinsicIDOperandMatcher ------------------------------------------===//
+
+void IntrinsicIDOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const {
+ Table << MatchTable::Opcode("GIM_CheckIntrinsicID")
+ << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
+ << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx)
+ << MatchTable::NamedValue("Intrinsic::" + II->EnumName)
+ << MatchTable::LineBreak;
+}
+
+//===- OperandImmPredicateMatcher -----------------------------------------===//
+
+void OperandImmPredicateMatcher::emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const {
+ Table << MatchTable::Opcode("GIM_CheckImmOperandPredicate")
+ << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
+ << MatchTable::Comment("MO") << MatchTable::IntValue(OpIdx)
+ << MatchTable::Comment("Predicate")
+ << MatchTable::NamedValue(getEnumNameForPredicate(Predicate))
+ << MatchTable::LineBreak;
+}
+
+//===- OperandMatcher -----------------------------------------------------===//
+
+std::string OperandMatcher::getOperandExpr(unsigned InsnVarID) const {
+ return "State.MIs[" + llvm::to_string(InsnVarID) + "]->getOperand(" +
+ llvm::to_string(OpIdx) + ")";
+}
+
+unsigned OperandMatcher::getInsnVarID() const { return Insn.getInsnVarID(); }
+
+void OperandMatcher::emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) {
+ if (!Optimized) {
+ std::string Comment;
+ raw_string_ostream CommentOS(Comment);
+ CommentOS << "MIs[" << getInsnVarID() << "] ";
+ if (SymbolicName.empty())
+ CommentOS << "Operand " << OpIdx;
+ else
+ CommentOS << SymbolicName;
+ Table << MatchTable::Comment(Comment) << MatchTable::LineBreak;
+ }
+
+ emitPredicateListOpcodes(Table, Rule);
+}
+
+bool OperandMatcher::isHigherPriorityThan(OperandMatcher &B) {
+ // Operand matchers involving more predicates have higher priority.
+ if (predicates_size() > B.predicates_size())
+ return true;
+ if (predicates_size() < B.predicates_size())
+ return false;
+
+ // This assumes that predicates are added in a consistent order.
+ for (auto &&Predicate : zip(predicates(), B.predicates())) {
+ if (std::get<0>(Predicate)->isHigherPriorityThan(*std::get<1>(Predicate)))
+ return true;
+ if (std::get<1>(Predicate)->isHigherPriorityThan(*std::get<0>(Predicate)))
+ return false;
+ }
+
+ return false;
+}
+
+unsigned OperandMatcher::countRendererFns() {
+ return std::accumulate(
+ predicates().begin(), predicates().end(), 0,
+ [](unsigned A,
+ const std::unique_ptr<OperandPredicateMatcher> &Predicate) {
+ return A + Predicate->countRendererFns();
+ });
+}
+
+Error OperandMatcher::addTypeCheckPredicate(const TypeSetByHwMode &VTy,
+ bool OperandIsAPointer) {
+ if (!VTy.isMachineValueType())
+ return failUnsupported("unsupported typeset");
+
+ if (VTy.getMachineValueType() == MVT::iPTR && OperandIsAPointer) {
+ addPredicate<PointerToAnyOperandMatcher>(0);
+ return Error::success();
+ }
+
+ auto OpTyOrNone = MVTToLLT(VTy.getMachineValueType().SimpleTy);
+ if (!OpTyOrNone)
+ return failUnsupported("unsupported type");
+
+ if (OperandIsAPointer)
+ addPredicate<PointerToAnyOperandMatcher>(OpTyOrNone->get().getSizeInBits());
+ else if (VTy.isPointer())
+ addPredicate<LLTOperandMatcher>(
+ LLT::pointer(VTy.getPtrAddrSpace(), OpTyOrNone->get().getSizeInBits()));
+ else
+ addPredicate<LLTOperandMatcher>(*OpTyOrNone);
+ return Error::success();
+}
+
+//===- InstructionOpcodeMatcher -------------------------------------------===//
+
+DenseMap<const CodeGenInstruction *, unsigned>
+ InstructionOpcodeMatcher::OpcodeValues;
+
+MatchTableRecord
+InstructionOpcodeMatcher::getInstValue(const CodeGenInstruction *I) const {
+ const auto VI = OpcodeValues.find(I);
+ if (VI != OpcodeValues.end())
+ return MatchTable::NamedValue(I->Namespace, I->TheDef->getName(),
+ VI->second);
+ return MatchTable::NamedValue(I->Namespace, I->TheDef->getName());
+}
+
+void InstructionOpcodeMatcher::initOpcodeValuesMap(
+ const CodeGenTarget &Target) {
+ OpcodeValues.clear();
+
+ unsigned OpcodeValue = 0;
+ for (const CodeGenInstruction *I : Target.getInstructionsByEnumValue())
+ OpcodeValues[I] = OpcodeValue++;
+}
+
+MatchTableRecord InstructionOpcodeMatcher::getValue() const {
+ assert(Insts.size() == 1);
+
+ const CodeGenInstruction *I = Insts[0];
+ const auto VI = OpcodeValues.find(I);
+ if (VI != OpcodeValues.end())
+ return MatchTable::NamedValue(I->Namespace, I->TheDef->getName(),
+ VI->second);
+ return MatchTable::NamedValue(I->Namespace, I->TheDef->getName());
+}
+
+void InstructionOpcodeMatcher::emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const {
+ StringRef CheckType =
+ Insts.size() == 1 ? "GIM_CheckOpcode" : "GIM_CheckOpcodeIsEither";
+ Table << MatchTable::Opcode(CheckType) << MatchTable::Comment("MI")
+ << MatchTable::IntValue(InsnVarID);
+
+ for (const CodeGenInstruction *I : Insts)
+ Table << getInstValue(I);
+ Table << MatchTable::LineBreak;
+}
+
+bool InstructionOpcodeMatcher::isHigherPriorityThan(
+ const InstructionPredicateMatcher &B) const {
+ if (InstructionPredicateMatcher::isHigherPriorityThan(B))
+ return true;
+ if (B.InstructionPredicateMatcher::isHigherPriorityThan(*this))
+ return false;
+
+ // Prioritize opcodes for cosmetic reasons in the generated source. Although
+ // this is cosmetic at the moment, we may want to drive a similar ordering
+ // using instruction frequency information to improve compile time.
+ if (const InstructionOpcodeMatcher *BO =
+ dyn_cast<InstructionOpcodeMatcher>(&B))
+ return Insts[0]->TheDef->getName() < BO->Insts[0]->TheDef->getName();
+
+ return false;
+}
+
+bool InstructionOpcodeMatcher::isConstantInstruction() const {
+ return Insts.size() == 1 && Insts[0]->TheDef->getName() == "G_CONSTANT";
+}
+
+StringRef InstructionOpcodeMatcher::getOpcode() const {
+ return Insts[0]->TheDef->getName();
+}
+
+bool InstructionOpcodeMatcher::isVariadicNumOperands() const {
+ // If one is variadic, they all should be.
+ return Insts[0]->Operands.isVariadic;
+}
+
+StringRef InstructionOpcodeMatcher::getOperandType(unsigned OpIdx) const {
+ // Types expected to be uniform for all alternatives.
+ return Insts[0]->Operands[OpIdx].OperandType;
+}
+
+//===- InstructionNumOperandsMatcher --------------------------------------===//
+
+void InstructionNumOperandsMatcher::emitPredicateOpcodes(
+ MatchTable &Table, RuleMatcher &Rule) const {
+ Table << MatchTable::Opcode("GIM_CheckNumOperands")
+ << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
+ << MatchTable::Comment("Expected") << MatchTable::IntValue(NumOperands)
+ << MatchTable::LineBreak;
+}
+
+//===- InstructionImmPredicateMatcher -------------------------------------===//
+
+bool InstructionImmPredicateMatcher::isIdentical(
+ const PredicateMatcher &B) const {
+ return InstructionPredicateMatcher::isIdentical(B) &&
+ Predicate.getOrigPatFragRecord() ==
+ cast<InstructionImmPredicateMatcher>(&B)
+ ->Predicate.getOrigPatFragRecord();
+}
+
+void InstructionImmPredicateMatcher::emitPredicateOpcodes(
+ MatchTable &Table, RuleMatcher &Rule) const {
+ Table << MatchTable::Opcode(getMatchOpcodeForImmPredicate(Predicate))
+ << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
+ << MatchTable::Comment("Predicate")
+ << MatchTable::NamedValue(getEnumNameForPredicate(Predicate))
+ << MatchTable::LineBreak;
+}
+
+//===- AtomicOrderingMMOPredicateMatcher ----------------------------------===//
+
+bool AtomicOrderingMMOPredicateMatcher::isIdentical(
+ const PredicateMatcher &B) const {
+ if (!InstructionPredicateMatcher::isIdentical(B))
+ return false;
+ const auto &R = *cast<AtomicOrderingMMOPredicateMatcher>(&B);
+ return Order == R.Order && Comparator == R.Comparator;
+}
+
+void AtomicOrderingMMOPredicateMatcher::emitPredicateOpcodes(
+ MatchTable &Table, RuleMatcher &Rule) const {
+ StringRef Opcode = "GIM_CheckAtomicOrdering";
+
+ if (Comparator == AO_OrStronger)
+ Opcode = "GIM_CheckAtomicOrderingOrStrongerThan";
+ if (Comparator == AO_WeakerThan)
+ Opcode = "GIM_CheckAtomicOrderingWeakerThan";
+
+ Table << MatchTable::Opcode(Opcode) << MatchTable::Comment("MI")
+ << MatchTable::IntValue(InsnVarID) << MatchTable::Comment("Order")
+ << MatchTable::NamedValue(("(int64_t)AtomicOrdering::" + Order).str())
+ << MatchTable::LineBreak;
+}
+
+//===- MemorySizePredicateMatcher -----------------------------------------===//
+
+void MemorySizePredicateMatcher::emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const {
+ Table << MatchTable::Opcode("GIM_CheckMemorySizeEqualTo")
+ << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
+ << MatchTable::Comment("MMO") << MatchTable::IntValue(MMOIdx)
+ << MatchTable::Comment("Size") << MatchTable::IntValue(Size)
+ << MatchTable::LineBreak;
+}
+
+//===- MemoryAddressSpacePredicateMatcher ---------------------------------===//
+
+bool MemoryAddressSpacePredicateMatcher::isIdentical(
+ const PredicateMatcher &B) const {
+ if (!InstructionPredicateMatcher::isIdentical(B))
+ return false;
+ auto *Other = cast<MemoryAddressSpacePredicateMatcher>(&B);
+ return MMOIdx == Other->MMOIdx && AddrSpaces == Other->AddrSpaces;
+}
+
+void MemoryAddressSpacePredicateMatcher::emitPredicateOpcodes(
+ MatchTable &Table, RuleMatcher &Rule) const {
+ Table << MatchTable::Opcode("GIM_CheckMemoryAddressSpace")
+ << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
+ << MatchTable::Comment("MMO")
+ << MatchTable::IntValue(MMOIdx)
+ // Encode number of address spaces to expect.
+ << MatchTable::Comment("NumAddrSpace")
+ << MatchTable::IntValue(AddrSpaces.size());
+ for (unsigned AS : AddrSpaces)
+ Table << MatchTable::Comment("AddrSpace") << MatchTable::IntValue(AS);
+
+ Table << MatchTable::LineBreak;
+}
+
+//===- MemoryAlignmentPredicateMatcher ------------------------------------===//
+
+bool MemoryAlignmentPredicateMatcher::isIdentical(
+ const PredicateMatcher &B) const {
+ if (!InstructionPredicateMatcher::isIdentical(B))
+ return false;
+ auto *Other = cast<MemoryAlignmentPredicateMatcher>(&B);
+ return MMOIdx == Other->MMOIdx && MinAlign == Other->MinAlign;
+}
+
+void MemoryAlignmentPredicateMatcher::emitPredicateOpcodes(
+ MatchTable &Table, RuleMatcher &Rule) const {
+ Table << MatchTable::Opcode("GIM_CheckMemoryAlignment")
+ << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
+ << MatchTable::Comment("MMO") << MatchTable::IntValue(MMOIdx)
+ << MatchTable::Comment("MinAlign") << MatchTable::IntValue(MinAlign)
+ << MatchTable::LineBreak;
+}
+
+//===- MemoryVsLLTSizePredicateMatcher ------------------------------------===//
+
+bool MemoryVsLLTSizePredicateMatcher::isIdentical(
+ const PredicateMatcher &B) const {
+ return InstructionPredicateMatcher::isIdentical(B) &&
+ MMOIdx == cast<MemoryVsLLTSizePredicateMatcher>(&B)->MMOIdx &&
+ Relation == cast<MemoryVsLLTSizePredicateMatcher>(&B)->Relation &&
+ OpIdx == cast<MemoryVsLLTSizePredicateMatcher>(&B)->OpIdx;
+}
+
+void MemoryVsLLTSizePredicateMatcher::emitPredicateOpcodes(
+ MatchTable &Table, RuleMatcher &Rule) const {
+ Table << MatchTable::Opcode(
+ Relation == EqualTo ? "GIM_CheckMemorySizeEqualToLLT"
+ : Relation == GreaterThan ? "GIM_CheckMemorySizeGreaterThanLLT"
+ : "GIM_CheckMemorySizeLessThanLLT")
+ << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
+ << MatchTable::Comment("MMO") << MatchTable::IntValue(MMOIdx)
+ << MatchTable::Comment("OpIdx") << MatchTable::IntValue(OpIdx)
+ << MatchTable::LineBreak;
+}
+
+//===- VectorSplatImmPredicateMatcher -------------------------------------===//
+
+void VectorSplatImmPredicateMatcher::emitPredicateOpcodes(
+ MatchTable &Table, RuleMatcher &Rule) const {
+ if (Kind == AllOnes)
+ Table << MatchTable::Opcode("GIM_CheckIsBuildVectorAllOnes");
+ else
+ Table << MatchTable::Opcode("GIM_CheckIsBuildVectorAllZeros");
+
+ Table << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID);
+ Table << MatchTable::LineBreak;
+}
+
+//===- GenericInstructionPredicateMatcher ---------------------------------===//
+
+GenericInstructionPredicateMatcher::GenericInstructionPredicateMatcher(
+ unsigned InsnVarID, TreePredicateFn Predicate)
+ : GenericInstructionPredicateMatcher(InsnVarID,
+ getEnumNameForPredicate(Predicate)) {}
+
+bool GenericInstructionPredicateMatcher::isIdentical(
+ const PredicateMatcher &B) const {
+ return InstructionPredicateMatcher::isIdentical(B) &&
+ EnumVal ==
+ static_cast<const GenericInstructionPredicateMatcher &>(B).EnumVal;
+}
+void GenericInstructionPredicateMatcher::emitPredicateOpcodes(
+ MatchTable &Table, RuleMatcher &Rule) const {
+ Table << MatchTable::Opcode("GIM_CheckCxxInsnPredicate")
+ << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
+ << MatchTable::Comment("FnId") << MatchTable::NamedValue(EnumVal)
+ << MatchTable::LineBreak;
+}
+
+//===- InstructionMatcher -------------------------------------------------===//
+
+OperandMatcher &
+InstructionMatcher::addOperand(unsigned OpIdx, const std::string &SymbolicName,
+ unsigned AllocatedTemporariesBaseID) {
+ Operands.emplace_back(new OperandMatcher(*this, OpIdx, SymbolicName,
+ AllocatedTemporariesBaseID));
+ if (!SymbolicName.empty())
+ Rule.defineOperand(SymbolicName, *Operands.back());
+
+ return *Operands.back();
+}
+
+OperandMatcher &InstructionMatcher::getOperand(unsigned OpIdx) {
+ auto I = llvm::find_if(Operands,
+ [&OpIdx](const std::unique_ptr<OperandMatcher> &X) {
+ return X->getOpIdx() == OpIdx;
+ });
+ if (I != Operands.end())
+ return **I;
+ llvm_unreachable("Failed to lookup operand");
+}
+
+OperandMatcher &InstructionMatcher::addPhysRegInput(Record *Reg, unsigned OpIdx,
+ unsigned TempOpIdx) {
+ assert(SymbolicName.empty());
+ OperandMatcher *OM = new OperandMatcher(*this, OpIdx, "", TempOpIdx);
+ Operands.emplace_back(OM);
+ Rule.definePhysRegOperand(Reg, *OM);
+ PhysRegInputs.emplace_back(Reg, OpIdx);
+ return *OM;
+}
+
+void InstructionMatcher::emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) {
+ if (NumOperandsCheck)
+ InstructionNumOperandsMatcher(InsnVarID, getNumOperands())
+ .emitPredicateOpcodes(Table, Rule);
+
+ // First emit all instruction level predicates need to be verified before we
+ // can verify operands.
+ emitFilteredPredicateListOpcodes(
+ [](const PredicateMatcher &P) { return !P.dependsOnOperands(); }, Table,
+ Rule);
+
+ // Emit all operand constraints.
+ for (const auto &Operand : Operands)
+ Operand->emitPredicateOpcodes(Table, Rule);
+
+ // All of the tablegen defined predicates should now be matched. Now emit
+ // any custom predicates that rely on all generated checks.
+ emitFilteredPredicateListOpcodes(
+ [](const PredicateMatcher &P) { return P.dependsOnOperands(); }, Table,
+ Rule);
+}
+
+bool InstructionMatcher::isHigherPriorityThan(InstructionMatcher &B) {
+ // Instruction matchers involving more operands have higher priority.
+ if (Operands.size() > B.Operands.size())
+ return true;
+ if (Operands.size() < B.Operands.size())
+ return false;
+
+ for (auto &&P : zip(predicates(), B.predicates())) {
+ auto L = static_cast<InstructionPredicateMatcher *>(std::get<0>(P).get());
+ auto R = static_cast<InstructionPredicateMatcher *>(std::get<1>(P).get());
+ if (L->isHigherPriorityThan(*R))
+ return true;
+ if (R->isHigherPriorityThan(*L))
+ return false;
+ }
+
+ for (auto Operand : zip(Operands, B.Operands)) {
+ if (std::get<0>(Operand)->isHigherPriorityThan(*std::get<1>(Operand)))
+ return true;
+ if (std::get<1>(Operand)->isHigherPriorityThan(*std::get<0>(Operand)))
+ return false;
+ }
+
+ return false;
+}
+
+unsigned InstructionMatcher::countRendererFns() {
+ return std::accumulate(
+ predicates().begin(), predicates().end(), 0,
+ [](unsigned A,
+ const std::unique_ptr<PredicateMatcher> &Predicate) {
+ return A + Predicate->countRendererFns();
+ }) +
+ std::accumulate(
+ Operands.begin(), Operands.end(), 0,
+ [](unsigned A, const std::unique_ptr<OperandMatcher> &Operand) {
+ return A + Operand->countRendererFns();
+ });
+}
+
+void InstructionMatcher::optimize() {
+ SmallVector<std::unique_ptr<PredicateMatcher>, 8> Stash;
+ const auto &OpcMatcher = getOpcodeMatcher();
+
+ Stash.push_back(predicates_pop_front());
+ if (Stash.back().get() == &OpcMatcher) {
+ if (NumOperandsCheck && OpcMatcher.isVariadicNumOperands() &&
+ getNumOperands() != 0)
+ Stash.emplace_back(
+ new InstructionNumOperandsMatcher(InsnVarID, getNumOperands()));
+ NumOperandsCheck = false;
+
+ for (auto &OM : Operands)
+ for (auto &OP : OM->predicates())
+ if (isa<IntrinsicIDOperandMatcher>(OP)) {
+ Stash.push_back(std::move(OP));
+ OM->eraseNullPredicates();
+ break;
+ }
+ }
+
+ if (InsnVarID > 0) {
+ assert(!Operands.empty() && "Nested instruction is expected to def a vreg");
+ for (auto &OP : Operands[0]->predicates())
+ OP.reset();
+ Operands[0]->eraseNullPredicates();
+ }
+ for (auto &OM : Operands) {
+ for (auto &OP : OM->predicates())
+ if (isa<LLTOperandMatcher>(OP))
+ Stash.push_back(std::move(OP));
+ OM->eraseNullPredicates();
+ }
+ while (!Stash.empty())
+ prependPredicate(Stash.pop_back_val());
+}
+
+//===- InstructionOperandMatcher ------------------------------------------===//
+
+void InstructionOperandMatcher::emitCaptureOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const {
+ const unsigned NewInsnVarID = InsnMatcher->getInsnVarID();
+ const bool IgnoreCopies = Flags & GISF_IgnoreCopies;
+ Table << MatchTable::Opcode(IgnoreCopies ? "GIM_RecordInsnIgnoreCopies"
+ : "GIM_RecordInsn")
+ << MatchTable::Comment("DefineMI") << MatchTable::IntValue(NewInsnVarID)
+ << MatchTable::Comment("MI") << MatchTable::IntValue(getInsnVarID())
+ << MatchTable::Comment("OpIdx") << MatchTable::IntValue(getOpIdx())
+ << MatchTable::Comment("MIs[" + llvm::to_string(NewInsnVarID) + "]")
+ << MatchTable::LineBreak;
+}
+
+bool InstructionOperandMatcher::isHigherPriorityThan(
+ const OperandPredicateMatcher &B) const {
+ if (OperandPredicateMatcher::isHigherPriorityThan(B))
+ return true;
+ if (B.OperandPredicateMatcher::isHigherPriorityThan(*this))
+ return false;
+
+ if (const InstructionOperandMatcher *BP =
+ dyn_cast<InstructionOperandMatcher>(&B))
+ if (InsnMatcher->isHigherPriorityThan(*BP->InsnMatcher))
+ return true;
+ return false;
+}
+
+//===- OperandRenderer ----------------------------------------------------===//
+
+OperandRenderer::~OperandRenderer() {}
+
+//===- CopyRenderer -------------------------------------------------------===//
+
+void CopyRenderer::emitRenderOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const {
+ const OperandMatcher &Operand = Rule.getOperandMatcher(SymbolicName);
+ unsigned OldInsnVarID = Rule.getInsnVarID(Operand.getInstructionMatcher());
+ Table << MatchTable::Opcode("GIR_Copy") << MatchTable::Comment("NewInsnID")
+ << MatchTable::IntValue(NewInsnID) << MatchTable::Comment("OldInsnID")
+ << MatchTable::IntValue(OldInsnVarID) << MatchTable::Comment("OpIdx")
+ << MatchTable::IntValue(Operand.getOpIdx())
+ << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
+}
+
+//===- CopyPhysRegRenderer ------------------------------------------------===//
+
+void CopyPhysRegRenderer::emitRenderOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const {
+ const OperandMatcher &Operand = Rule.getPhysRegOperandMatcher(PhysReg);
+ unsigned OldInsnVarID = Rule.getInsnVarID(Operand.getInstructionMatcher());
+ Table << MatchTable::Opcode("GIR_Copy") << MatchTable::Comment("NewInsnID")
+ << MatchTable::IntValue(NewInsnID) << MatchTable::Comment("OldInsnID")
+ << MatchTable::IntValue(OldInsnVarID) << MatchTable::Comment("OpIdx")
+ << MatchTable::IntValue(Operand.getOpIdx())
+ << MatchTable::Comment(PhysReg->getName()) << MatchTable::LineBreak;
+}
+
+//===- CopyOrAddZeroRegRenderer -------------------------------------------===//
+
+void CopyOrAddZeroRegRenderer::emitRenderOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const {
+ const OperandMatcher &Operand = Rule.getOperandMatcher(SymbolicName);
+ unsigned OldInsnVarID = Rule.getInsnVarID(Operand.getInstructionMatcher());
+ Table << MatchTable::Opcode("GIR_CopyOrAddZeroReg")
+ << MatchTable::Comment("NewInsnID") << MatchTable::IntValue(NewInsnID)
+ << MatchTable::Comment("OldInsnID")
+ << MatchTable::IntValue(OldInsnVarID) << MatchTable::Comment("OpIdx")
+ << MatchTable::IntValue(Operand.getOpIdx())
+ << MatchTable::NamedValue(
+ (ZeroRegisterDef->getValue("Namespace")
+ ? ZeroRegisterDef->getValueAsString("Namespace")
+ : ""),
+ ZeroRegisterDef->getName())
+ << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
+}
+
+//===- CopyConstantAsImmRenderer ------------------------------------------===//
+
+void CopyConstantAsImmRenderer::emitRenderOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const {
+ InstructionMatcher &InsnMatcher = Rule.getInstructionMatcher(SymbolicName);
+ unsigned OldInsnVarID = Rule.getInsnVarID(InsnMatcher);
+ Table << MatchTable::Opcode(Signed ? "GIR_CopyConstantAsSImm"
+ : "GIR_CopyConstantAsUImm")
+ << MatchTable::Comment("NewInsnID") << MatchTable::IntValue(NewInsnID)
+ << MatchTable::Comment("OldInsnID")
+ << MatchTable::IntValue(OldInsnVarID)
+ << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
+}
+
+//===- CopyFConstantAsFPImmRenderer ---------------------------------------===//
+
+void CopyFConstantAsFPImmRenderer::emitRenderOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const {
+ InstructionMatcher &InsnMatcher = Rule.getInstructionMatcher(SymbolicName);
+ unsigned OldInsnVarID = Rule.getInsnVarID(InsnMatcher);
+ Table << MatchTable::Opcode("GIR_CopyFConstantAsFPImm")
+ << MatchTable::Comment("NewInsnID") << MatchTable::IntValue(NewInsnID)
+ << MatchTable::Comment("OldInsnID")
+ << MatchTable::IntValue(OldInsnVarID)
+ << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
+}
+
+//===- CopySubRegRenderer -------------------------------------------------===//
+
+void CopySubRegRenderer::emitRenderOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const {
+ const OperandMatcher &Operand = Rule.getOperandMatcher(SymbolicName);
+ unsigned OldInsnVarID = Rule.getInsnVarID(Operand.getInstructionMatcher());
+ Table << MatchTable::Opcode("GIR_CopySubReg")
+ << MatchTable::Comment("NewInsnID") << MatchTable::IntValue(NewInsnID)
+ << MatchTable::Comment("OldInsnID")
+ << MatchTable::IntValue(OldInsnVarID) << MatchTable::Comment("OpIdx")
+ << MatchTable::IntValue(Operand.getOpIdx())
+ << MatchTable::Comment("SubRegIdx")
+ << MatchTable::IntValue(SubReg->EnumValue)
+ << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
+}
+
+//===- AddRegisterRenderer ------------------------------------------------===//
+
+void AddRegisterRenderer::emitRenderOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const {
+ Table << MatchTable::Opcode("GIR_AddRegister")
+ << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID);
+ if (RegisterDef->getName() != "zero_reg") {
+ Table << MatchTable::NamedValue(
+ (RegisterDef->getValue("Namespace")
+ ? RegisterDef->getValueAsString("Namespace")
+ : ""),
+ RegisterDef->getName());
+ } else {
+ Table << MatchTable::NamedValue(Target.getRegNamespace(), "NoRegister");
+ }
+ Table << MatchTable::Comment("AddRegisterRegFlags");
+
+ // TODO: This is encoded as a 64-bit element, but only 16 or 32-bits are
+ // really needed for a physical register reference. We can pack the
+ // register and flags in a single field.
+ if (IsDef)
+ Table << MatchTable::NamedValue("RegState::Define");
+ else
+ Table << MatchTable::IntValue(0);
+ Table << MatchTable::LineBreak;
+}
+
+//===- TempRegRenderer ----------------------------------------------------===//
+
+void TempRegRenderer::emitRenderOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const {
+ if (SubRegIdx) {
+ assert(!IsDef);
+ Table << MatchTable::Opcode("GIR_AddTempSubRegister");
+ } else
+ Table << MatchTable::Opcode("GIR_AddTempRegister");
+
+ Table << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
+ << MatchTable::Comment("TempRegID") << MatchTable::IntValue(TempRegID)
+ << MatchTable::Comment("TempRegFlags");
+
+ if (IsDef) {
+ SmallString<32> RegFlags;
+ RegFlags += "RegState::Define";
+ if (IsDead)
+ RegFlags += "|RegState::Dead";
+ Table << MatchTable::NamedValue(RegFlags);
+ } else
+ Table << MatchTable::IntValue(0);
+
+ if (SubRegIdx)
+ Table << MatchTable::NamedValue(SubRegIdx->getQualifiedName());
+ Table << MatchTable::LineBreak;
+}
+
+//===- SubRegIndexRenderer ------------------------------------------------===//
+
+void SubRegIndexRenderer::emitRenderOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const {
+ Table << MatchTable::Opcode("GIR_AddImm") << MatchTable::Comment("InsnID")
+ << MatchTable::IntValue(InsnID) << MatchTable::Comment("SubRegIndex")
+ << MatchTable::IntValue(SubRegIdx->EnumValue) << MatchTable::LineBreak;
+}
+
+//===- RenderComplexPatternOperand ----------------------------------------===//
+
+void RenderComplexPatternOperand::emitRenderOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const {
+ Table << MatchTable::Opcode(
+ SubOperand ? (SubReg ? "GIR_ComplexSubOperandSubRegRenderer"
+ : "GIR_ComplexSubOperandRenderer")
+ : "GIR_ComplexRenderer")
+ << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
+ << MatchTable::Comment("RendererID")
+ << MatchTable::IntValue(RendererID);
+ if (SubOperand)
+ Table << MatchTable::Comment("SubOperand")
+ << MatchTable::IntValue(*SubOperand);
+ if (SubReg)
+ Table << MatchTable::Comment("SubRegIdx")
+ << MatchTable::IntValue(SubReg->EnumValue);
+ Table << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
+}
+
+//===- CustomRenderer -----------------------------------------------------===//
+
+void CustomRenderer::emitRenderOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const {
+ InstructionMatcher &InsnMatcher = Rule.getInstructionMatcher(SymbolicName);
+ unsigned OldInsnVarID = Rule.getInsnVarID(InsnMatcher);
+ Table << MatchTable::Opcode("GIR_CustomRenderer")
+ << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
+ << MatchTable::Comment("OldInsnID")
+ << MatchTable::IntValue(OldInsnVarID) << MatchTable::Comment("Renderer")
+ << MatchTable::NamedValue("GICR_" +
+ Renderer.getValueAsString("RendererFn").str())
+ << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
+}
+
+//===- CustomOperandRenderer ----------------------------------------------===//
+
+void CustomOperandRenderer::emitRenderOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const {
+ const OperandMatcher &OpdMatcher = Rule.getOperandMatcher(SymbolicName);
+ Table << MatchTable::Opcode("GIR_CustomOperandRenderer")
+ << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
+ << MatchTable::Comment("OldInsnID")
+ << MatchTable::IntValue(OpdMatcher.getInsnVarID())
+ << MatchTable::Comment("OpIdx")
+ << MatchTable::IntValue(OpdMatcher.getOpIdx())
+ << MatchTable::Comment("OperandRenderer")
+ << MatchTable::NamedValue("GICR_" +
+ Renderer.getValueAsString("RendererFn").str())
+ << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
+}
+
+//===- CustomCXXAction ----------------------------------------------------===//
+
+void CustomCXXAction::emitActionOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const {
+ Table << MatchTable::Opcode("GIR_CustomAction")
+ << MatchTable::NamedValue(FnEnumName) << MatchTable::LineBreak;
+}
+
+//===- BuildMIAction ------------------------------------------------------===//
+
+bool BuildMIAction::canMutate(RuleMatcher &Rule,
+ const InstructionMatcher *Insn) const {
+ if (!Insn)
+ return false;
+
+ if (OperandRenderers.size() != Insn->getNumOperands())
+ return false;
+
+ for (const auto &Renderer : enumerate(OperandRenderers)) {
+ if (const auto *Copy = dyn_cast<CopyRenderer>(&*Renderer.value())) {
+ const OperandMatcher &OM =
+ Rule.getOperandMatcher(Copy->getSymbolicName());
+ if (Insn != &OM.getInstructionMatcher() ||
+ OM.getOpIdx() != Renderer.index())
+ return false;
+ } else
+ return false;
+ }
+
+ return true;
+}
+
+void BuildMIAction::chooseInsnToMutate(RuleMatcher &Rule) {
+ for (auto *MutateCandidate : Rule.mutatable_insns()) {
+ if (canMutate(Rule, MutateCandidate)) {
+ // Take the first one we're offered that we're able to mutate.
+ Rule.reserveInsnMatcherForMutation(MutateCandidate);
+ Matched = MutateCandidate;
+ return;
+ }
+ }
+}
+
+void BuildMIAction::emitActionOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const {
+ if (Matched) {
+ assert(canMutate(Rule, Matched) &&
+ "Arranged to mutate an insn that isn't mutatable");
+
+ unsigned RecycleInsnID = Rule.getInsnVarID(*Matched);
+ Table << MatchTable::Opcode("GIR_MutateOpcode")
+ << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
+ << MatchTable::Comment("RecycleInsnID")
+ << MatchTable::IntValue(RecycleInsnID)
+ << MatchTable::Comment("Opcode")
+ << MatchTable::NamedValue(I->Namespace, I->TheDef->getName())
+ << MatchTable::LineBreak;
+
+ if (!I->ImplicitDefs.empty() || !I->ImplicitUses.empty()) {
+ for (auto *Def : I->ImplicitDefs) {
+ auto Namespace = Def->getValue("Namespace")
+ ? Def->getValueAsString("Namespace")
+ : "";
+ Table << MatchTable::Opcode("GIR_AddImplicitDef")
+ << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
+ << MatchTable::NamedValue(Namespace, Def->getName())
+ << MatchTable::LineBreak;
+ }
+ for (auto *Use : I->ImplicitUses) {
+ auto Namespace = Use->getValue("Namespace")
+ ? Use->getValueAsString("Namespace")
+ : "";
+ Table << MatchTable::Opcode("GIR_AddImplicitUse")
+ << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
+ << MatchTable::NamedValue(Namespace, Use->getName())
+ << MatchTable::LineBreak;
+ }
+ }
+ return;
+ }
+
+ // TODO: Simple permutation looks like it could be almost as common as
+ // mutation due to commutative operations.
+
+ Table << MatchTable::Opcode("GIR_BuildMI") << MatchTable::Comment("InsnID")
+ << MatchTable::IntValue(InsnID) << MatchTable::Comment("Opcode")
+ << MatchTable::NamedValue(I->Namespace, I->TheDef->getName())
+ << MatchTable::LineBreak;
+ for (const auto &Renderer : OperandRenderers)
+ Renderer->emitRenderOpcodes(Table, Rule);
+
+ if (I->mayLoad || I->mayStore) {
+ Table << MatchTable::Opcode("GIR_MergeMemOperands")
+ << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
+ << MatchTable::Comment("MergeInsnID's");
+ // Emit the ID's for all the instructions that are matched by this rule.
+ // TODO: Limit this to matched instructions that mayLoad/mayStore or have
+ // some other means of having a memoperand. Also limit this to
+ // emitted instructions that expect to have a memoperand too. For
+ // example, (G_SEXT (G_LOAD x)) that results in separate load and
+ // sign-extend instructions shouldn't put the memoperand on the
+ // sign-extend since it has no effect there.
+ std::vector<unsigned> MergeInsnIDs;
+ for (const auto &IDMatcherPair : Rule.defined_insn_vars())
+ MergeInsnIDs.push_back(IDMatcherPair.second);
+ llvm::sort(MergeInsnIDs);
+ for (const auto &MergeInsnID : MergeInsnIDs)
+ Table << MatchTable::IntValue(MergeInsnID);
+ Table << MatchTable::NamedValue("GIU_MergeMemOperands_EndOfList")
+ << MatchTable::LineBreak;
+ }
+
+ // FIXME: This is a hack but it's sufficient for ISel. We'll need to do
+ // better for combines. Particularly when there are multiple match
+ // roots.
+ if (InsnID == 0)
+ Table << MatchTable::Opcode("GIR_EraseFromParent")
+ << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
+ << MatchTable::LineBreak;
+}
+
+//===- ConstrainOperandToRegClassAction -----------------------------------===//
+
+void ConstrainOperandToRegClassAction::emitActionOpcodes(
+ MatchTable &Table, RuleMatcher &Rule) const {
+ Table << MatchTable::Opcode("GIR_ConstrainOperandRC")
+ << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
+ << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx)
+ << MatchTable::NamedValue(RC.getQualifiedName() + "RegClassID")
+ << MatchTable::LineBreak;
+}
+
+//===- MakeTempRegisterAction ---------------------------------------------===//
+
+void MakeTempRegisterAction::emitActionOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const {
+ Table << MatchTable::Opcode("GIR_MakeTempReg")
+ << MatchTable::Comment("TempRegID") << MatchTable::IntValue(TempRegID)
+ << MatchTable::Comment("TypeID")
+ << MatchTable::NamedValue(Ty.getCxxEnumValue())
+ << MatchTable::LineBreak;
+}
+
+} // namespace gi
+} // namespace llvm
diff --git a/llvm/utils/TableGen/GlobalISelMatchTable.h b/llvm/utils/TableGen/GlobalISelMatchTable.h
new file mode 100644
index 000000000000..fcb3392226c1
--- /dev/null
+++ b/llvm/utils/TableGen/GlobalISelMatchTable.h
@@ -0,0 +1,2162 @@
+//===- GlobalISelMatchTable.h ---------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// This file contains the code related to the GlobalISel Match Table emitted by
+/// GlobalISelEmitter.cpp. The generated match table is interpreted at runtime
+/// by `GIMatchTableExecutorImpl.h` to match & apply ISel patterns.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_UTILS_TABLEGEN_GLOBALISELMATCHTABLE_H
+#define LLVM_UTILS_TABLEGEN_GLOBALISELMATCHTABLE_H
+
+#include "CodeGenDAGPatterns.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/CodeGen/LowLevelType.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/SaveAndRestore.h"
+#include <deque>
+#include <list>
+#include <map>
+#include <memory>
+#include <optional>
+#include <set>
+#include <string>
+#include <vector>
+
+namespace llvm {
+
+class raw_ostream;
+class Record;
+class SMLoc;
+class CodeGenRegisterClass;
+
+// Use a namespace to avoid conflicts because there's some fairly generic names
+// in there (e.g. Matcher).
+namespace gi {
+class MatchTable;
+class Matcher;
+class OperandMatcher;
+class MatchAction;
+class PredicateMatcher;
+class InstructionMatcher;
+
+enum {
+ GISF_IgnoreCopies = 0x1,
+};
+
+using GISelFlags = std::uint16_t;
+
+//===- Helper functions ---------------------------------------------------===//
+
+std::string getNameForFeatureBitset(const std::vector<Record *> &FeatureBitset);
+
+/// Takes a sequence of \p Rules and group them based on the predicates
+/// they share. \p MatcherStorage is used as a memory container
+/// for the group that are created as part of this process.
+///
+/// What this optimization does looks like if GroupT = GroupMatcher:
+/// Output without optimization:
+/// \verbatim
+/// # R1
+/// # predicate A
+/// # predicate B
+/// ...
+/// # R2
+/// # predicate A // <-- effectively this is going to be checked twice.
+/// // Once in R1 and once in R2.
+/// # predicate C
+/// \endverbatim
+/// Output with optimization:
+/// \verbatim
+/// # Group1_2
+/// # predicate A // <-- Check is now shared.
+/// # R1
+/// # predicate B
+/// # R2
+/// # predicate C
+/// \endverbatim
+template <class GroupT>
+std::vector<Matcher *>
+optimizeRules(ArrayRef<Matcher *> Rules,
+ std::vector<std::unique_ptr<Matcher>> &MatcherStorage);
+
+/// A record to be stored in a MatchTable.
+///
+/// This class represents any and all output that may be required to emit the
+/// MatchTable. Instances are most often configured to represent an opcode or
+/// value that will be emitted to the table with some formatting but it can also
+/// represent commas, comments, and other formatting instructions.
+struct MatchTableRecord {
+ enum RecordFlagsBits {
+ MTRF_None = 0x0,
+ /// Causes EmitStr to be formatted as comment when emitted.
+ MTRF_Comment = 0x1,
+ /// Causes the record value to be followed by a comma when emitted.
+ MTRF_CommaFollows = 0x2,
+ /// Causes the record value to be followed by a line break when emitted.
+ MTRF_LineBreakFollows = 0x4,
+ /// Indicates that the record defines a label and causes an additional
+ /// comment to be emitted containing the index of the label.
+ MTRF_Label = 0x8,
+ /// Causes the record to be emitted as the index of the label specified by
+ /// LabelID along with a comment indicating where that label is.
+ MTRF_JumpTarget = 0x10,
+ /// Causes the formatter to add a level of indentation before emitting the
+ /// record.
+ MTRF_Indent = 0x20,
+ /// Causes the formatter to remove a level of indentation after emitting the
+ /// record.
+ MTRF_Outdent = 0x40,
+ };
+
+ /// When MTRF_Label or MTRF_JumpTarget is used, indicates a label id to
+ /// reference or define.
+ unsigned LabelID;
+ /// The string to emit. Depending on the MTRF_* flags it may be a comment, a
+ /// value, a label name.
+ std::string EmitStr;
+
+private:
+ /// The number of MatchTable elements described by this record. Comments are 0
+ /// while values are typically 1. Values >1 may occur when we need to emit
+ /// values that exceed the size of a MatchTable element.
+ unsigned NumElements;
+
+public:
+ /// A bitfield of RecordFlagsBits flags.
+ unsigned Flags;
+
+ /// The actual run-time value, if known
+ int64_t RawValue;
+
+ MatchTableRecord(std::optional<unsigned> LabelID_, StringRef EmitStr,
+ unsigned NumElements, unsigned Flags,
+ int64_t RawValue = std::numeric_limits<int64_t>::min())
+ : LabelID(LabelID_.value_or(~0u)), EmitStr(EmitStr),
+ NumElements(NumElements), Flags(Flags), RawValue(RawValue) {
+ assert((!LabelID_ || LabelID != ~0u) &&
+ "This value is reserved for non-labels");
+ }
+ MatchTableRecord(const MatchTableRecord &Other) = default;
+ MatchTableRecord(MatchTableRecord &&Other) = default;
+
+ /// Useful if a Match Table Record gets optimized out
+ void turnIntoComment() {
+ Flags |= MTRF_Comment;
+ Flags &= ~MTRF_CommaFollows;
+ NumElements = 0;
+ }
+
+ /// For Jump Table generation purposes
+ bool operator<(const MatchTableRecord &Other) const {
+ return RawValue < Other.RawValue;
+ }
+ int64_t getRawValue() const { return RawValue; }
+
+ void emit(raw_ostream &OS, bool LineBreakNextAfterThis,
+ const MatchTable &Table) const;
+ unsigned size() const { return NumElements; }
+};
+
+/// Holds the contents of a generated MatchTable to enable formatting and the
+/// necessary index tracking needed to support GIM_Try.
+class MatchTable {
+ /// An unique identifier for the table. The generated table will be named
+ /// MatchTable${ID}.
+ unsigned ID;
+ /// The records that make up the table. Also includes comments describing the
+ /// values being emitted and line breaks to format it.
+ std::vector<MatchTableRecord> Contents;
+ /// The currently defined labels.
+ DenseMap<unsigned, unsigned> LabelMap;
+ /// Tracks the sum of MatchTableRecord::NumElements as the table is built.
+ unsigned CurrentSize = 0;
+ /// A unique identifier for a MatchTable label.
+ unsigned CurrentLabelID = 0;
+ /// Determines if the table should be instrumented for rule coverage tracking.
+ bool IsWithCoverage;
+ /// Whether this table is for the GISel combiner.
+ bool IsCombinerTable;
+
+public:
+ static MatchTableRecord LineBreak;
+ static MatchTableRecord Comment(StringRef Comment);
+ static MatchTableRecord Opcode(StringRef Opcode, int IndentAdjust = 0);
+ static MatchTableRecord NamedValue(StringRef NamedValue);
+ static MatchTableRecord NamedValue(StringRef NamedValue, int64_t RawValue);
+ static MatchTableRecord NamedValue(StringRef Namespace, StringRef NamedValue);
+ static MatchTableRecord NamedValue(StringRef Namespace, StringRef NamedValue,
+ int64_t RawValue);
+ static MatchTableRecord IntValue(int64_t IntValue);
+ static MatchTableRecord Label(unsigned LabelID);
+ static MatchTableRecord JumpTarget(unsigned LabelID);
+
+ static MatchTable buildTable(ArrayRef<Matcher *> Rules, bool WithCoverage,
+ bool IsCombiner = false);
+
+ MatchTable(bool WithCoverage, bool IsCombinerTable, unsigned ID = 0)
+ : ID(ID), IsWithCoverage(WithCoverage), IsCombinerTable(IsCombinerTable) {
+ }
+
+ bool isWithCoverage() const { return IsWithCoverage; }
+ bool isCombiner() const { return IsCombinerTable; }
+
+ void push_back(const MatchTableRecord &Value) {
+ if (Value.Flags & MatchTableRecord::MTRF_Label)
+ defineLabel(Value.LabelID);
+ Contents.push_back(Value);
+ CurrentSize += Value.size();
+ }
+
+ unsigned allocateLabelID() { return CurrentLabelID++; }
+
+ void defineLabel(unsigned LabelID) {
+ LabelMap.insert(std::make_pair(LabelID, CurrentSize));
+ }
+
+ unsigned getLabelIndex(unsigned LabelID) const {
+ const auto I = LabelMap.find(LabelID);
+ assert(I != LabelMap.end() && "Use of undeclared label");
+ return I->second;
+ }
+
+ void emitUse(raw_ostream &OS) const;
+ void emitDeclaration(raw_ostream &OS) const;
+};
+
+inline MatchTable &operator<<(MatchTable &Table,
+ const MatchTableRecord &Value) {
+ Table.push_back(Value);
+ return Table;
+}
+
+/// This class stands in for LLT wherever we want to tablegen-erate an
+/// equivalent at compiler run-time.
+class LLTCodeGen {
+private:
+ LLT Ty;
+
+public:
+ LLTCodeGen() = default;
+ LLTCodeGen(const LLT &Ty) : Ty(Ty) {}
+
+ std::string getCxxEnumValue() const;
+
+ void emitCxxEnumValue(raw_ostream &OS) const;
+ void emitCxxConstructorCall(raw_ostream &OS) const;
+
+ const LLT &get() const { return Ty; }
+
+ /// This ordering is used for std::unique() and llvm::sort(). There's no
+ /// particular logic behind the order but either A < B or B < A must be
+ /// true if A != B.
+ bool operator<(const LLTCodeGen &Other) const;
+ bool operator==(const LLTCodeGen &B) const { return Ty == B.Ty; }
+};
+
+// Track all types that are used so we can emit the corresponding enum.
+extern std::set<LLTCodeGen> KnownTypes;
+
+/// Convert an MVT to an equivalent LLT if possible, or the invalid LLT() for
+/// MVTs that don't map cleanly to an LLT (e.g., iPTR, *any, ...).
+std::optional<LLTCodeGen> MVTToLLT(MVT::SimpleValueType SVT);
+
+//===- Matchers -----------------------------------------------------------===//
+class Matcher {
+public:
+ virtual ~Matcher();
+ virtual void optimize();
+ virtual void emit(MatchTable &Table) = 0;
+
+ virtual bool hasFirstCondition() const = 0;
+ virtual const PredicateMatcher &getFirstCondition() const = 0;
+ virtual std::unique_ptr<PredicateMatcher> popFirstCondition() = 0;
+};
+
+class GroupMatcher final : public Matcher {
+ /// Conditions that form a common prefix of all the matchers contained.
+ SmallVector<std::unique_ptr<PredicateMatcher>, 1> Conditions;
+
+ /// All the nested matchers, sharing a common prefix.
+ std::vector<Matcher *> Matchers;
+
+ /// An owning collection for any auxiliary matchers created while optimizing
+ /// nested matchers contained.
+ std::vector<std::unique_ptr<Matcher>> MatcherStorage;
+
+public:
+ /// Add a matcher to the collection of nested matchers if it meets the
+ /// requirements, and return true. If it doesn't, do nothing and return false.
+ ///
+ /// Expected to preserve its argument, so it could be moved out later on.
+ bool addMatcher(Matcher &Candidate);
+
+ /// Mark the matcher as fully-built and ensure any invariants expected by both
+ /// optimize() and emit(...) methods. Generally, both sequences of calls
+ /// are expected to lead to a sensible result:
+ ///
+ /// addMatcher(...)*; finalize(); optimize(); emit(...); and
+ /// addMatcher(...)*; finalize(); emit(...);
+ ///
+ /// or generally
+ ///
+ /// addMatcher(...)*; finalize(); { optimize()*; emit(...); }*
+ ///
+ /// Multiple calls to optimize() are expected to be handled gracefully, though
+ /// optimize() is not expected to be idempotent. Multiple calls to finalize()
+ /// aren't generally supported. emit(...) is expected to be non-mutating and
+ /// producing the exact same results upon repeated calls.
+ ///
+ /// addMatcher() calls after the finalize() call are not supported.
+ ///
+ /// finalize() and optimize() are both allowed to mutate the contained
+ /// matchers, so moving them out after finalize() is not supported.
+ void finalize();
+ void optimize() override;
+ void emit(MatchTable &Table) override;
+
+ /// Could be used to move out the matchers added previously, unless finalize()
+ /// has been already called. If any of the matchers are moved out, the group
+ /// becomes safe to destroy, but not safe to re-use for anything else.
+ iterator_range<std::vector<Matcher *>::iterator> matchers() {
+ return make_range(Matchers.begin(), Matchers.end());
+ }
+ size_t size() const { return Matchers.size(); }
+ bool empty() const { return Matchers.empty(); }
+
+ std::unique_ptr<PredicateMatcher> popFirstCondition() override {
+ assert(!Conditions.empty() &&
+ "Trying to pop a condition from a condition-less group");
+ std::unique_ptr<PredicateMatcher> P = std::move(Conditions.front());
+ Conditions.erase(Conditions.begin());
+ return P;
+ }
+ const PredicateMatcher &getFirstCondition() const override {
+ assert(!Conditions.empty() &&
+ "Trying to get a condition from a condition-less group");
+ return *Conditions.front();
+ }
+ bool hasFirstCondition() const override { return !Conditions.empty(); }
+
+private:
+ /// See if a candidate matcher could be added to this group solely by
+ /// analyzing its first condition.
+ bool candidateConditionMatches(const PredicateMatcher &Predicate) const;
+};
+
+class SwitchMatcher : public Matcher {
+ /// All the nested matchers, representing distinct switch-cases. The first
+ /// conditions (as Matcher::getFirstCondition() reports) of all the nested
+ /// matchers must share the same type and path to a value they check, in other
+ /// words, be isIdenticalDownToValue, but have different values they check
+ /// against.
+ std::vector<Matcher *> Matchers;
+
+ /// The representative condition, with a type and a path (InsnVarID and OpIdx
+ /// in most cases) shared by all the matchers contained.
+ std::unique_ptr<PredicateMatcher> Condition = nullptr;
+
+ /// Temporary set used to check that the case values don't repeat within the
+ /// same switch.
+ std::set<MatchTableRecord> Values;
+
+ /// An owning collection for any auxiliary matchers created while optimizing
+ /// nested matchers contained.
+ std::vector<std::unique_ptr<Matcher>> MatcherStorage;
+
+public:
+ bool addMatcher(Matcher &Candidate);
+
+ void finalize();
+ void emit(MatchTable &Table) override;
+
+ iterator_range<std::vector<Matcher *>::iterator> matchers() {
+ return make_range(Matchers.begin(), Matchers.end());
+ }
+ size_t size() const { return Matchers.size(); }
+ bool empty() const { return Matchers.empty(); }
+
+ std::unique_ptr<PredicateMatcher> popFirstCondition() override {
+ // SwitchMatcher doesn't have a common first condition for its cases, as all
+ // the cases only share a kind of a value (a type and a path to it) they
+ // match, but deliberately differ in the actual value they match.
+ llvm_unreachable("Trying to pop a condition from a condition-less group");
+ }
+
+ const PredicateMatcher &getFirstCondition() const override {
+ llvm_unreachable("Trying to pop a condition from a condition-less group");
+ }
+
+ bool hasFirstCondition() const override { return false; }
+
+private:
+ /// See if the predicate type has a Switch-implementation for it.
+ static bool isSupportedPredicateType(const PredicateMatcher &Predicate);
+
+ bool candidateConditionMatches(const PredicateMatcher &Predicate) const;
+
+ /// emit()-helper
+ static void emitPredicateSpecificOpcodes(const PredicateMatcher &P,
+ MatchTable &Table);
+};
+
+/// Generates code to check that a match rule matches.
+class RuleMatcher : public Matcher {
+public:
+ using ActionList = std::list<std::unique_ptr<MatchAction>>;
+ using action_iterator = ActionList::iterator;
+
+protected:
+ /// A list of matchers that all need to succeed for the current rule to match.
+ /// FIXME: This currently supports a single match position but could be
+ /// extended to support multiple positions to support div/rem fusion or
+ /// load-multiple instructions.
+ using MatchersTy = std::vector<std::unique_ptr<InstructionMatcher>>;
+ MatchersTy Matchers;
+
+ /// A list of actions that need to be taken when all predicates in this rule
+ /// have succeeded.
+ ActionList Actions;
+
+ using DefinedInsnVariablesMap = std::map<InstructionMatcher *, unsigned>;
+
+ /// A map of instruction matchers to the local variables
+ DefinedInsnVariablesMap InsnVariableIDs;
+
+ using MutatableInsnSet = SmallPtrSet<InstructionMatcher *, 4>;
+
+ // The set of instruction matchers that have not yet been claimed for mutation
+ // by a BuildMI.
+ MutatableInsnSet MutatableInsns;
+
+ /// A map of named operands defined by the matchers that may be referenced by
+ /// the renderers.
+ StringMap<OperandMatcher *> DefinedOperands;
+
+ /// A map of anonymous physical register operands defined by the matchers that
+ /// may be referenced by the renderers.
+ DenseMap<Record *, OperandMatcher *> PhysRegOperands;
+
+ /// ID for the next instruction variable defined with
+ /// implicitlyDefineInsnVar()
+ unsigned NextInsnVarID;
+
+ /// ID for the next output instruction allocated with allocateOutputInsnID()
+ unsigned NextOutputInsnID;
+
+ /// ID for the next temporary register ID allocated with allocateTempRegID()
+ unsigned NextTempRegID;
+
+ /// Current GISelFlags
+ GISelFlags Flags = 0;
+
+ std::vector<std::string> RequiredSimplePredicates;
+ std::vector<Record *> RequiredFeatures;
+ std::vector<std::unique_ptr<PredicateMatcher>> EpilogueMatchers;
+
+ ArrayRef<SMLoc> SrcLoc;
+
+ typedef std::tuple<Record *, unsigned, unsigned>
+ DefinedComplexPatternSubOperand;
+ typedef StringMap<DefinedComplexPatternSubOperand>
+ DefinedComplexPatternSubOperandMap;
+ /// A map of Symbolic Names to ComplexPattern sub-operands.
+ DefinedComplexPatternSubOperandMap ComplexSubOperands;
+ /// A map used to for multiple referenced error check of ComplexSubOperand.
+ /// ComplexSubOperand can't be referenced multiple from different operands,
+ /// however multiple references from same operand are allowed since that is
+ /// how 'same operand checks' are generated.
+ StringMap<std::string> ComplexSubOperandsParentName;
+
+ uint64_t RuleID;
+ static uint64_t NextRuleID;
+
+ GISelFlags updateGISelFlag(GISelFlags CurFlags, const Record *R,
+ StringRef FlagName, GISelFlags FlagBit);
+
+public:
+ RuleMatcher(ArrayRef<SMLoc> SrcLoc)
+ : NextInsnVarID(0), NextOutputInsnID(0), NextTempRegID(0), SrcLoc(SrcLoc),
+ RuleID(NextRuleID++) {}
+ RuleMatcher(RuleMatcher &&Other) = default;
+ RuleMatcher &operator=(RuleMatcher &&Other) = default;
+
+ uint64_t getRuleID() const { return RuleID; }
+
+ InstructionMatcher &addInstructionMatcher(StringRef SymbolicName);
+ void addRequiredFeature(Record *Feature);
+ const std::vector<Record *> &getRequiredFeatures() const;
+
+ void addRequiredSimplePredicate(StringRef PredName);
+ const std::vector<std::string> &getRequiredSimplePredicates();
+
+ // Emplaces an action of the specified Kind at the end of the action list.
+ //
+ // Returns a reference to the newly created action.
+ //
+ // Like std::vector::emplace_back(), may invalidate all iterators if the new
+ // size exceeds the capacity. Otherwise, only invalidates the past-the-end
+ // iterator.
+ template <class Kind, class... Args> Kind &addAction(Args &&...args) {
+ Actions.emplace_back(std::make_unique<Kind>(std::forward<Args>(args)...));
+ return *static_cast<Kind *>(Actions.back().get());
+ }
+
+ // Emplaces an action of the specified Kind before the given insertion point.
+ //
+ // Returns an iterator pointing at the newly created instruction.
+ //
+ // Like std::vector::insert(), may invalidate all iterators if the new size
+ // exceeds the capacity. Otherwise, only invalidates the iterators from the
+ // insertion point onwards.
+ template <class Kind, class... Args>
+ action_iterator insertAction(action_iterator InsertPt, Args &&...args) {
+ return Actions.emplace(InsertPt,
+ std::make_unique<Kind>(std::forward<Args>(args)...));
+ }
+
+ // Update the active GISelFlags based on the GISelFlags Record R.
+ // A SaveAndRestore object is returned so the old GISelFlags are restored
+ // at the end of the scope.
+ SaveAndRestore<GISelFlags> setGISelFlags(const Record *R);
+ GISelFlags getGISelFlags() const { return Flags; }
+
+ /// Define an instruction without emitting any code to do so.
+ unsigned implicitlyDefineInsnVar(InstructionMatcher &Matcher);
+
+ unsigned getInsnVarID(InstructionMatcher &InsnMatcher) const;
+ DefinedInsnVariablesMap::const_iterator defined_insn_vars_begin() const {
+ return InsnVariableIDs.begin();
+ }
+ DefinedInsnVariablesMap::const_iterator defined_insn_vars_end() const {
+ return InsnVariableIDs.end();
+ }
+ iterator_range<typename DefinedInsnVariablesMap::const_iterator>
+ defined_insn_vars() const {
+ return make_range(defined_insn_vars_begin(), defined_insn_vars_end());
+ }
+
+ MutatableInsnSet::const_iterator mutatable_insns_begin() const {
+ return MutatableInsns.begin();
+ }
+ MutatableInsnSet::const_iterator mutatable_insns_end() const {
+ return MutatableInsns.end();
+ }
+ iterator_range<typename MutatableInsnSet::const_iterator>
+ mutatable_insns() const {
+ return make_range(mutatable_insns_begin(), mutatable_insns_end());
+ }
+ void reserveInsnMatcherForMutation(InstructionMatcher *InsnMatcher) {
+ bool R = MutatableInsns.erase(InsnMatcher);
+ assert(R && "Reserving a mutatable insn that isn't available");
+ (void)R;
+ }
+
+ action_iterator actions_begin() { return Actions.begin(); }
+ action_iterator actions_end() { return Actions.end(); }
+ iterator_range<action_iterator> actions() {
+ return make_range(actions_begin(), actions_end());
+ }
+
+ void defineOperand(StringRef SymbolicName, OperandMatcher &OM);
+
+ void definePhysRegOperand(Record *Reg, OperandMatcher &OM);
+
+ Error defineComplexSubOperand(StringRef SymbolicName, Record *ComplexPattern,
+ unsigned RendererID, unsigned SubOperandID,
+ StringRef ParentSymbolicName);
+
+ std::optional<DefinedComplexPatternSubOperand>
+ getComplexSubOperand(StringRef SymbolicName) const {
+ const auto &I = ComplexSubOperands.find(SymbolicName);
+ if (I == ComplexSubOperands.end())
+ return std::nullopt;
+ return I->second;
+ }
+
+ InstructionMatcher &getInstructionMatcher(StringRef SymbolicName) const;
+ const OperandMatcher &getOperandMatcher(StringRef Name) const;
+ const OperandMatcher &getPhysRegOperandMatcher(Record *) const;
+
+ void optimize() override;
+ void emit(MatchTable &Table) override;
+
+ /// Compare the priority of this object and B.
+ ///
+ /// Returns true if this object is more important than B.
+ bool isHigherPriorityThan(const RuleMatcher &B) const;
+
+ /// Report the maximum number of temporary operands needed by the rule
+ /// matcher.
+ unsigned countRendererFns() const;
+
+ std::unique_ptr<PredicateMatcher> popFirstCondition() override;
+ const PredicateMatcher &getFirstCondition() const override;
+ LLTCodeGen getFirstConditionAsRootType();
+ bool hasFirstCondition() const override;
+ unsigned getNumOperands() const;
+ StringRef getOpcode() const;
+
+ // FIXME: Remove this as soon as possible
+ InstructionMatcher &insnmatchers_front() const { return *Matchers.front(); }
+
+ unsigned allocateOutputInsnID() { return NextOutputInsnID++; }
+ unsigned allocateTempRegID() { return NextTempRegID++; }
+
+ iterator_range<MatchersTy::iterator> insnmatchers() {
+ return make_range(Matchers.begin(), Matchers.end());
+ }
+ bool insnmatchers_empty() const { return Matchers.empty(); }
+ void insnmatchers_pop_front() { Matchers.erase(Matchers.begin()); }
+};
+
+template <class PredicateTy> class PredicateListMatcher {
+private:
+ /// Template instantiations should specialize this to return a string to use
+ /// for the comment emitted when there are no predicates.
+ std::string getNoPredicateComment() const;
+
+protected:
+ using PredicatesTy = std::deque<std::unique_ptr<PredicateTy>>;
+ PredicatesTy Predicates;
+
+ /// Track if the list of predicates was manipulated by one of the optimization
+ /// methods.
+ bool Optimized = false;
+
+public:
+ typename PredicatesTy::iterator predicates_begin() {
+ return Predicates.begin();
+ }
+ typename PredicatesTy::iterator predicates_end() { return Predicates.end(); }
+ iterator_range<typename PredicatesTy::iterator> predicates() {
+ return make_range(predicates_begin(), predicates_end());
+ }
+ typename PredicatesTy::size_type predicates_size() const {
+ return Predicates.size();
+ }
+ bool predicates_empty() const { return Predicates.empty(); }
+
+ std::unique_ptr<PredicateTy> predicates_pop_front() {
+ std::unique_ptr<PredicateTy> Front = std::move(Predicates.front());
+ Predicates.pop_front();
+ Optimized = true;
+ return Front;
+ }
+
+ void prependPredicate(std::unique_ptr<PredicateTy> &&Predicate) {
+ Predicates.push_front(std::move(Predicate));
+ }
+
+ void eraseNullPredicates() {
+ const auto NewEnd =
+ std::stable_partition(Predicates.begin(), Predicates.end(),
+ std::logical_not<std::unique_ptr<PredicateTy>>());
+ if (NewEnd != Predicates.begin()) {
+ Predicates.erase(Predicates.begin(), NewEnd);
+ Optimized = true;
+ }
+ }
+
+ /// Emit MatchTable opcodes that tests whether all the predicates are met.
+ template <class... Args>
+ void emitPredicateListOpcodes(MatchTable &Table, Args &&...args) {
+ if (Predicates.empty() && !Optimized) {
+ Table << MatchTable::Comment(getNoPredicateComment())
+ << MatchTable::LineBreak;
+ return;
+ }
+
+ for (const auto &Predicate : predicates())
+ Predicate->emitPredicateOpcodes(Table, std::forward<Args>(args)...);
+ }
+
+ /// Provide a function to avoid emitting certain predicates. This is used to
+ /// defer some predicate checks until after others
+ using PredicateFilterFunc = std::function<bool(const PredicateTy &)>;
+
+ /// Emit MatchTable opcodes for predicates which satisfy \p
+ /// ShouldEmitPredicate. This should be called multiple times to ensure all
+ /// predicates are eventually added to the match table.
+ template <class... Args>
+ void emitFilteredPredicateListOpcodes(PredicateFilterFunc ShouldEmitPredicate,
+ MatchTable &Table, Args &&...args) {
+ if (Predicates.empty() && !Optimized) {
+ Table << MatchTable::Comment(getNoPredicateComment())
+ << MatchTable::LineBreak;
+ return;
+ }
+
+ for (const auto &Predicate : predicates()) {
+ if (ShouldEmitPredicate(*Predicate))
+ Predicate->emitPredicateOpcodes(Table, std::forward<Args>(args)...);
+ }
+ }
+};
+
+class PredicateMatcher {
+public:
+ /// This enum is used for RTTI and also defines the priority that is given to
+ /// the predicate when generating the matcher code. Kinds with higher priority
+ /// must be tested first.
+ ///
+ /// The relative priority of OPM_LLT, OPM_RegBank, and OPM_MBB do not matter
+ /// but OPM_Int must have priority over OPM_RegBank since constant integers
+ /// are represented by a virtual register defined by a G_CONSTANT instruction.
+ ///
+ /// Note: The relative priority between IPM_ and OPM_ does not matter, they
+ /// are currently not compared between each other.
+ enum PredicateKind {
+ IPM_Opcode,
+ IPM_NumOperands,
+ IPM_ImmPredicate,
+ IPM_Imm,
+ IPM_AtomicOrderingMMO,
+ IPM_MemoryLLTSize,
+ IPM_MemoryVsLLTSize,
+ IPM_MemoryAddressSpace,
+ IPM_MemoryAlignment,
+ IPM_VectorSplatImm,
+ IPM_NoUse,
+ IPM_GenericPredicate,
+ OPM_SameOperand,
+ OPM_ComplexPattern,
+ OPM_IntrinsicID,
+ OPM_CmpPredicate,
+ OPM_Instruction,
+ OPM_Int,
+ OPM_LiteralInt,
+ OPM_LLT,
+ OPM_PointerToAny,
+ OPM_RegBank,
+ OPM_MBB,
+ OPM_RecordNamedOperand,
+ };
+
+protected:
+ PredicateKind Kind;
+ unsigned InsnVarID;
+ unsigned OpIdx;
+
+public:
+ PredicateMatcher(PredicateKind Kind, unsigned InsnVarID, unsigned OpIdx = ~0)
+ : Kind(Kind), InsnVarID(InsnVarID), OpIdx(OpIdx) {}
+ virtual ~PredicateMatcher();
+
+ unsigned getInsnVarID() const { return InsnVarID; }
+ unsigned getOpIdx() const { return OpIdx; }
+
+ /// Emit MatchTable opcodes that check the predicate for the given operand.
+ virtual void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const = 0;
+
+ PredicateKind getKind() const { return Kind; }
+
+ bool dependsOnOperands() const {
+ // Custom predicates really depend on the context pattern of the
+ // instruction, not just the individual instruction. This therefore
+ // implicitly depends on all other pattern constraints.
+ return Kind == IPM_GenericPredicate;
+ }
+
+ virtual bool isIdentical(const PredicateMatcher &B) const {
+ return B.getKind() == getKind() && InsnVarID == B.InsnVarID &&
+ OpIdx == B.OpIdx;
+ }
+
+ virtual bool isIdenticalDownToValue(const PredicateMatcher &B) const {
+ return hasValue() && PredicateMatcher::isIdentical(B);
+ }
+
+ virtual MatchTableRecord getValue() const {
+ assert(hasValue() && "Can not get a value of a value-less predicate!");
+ llvm_unreachable("Not implemented yet");
+ }
+ virtual bool hasValue() const { return false; }
+
+ /// Report the maximum number of temporary operands needed by the predicate
+ /// matcher.
+ virtual unsigned countRendererFns() const { return 0; }
+};
+
+/// Generates code to check a predicate of an operand.
+///
+/// Typical predicates include:
+/// * Operand is a particular register.
+/// * Operand is assigned a particular register bank.
+/// * Operand is an MBB.
+class OperandPredicateMatcher : public PredicateMatcher {
+public:
+ OperandPredicateMatcher(PredicateKind Kind, unsigned InsnVarID,
+ unsigned OpIdx)
+ : PredicateMatcher(Kind, InsnVarID, OpIdx) {}
+ virtual ~OperandPredicateMatcher();
+
+ /// Compare the priority of this object and B.
+ ///
+ /// Returns true if this object is more important than B.
+ virtual bool isHigherPriorityThan(const OperandPredicateMatcher &B) const;
+};
+
+template <>
+inline std::string
+PredicateListMatcher<OperandPredicateMatcher>::getNoPredicateComment() const {
+ return "No operand predicates";
+}
+
+/// Generates code to check that a register operand is defined by the same exact
+/// one as another.
+class SameOperandMatcher : public OperandPredicateMatcher {
+ std::string MatchingName;
+ unsigned OrigOpIdx;
+
+ GISelFlags Flags;
+
+public:
+ SameOperandMatcher(unsigned InsnVarID, unsigned OpIdx, StringRef MatchingName,
+ unsigned OrigOpIdx, GISelFlags Flags)
+ : OperandPredicateMatcher(OPM_SameOperand, InsnVarID, OpIdx),
+ MatchingName(MatchingName), OrigOpIdx(OrigOpIdx), Flags(Flags) {}
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == OPM_SameOperand;
+ }
+
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override;
+
+ bool isIdentical(const PredicateMatcher &B) const override {
+ return OperandPredicateMatcher::isIdentical(B) &&
+ OrigOpIdx == cast<SameOperandMatcher>(&B)->OrigOpIdx &&
+ MatchingName == cast<SameOperandMatcher>(&B)->MatchingName;
+ }
+};
+
+/// Generates code to check that an operand is a particular LLT.
+class LLTOperandMatcher : public OperandPredicateMatcher {
+protected:
+ LLTCodeGen Ty;
+
+public:
+ static std::map<LLTCodeGen, unsigned> TypeIDValues;
+
+ static void initTypeIDValuesMap() {
+ TypeIDValues.clear();
+
+ unsigned ID = 0;
+ for (const LLTCodeGen &LLTy : KnownTypes)
+ TypeIDValues[LLTy] = ID++;
+ }
+
+ LLTOperandMatcher(unsigned InsnVarID, unsigned OpIdx, const LLTCodeGen &Ty)
+ : OperandPredicateMatcher(OPM_LLT, InsnVarID, OpIdx), Ty(Ty) {
+ KnownTypes.insert(Ty);
+ }
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == OPM_LLT;
+ }
+
+ bool isIdentical(const PredicateMatcher &B) const override {
+ return OperandPredicateMatcher::isIdentical(B) &&
+ Ty == cast<LLTOperandMatcher>(&B)->Ty;
+ }
+
+ MatchTableRecord getValue() const override;
+ bool hasValue() const override;
+
+ LLTCodeGen getTy() const { return Ty; }
+
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override;
+};
+
+/// Generates code to check that an operand is a pointer to any address space.
+///
+/// In SelectionDAG, the types did not describe pointers or address spaces. As a
+/// result, iN is used to describe a pointer of N bits to any address space and
+/// PatFrag predicates are typically used to constrain the address space.
+/// There's no reliable means to derive the missing type information from the
+/// pattern so imported rules must test the components of a pointer separately.
+///
+/// If SizeInBits is zero, then the pointer size will be obtained from the
+/// subtarget.
+class PointerToAnyOperandMatcher : public OperandPredicateMatcher {
+protected:
+ unsigned SizeInBits;
+
+public:
+ PointerToAnyOperandMatcher(unsigned InsnVarID, unsigned OpIdx,
+ unsigned SizeInBits)
+ : OperandPredicateMatcher(OPM_PointerToAny, InsnVarID, OpIdx),
+ SizeInBits(SizeInBits) {}
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == OPM_PointerToAny;
+ }
+
+ bool isIdentical(const PredicateMatcher &B) const override {
+ return OperandPredicateMatcher::isIdentical(B) &&
+ SizeInBits == cast<PointerToAnyOperandMatcher>(&B)->SizeInBits;
+ }
+
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override;
+};
+
+/// Generates code to record named operand in RecordedOperands list at StoreIdx.
+/// Predicates with 'let PredicateCodeUsesOperands = 1' get RecordedOperands as
+/// an argument to predicate's c++ code once all operands have been matched.
+class RecordNamedOperandMatcher : public OperandPredicateMatcher {
+protected:
+ unsigned StoreIdx;
+ std::string Name;
+
+public:
+ RecordNamedOperandMatcher(unsigned InsnVarID, unsigned OpIdx,
+ unsigned StoreIdx, StringRef Name)
+ : OperandPredicateMatcher(OPM_RecordNamedOperand, InsnVarID, OpIdx),
+ StoreIdx(StoreIdx), Name(Name) {}
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == OPM_RecordNamedOperand;
+ }
+
+ bool isIdentical(const PredicateMatcher &B) const override {
+ return OperandPredicateMatcher::isIdentical(B) &&
+ StoreIdx == cast<RecordNamedOperandMatcher>(&B)->StoreIdx &&
+ Name == cast<RecordNamedOperandMatcher>(&B)->Name;
+ }
+
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override;
+};
+
+/// Generates code to check that an operand is a particular target constant.
+class ComplexPatternOperandMatcher : public OperandPredicateMatcher {
+protected:
+ const OperandMatcher &Operand;
+ const Record &TheDef;
+
+ unsigned getAllocatedTemporariesBaseID() const;
+
+public:
+ bool isIdentical(const PredicateMatcher &B) const override { return false; }
+
+ ComplexPatternOperandMatcher(unsigned InsnVarID, unsigned OpIdx,
+ const OperandMatcher &Operand,
+ const Record &TheDef)
+ : OperandPredicateMatcher(OPM_ComplexPattern, InsnVarID, OpIdx),
+ Operand(Operand), TheDef(TheDef) {}
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == OPM_ComplexPattern;
+ }
+
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override;
+ unsigned countRendererFns() const override { return 1; }
+};
+
+/// Generates code to check that an operand is in a particular register bank.
+class RegisterBankOperandMatcher : public OperandPredicateMatcher {
+protected:
+ const CodeGenRegisterClass &RC;
+
+public:
+ RegisterBankOperandMatcher(unsigned InsnVarID, unsigned OpIdx,
+ const CodeGenRegisterClass &RC)
+ : OperandPredicateMatcher(OPM_RegBank, InsnVarID, OpIdx), RC(RC) {}
+
+ bool isIdentical(const PredicateMatcher &B) const override;
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == OPM_RegBank;
+ }
+
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override;
+};
+
+/// Generates code to check that an operand is a basic block.
+class MBBOperandMatcher : public OperandPredicateMatcher {
+public:
+ MBBOperandMatcher(unsigned InsnVarID, unsigned OpIdx)
+ : OperandPredicateMatcher(OPM_MBB, InsnVarID, OpIdx) {}
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == OPM_MBB;
+ }
+
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override;
+};
+
+class ImmOperandMatcher : public OperandPredicateMatcher {
+public:
+ ImmOperandMatcher(unsigned InsnVarID, unsigned OpIdx)
+ : OperandPredicateMatcher(IPM_Imm, InsnVarID, OpIdx) {}
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == IPM_Imm;
+ }
+
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override;
+};
+
+/// Generates code to check that an operand is a G_CONSTANT with a particular
+/// int.
+class ConstantIntOperandMatcher : public OperandPredicateMatcher {
+protected:
+ int64_t Value;
+
+public:
+ ConstantIntOperandMatcher(unsigned InsnVarID, unsigned OpIdx, int64_t Value)
+ : OperandPredicateMatcher(OPM_Int, InsnVarID, OpIdx), Value(Value) {}
+
+ bool isIdentical(const PredicateMatcher &B) const override {
+ return OperandPredicateMatcher::isIdentical(B) &&
+ Value == cast<ConstantIntOperandMatcher>(&B)->Value;
+ }
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == OPM_Int;
+ }
+
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override;
+};
+
+/// Generates code to check that an operand is a raw int (where MO.isImm() or
+/// MO.isCImm() is true).
+class LiteralIntOperandMatcher : public OperandPredicateMatcher {
+protected:
+ int64_t Value;
+
+public:
+ LiteralIntOperandMatcher(unsigned InsnVarID, unsigned OpIdx, int64_t Value)
+ : OperandPredicateMatcher(OPM_LiteralInt, InsnVarID, OpIdx),
+ Value(Value) {}
+
+ bool isIdentical(const PredicateMatcher &B) const override {
+ return OperandPredicateMatcher::isIdentical(B) &&
+ Value == cast<LiteralIntOperandMatcher>(&B)->Value;
+ }
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == OPM_LiteralInt;
+ }
+
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override;
+};
+
+/// Generates code to check that an operand is an CmpInst predicate
+class CmpPredicateOperandMatcher : public OperandPredicateMatcher {
+protected:
+ std::string PredName;
+
+public:
+ CmpPredicateOperandMatcher(unsigned InsnVarID, unsigned OpIdx, std::string P)
+ : OperandPredicateMatcher(OPM_CmpPredicate, InsnVarID, OpIdx),
+ PredName(P) {}
+
+ bool isIdentical(const PredicateMatcher &B) const override {
+ return OperandPredicateMatcher::isIdentical(B) &&
+ PredName == cast<CmpPredicateOperandMatcher>(&B)->PredName;
+ }
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == OPM_CmpPredicate;
+ }
+
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override;
+};
+
+/// Generates code to check that an operand is an intrinsic ID.
+class IntrinsicIDOperandMatcher : public OperandPredicateMatcher {
+protected:
+ const CodeGenIntrinsic *II;
+
+public:
+ IntrinsicIDOperandMatcher(unsigned InsnVarID, unsigned OpIdx,
+ const CodeGenIntrinsic *II)
+ : OperandPredicateMatcher(OPM_IntrinsicID, InsnVarID, OpIdx), II(II) {}
+
+ bool isIdentical(const PredicateMatcher &B) const override {
+ return OperandPredicateMatcher::isIdentical(B) &&
+ II == cast<IntrinsicIDOperandMatcher>(&B)->II;
+ }
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == OPM_IntrinsicID;
+ }
+
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override;
+};
+
+/// Generates code to check that this operand is an immediate whose value meets
+/// an immediate predicate.
+class OperandImmPredicateMatcher : public OperandPredicateMatcher {
+protected:
+ TreePredicateFn Predicate;
+
+public:
+ OperandImmPredicateMatcher(unsigned InsnVarID, unsigned OpIdx,
+ const TreePredicateFn &Predicate)
+ : OperandPredicateMatcher(IPM_ImmPredicate, InsnVarID, OpIdx),
+ Predicate(Predicate) {}
+
+ bool isIdentical(const PredicateMatcher &B) const override {
+ return OperandPredicateMatcher::isIdentical(B) &&
+ Predicate.getOrigPatFragRecord() ==
+ cast<OperandImmPredicateMatcher>(&B)
+ ->Predicate.getOrigPatFragRecord();
+ }
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == IPM_ImmPredicate;
+ }
+
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override;
+};
+
+/// Generates code to check that a set of predicates match for a particular
+/// operand.
+class OperandMatcher : public PredicateListMatcher<OperandPredicateMatcher> {
+protected:
+ InstructionMatcher &Insn;
+ unsigned OpIdx;
+ std::string SymbolicName;
+
+ /// The index of the first temporary variable allocated to this operand. The
+ /// number of allocated temporaries can be found with
+ /// countRendererFns().
+ unsigned AllocatedTemporariesBaseID;
+
+public:
+ OperandMatcher(InstructionMatcher &Insn, unsigned OpIdx,
+ const std::string &SymbolicName,
+ unsigned AllocatedTemporariesBaseID)
+ : Insn(Insn), OpIdx(OpIdx), SymbolicName(SymbolicName),
+ AllocatedTemporariesBaseID(AllocatedTemporariesBaseID) {}
+
+ bool hasSymbolicName() const { return !SymbolicName.empty(); }
+ StringRef getSymbolicName() const { return SymbolicName; }
+ void setSymbolicName(StringRef Name) {
+ assert(SymbolicName.empty() && "Operand already has a symbolic name");
+ SymbolicName = std::string(Name);
+ }
+
+ /// Construct a new operand predicate and add it to the matcher.
+ template <class Kind, class... Args>
+ std::optional<Kind *> addPredicate(Args &&...args) {
+ if (isSameAsAnotherOperand())
+ return std::nullopt;
+ Predicates.emplace_back(std::make_unique<Kind>(
+ getInsnVarID(), getOpIdx(), std::forward<Args>(args)...));
+ return static_cast<Kind *>(Predicates.back().get());
+ }
+
+ unsigned getOpIdx() const { return OpIdx; }
+ unsigned getInsnVarID() const;
+
+ std::string getOperandExpr(unsigned InsnVarID) const;
+
+ InstructionMatcher &getInstructionMatcher() const { return Insn; }
+
+ Error addTypeCheckPredicate(const TypeSetByHwMode &VTy,
+ bool OperandIsAPointer);
+
+ /// Emit MatchTable opcodes that test whether the instruction named in
+ /// InsnVarID matches all the predicates and all the operands.
+ void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule);
+
+ /// Compare the priority of this object and B.
+ ///
+ /// Returns true if this object is more important than B.
+ bool isHigherPriorityThan(OperandMatcher &B);
+
+ /// Report the maximum number of temporary operands needed by the operand
+ /// matcher.
+ unsigned countRendererFns();
+
+ unsigned getAllocatedTemporariesBaseID() const {
+ return AllocatedTemporariesBaseID;
+ }
+
+ bool isSameAsAnotherOperand() {
+ for (const auto &Predicate : predicates())
+ if (isa<SameOperandMatcher>(Predicate))
+ return true;
+ return false;
+ }
+};
+
+/// Generates code to check a predicate on an instruction.
+///
+/// Typical predicates include:
+/// * The opcode of the instruction is a particular value.
+/// * The nsw/nuw flag is/isn't set.
+class InstructionPredicateMatcher : public PredicateMatcher {
+public:
+ InstructionPredicateMatcher(PredicateKind Kind, unsigned InsnVarID)
+ : PredicateMatcher(Kind, InsnVarID) {}
+ virtual ~InstructionPredicateMatcher() {}
+
+ /// Compare the priority of this object and B.
+ ///
+ /// Returns true if this object is more important than B.
+ virtual bool
+ isHigherPriorityThan(const InstructionPredicateMatcher &B) const {
+ return Kind < B.Kind;
+ };
+};
+
+template <>
+inline std::string
+PredicateListMatcher<PredicateMatcher>::getNoPredicateComment() const {
+ return "No instruction predicates";
+}
+
+/// Generates code to check the opcode of an instruction.
+class InstructionOpcodeMatcher : public InstructionPredicateMatcher {
+protected:
+ // Allow matching one to several, similar opcodes that share properties. This
+ // is to handle patterns where one SelectionDAG operation maps to multiple
+ // GlobalISel ones (e.g. G_BUILD_VECTOR and G_BUILD_VECTOR_TRUNC). The first
+ // is treated as the canonical opcode.
+ SmallVector<const CodeGenInstruction *, 2> Insts;
+
+ static DenseMap<const CodeGenInstruction *, unsigned> OpcodeValues;
+
+ MatchTableRecord getInstValue(const CodeGenInstruction *I) const;
+
+public:
+ static void initOpcodeValuesMap(const CodeGenTarget &Target);
+
+ InstructionOpcodeMatcher(unsigned InsnVarID,
+ ArrayRef<const CodeGenInstruction *> I)
+ : InstructionPredicateMatcher(IPM_Opcode, InsnVarID),
+ Insts(I.begin(), I.end()) {
+ assert((Insts.size() == 1 || Insts.size() == 2) &&
+ "unexpected number of opcode alternatives");
+ }
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == IPM_Opcode;
+ }
+
+ bool isIdentical(const PredicateMatcher &B) const override {
+ return InstructionPredicateMatcher::isIdentical(B) &&
+ Insts == cast<InstructionOpcodeMatcher>(&B)->Insts;
+ }
+
+ bool hasValue() const override {
+ return Insts.size() == 1 && OpcodeValues.count(Insts[0]);
+ }
+
+ // TODO: This is used for the SwitchMatcher optimization. We should be able to
+ // return a list of the opcodes to match.
+ MatchTableRecord getValue() const override;
+
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override;
+
+ /// Compare the priority of this object and B.
+ ///
+ /// Returns true if this object is more important than B.
+ bool
+ isHigherPriorityThan(const InstructionPredicateMatcher &B) const override;
+
+ bool isConstantInstruction() const;
+
+ // The first opcode is the canonical opcode, and later are alternatives.
+ StringRef getOpcode() const;
+ ArrayRef<const CodeGenInstruction *> getAlternativeOpcodes() { return Insts; }
+ bool isVariadicNumOperands() const;
+ StringRef getOperandType(unsigned OpIdx) const;
+};
+
+class InstructionNumOperandsMatcher final : public InstructionPredicateMatcher {
+ unsigned NumOperands = 0;
+
+public:
+ InstructionNumOperandsMatcher(unsigned InsnVarID, unsigned NumOperands)
+ : InstructionPredicateMatcher(IPM_NumOperands, InsnVarID),
+ NumOperands(NumOperands) {}
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == IPM_NumOperands;
+ }
+
+ bool isIdentical(const PredicateMatcher &B) const override {
+ return InstructionPredicateMatcher::isIdentical(B) &&
+ NumOperands == cast<InstructionNumOperandsMatcher>(&B)->NumOperands;
+ }
+
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override;
+};
+
+/// Generates code to check that this instruction is a constant whose value
+/// meets an immediate predicate.
+///
+/// Immediates are slightly odd since they are typically used like an operand
+/// but are represented as an operator internally. We typically write simm8:$src
+/// in a tablegen pattern, but this is just syntactic sugar for
+/// (imm:i32)<<P:Predicate_simm8>>:$imm which more directly describes the nodes
+/// that will be matched and the predicate (which is attached to the imm
+/// operator) that will be tested. In SelectionDAG this describes a
+/// ConstantSDNode whose internal value will be tested using the simm8
+/// predicate.
+///
+/// The corresponding GlobalISel representation is %1 = G_CONSTANT iN Value. In
+/// this representation, the immediate could be tested with an
+/// InstructionMatcher, InstructionOpcodeMatcher, OperandMatcher, and a
+/// OperandPredicateMatcher-subclass to check the Value meets the predicate but
+/// there are two implementation issues with producing that matcher
+/// configuration from the SelectionDAG pattern:
+/// * ImmLeaf is a PatFrag whose root is an InstructionMatcher. This means that
+/// were we to sink the immediate predicate to the operand we would have to
+/// have two partial implementations of PatFrag support, one for immediates
+/// and one for non-immediates.
+/// * At the point we handle the predicate, the OperandMatcher hasn't been
+/// created yet. If we were to sink the predicate to the OperandMatcher we
+/// would also have to complicate (or duplicate) the code that descends and
+/// creates matchers for the subtree.
+/// Overall, it's simpler to handle it in the place it was found.
+class InstructionImmPredicateMatcher : public InstructionPredicateMatcher {
+protected:
+ TreePredicateFn Predicate;
+
+public:
+ InstructionImmPredicateMatcher(unsigned InsnVarID,
+ const TreePredicateFn &Predicate)
+ : InstructionPredicateMatcher(IPM_ImmPredicate, InsnVarID),
+ Predicate(Predicate) {}
+
+ bool isIdentical(const PredicateMatcher &B) const override;
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == IPM_ImmPredicate;
+ }
+
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override;
+};
+
+/// Generates code to check that a memory instruction has a atomic ordering
+/// MachineMemoryOperand.
+class AtomicOrderingMMOPredicateMatcher : public InstructionPredicateMatcher {
+public:
+ enum AOComparator {
+ AO_Exactly,
+ AO_OrStronger,
+ AO_WeakerThan,
+ };
+
+protected:
+ StringRef Order;
+ AOComparator Comparator;
+
+public:
+ AtomicOrderingMMOPredicateMatcher(unsigned InsnVarID, StringRef Order,
+ AOComparator Comparator = AO_Exactly)
+ : InstructionPredicateMatcher(IPM_AtomicOrderingMMO, InsnVarID),
+ Order(Order), Comparator(Comparator) {}
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == IPM_AtomicOrderingMMO;
+ }
+
+ bool isIdentical(const PredicateMatcher &B) const override;
+
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override;
+};
+
+/// Generates code to check that the size of an MMO is exactly N bytes.
+class MemorySizePredicateMatcher : public InstructionPredicateMatcher {
+protected:
+ unsigned MMOIdx;
+ uint64_t Size;
+
+public:
+ MemorySizePredicateMatcher(unsigned InsnVarID, unsigned MMOIdx, unsigned Size)
+ : InstructionPredicateMatcher(IPM_MemoryLLTSize, InsnVarID),
+ MMOIdx(MMOIdx), Size(Size) {}
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == IPM_MemoryLLTSize;
+ }
+ bool isIdentical(const PredicateMatcher &B) const override {
+ return InstructionPredicateMatcher::isIdentical(B) &&
+ MMOIdx == cast<MemorySizePredicateMatcher>(&B)->MMOIdx &&
+ Size == cast<MemorySizePredicateMatcher>(&B)->Size;
+ }
+
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override;
+};
+
+class MemoryAddressSpacePredicateMatcher : public InstructionPredicateMatcher {
+protected:
+ unsigned MMOIdx;
+ SmallVector<unsigned, 4> AddrSpaces;
+
+public:
+ MemoryAddressSpacePredicateMatcher(unsigned InsnVarID, unsigned MMOIdx,
+ ArrayRef<unsigned> AddrSpaces)
+ : InstructionPredicateMatcher(IPM_MemoryAddressSpace, InsnVarID),
+ MMOIdx(MMOIdx), AddrSpaces(AddrSpaces.begin(), AddrSpaces.end()) {}
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == IPM_MemoryAddressSpace;
+ }
+
+ bool isIdentical(const PredicateMatcher &B) const override;
+
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override;
+};
+
+class MemoryAlignmentPredicateMatcher : public InstructionPredicateMatcher {
+protected:
+ unsigned MMOIdx;
+ int MinAlign;
+
+public:
+ MemoryAlignmentPredicateMatcher(unsigned InsnVarID, unsigned MMOIdx,
+ int MinAlign)
+ : InstructionPredicateMatcher(IPM_MemoryAlignment, InsnVarID),
+ MMOIdx(MMOIdx), MinAlign(MinAlign) {
+ assert(MinAlign > 0);
+ }
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == IPM_MemoryAlignment;
+ }
+
+ bool isIdentical(const PredicateMatcher &B) const override;
+
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override;
+};
+
+/// Generates code to check that the size of an MMO is less-than, equal-to, or
+/// greater than a given LLT.
+class MemoryVsLLTSizePredicateMatcher : public InstructionPredicateMatcher {
+public:
+ enum RelationKind {
+ GreaterThan,
+ EqualTo,
+ LessThan,
+ };
+
+protected:
+ unsigned MMOIdx;
+ RelationKind Relation;
+ unsigned OpIdx;
+
+public:
+ MemoryVsLLTSizePredicateMatcher(unsigned InsnVarID, unsigned MMOIdx,
+ enum RelationKind Relation, unsigned OpIdx)
+ : InstructionPredicateMatcher(IPM_MemoryVsLLTSize, InsnVarID),
+ MMOIdx(MMOIdx), Relation(Relation), OpIdx(OpIdx) {}
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == IPM_MemoryVsLLTSize;
+ }
+ bool isIdentical(const PredicateMatcher &B) const override;
+
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override;
+};
+
+// Matcher for immAllOnesV/immAllZerosV
+class VectorSplatImmPredicateMatcher : public InstructionPredicateMatcher {
+public:
+ enum SplatKind { AllZeros, AllOnes };
+
+private:
+ SplatKind Kind;
+
+public:
+ VectorSplatImmPredicateMatcher(unsigned InsnVarID, SplatKind K)
+ : InstructionPredicateMatcher(IPM_VectorSplatImm, InsnVarID), Kind(K) {}
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == IPM_VectorSplatImm;
+ }
+
+ bool isIdentical(const PredicateMatcher &B) const override {
+ return InstructionPredicateMatcher::isIdentical(B) &&
+ Kind == static_cast<const VectorSplatImmPredicateMatcher &>(B).Kind;
+ }
+
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override;
+};
+
+/// Generates code to check an arbitrary C++ instruction predicate.
+class GenericInstructionPredicateMatcher : public InstructionPredicateMatcher {
+protected:
+ std::string EnumVal;
+
+public:
+ GenericInstructionPredicateMatcher(unsigned InsnVarID,
+ TreePredicateFn Predicate);
+
+ GenericInstructionPredicateMatcher(unsigned InsnVarID,
+ const std::string &EnumVal)
+ : InstructionPredicateMatcher(IPM_GenericPredicate, InsnVarID),
+ EnumVal(EnumVal) {}
+
+ static bool classof(const InstructionPredicateMatcher *P) {
+ return P->getKind() == IPM_GenericPredicate;
+ }
+ bool isIdentical(const PredicateMatcher &B) const override;
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override;
+};
+
+/// Generates code to check for the absence of use of the result.
+// TODO? Generalize this to support checking for one use.
+class NoUsePredicateMatcher : public InstructionPredicateMatcher {
+public:
+ NoUsePredicateMatcher(unsigned InsnVarID)
+ : InstructionPredicateMatcher(IPM_NoUse, InsnVarID) {}
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == IPM_NoUse;
+ }
+
+ bool isIdentical(const PredicateMatcher &B) const override {
+ return InstructionPredicateMatcher::isIdentical(B);
+ }
+
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override {
+ Table << MatchTable::Opcode("GIM_CheckHasNoUse")
+ << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
+ << MatchTable::LineBreak;
+ }
+};
+
+/// Generates code to check that a set of predicates and operands match for a
+/// particular instruction.
+///
+/// Typical predicates include:
+/// * Has a specific opcode.
+/// * Has an nsw/nuw flag or doesn't.
+class InstructionMatcher final : public PredicateListMatcher<PredicateMatcher> {
+protected:
+ typedef std::vector<std::unique_ptr<OperandMatcher>> OperandVec;
+
+ RuleMatcher &Rule;
+
+ /// The operands to match. All rendered operands must be present even if the
+ /// condition is always true.
+ OperandVec Operands;
+ bool NumOperandsCheck = true;
+
+ std::string SymbolicName;
+ unsigned InsnVarID;
+
+ /// PhysRegInputs - List list has an entry for each explicitly specified
+ /// physreg input to the pattern. The first elt is the Register node, the
+ /// second is the recorded slot number the input pattern match saved it in.
+ SmallVector<std::pair<Record *, unsigned>, 2> PhysRegInputs;
+
+public:
+ InstructionMatcher(RuleMatcher &Rule, StringRef SymbolicName,
+ bool NumOpsCheck = true)
+ : Rule(Rule), NumOperandsCheck(NumOpsCheck), SymbolicName(SymbolicName) {
+ // We create a new instruction matcher.
+ // Get a new ID for that instruction.
+ InsnVarID = Rule.implicitlyDefineInsnVar(*this);
+ }
+
+ /// Construct a new instruction predicate and add it to the matcher.
+ template <class Kind, class... Args>
+ std::optional<Kind *> addPredicate(Args &&...args) {
+ Predicates.emplace_back(
+ std::make_unique<Kind>(getInsnVarID(), std::forward<Args>(args)...));
+ return static_cast<Kind *>(Predicates.back().get());
+ }
+
+ RuleMatcher &getRuleMatcher() const { return Rule; }
+
+ unsigned getInsnVarID() const { return InsnVarID; }
+
+ /// Add an operand to the matcher.
+ OperandMatcher &addOperand(unsigned OpIdx, const std::string &SymbolicName,
+ unsigned AllocatedTemporariesBaseID);
+ OperandMatcher &getOperand(unsigned OpIdx);
+ OperandMatcher &addPhysRegInput(Record *Reg, unsigned OpIdx,
+ unsigned TempOpIdx);
+
+ ArrayRef<std::pair<Record *, unsigned>> getPhysRegInputs() const {
+ return PhysRegInputs;
+ }
+
+ StringRef getSymbolicName() const { return SymbolicName; }
+ unsigned getNumOperands() const { return Operands.size(); }
+ OperandVec::iterator operands_begin() { return Operands.begin(); }
+ OperandVec::iterator operands_end() { return Operands.end(); }
+ iterator_range<OperandVec::iterator> operands() {
+ return make_range(operands_begin(), operands_end());
+ }
+ OperandVec::const_iterator operands_begin() const { return Operands.begin(); }
+ OperandVec::const_iterator operands_end() const { return Operands.end(); }
+ iterator_range<OperandVec::const_iterator> operands() const {
+ return make_range(operands_begin(), operands_end());
+ }
+ bool operands_empty() const { return Operands.empty(); }
+
+ void pop_front() { Operands.erase(Operands.begin()); }
+
+ void optimize();
+
+ /// Emit MatchTable opcodes that test whether the instruction named in
+ /// InsnVarName matches all the predicates and all the operands.
+ void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule);
+
+ /// Compare the priority of this object and B.
+ ///
+ /// Returns true if this object is more important than B.
+ bool isHigherPriorityThan(InstructionMatcher &B);
+
+ /// Report the maximum number of temporary operands needed by the instruction
+ /// matcher.
+ unsigned countRendererFns();
+
+ InstructionOpcodeMatcher &getOpcodeMatcher() {
+ for (auto &P : predicates())
+ if (auto *OpMatcher = dyn_cast<InstructionOpcodeMatcher>(P.get()))
+ return *OpMatcher;
+ llvm_unreachable("Didn't find an opcode matcher");
+ }
+
+ bool isConstantInstruction() {
+ return getOpcodeMatcher().isConstantInstruction();
+ }
+
+ StringRef getOpcode() { return getOpcodeMatcher().getOpcode(); }
+};
+
+/// Generates code to check that the operand is a register defined by an
+/// instruction that matches the given instruction matcher.
+///
+/// For example, the pattern:
+/// (set $dst, (G_MUL (G_ADD $src1, $src2), $src3))
+/// would use an InstructionOperandMatcher for operand 1 of the G_MUL to match
+/// the:
+/// (G_ADD $src1, $src2)
+/// subpattern.
+class InstructionOperandMatcher : public OperandPredicateMatcher {
+protected:
+ std::unique_ptr<InstructionMatcher> InsnMatcher;
+
+ GISelFlags Flags;
+
+public:
+ InstructionOperandMatcher(unsigned InsnVarID, unsigned OpIdx,
+ RuleMatcher &Rule, StringRef SymbolicName,
+ bool NumOpsCheck = true)
+ : OperandPredicateMatcher(OPM_Instruction, InsnVarID, OpIdx),
+ InsnMatcher(new InstructionMatcher(Rule, SymbolicName, NumOpsCheck)),
+ Flags(Rule.getGISelFlags()) {}
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == OPM_Instruction;
+ }
+
+ InstructionMatcher &getInsnMatcher() const { return *InsnMatcher; }
+
+ void emitCaptureOpcodes(MatchTable &Table, RuleMatcher &Rule) const;
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override {
+ emitCaptureOpcodes(Table, Rule);
+ InsnMatcher->emitPredicateOpcodes(Table, Rule);
+ }
+
+ bool isHigherPriorityThan(const OperandPredicateMatcher &B) const override;
+
+ /// Report the maximum number of temporary operands needed by the predicate
+ /// matcher.
+ unsigned countRendererFns() const override {
+ return InsnMatcher->countRendererFns();
+ }
+};
+
+//===- Actions ------------------------------------------------------------===//
+class OperandRenderer {
+public:
+ enum RendererKind {
+ OR_Copy,
+ OR_CopyOrAddZeroReg,
+ OR_CopySubReg,
+ OR_CopyPhysReg,
+ OR_CopyConstantAsImm,
+ OR_CopyFConstantAsFPImm,
+ OR_Imm,
+ OR_SubRegIndex,
+ OR_Register,
+ OR_TempRegister,
+ OR_ComplexPattern,
+ OR_Custom,
+ OR_CustomOperand
+ };
+
+protected:
+ RendererKind Kind;
+
+public:
+ OperandRenderer(RendererKind Kind) : Kind(Kind) {}
+ virtual ~OperandRenderer();
+
+ RendererKind getKind() const { return Kind; }
+
+ virtual void emitRenderOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const = 0;
+};
+
+/// A CopyRenderer emits code to copy a single operand from an existing
+/// instruction to the one being built.
+class CopyRenderer : public OperandRenderer {
+protected:
+ unsigned NewInsnID;
+ /// The name of the operand.
+ const StringRef SymbolicName;
+
+public:
+ CopyRenderer(unsigned NewInsnID, StringRef SymbolicName)
+ : OperandRenderer(OR_Copy), NewInsnID(NewInsnID),
+ SymbolicName(SymbolicName) {
+ assert(!SymbolicName.empty() && "Cannot copy from an unspecified source");
+ }
+
+ static bool classof(const OperandRenderer *R) {
+ return R->getKind() == OR_Copy;
+ }
+
+ StringRef getSymbolicName() const { return SymbolicName; }
+
+ void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override;
+};
+
+/// A CopyRenderer emits code to copy a virtual register to a specific physical
+/// register.
+class CopyPhysRegRenderer : public OperandRenderer {
+protected:
+ unsigned NewInsnID;
+ Record *PhysReg;
+
+public:
+ CopyPhysRegRenderer(unsigned NewInsnID, Record *Reg)
+ : OperandRenderer(OR_CopyPhysReg), NewInsnID(NewInsnID), PhysReg(Reg) {
+ assert(PhysReg);
+ }
+
+ static bool classof(const OperandRenderer *R) {
+ return R->getKind() == OR_CopyPhysReg;
+ }
+
+ Record *getPhysReg() const { return PhysReg; }
+
+ void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override;
+};
+
+/// A CopyOrAddZeroRegRenderer emits code to copy a single operand from an
+/// existing instruction to the one being built. If the operand turns out to be
+/// a 'G_CONSTANT 0' then it replaces the operand with a zero register.
+class CopyOrAddZeroRegRenderer : public OperandRenderer {
+protected:
+ unsigned NewInsnID;
+ /// The name of the operand.
+ const StringRef SymbolicName;
+ const Record *ZeroRegisterDef;
+
+public:
+ CopyOrAddZeroRegRenderer(unsigned NewInsnID, StringRef SymbolicName,
+ Record *ZeroRegisterDef)
+ : OperandRenderer(OR_CopyOrAddZeroReg), NewInsnID(NewInsnID),
+ SymbolicName(SymbolicName), ZeroRegisterDef(ZeroRegisterDef) {
+ assert(!SymbolicName.empty() && "Cannot copy from an unspecified source");
+ }
+
+ static bool classof(const OperandRenderer *R) {
+ return R->getKind() == OR_CopyOrAddZeroReg;
+ }
+
+ StringRef getSymbolicName() const { return SymbolicName; }
+
+ void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override;
+};
+
+/// A CopyConstantAsImmRenderer emits code to render a G_CONSTANT instruction to
+/// an extended immediate operand.
+class CopyConstantAsImmRenderer : public OperandRenderer {
+protected:
+ unsigned NewInsnID;
+ /// The name of the operand.
+ const std::string SymbolicName;
+ bool Signed;
+
+public:
+ CopyConstantAsImmRenderer(unsigned NewInsnID, StringRef SymbolicName)
+ : OperandRenderer(OR_CopyConstantAsImm), NewInsnID(NewInsnID),
+ SymbolicName(SymbolicName), Signed(true) {}
+
+ static bool classof(const OperandRenderer *R) {
+ return R->getKind() == OR_CopyConstantAsImm;
+ }
+
+ StringRef getSymbolicName() const { return SymbolicName; }
+
+ void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override;
+};
+
+/// A CopyFConstantAsFPImmRenderer emits code to render a G_FCONSTANT
+/// instruction to an extended immediate operand.
+class CopyFConstantAsFPImmRenderer : public OperandRenderer {
+protected:
+ unsigned NewInsnID;
+ /// The name of the operand.
+ const std::string SymbolicName;
+
+public:
+ CopyFConstantAsFPImmRenderer(unsigned NewInsnID, StringRef SymbolicName)
+ : OperandRenderer(OR_CopyFConstantAsFPImm), NewInsnID(NewInsnID),
+ SymbolicName(SymbolicName) {}
+
+ static bool classof(const OperandRenderer *R) {
+ return R->getKind() == OR_CopyFConstantAsFPImm;
+ }
+
+ StringRef getSymbolicName() const { return SymbolicName; }
+
+ void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override;
+};
+
+/// A CopySubRegRenderer emits code to copy a single register operand from an
+/// existing instruction to the one being built and indicate that only a
+/// subregister should be copied.
+class CopySubRegRenderer : public OperandRenderer {
+protected:
+ unsigned NewInsnID;
+ /// The name of the operand.
+ const StringRef SymbolicName;
+ /// The subregister to extract.
+ const CodeGenSubRegIndex *SubReg;
+
+public:
+ CopySubRegRenderer(unsigned NewInsnID, StringRef SymbolicName,
+ const CodeGenSubRegIndex *SubReg)
+ : OperandRenderer(OR_CopySubReg), NewInsnID(NewInsnID),
+ SymbolicName(SymbolicName), SubReg(SubReg) {}
+
+ static bool classof(const OperandRenderer *R) {
+ return R->getKind() == OR_CopySubReg;
+ }
+
+ StringRef getSymbolicName() const { return SymbolicName; }
+
+ void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override;
+};
+
+/// Adds a specific physical register to the instruction being built.
+/// This is typically useful for WZR/XZR on AArch64.
+class AddRegisterRenderer : public OperandRenderer {
+protected:
+ unsigned InsnID;
+ const Record *RegisterDef;
+ bool IsDef;
+ const CodeGenTarget &Target;
+
+public:
+ AddRegisterRenderer(unsigned InsnID, const CodeGenTarget &Target,
+ const Record *RegisterDef, bool IsDef = false)
+ : OperandRenderer(OR_Register), InsnID(InsnID), RegisterDef(RegisterDef),
+ IsDef(IsDef), Target(Target) {}
+
+ static bool classof(const OperandRenderer *R) {
+ return R->getKind() == OR_Register;
+ }
+
+ void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override;
+};
+
+/// Adds a specific temporary virtual register to the instruction being built.
+/// This is used to chain instructions together when emitting multiple
+/// instructions.
+class TempRegRenderer : public OperandRenderer {
+protected:
+ unsigned InsnID;
+ unsigned TempRegID;
+ const CodeGenSubRegIndex *SubRegIdx;
+ bool IsDef;
+ bool IsDead;
+
+public:
+ TempRegRenderer(unsigned InsnID, unsigned TempRegID, bool IsDef = false,
+ const CodeGenSubRegIndex *SubReg = nullptr,
+ bool IsDead = false)
+ : OperandRenderer(OR_Register), InsnID(InsnID), TempRegID(TempRegID),
+ SubRegIdx(SubReg), IsDef(IsDef), IsDead(IsDead) {}
+
+ static bool classof(const OperandRenderer *R) {
+ return R->getKind() == OR_TempRegister;
+ }
+
+ void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override;
+};
+
+/// Adds a specific immediate to the instruction being built.
+class ImmRenderer : public OperandRenderer {
+protected:
+ unsigned InsnID;
+ int64_t Imm;
+
+public:
+ ImmRenderer(unsigned InsnID, int64_t Imm)
+ : OperandRenderer(OR_Imm), InsnID(InsnID), Imm(Imm) {}
+
+ static bool classof(const OperandRenderer *R) {
+ return R->getKind() == OR_Imm;
+ }
+
+ void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
+ Table << MatchTable::Opcode("GIR_AddImm") << MatchTable::Comment("InsnID")
+ << MatchTable::IntValue(InsnID) << MatchTable::Comment("Imm")
+ << MatchTable::IntValue(Imm) << MatchTable::LineBreak;
+ }
+};
+
+/// Adds an enum value for a subreg index to the instruction being built.
+class SubRegIndexRenderer : public OperandRenderer {
+protected:
+ unsigned InsnID;
+ const CodeGenSubRegIndex *SubRegIdx;
+
+public:
+ SubRegIndexRenderer(unsigned InsnID, const CodeGenSubRegIndex *SRI)
+ : OperandRenderer(OR_SubRegIndex), InsnID(InsnID), SubRegIdx(SRI) {}
+
+ static bool classof(const OperandRenderer *R) {
+ return R->getKind() == OR_SubRegIndex;
+ }
+
+ void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override;
+};
+
+/// Adds operands by calling a renderer function supplied by the ComplexPattern
+/// matcher function.
+class RenderComplexPatternOperand : public OperandRenderer {
+private:
+ unsigned InsnID;
+ const Record &TheDef;
+ /// The name of the operand.
+ const StringRef SymbolicName;
+ /// The renderer number. This must be unique within a rule since it's used to
+ /// identify a temporary variable to hold the renderer function.
+ unsigned RendererID;
+ /// When provided, this is the suboperand of the ComplexPattern operand to
+ /// render. Otherwise all the suboperands will be rendered.
+ std::optional<unsigned> SubOperand;
+ /// The subregister to extract. Render the whole register if not specified.
+ const CodeGenSubRegIndex *SubReg;
+
+ unsigned getNumOperands() const {
+ return TheDef.getValueAsDag("Operands")->getNumArgs();
+ }
+
+public:
+ RenderComplexPatternOperand(unsigned InsnID, const Record &TheDef,
+ StringRef SymbolicName, unsigned RendererID,
+ std::optional<unsigned> SubOperand = std::nullopt,
+ const CodeGenSubRegIndex *SubReg = nullptr)
+ : OperandRenderer(OR_ComplexPattern), InsnID(InsnID), TheDef(TheDef),
+ SymbolicName(SymbolicName), RendererID(RendererID),
+ SubOperand(SubOperand), SubReg(SubReg) {}
+
+ static bool classof(const OperandRenderer *R) {
+ return R->getKind() == OR_ComplexPattern;
+ }
+
+ void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override;
+};
+
+class CustomRenderer : public OperandRenderer {
+protected:
+ unsigned InsnID;
+ const Record &Renderer;
+ /// The name of the operand.
+ const std::string SymbolicName;
+
+public:
+ CustomRenderer(unsigned InsnID, const Record &Renderer,
+ StringRef SymbolicName)
+ : OperandRenderer(OR_Custom), InsnID(InsnID), Renderer(Renderer),
+ SymbolicName(SymbolicName) {}
+
+ static bool classof(const OperandRenderer *R) {
+ return R->getKind() == OR_Custom;
+ }
+
+ void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override;
+};
+
+class CustomOperandRenderer : public OperandRenderer {
+protected:
+ unsigned InsnID;
+ const Record &Renderer;
+ /// The name of the operand.
+ const std::string SymbolicName;
+
+public:
+ CustomOperandRenderer(unsigned InsnID, const Record &Renderer,
+ StringRef SymbolicName)
+ : OperandRenderer(OR_CustomOperand), InsnID(InsnID), Renderer(Renderer),
+ SymbolicName(SymbolicName) {}
+
+ static bool classof(const OperandRenderer *R) {
+ return R->getKind() == OR_CustomOperand;
+ }
+
+ void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override;
+};
+
+/// An action taken when all Matcher predicates succeeded for a parent rule.
+///
+/// Typical actions include:
+/// * Changing the opcode of an instruction.
+/// * Adding an operand to an instruction.
+class MatchAction {
+public:
+ virtual ~MatchAction() {}
+
+ /// Emit the MatchTable opcodes to implement the action.
+ virtual void emitActionOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const = 0;
+};
+
+/// Generates a comment describing the matched rule being acted upon.
+class DebugCommentAction : public MatchAction {
+private:
+ std::string S;
+
+public:
+ DebugCommentAction(StringRef S) : S(std::string(S)) {}
+
+ void emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
+ Table << MatchTable::Comment(S) << MatchTable::LineBreak;
+ }
+};
+
+class CustomCXXAction : public MatchAction {
+ std::string FnEnumName;
+
+public:
+ CustomCXXAction(StringRef FnEnumName) : FnEnumName(FnEnumName.str()) {}
+
+ void emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule) const override;
+};
+
+/// Generates code to build an instruction or mutate an existing instruction
+/// into the desired instruction when this is possible.
+class BuildMIAction : public MatchAction {
+private:
+ unsigned InsnID;
+ const CodeGenInstruction *I;
+ InstructionMatcher *Matched;
+ std::vector<std::unique_ptr<OperandRenderer>> OperandRenderers;
+
+ /// True if the instruction can be built solely by mutating the opcode.
+ bool canMutate(RuleMatcher &Rule, const InstructionMatcher *Insn) const;
+
+public:
+ BuildMIAction(unsigned InsnID, const CodeGenInstruction *I)
+ : InsnID(InsnID), I(I), Matched(nullptr) {}
+
+ unsigned getInsnID() const { return InsnID; }
+ const CodeGenInstruction *getCGI() const { return I; }
+
+ void chooseInsnToMutate(RuleMatcher &Rule);
+
+ template <class Kind, class... Args> Kind &addRenderer(Args &&...args) {
+ OperandRenderers.emplace_back(
+ std::make_unique<Kind>(InsnID, std::forward<Args>(args)...));
+ return *static_cast<Kind *>(OperandRenderers.back().get());
+ }
+
+ void emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule) const override;
+};
+
+/// Generates code to constrain the operands of an output instruction to the
+/// register classes specified by the definition of that instruction.
+class ConstrainOperandsToDefinitionAction : public MatchAction {
+ unsigned InsnID;
+
+public:
+ ConstrainOperandsToDefinitionAction(unsigned InsnID) : InsnID(InsnID) {}
+
+ void emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
+ Table << MatchTable::Opcode("GIR_ConstrainSelectedInstOperands")
+ << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
+ << MatchTable::LineBreak;
+ }
+};
+
+/// Generates code to constrain the specified operand of an output instruction
+/// to the specified register class.
+class ConstrainOperandToRegClassAction : public MatchAction {
+ unsigned InsnID;
+ unsigned OpIdx;
+ const CodeGenRegisterClass &RC;
+
+public:
+ ConstrainOperandToRegClassAction(unsigned InsnID, unsigned OpIdx,
+ const CodeGenRegisterClass &RC)
+ : InsnID(InsnID), OpIdx(OpIdx), RC(RC) {}
+
+ void emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule) const override;
+};
+
+/// Generates code to create a temporary register which can be used to chain
+/// instructions together.
+class MakeTempRegisterAction : public MatchAction {
+private:
+ LLTCodeGen Ty;
+ unsigned TempRegID;
+
+public:
+ MakeTempRegisterAction(const LLTCodeGen &Ty, unsigned TempRegID)
+ : Ty(Ty), TempRegID(TempRegID) {
+ KnownTypes.insert(Ty);
+ }
+
+ void emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule) const override;
+};
+
+} // namespace gi
+} // namespace llvm
+
+#endif
diff --git a/llvm/utils/TableGen/GlobalISelMatchTableExecutorEmitter.cpp b/llvm/utils/TableGen/GlobalISelMatchTableExecutorEmitter.cpp
new file mode 100644
index 000000000000..8dc422b140a5
--- /dev/null
+++ b/llvm/utils/TableGen/GlobalISelMatchTableExecutorEmitter.cpp
@@ -0,0 +1,267 @@
+//===- GlobalISelMatchTableExecutorEmitter.cpp ----------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "GlobalISelMatchTableExecutorEmitter.h"
+#include "GlobalISelMatchTable.h"
+
+using namespace llvm;
+using namespace llvm::gi;
+
+void GlobalISelMatchTableExecutorEmitter::emitSubtargetFeatureBitsetImpl(
+ raw_ostream &OS, ArrayRef<RuleMatcher> Rules) {
+ SubtargetFeatureInfo::emitSubtargetFeatureBitEnumeration(SubtargetFeatures,
+ OS);
+
+ // Separate subtarget features by how often they must be recomputed.
+ SubtargetFeatureInfoMap ModuleFeatures;
+ std::copy_if(SubtargetFeatures.begin(), SubtargetFeatures.end(),
+ std::inserter(ModuleFeatures, ModuleFeatures.end()),
+ [](const SubtargetFeatureInfoMap::value_type &X) {
+ return !X.second.mustRecomputePerFunction();
+ });
+ SubtargetFeatureInfoMap FunctionFeatures;
+ std::copy_if(SubtargetFeatures.begin(), SubtargetFeatures.end(),
+ std::inserter(FunctionFeatures, FunctionFeatures.end()),
+ [](const SubtargetFeatureInfoMap::value_type &X) {
+ return X.second.mustRecomputePerFunction();
+ });
+
+ SubtargetFeatureInfo::emitComputeAvailableFeatures(
+ getTarget().getName(), getClassName(), "computeAvailableModuleFeatures",
+ ModuleFeatures, OS);
+
+ OS << "void " << getClassName()
+ << "::setupGeneratedPerFunctionState(MachineFunction &MF) {\n"
+ " AvailableFunctionFeatures = computeAvailableFunctionFeatures("
+ "(const "
+ << getTarget().getName()
+ << "Subtarget *)&MF.getSubtarget(), &MF);\n"
+ "}\n";
+
+ SubtargetFeatureInfo::emitComputeAvailableFeatures(
+ getTarget().getName(), getClassName(), "computeAvailableFunctionFeatures",
+ FunctionFeatures, OS, "const MachineFunction *MF");
+
+ // Emit a table containing the PredicateBitsets objects needed by the matcher
+ // and an enum for the matcher to reference them with.
+ std::vector<std::vector<Record *>> FeatureBitsets;
+ FeatureBitsets.reserve(Rules.size());
+ for (auto &Rule : Rules)
+ FeatureBitsets.push_back(Rule.getRequiredFeatures());
+ llvm::sort(FeatureBitsets, [&](const std::vector<Record *> &A,
+ const std::vector<Record *> &B) {
+ if (A.size() < B.size())
+ return true;
+ if (A.size() > B.size())
+ return false;
+ for (auto [First, Second] : zip(A, B)) {
+ if (First->getName() < Second->getName())
+ return true;
+ if (First->getName() > Second->getName())
+ return false;
+ }
+ return false;
+ });
+ FeatureBitsets.erase(
+ std::unique(FeatureBitsets.begin(), FeatureBitsets.end()),
+ FeatureBitsets.end());
+ OS << "// Feature bitsets.\n"
+ << "enum {\n"
+ << " GIFBS_Invalid,\n";
+ for (const auto &FeatureBitset : FeatureBitsets) {
+ if (FeatureBitset.empty())
+ continue;
+ OS << " " << getNameForFeatureBitset(FeatureBitset) << ",\n";
+ }
+ OS << "};\n"
+ << "const static PredicateBitset FeatureBitsets[] {\n"
+ << " {}, // GIFBS_Invalid\n";
+ for (const auto &FeatureBitset : FeatureBitsets) {
+ if (FeatureBitset.empty())
+ continue;
+ OS << " {";
+ for (const auto &Feature : FeatureBitset) {
+ const auto &I = SubtargetFeatures.find(Feature);
+ assert(I != SubtargetFeatures.end() && "Didn't import predicate?");
+ OS << I->second.getEnumBitName() << ", ";
+ }
+ OS << "},\n";
+ }
+ OS << "};\n\n";
+}
+
+void GlobalISelMatchTableExecutorEmitter::emitComplexPredicates(
+ raw_ostream &OS, ArrayRef<Record *> ComplexOperandMatchers) {
+ // Emit complex predicate table and an enum to reference them with.
+ OS << "// ComplexPattern predicates.\n"
+ << "enum {\n"
+ << " GICP_Invalid,\n";
+ for (const auto &Record : ComplexOperandMatchers)
+ OS << " GICP_" << Record->getName() << ",\n";
+ OS << "};\n"
+ << "// See constructor for table contents\n\n";
+
+ OS << getClassName() << "::ComplexMatcherMemFn\n"
+ << getClassName() << "::ComplexPredicateFns[] = {\n"
+ << " nullptr, // GICP_Invalid\n";
+ for (const auto &Record : ComplexOperandMatchers)
+ OS << " &" << getClassName()
+ << "::" << Record->getValueAsString("MatcherFn") << ", // "
+ << Record->getName() << "\n";
+ OS << "};\n\n";
+}
+
+void GlobalISelMatchTableExecutorEmitter::emitCustomOperandRenderers(
+ raw_ostream &OS, ArrayRef<StringRef> CustomOperandRenderers) {
+ OS << "// Custom renderers.\n"
+ << "enum {\n"
+ << " GICR_Invalid,\n";
+ for (const auto &Fn : CustomOperandRenderers)
+ OS << " GICR_" << Fn << ",\n";
+ OS << "};\n";
+
+ OS << getClassName() << "::CustomRendererFn\n"
+ << getClassName() << "::CustomRenderers[] = {\n"
+ << " nullptr, // GICR_Invalid\n";
+ for (const auto &Fn : CustomOperandRenderers)
+ OS << " &" << getClassName() << "::" << Fn << ",\n";
+ OS << "};\n\n";
+}
+
+void GlobalISelMatchTableExecutorEmitter::emitTypeObjects(
+ raw_ostream &OS, ArrayRef<LLTCodeGen> TypeObjects) {
+ OS << "// LLT Objects.\n"
+ << "enum {\n";
+ for (const auto &TypeObject : TypeObjects) {
+ OS << " ";
+ TypeObject.emitCxxEnumValue(OS);
+ OS << ",\n";
+ }
+ OS << "};\n"
+ << "const static size_t NumTypeObjects = " << TypeObjects.size() << ";\n"
+ << "const static LLT TypeObjects[] = {\n";
+ for (const auto &TypeObject : TypeObjects) {
+ OS << " ";
+ TypeObject.emitCxxConstructorCall(OS);
+ OS << ",\n";
+ }
+ OS << "};\n\n";
+}
+
+void GlobalISelMatchTableExecutorEmitter::emitMatchTable(
+ raw_ostream &OS, const MatchTable &Table) {
+ OS << "const int64_t *" << getClassName() << "::getMatchTable() const {\n";
+ Table.emitDeclaration(OS);
+ OS << " return ";
+ Table.emitUse(OS);
+ OS << ";\n}\n";
+}
+
+void GlobalISelMatchTableExecutorEmitter::emitExecutorImpl(
+ raw_ostream &OS, const MatchTable &Table, ArrayRef<LLTCodeGen> TypeObjects,
+ ArrayRef<RuleMatcher> Rules, ArrayRef<Record *> ComplexOperandMatchers,
+ ArrayRef<StringRef> CustomOperandRenderers, StringRef IfDefName) {
+ OS << "#ifdef " << IfDefName << "\n";
+ emitTypeObjects(OS, TypeObjects);
+ emitSubtargetFeatureBitsetImpl(OS, Rules);
+ emitComplexPredicates(OS, ComplexOperandMatchers);
+ emitMIPredicateFns(OS);
+ emitI64ImmPredicateFns(OS);
+ emitAPFloatImmPredicateFns(OS);
+ emitAPIntImmPredicateFns(OS);
+ emitTestSimplePredicate(OS);
+ emitCustomOperandRenderers(OS, CustomOperandRenderers);
+ emitAdditionalImpl(OS);
+ emitRunCustomAction(OS);
+ emitMatchTable(OS, Table);
+ OS << "#endif // ifdef " << IfDefName << "\n\n";
+}
+
+void GlobalISelMatchTableExecutorEmitter::emitPredicateBitset(
+ raw_ostream &OS, StringRef IfDefName) {
+ OS << "#ifdef " << IfDefName << "\n"
+ << "const unsigned MAX_SUBTARGET_PREDICATES = " << SubtargetFeatures.size()
+ << ";\n"
+ << "using PredicateBitset = "
+ "llvm::PredicateBitsetImpl<MAX_SUBTARGET_PREDICATES>;\n"
+ << "#endif // ifdef " << IfDefName << "\n\n";
+}
+
+void GlobalISelMatchTableExecutorEmitter::emitTemporariesDecl(
+ raw_ostream &OS, StringRef IfDefName) {
+ OS << "#ifdef " << IfDefName << "\n"
+ << " mutable MatcherState State;\n"
+ << " typedef "
+ "ComplexRendererFns("
+ << getClassName() << "::*ComplexMatcherMemFn)(MachineOperand &) const;\n"
+
+ << " typedef void(" << getClassName()
+ << "::*CustomRendererFn)(MachineInstrBuilder &, const "
+ "MachineInstr &, int) "
+ "const;\n"
+ << " const ExecInfoTy<PredicateBitset, ComplexMatcherMemFn, "
+ "CustomRendererFn> "
+ "ExecInfo;\n"
+ << " static " << getClassName()
+ << "::ComplexMatcherMemFn ComplexPredicateFns[];\n"
+ << " static " << getClassName()
+ << "::CustomRendererFn CustomRenderers[];\n"
+ << " bool testImmPredicate_I64(unsigned PredicateID, int64_t Imm) const "
+ "override;\n"
+ << " bool testImmPredicate_APInt(unsigned PredicateID, const APInt &Imm) "
+ "const override;\n"
+ << " bool testImmPredicate_APFloat(unsigned PredicateID, const APFloat "
+ "&Imm) const override;\n"
+ << " const int64_t *getMatchTable() const override;\n"
+ << " bool testMIPredicate_MI(unsigned PredicateID, const MachineInstr &MI"
+ ", const MatcherState &State) "
+ "const override;\n"
+ << " bool testSimplePredicate(unsigned PredicateID) const override;\n"
+ << " void runCustomAction(unsigned FnID, const MatcherState &State) "
+ "const override;\n";
+ emitAdditionalTemporariesDecl(OS, " ");
+ OS << "#endif // ifdef " << IfDefName << "\n\n";
+}
+
+void GlobalISelMatchTableExecutorEmitter::emitTemporariesInit(
+ raw_ostream &OS, unsigned MaxTemporaries, StringRef IfDefName) {
+ OS << "#ifdef " << IfDefName << "\n"
+ << ", State(" << MaxTemporaries << "),\n"
+ << "ExecInfo(TypeObjects, NumTypeObjects, FeatureBitsets"
+ << ", ComplexPredicateFns, CustomRenderers)\n"
+ << "#endif // ifdef " << IfDefName << "\n\n";
+
+ emitAdditionalTemporariesInit(OS);
+}
+
+void GlobalISelMatchTableExecutorEmitter::emitPredicatesDecl(
+ raw_ostream &OS, StringRef IfDefName) {
+ OS << "#ifdef " << IfDefName << "\n"
+ << "PredicateBitset AvailableModuleFeatures;\n"
+ << "mutable PredicateBitset AvailableFunctionFeatures;\n"
+ << "PredicateBitset getAvailableFeatures() const {\n"
+ << " return AvailableModuleFeatures | AvailableFunctionFeatures;\n"
+ << "}\n"
+ << "PredicateBitset\n"
+ << "computeAvailableModuleFeatures(const " << getTarget().getName()
+ << "Subtarget *Subtarget) const;\n"
+ << "PredicateBitset\n"
+ << "computeAvailableFunctionFeatures(const " << getTarget().getName()
+ << "Subtarget *Subtarget,\n"
+ << " const MachineFunction *MF) const;\n"
+ << "void setupGeneratedPerFunctionState(MachineFunction &MF) override;\n"
+ << "#endif // ifdef " << IfDefName << "\n";
+}
+
+void GlobalISelMatchTableExecutorEmitter::emitPredicatesInit(
+ raw_ostream &OS, StringRef IfDefName) {
+ OS << "#ifdef " << IfDefName << "\n"
+ << "AvailableModuleFeatures(computeAvailableModuleFeatures(&STI)),\n"
+ << "AvailableFunctionFeatures()\n"
+ << "#endif // ifdef " << IfDefName << "\n";
+}
diff --git a/llvm/utils/TableGen/GlobalISelMatchTableExecutorEmitter.h b/llvm/utils/TableGen/GlobalISelMatchTableExecutorEmitter.h
new file mode 100644
index 000000000000..d526e08a96e3
--- /dev/null
+++ b/llvm/utils/TableGen/GlobalISelMatchTableExecutorEmitter.h
@@ -0,0 +1,228 @@
+//===- GlobalISelMatchTableExecutorEmitter.h ------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// This file contains common code related to emitting
+/// GIMatchTableExecutor-derived classes.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_UTILS_TABLEGEN_GLOBALISELMATCHTABLEEXECUTOREMITTER_H
+#define LLVM_UTILS_TABLEGEN_GLOBALISELMATCHTABLEEXECUTOREMITTER_H
+
+#include "SubtargetFeatureInfo.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include <functional>
+#include <vector>
+
+namespace llvm {
+class CodeGenTarget;
+
+namespace gi {
+class RuleMatcher;
+class LLTCodeGen;
+class MatchTable;
+} // namespace gi
+
+/// Abstract base class for TableGen backends that emit a
+/// `GIMatchTableExecutor`-derived class.
+class GlobalISelMatchTableExecutorEmitter {
+ /// Emits logic to check features required by \p Rules using the
+
+ /// SubtargetFeatures map.
+ void emitSubtargetFeatureBitsetImpl(raw_ostream &OS,
+ ArrayRef<gi::RuleMatcher> Rules);
+
+ /// Emits an enum + an array that stores references to
+ /// \p ComplexOperandMatchers.
+ void emitComplexPredicates(raw_ostream &OS,
+ ArrayRef<Record *> ComplexOperandMatchers);
+
+ /// Emits an enum + an array that stores references to
+ /// \p CustomOperandRenderers.
+ void emitCustomOperandRenderers(raw_ostream &OS,
+ ArrayRef<StringRef> CustomOperandRenderers);
+
+ /// Emits an enum + an array to reference \p TypeObjects (LLTs) in the match
+ /// table.
+ void emitTypeObjects(raw_ostream &OS, ArrayRef<gi::LLTCodeGen> TypeObjects);
+
+ /// Emits the getMatchTable function which contains all of the match table's
+ /// opcodes.
+ void emitMatchTable(raw_ostream &OS, const gi::MatchTable &Table);
+
+ /// Helper function to emit `test` functions for the executor. This emits both
+ /// an enum to reference predicates in the MatchTable, and a function to
+ /// switch over the enum & execute the predicate's C++ code.
+ ///
+ /// \tparam PredicateObject An object representing a predicate to emit.
+ /// \param OS Output stream
+ /// \param TypeIdentifier Identifier used for the type of the predicate,
+ /// e.g. `MI` for MachineInstrs.
+ /// \param ArgType Full type of the argument, e.g. `const MachineInstr &`
+ /// \param ArgName Name of the argument, e.g. `MI` for MachineInstrs.
+ /// \param AdditionalArgs Optional additional argument declarations.
+ /// \param AdditionalDeclarations Optional declarations to write at the start
+ /// of the function, before switching over the predicates enum.
+ /// \param Predicates Predicates to emit.
+ /// \param GetPredEnumName Returns an enum name for a given predicate.
+ /// \param GetPredCode Returns the C++ code of a given predicate.
+ /// \param Comment Optional comment for the enum declaration.
+ template <typename PredicateObject>
+ void emitCxxPredicateFns(
+ raw_ostream &OS, StringRef TypeIdentifier, StringRef ArgType,
+ StringRef ArgName, StringRef AdditionalArgs,
+ StringRef AdditionalDeclarations, ArrayRef<PredicateObject> Predicates,
+ std::function<StringRef(PredicateObject)> GetPredEnumName,
+ std::function<StringRef(PredicateObject)> GetPredCode,
+ StringRef Comment) {
+ if (!Comment.empty())
+ OS << "// " << Comment << "\n";
+ if (!Predicates.empty()) {
+ OS << "enum {\n";
+ StringRef EnumeratorSeparator = " = GICXXPred_Invalid + 1,\n";
+ for (const auto &Pred : Predicates) {
+ OS << " GICXXPred_" << TypeIdentifier << "_Predicate_"
+ << GetPredEnumName(Pred) << EnumeratorSeparator;
+ EnumeratorSeparator = ",\n";
+ }
+ OS << "};\n";
+ }
+
+ OS << "bool " << getClassName() << "::test" << ArgName << "Predicate_"
+ << TypeIdentifier << "(unsigned PredicateID, " << ArgType << " "
+ << ArgName << AdditionalArgs << ") const {\n"
+ << AdditionalDeclarations;
+ if (!AdditionalDeclarations.empty())
+ OS << "\n";
+ if (!Predicates.empty()) {
+ OS << " switch (PredicateID) {\n";
+ for (const auto &Pred : Predicates) {
+ const auto Code = GetPredCode(Pred);
+ OS << " case GICXXPred_" << TypeIdentifier << "_Predicate_"
+ << GetPredEnumName(Pred) << ": {\n"
+ << " " << Code << "\n";
+ if (!StringRef(Code).ltrim().startswith("return")) {
+ OS << " llvm_unreachable(\"" << GetPredEnumName(Pred)
+ << " should have returned\");\n";
+ }
+ OS << " }\n";
+ }
+ OS << " }\n";
+ }
+ OS << " llvm_unreachable(\"Unknown predicate\");\n"
+ << " return false;\n"
+ << "}\n";
+ }
+
+protected:
+ /// Emits `testMIPredicate_MI`.
+ /// \tparam PredicateObject An object representing a predicate to emit.
+ /// \param OS Output stream
+ /// \param AdditionalDecls Additional C++ variable declarations.
+ /// \param Predicates Predicates to emit.
+ /// \param GetPredEnumName Returns an enum name for a given predicate.
+ /// \param GetPredCode Returns the C++ code of a given predicate.
+ /// \param Comment Optional comment for the enum declaration.
+ template <typename PredicateObject>
+ void emitMIPredicateFnsImpl(
+ raw_ostream &OS, StringRef AdditionalDecls,
+ ArrayRef<PredicateObject> Predicates,
+ std::function<StringRef(PredicateObject)> GetPredEnumName,
+ std::function<StringRef(PredicateObject)> GetPredCode,
+ StringRef Comment = "") {
+ return emitCxxPredicateFns(
+ OS, "MI", "const MachineInstr &", "MI", ", const MatcherState &State",
+ AdditionalDecls, Predicates, GetPredEnumName, GetPredCode, Comment);
+ }
+
+ /// Helper function to emit the following executor functions:
+ /// * testImmPredicate_I64 (TypeIdentifier=I64)
+ /// * testImmPredicate_APInt (TypeIdentifier=APInt)
+ /// * testImmPredicate_APFloat (TypeIdentifier=APFloat)
+ ///
+ /// \tparam PredicateObject An object representing a predicate to emit.
+ /// \param OS Output stream
+ /// \param TypeIdentifier Identifier used for the type of the predicate
+ /// \param ArgType Full type of the argument
+ /// \param Predicates Predicates to emit.
+ /// \param GetPredEnumName Returns an enum name for a given predicate.
+ /// \param GetPredCode Returns the C++ code of a given predicate.
+ /// \param Comment Optional comment for the enum declaration.
+ template <typename PredicateObject>
+ void emitImmPredicateFnsImpl(
+ raw_ostream &OS, StringRef TypeIdentifier, StringRef ArgType,
+ ArrayRef<PredicateObject> Predicates,
+ std::function<StringRef(PredicateObject)> GetPredEnumName,
+ std::function<StringRef(PredicateObject)> GetPredCode,
+ StringRef Comment = "") {
+ return emitCxxPredicateFns(OS, TypeIdentifier, ArgType, "Imm", "", "",
+ Predicates, GetPredEnumName, GetPredCode,
+ Comment);
+ }
+
+ GlobalISelMatchTableExecutorEmitter() = default;
+
+public:
+ virtual ~GlobalISelMatchTableExecutorEmitter() = default;
+
+ virtual const CodeGenTarget &getTarget() const = 0;
+
+ /// \returns the name of the class being emitted including any prefixes, e.g.
+ /// `AMDGPUInstructionSelector`.
+ virtual StringRef getClassName() const = 0;
+
+ /// Emit additional content in emitExecutorImpl
+ virtual void emitAdditionalImpl(raw_ostream &OS) {}
+
+ /// Emit additional content in emitTemporariesDecl.
+ virtual void emitAdditionalTemporariesDecl(raw_ostream &OS,
+ StringRef Indent) {}
+
+ /// Emit additional content in emitTemporariesInit.
+ virtual void emitAdditionalTemporariesInit(raw_ostream &OS) {}
+
+ /// Emit the `testMIPredicate_MI` function.
+ /// Note: `emitMIPredicateFnsImpl` can be used to do most of the work.
+ virtual void emitMIPredicateFns(raw_ostream &OS) = 0;
+
+ /// Emit the `testImmPredicate_I64` function.
+ /// Note: `emitImmPredicateFnsImpl` can be used to do most of the work.
+ virtual void emitI64ImmPredicateFns(raw_ostream &OS) = 0;
+
+ /// Emit the `testImmPredicate_APFloat` function.
+ /// Note: `emitImmPredicateFnsImpl` can be used to do most of the work.
+ virtual void emitAPFloatImmPredicateFns(raw_ostream &OS) = 0;
+
+ /// Emit the `testImmPredicate_APInt` function.
+ /// Note: `emitImmPredicateFnsImpl` can be used to do most of the work.
+ virtual void emitAPIntImmPredicateFns(raw_ostream &OS) = 0;
+ virtual void emitTestSimplePredicate(raw_ostream &OS) = 0;
+ virtual void emitRunCustomAction(raw_ostream &OS) = 0;
+
+ void emitExecutorImpl(raw_ostream &OS, const gi::MatchTable &Table,
+ ArrayRef<gi::LLTCodeGen> TypeObjects,
+ ArrayRef<gi::RuleMatcher> Rules,
+ ArrayRef<Record *> ComplexOperandMatchers,
+ ArrayRef<StringRef> CustomOperandRenderers,
+ StringRef IfDefName);
+ void emitPredicateBitset(raw_ostream &OS, StringRef IfDefName);
+ void emitTemporariesDecl(raw_ostream &OS, StringRef IfDefName);
+ void emitTemporariesInit(raw_ostream &OS, unsigned MaxTemporaries,
+ StringRef IfDefName);
+ void emitPredicatesDecl(raw_ostream &OS, StringRef IfDefName);
+ void emitPredicatesInit(raw_ostream &OS, StringRef IfDefName);
+
+ // Map of predicates to their subtarget features.
+ SubtargetFeatureInfoMap SubtargetFeatures;
+};
+} // namespace llvm
+
+#endif
diff --git a/llvm/utils/TableGen/InfoByHwMode.cpp b/llvm/utils/TableGen/InfoByHwMode.cpp
index 73c4fbf0a5eb..4e9136e936af 100644
--- a/llvm/utils/TableGen/InfoByHwMode.cpp
+++ b/llvm/utils/TableGen/InfoByHwMode.cpp
@@ -17,7 +17,7 @@
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
-
+#include "llvm/TableGen/Record.h"
#include <string>
using namespace llvm;
@@ -65,8 +65,8 @@ MVT &ValueTypeByHwMode::getOrCreateTypeForMode(unsigned Mode, MVT Type) {
return F->second;
// If Mode is not in the map, look up the default mode. If it exists,
// make a copy of it for Mode and return it.
- auto D = Map.find(DefaultMode);
- if (D != Map.end())
+ auto D = Map.begin();
+ if (D != Map.end() && D->first == DefaultMode)
return Map.insert(std::make_pair(Mode, D->second)).first->second;
// If default mode is not present either, use provided Type.
return Map.insert(std::make_pair(Mode, Type)).first->second;
diff --git a/llvm/utils/TableGen/InfoByHwMode.h b/llvm/utils/TableGen/InfoByHwMode.h
index 44927d0bf0df..b8a6645baca5 100644
--- a/llvm/utils/TableGen/InfoByHwMode.h
+++ b/llvm/utils/TableGen/InfoByHwMode.h
@@ -16,10 +16,16 @@
#include "CodeGenHwModes.h"
#include "llvm/ADT/SmallSet.h"
-#include "llvm/Support/MachineValueType.h"
-
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/CodeGen/MachineValueType.h"
+#include "llvm/Support/Compiler.h"
+#include <cassert>
+#include <limits>
#include <map>
#include <string>
+#include <tuple>
+#include <utility>
namespace llvm {
@@ -38,18 +44,44 @@ template <typename InfoT>
void union_modes(const InfoByHwMode<InfoT> &A,
const InfoByHwMode<InfoT> &B,
SmallVectorImpl<unsigned> &Modes) {
- SmallSet<unsigned, 4> U;
- for (const auto &P : A)
- U.insert(P.first);
- for (const auto &P : B)
- U.insert(P.first);
- // Make sure that the default mode is last on the list.
+ auto AI = A.begin();
+ auto BI = B.begin();
+
+ // Skip default mode, but remember if we had one.
bool HasDefault = false;
- for (unsigned M : U)
- if (M != DefaultMode)
- Modes.push_back(M);
- else
- HasDefault = true;
+ if (AI != A.end() && AI->first == DefaultMode) {
+ HasDefault = true;
+ ++AI;
+ }
+ if (BI != B.end() && BI->first == DefaultMode) {
+ HasDefault = true;
+ ++BI;
+ }
+
+ while (AI != A.end()) {
+ // If we're done with B, finish A.
+ if (BI == B.end()) {
+ for (; AI != A.end(); ++AI)
+ Modes.push_back(AI->first);
+ break;
+ }
+
+ if (BI->first < AI->first) {
+ Modes.push_back(BI->first);
+ ++BI;
+ } else {
+ Modes.push_back(AI->first);
+ if (AI->first == BI->first)
+ ++BI;
+ ++AI;
+ }
+ }
+
+ // Finish B.
+ for (; BI != B.end(); ++BI)
+ Modes.push_back(BI->first);
+
+ // Make sure that the default mode is last on the list.
if (HasDefault)
Modes.push_back(DefaultMode);
}
@@ -78,20 +110,27 @@ struct InfoByHwMode {
LLVM_ATTRIBUTE_ALWAYS_INLINE
bool hasMode(unsigned M) const { return Map.find(M) != Map.end(); }
LLVM_ATTRIBUTE_ALWAYS_INLINE
- bool hasDefault() const { return hasMode(DefaultMode); }
+ bool hasDefault() const {
+ return !Map.empty() && Map.begin()->first == DefaultMode;
+ }
InfoT &get(unsigned Mode) {
- if (!hasMode(Mode)) {
- assert(hasMode(DefaultMode));
- Map.insert({Mode, Map.at(DefaultMode)});
- }
- return Map.at(Mode);
+ auto F = Map.find(Mode);
+ if (F != Map.end())
+ return F->second;
+
+ // Copy and insert the default mode which should be first.
+ assert(hasDefault());
+ auto P = Map.insert({Mode, Map.begin()->second});
+ return P.first->second;
}
const InfoT &get(unsigned Mode) const {
auto F = Map.find(Mode);
- if (Mode != DefaultMode && F == Map.end())
- F = Map.find(DefaultMode);
- assert(F != Map.end());
+ if (F != Map.end())
+ return F->second;
+ // Get the default mode which should be first.
+ F = Map.begin();
+ assert(F != Map.end() && F->first == DefaultMode);
return F->second;
}
@@ -100,7 +139,7 @@ struct InfoByHwMode {
return Map.size() == 1 && Map.begin()->first == DefaultMode;
}
LLVM_ATTRIBUTE_ALWAYS_INLINE
- InfoT getSimple() const {
+ const InfoT &getSimple() const {
assert(isSimple());
return Map.begin()->second;
}
diff --git a/llvm/utils/TableGen/InstrDocsEmitter.cpp b/llvm/utils/TableGen/InstrDocsEmitter.cpp
index bc391227edd1..616e7b589288 100644
--- a/llvm/utils/TableGen/InstrDocsEmitter.cpp
+++ b/llvm/utils/TableGen/InstrDocsEmitter.cpp
@@ -21,25 +21,24 @@
#include "CodeGenDAGPatterns.h"
#include "CodeGenInstruction.h"
#include "CodeGenTarget.h"
-#include "TableGenBackends.h"
#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
#include <string>
#include <vector>
using namespace llvm;
-namespace llvm {
-
-void writeTitle(StringRef Str, raw_ostream &OS, char Kind = '-') {
- OS << std::string(Str.size(), Kind) << "\n" << Str << "\n"
+static void writeTitle(StringRef Str, raw_ostream &OS, char Kind = '-') {
+ OS << std::string(Str.size(), Kind) << "\n"
+ << Str << "\n"
<< std::string(Str.size(), Kind) << "\n";
}
-void writeHeader(StringRef Str, raw_ostream &OS, char Kind = '-') {
+static void writeHeader(StringRef Str, raw_ostream &OS, char Kind = '-') {
OS << Str << "\n" << std::string(Str.size(), Kind) << "\n";
}
-std::string escapeForRST(StringRef Str) {
+static std::string escapeForRST(StringRef Str) {
std::string Result;
Result.reserve(Str.size() + 4);
for (char C : Str) {
@@ -55,7 +54,7 @@ std::string escapeForRST(StringRef Str) {
return Result;
}
-void EmitInstrDocs(RecordKeeper &RK, raw_ostream &OS) {
+static void EmitInstrDocs(RecordKeeper &RK, raw_ostream &OS) {
CodeGenDAGPatterns CDP(RK);
CodeGenTarget &Target = CDP.getTargetInfo();
unsigned VariantCount = Target.getAsmParserVariantCount();
@@ -216,4 +215,5 @@ void EmitInstrDocs(RecordKeeper &RK, raw_ostream &OS) {
}
}
-} // end namespace llvm
+static TableGen::Emitter::Opt X("gen-instr-docs", EmitInstrDocs,
+ "Generate instruction documentation");
diff --git a/llvm/utils/TableGen/InstrInfoEmitter.cpp b/llvm/utils/TableGen/InstrInfoEmitter.cpp
index 564c3ed64e26..cab9ecd4ea97 100644
--- a/llvm/utils/TableGen/InstrInfoEmitter.cpp
+++ b/llvm/utils/TableGen/InstrInfoEmitter.cpp
@@ -61,7 +61,9 @@ public:
private:
void emitEnums(raw_ostream &OS);
- typedef std::map<std::vector<std::string>, unsigned> OperandInfoMapTy;
+ typedef std::vector<std::string> OperandInfoTy;
+ typedef std::vector<OperandInfoTy> OperandInfoListTy;
+ typedef std::map<OperandInfoTy, unsigned> OperandInfoMapTy;
/// The keys of this map are maps which have OpName enum values as their keys
/// and instruction operand indices as their values. The values of this map
@@ -86,9 +88,8 @@ private:
void emitFeatureVerifier(raw_ostream &OS, const CodeGenTarget &Target);
void emitRecord(const CodeGenInstruction &Inst, unsigned Num,
Record *InstrInfo,
- std::map<std::vector<Record*>, unsigned> &EL,
- const OperandInfoMapTy &OpInfo,
- raw_ostream &OS);
+ std::map<std::vector<Record *>, unsigned> &EL,
+ const OperandInfoMapTy &OperandInfo, raw_ostream &OS);
void emitOperandTypeMappings(
raw_ostream &OS, const CodeGenTarget &Target,
ArrayRef<const CodeGenInstruction *> NumberedInstructions);
@@ -108,27 +109,21 @@ private:
ArrayRef<const CodeGenInstruction *> NumberedInstructions);
// Operand information.
- void EmitOperandInfo(raw_ostream &OS, OperandInfoMapTy &OperandInfoIDs);
- std::vector<std::string> GetOperandInfo(const CodeGenInstruction &Inst);
+ unsigned CollectOperandInfo(OperandInfoListTy &OperandInfoList,
+ OperandInfoMapTy &OperandInfoMap);
+ void EmitOperandInfo(raw_ostream &OS, OperandInfoListTy &OperandInfoList);
+ OperandInfoTy GetOperandInfo(const CodeGenInstruction &Inst);
};
} // end anonymous namespace
-static void PrintDefList(const std::vector<Record*> &Uses,
- unsigned Num, raw_ostream &OS) {
- OS << "static const MCPhysReg ImplicitList" << Num << "[] = { ";
- for (auto [Idx, U] : enumerate(Uses))
- OS << (Idx ? ", " : "") << getQualifiedName(U);
- OS << " };\n";
-}
-
//===----------------------------------------------------------------------===//
// Operand Info Emission.
//===----------------------------------------------------------------------===//
-std::vector<std::string>
+InstrInfoEmitter::OperandInfoTy
InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) {
- std::vector<std::string> Result;
+ OperandInfoTy Result;
for (auto &Op : Inst.Operands) {
// Handle aggregate operands and normal operands the same way by expanding
@@ -215,24 +210,30 @@ InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) {
return Result;
}
-void InstrInfoEmitter::EmitOperandInfo(raw_ostream &OS,
- OperandInfoMapTy &OperandInfoIDs) {
- // ID #0 is for no operand info.
- unsigned OperandListNum = 0;
- OperandInfoIDs[std::vector<std::string>()] = ++OperandListNum;
-
- OS << "\n";
+unsigned
+InstrInfoEmitter::CollectOperandInfo(OperandInfoListTy &OperandInfoList,
+ OperandInfoMapTy &OperandInfoMap) {
const CodeGenTarget &Target = CDP.getTargetInfo();
+ unsigned Offset = 0;
for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) {
- std::vector<std::string> OperandInfo = GetOperandInfo(*Inst);
- unsigned &N = OperandInfoIDs[OperandInfo];
- if (N != 0) continue;
+ OperandInfoTy OperandInfo = GetOperandInfo(*Inst);
+ if (OperandInfoMap.insert({OperandInfo, Offset}).second) {
+ OperandInfoList.push_back(OperandInfo);
+ Offset += OperandInfo.size();
+ }
+ }
+ return Offset;
+}
- N = ++OperandListNum;
- OS << "static const MCOperandInfo OperandInfo" << N << "[] = { ";
- for (const std::string &Info : OperandInfo)
- OS << "{ " << Info << " }, ";
- OS << "};\n";
+void InstrInfoEmitter::EmitOperandInfo(raw_ostream &OS,
+ OperandInfoListTy &OperandInfoList) {
+ unsigned Offset = 0;
+ for (auto &OperandInfo : OperandInfoList) {
+ OS << " /* " << Offset << " */";
+ for (auto &Info : OperandInfo)
+ OS << " { " << Info << " },";
+ OS << '\n';
+ Offset += OperandInfo.size();
}
}
@@ -419,8 +420,7 @@ void InstrInfoEmitter::emitOperandTypeMappings(
// Size the unsigned integer offset to save space.
assert(OperandRecords.size() <= UINT32_MAX &&
"Too many operands for offset table");
- OS << ((OperandRecords.size() <= UINT16_MAX) ? " const uint16_t"
- : " const uint32_t");
+ OS << " static const " << getMinimalTypeForRange(OperandRecords.size());
OS << " Offsets[] = {\n";
for (int I = 0, E = OperandOffsets.size(); I != E; ++I) {
OS << " /* " << getInstrName(I) << " */\n";
@@ -436,7 +436,8 @@ void InstrInfoEmitter::emitOperandTypeMappings(
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 << " static";
+ OS << ((EnumVal <= INT8_MAX) ? " const int8_t" : " const int16_t");
OS << " OpcodeOperandTypes[] = {\n ";
for (int I = 0, E = OperandRecords.size(), CurOffset = 0; I != E; ++I) {
// We print each Opcode's operands in its own row.
@@ -732,23 +733,19 @@ void InstrInfoEmitter::emitFeatureVerifier(raw_ostream &OS,
std::map<Record *, SubtargetFeatureInfo, LessRecordByID> SubtargetFeatures;
SubtargetFeatures.insert(All.begin(), All.end());
- OS << "#ifdef ENABLE_INSTR_PREDICATE_VERIFIER\n"
- << "#undef ENABLE_INSTR_PREDICATE_VERIFIER\n"
- << "#include <sstream>\n\n";
-
- OS << "namespace llvm {\n";
- OS << "namespace " << Target.getName() << "_MC {\n\n";
+ OS << "#if defined(ENABLE_INSTR_PREDICATE_VERIFIER) && !defined(NDEBUG)\n"
+ << "#define GET_COMPUTE_FEATURES\n"
+ << "#endif\n";
+ OS << "#ifdef GET_COMPUTE_FEATURES\n"
+ << "#undef GET_COMPUTE_FEATURES\n"
+ << "namespace llvm {\n"
+ << "namespace " << Target.getName() << "_MC {\n\n";
// Emit the subtarget feature enumeration.
SubtargetFeatureInfo::emitSubtargetFeatureBitEnumeration(SubtargetFeatures,
OS);
-
- // Emit the name table for error messages.
- OS << "#ifndef NDEBUG\n";
- SubtargetFeatureInfo::emitNameTable(SubtargetFeatures, OS);
- OS << "#endif // NDEBUG\n\n";
-
// Emit the available features compute function.
+ OS << "inline ";
SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures(
Target.getName(), "", "computeAvailableFeatures", SubtargetFeatures, OS);
@@ -779,22 +776,21 @@ void InstrInfoEmitter::emitFeatureVerifier(raw_ostream &OS,
FeatureBitsets.erase(
std::unique(FeatureBitsets.begin(), FeatureBitsets.end()),
FeatureBitsets.end());
- OS << "#ifndef NDEBUG\n"
- << "// Feature bitsets.\n"
- << "enum : " << getMinimalTypeForRange(FeatureBitsets.size()) << " {\n"
- << " CEFBS_None,\n";
+ OS << "inline FeatureBitset computeRequiredFeatures(unsigned Opcode) {\n"
+ << " enum : " << getMinimalTypeForRange(FeatureBitsets.size()) << " {\n"
+ << " CEFBS_None,\n";
for (const auto &FeatureBitset : FeatureBitsets) {
if (FeatureBitset.empty())
continue;
- OS << " " << getNameForFeatureBitset(FeatureBitset) << ",\n";
+ OS << " " << getNameForFeatureBitset(FeatureBitset) << ",\n";
}
- OS << "};\n\n"
- << "static constexpr FeatureBitset FeatureBitsets[] = {\n"
- << " {}, // CEFBS_None\n";
+ OS << " };\n\n"
+ << " static constexpr FeatureBitset FeatureBitsets[] = {\n"
+ << " {}, // CEFBS_None\n";
for (const auto &FeatureBitset : FeatureBitsets) {
if (FeatureBitset.empty())
continue;
- OS << " {";
+ OS << " {";
for (const auto &Feature : FeatureBitset) {
const auto &I = SubtargetFeatures.find(Feature);
assert(I != SubtargetFeatures.end() && "Didn't import predicate?");
@@ -802,13 +798,7 @@ void InstrInfoEmitter::emitFeatureVerifier(raw_ostream &OS,
}
OS << "},\n";
}
- OS << "};\n"
- << "#endif // NDEBUG\n\n";
-
- // Emit the predicate verifier.
- OS << "void verifyInstructionPredicates(\n"
- << " unsigned Opcode, const FeatureBitset &Features) {\n"
- << "#ifndef NDEBUG\n"
+ OS << " };\n"
<< " static " << getMinimalTypeForRange(FeatureBitsets.size())
<< " RequiredFeaturesRefs[] = {\n";
unsigned InstIdx = 0;
@@ -827,12 +817,35 @@ void InstrInfoEmitter::emitFeatureVerifier(raw_ostream &OS,
OS << ", // " << Inst->TheDef->getName() << " = " << InstIdx << "\n";
InstIdx++;
}
- OS << " };\n\n";
- OS << " assert(Opcode < " << InstIdx << ");\n";
+ OS << " };\n\n"
+ << " assert(Opcode < " << InstIdx << ");\n"
+ << " return FeatureBitsets[RequiredFeaturesRefs[Opcode]];\n"
+ << "}\n\n";
+
+ OS << "} // end namespace " << Target.getName() << "_MC\n"
+ << "} // end namespace llvm\n"
+ << "#endif // GET_COMPUTE_FEATURES\n\n";
+
+ OS << "#ifdef ENABLE_INSTR_PREDICATE_VERIFIER\n"
+ << "#undef ENABLE_INSTR_PREDICATE_VERIFIER\n"
+ << "#include <sstream>\n\n";
+
+ OS << "namespace llvm {\n";
+ OS << "namespace " << Target.getName() << "_MC {\n\n";
+
+ // Emit the name table for error messages.
+ OS << "#ifndef NDEBUG\n";
+ SubtargetFeatureInfo::emitNameTable(SubtargetFeatures, OS);
+ OS << "#endif // NDEBUG\n\n";
+
+ // Emit the predicate verifier.
+ OS << "void verifyInstructionPredicates(\n"
+ << " unsigned Opcode, const FeatureBitset &Features) {\n"
+ << "#ifndef NDEBUG\n";
OS << " FeatureBitset AvailableFeatures = "
"computeAvailableFeatures(Features);\n";
- OS << " const FeatureBitset &RequiredFeatures = "
- "FeatureBitsets[RequiredFeaturesRefs[Opcode]];\n";
+ OS << " FeatureBitset RequiredFeatures = "
+ << "computeRequiredFeatures(Opcode);\n";
OS << " FeatureBitset MissingFeatures =\n"
<< " (AvailableFeatures & RequiredFeatures) ^\n"
<< " RequiredFeatures;\n"
@@ -891,54 +904,90 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
emitSourceFileHeader("Target Instruction Enum Values and Descriptors", OS);
emitEnums(OS);
- OS << "#ifdef GET_INSTRINFO_MC_DESC\n";
- OS << "#undef GET_INSTRINFO_MC_DESC\n";
-
- OS << "namespace llvm {\n\n";
-
CodeGenTarget &Target = CDP.getTargetInfo();
const std::string &TargetName = std::string(Target.getName());
Record *InstrInfo = Target.getInstructionSet();
- // Keep track of all of the def lists we have emitted already.
- std::map<std::vector<Record*>, unsigned> EmittedLists;
- unsigned ListNumber = 0;
+ // Collect all of the operand info records.
+ Records.startTimer("Collect operand info");
+ OperandInfoListTy OperandInfoList;
+ OperandInfoMapTy OperandInfoMap;
+ unsigned OperandInfoSize =
+ CollectOperandInfo(OperandInfoList, OperandInfoMap);
- // Emit all of the instruction's implicit uses and defs.
- Records.startTimer("Emit uses/defs");
+ // Collect all of the instruction's implicit uses and defs.
+ Records.startTimer("Collect uses/defs");
+ std::map<std::vector<Record*>, unsigned> EmittedLists;
+ std::vector<std::vector<Record *>> ImplicitLists;
+ unsigned ImplicitListSize = 0;
for (const CodeGenInstruction *II : Target.getInstructionsByEnumValue()) {
std::vector<Record *> ImplicitOps = II->ImplicitUses;
llvm::append_range(ImplicitOps, II->ImplicitDefs);
- if (!ImplicitOps.empty()) {
- unsigned &IL = EmittedLists[ImplicitOps];
- if (!IL) {
- IL = ++ListNumber;
- PrintDefList(ImplicitOps, IL, OS);
- }
+ if (EmittedLists.insert({ImplicitOps, ImplicitListSize}).second) {
+ ImplicitLists.push_back(ImplicitOps);
+ ImplicitListSize += ImplicitOps.size();
}
}
- OperandInfoMapTy OperandInfoIDs;
+ ArrayRef<const CodeGenInstruction *> NumberedInstructions =
+ Target.getInstructionsByEnumValue();
+ OS << "#if defined(GET_INSTRINFO_MC_DESC) || "
+ "defined(GET_INSTRINFO_CTOR_DTOR)\n";
+ OS << "namespace llvm {\n\n";
- // Emit all of the operand info records.
- Records.startTimer("Emit operand info");
- EmitOperandInfo(OS, OperandInfoIDs);
+ OS << "struct " << TargetName << "InstrTable {\n";
+ OS << " MCInstrDesc Insts[" << NumberedInstructions.size() << "];\n";
+ OS << " static_assert(alignof(MCInstrDesc) >= alignof(MCOperandInfo), "
+ "\"Unwanted padding between Insts and OperandInfo\");\n";
+ OS << " MCOperandInfo OperandInfo[" << OperandInfoSize << "];\n";
+ OS << " static_assert(alignof(MCOperandInfo) >= alignof(MCPhysReg), "
+ "\"Unwanted padding between OperandInfo and ImplicitOps\");\n";
+ OS << " MCPhysReg ImplicitOps[" << std::max(ImplicitListSize, 1U) << "];\n";
+ OS << "};\n\n";
+
+ OS << "} // end namespace llvm\n";
+ OS << "#endif // defined(GET_INSTRINFO_MC_DESC) || "
+ "defined(GET_INSTRINFO_CTOR_DTOR)\n\n";
+
+ OS << "#ifdef GET_INSTRINFO_MC_DESC\n";
+ OS << "#undef GET_INSTRINFO_MC_DESC\n";
+ OS << "namespace llvm {\n\n";
// Emit all of the MCInstrDesc records in reverse ENUM ordering.
Records.startTimer("Emit InstrDesc records");
- OS << "\nextern const MCInstrDesc " << TargetName << "Insts[] = {\n";
- ArrayRef<const CodeGenInstruction*> NumberedInstructions =
- Target.getInstructionsByEnumValue();
+ OS << "static_assert(sizeof(MCOperandInfo) % sizeof(MCPhysReg) == 0);\n";
+ OS << "static constexpr unsigned " << TargetName << "ImpOpBase = sizeof "
+ << TargetName << "InstrTable::OperandInfo / (sizeof(MCPhysReg));\n\n";
+ OS << "extern const " << TargetName << "InstrTable " << TargetName
+ << "Descs = {\n {\n";
SequenceToOffsetTable<std::string> InstrNames;
unsigned Num = NumberedInstructions.size();
for (const CodeGenInstruction *Inst : reverse(NumberedInstructions)) {
// Keep a list of the instruction names.
InstrNames.add(std::string(Inst->TheDef->getName()));
// Emit the record into the table.
- emitRecord(*Inst, --Num, InstrInfo, EmittedLists, OperandInfoIDs, OS);
+ emitRecord(*Inst, --Num, InstrInfo, EmittedLists, OperandInfoMap, OS);
}
- OS << "};\n\n";
+
+ OS << " }, {\n";
+
+ // Emit all of the operand info records.
+ Records.startTimer("Emit operand info");
+ EmitOperandInfo(OS, OperandInfoList);
+
+ OS << " }, {\n";
+
+ // Emit all of the instruction's implicit uses and defs.
+ Records.startTimer("Emit uses/defs");
+ for (auto &List : ImplicitLists) {
+ OS << " /* " << EmittedLists[List] << " */";
+ for (auto &Reg : List)
+ OS << ' ' << getQualifiedName(Reg) << ',';
+ OS << '\n';
+ }
+
+ OS << " }\n};\n\n";
// Emit the array of instruction names.
Records.startTimer("Emit instruction names");
@@ -1005,7 +1054,7 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
Records.startTimer("Emit initialization routine");
OS << "static inline void Init" << TargetName
<< "MCInstrInfo(MCInstrInfo *II) {\n";
- OS << " II->InitMCInstrInfo(" << TargetName << "Insts, " << TargetName
+ OS << " II->InitMCInstrInfo(" << TargetName << "Descs.Insts, " << TargetName
<< "InstrNameIndices, " << TargetName << "InstrNameData, ";
if (HasDeprecationFeatures)
OS << TargetName << "InstrDeprecationFeatures, ";
@@ -1053,7 +1102,8 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
OS << "#undef GET_INSTRINFO_CTOR_DTOR\n";
OS << "namespace llvm {\n";
- OS << "extern const MCInstrDesc " << TargetName << "Insts[];\n";
+ OS << "extern const " << TargetName << "InstrTable " << TargetName
+ << "Descs;\n";
OS << "extern const unsigned " << TargetName << "InstrNameIndices[];\n";
OS << "extern const char " << TargetName << "InstrNameData[];\n";
if (HasDeprecationFeatures)
@@ -1067,7 +1117,7 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
"CatchRetOpcode, unsigned ReturnOpcode)\n"
<< " : TargetInstrInfo(CFSetupOpcode, CFDestroyOpcode, CatchRetOpcode, "
"ReturnOpcode) {\n"
- << " InitMCInstrInfo(" << TargetName << "Insts, " << TargetName
+ << " InitMCInstrInfo(" << TargetName << "Descs.Insts, " << TargetName
<< "InstrNameIndices, " << TargetName << "InstrNameData, ";
if (HasDeprecationFeatures)
OS << TargetName << "InstrDeprecationFeatures, ";
@@ -1101,27 +1151,34 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
emitFeatureVerifier(OS, Target);
}
-void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num,
- Record *InstrInfo,
- std::map<std::vector<Record*>, unsigned> &EmittedLists,
- const OperandInfoMapTy &OpInfo,
- raw_ostream &OS) {
+void InstrInfoEmitter::emitRecord(
+ const CodeGenInstruction &Inst, unsigned Num, Record *InstrInfo,
+ std::map<std::vector<Record *>, unsigned> &EmittedLists,
+ const OperandInfoMapTy &OperandInfoMap, raw_ostream &OS) {
int MinOperands = 0;
if (!Inst.Operands.empty())
// Each logical operand can be multiple MI operands.
MinOperands = Inst.Operands.back().MIOperandNo +
Inst.Operands.back().MINumOperands;
- OS << " { ";
- OS << Num << ",\t" << MinOperands << ",\t"
- << Inst.Operands.NumDefs << ",\t"
+ OS << " { ";
+ OS << Num << ",\t" << MinOperands << ",\t" << Inst.Operands.NumDefs << ",\t"
<< Inst.TheDef->getValueAsInt("Size") << ",\t"
- << SchedModels.getSchedClassIdx(Inst) << ",\t"
- << Inst.ImplicitUses.size() << ",\t"
- << Inst.ImplicitDefs.size() << ",\t0";
+ << SchedModels.getSchedClassIdx(Inst) << ",\t";
CodeGenTarget &Target = CDP.getTargetInfo();
+ // Emit the implicit use/def list...
+ OS << Inst.ImplicitUses.size() << ",\t" << Inst.ImplicitDefs.size() << ",\t";
+ std::vector<Record *> ImplicitOps = Inst.ImplicitUses;
+ llvm::append_range(ImplicitOps, Inst.ImplicitDefs);
+ OS << Target.getName() << "ImpOpBase + " << EmittedLists[ImplicitOps]
+ << ",\t";
+
+ // Emit the operand info offset.
+ OperandInfoTy OperandInfo = GetOperandInfo(Inst);
+ OS << OperandInfoMap.find(OperandInfo)->second << ",\t0";
+
// Emit all of the target independent flags...
if (Inst.isPreISelOpcode) OS << "|(1ULL<<MCID::PreISelOpcode)";
if (Inst.isPseudo) OS << "|(1ULL<<MCID::Pseudo)";
@@ -1181,22 +1238,7 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num,
}
OS << ", 0x";
OS.write_hex(Value);
- OS << "ULL, ";
-
- // Emit the implicit use/def list...
- std::vector<Record *> ImplicitOps = Inst.ImplicitUses;
- llvm::append_range(ImplicitOps, Inst.ImplicitDefs);
- if (ImplicitOps.empty())
- OS << "nullptr, ";
- else
- OS << "ImplicitList" << EmittedLists[ImplicitOps] << ", ";
-
- // Emit the operand info.
- std::vector<std::string> OperandInfo = GetOperandInfo(Inst);
- if (OperandInfo.empty())
- OS << "nullptr";
- else
- OS << "OperandInfo" << OpInfo.find(OperandInfo)->second;
+ OS << "ULL";
OS << " }, // Inst #" << Num << " = " << Inst.TheDef->getName() << "\n";
}
@@ -1245,13 +1287,12 @@ void InstrInfoEmitter::emitEnums(raw_ostream &OS) {
OS << "#endif // GET_INSTRINFO_SCHED_ENUM\n\n";
}
-namespace llvm {
-
-void EmitInstrInfo(RecordKeeper &RK, raw_ostream &OS) {
+static void EmitInstrInfo(RecordKeeper &RK, raw_ostream &OS) {
RK.startTimer("Analyze DAG patterns");
InstrInfoEmitter(RK).run(OS);
RK.startTimer("Emit map table");
EmitMapTable(RK, OS);
}
-} // end namespace llvm
+static TableGen::Emitter::Opt X("gen-instr-info", EmitInstrInfo,
+ "Generate instruction descriptions");
diff --git a/llvm/utils/TableGen/IntrinsicEmitter.cpp b/llvm/utils/TableGen/IntrinsicEmitter.cpp
index 946a58417594..09aad78536fe 100644
--- a/llvm/utils/TableGen/IntrinsicEmitter.cpp
+++ b/llvm/utils/TableGen/IntrinsicEmitter.cpp
@@ -11,16 +11,29 @@
//===----------------------------------------------------------------------===//
#include "CodeGenIntrinsics.h"
-#include "CodeGenTarget.h"
#include "SequenceToOffsetTable.h"
-#include "TableGenBackends.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ModRef.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/StringToOffsetTable.h"
#include "llvm/TableGen/TableGenBackend.h"
#include <algorithm>
+#include <array>
+#include <cassert>
+#include <map>
+#include <optional>
+#include <string>
+#include <utility>
+#include <vector>
using namespace llvm;
cl::OptionCategory GenIntrinsicCat("Options for -gen-intrinsic-enums");
@@ -39,6 +52,8 @@ public:
void run(raw_ostream &OS, bool Enums);
void EmitEnumInfo(const CodeGenIntrinsicTable &Ints, raw_ostream &OS);
+ void EmitArgKind(raw_ostream &OS);
+ void EmitIITInfo(raw_ostream &OS);
void EmitTargetInfo(const CodeGenIntrinsicTable &Ints, raw_ostream &OS);
void EmitIntrinsicToNameTable(const CodeGenIntrinsicTable &Ints,
raw_ostream &OS);
@@ -63,7 +78,13 @@ void IntrinsicEmitter::run(raw_ostream &OS, bool Enums) {
if (Enums) {
// Emit the enum information.
EmitEnumInfo(Ints, OS);
+
+ // Emit ArgKind for Intrinsics.h.
+ EmitArgKind(OS);
} else {
+ // Emit IIT_Info constants.
+ EmitIITInfo(OS);
+
// Emit the target metadata.
EmitTargetInfo(Ints, OS);
@@ -110,7 +131,9 @@ void IntrinsicEmitter::EmitEnumInfo(const CodeGenIntrinsicTable &Ints,
}
// Generate a complete header for target specific intrinsics.
- if (!IntrinsicPrefix.empty()) {
+ if (IntrinsicPrefix.empty()) {
+ OS << "#ifdef GET_INTRINSIC_ENUM_VALUES\n";
+ } else {
std::string UpperPrefix = StringRef(IntrinsicPrefix).upper();
OS << "#ifndef LLVM_IR_INTRINSIC_" << UpperPrefix << "_ENUMS_H\n";
OS << "#define LLVM_IR_INTRINSIC_" << UpperPrefix << "_ENUMS_H\n\n";
@@ -137,6 +160,7 @@ void IntrinsicEmitter::EmitEnumInfo(const CodeGenIntrinsicTable &Ints,
// Emit num_intrinsics into the target neutral enum.
if (IntrinsicPrefix.empty()) {
OS << " num_intrinsics = " << (Ints.size() + 1) << "\n";
+ OS << "#endif\n\n";
} else {
OS << "}; // enum\n";
OS << "} // namespace Intrinsic\n";
@@ -145,6 +169,41 @@ void IntrinsicEmitter::EmitEnumInfo(const CodeGenIntrinsicTable &Ints,
}
}
+void IntrinsicEmitter::EmitArgKind(raw_ostream &OS) {
+ if (!IntrinsicPrefix.empty())
+ return;
+ OS << "// llvm::Intrinsic::IITDescriptor::ArgKind\n";
+ OS << "#ifdef GET_INTRINSIC_ARGKIND\n";
+ if (auto RecArgKind = Records.getDef("ArgKind")) {
+ for (auto &RV : RecArgKind->getValues())
+ OS << " AK_" << RV.getName() << " = " << *RV.getValue() << ",\n";
+ } else {
+ OS << "#error \"ArgKind is not defined\"\n";
+ }
+ OS << "#endif\n\n";
+}
+
+void IntrinsicEmitter::EmitIITInfo(raw_ostream &OS) {
+ OS << "#ifdef GET_INTRINSIC_IITINFO\n";
+ std::array<StringRef, 256> RecsByNumber;
+ auto IIT_Base = Records.getAllDerivedDefinitionsIfDefined("IIT_Base");
+ for (auto Rec : IIT_Base) {
+ auto Number = Rec->getValueAsInt("Number");
+ assert(0 <= Number && Number < (int)RecsByNumber.size() &&
+ "IIT_Info.Number should be uint8_t");
+ assert(RecsByNumber[Number].empty() && "Duplicate IIT_Info.Number");
+ RecsByNumber[Number] = Rec->getName();
+ }
+ if (IIT_Base.size() > 0) {
+ for (unsigned I = 0, E = RecsByNumber.size(); I < E; ++I)
+ if (!RecsByNumber[I].empty())
+ OS << " " << RecsByNumber[I] << " = " << I << ",\n";
+ } else {
+ OS << "#error \"class IIT_Base is not defined\"\n";
+ }
+ OS << "#endif\n\n";
+}
+
void IntrinsicEmitter::EmitTargetInfo(const CodeGenIntrinsicTable &Ints,
raw_ostream &OS) {
OS << "// Target mapping\n";
@@ -191,327 +250,16 @@ void IntrinsicEmitter::EmitIntrinsicToOverloadTable(
OS << "#endif\n\n";
}
-
-// NOTE: This must be kept in synch with the copy in lib/IR/Function.cpp!
-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,
-
- // Values from 16+ are only encodable with the inefficient encoding.
- IIT_V64 = 16,
- IIT_MMX = 17,
- IIT_TOKEN = 18,
- IIT_METADATA = 19,
- IIT_EMPTYSTRUCT = 20,
- IIT_STRUCT2 = 21,
- IIT_STRUCT3 = 22,
- IIT_STRUCT4 = 23,
- IIT_STRUCT5 = 24,
- IIT_EXTEND_ARG = 25,
- IIT_TRUNC_ARG = 26,
- IIT_ANYPTR = 27,
- IIT_V1 = 28,
- IIT_VARARG = 29,
- IIT_HALF_VEC_ARG = 30,
- IIT_SAME_VEC_WIDTH_ARG = 31,
- IIT_PTR_TO_ARG = 32,
- IIT_PTR_TO_ELT = 33,
- IIT_VEC_OF_ANYPTRS_TO_ELT = 34,
- IIT_I128 = 35,
- IIT_V512 = 36,
- IIT_V1024 = 37,
- IIT_STRUCT6 = 38,
- IIT_STRUCT7 = 39,
- IIT_STRUCT8 = 40,
- IIT_F128 = 41,
- IIT_VEC_ELEMENT = 42,
- IIT_SCALABLE_VEC = 43,
- IIT_SUBDIVIDE2_ARG = 44,
- IIT_SUBDIVIDE4_ARG = 45,
- IIT_VEC_OF_BITCASTS_TO_INT = 46,
- IIT_V128 = 47,
- IIT_BF16 = 48,
- IIT_STRUCT9 = 49,
- IIT_V256 = 50,
- IIT_AMX = 51,
- IIT_PPCF128 = 52,
- IIT_V3 = 53,
- IIT_EXTERNREF = 54,
- 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);
- case 64: return Sig.push_back(IIT_I64);
- case 128: return Sig.push_back(IIT_I128);
- }
- }
-
- switch (VT) {
- default: PrintFatalError("unhandled MVT in intrinsic!");
- case MVT::f16: return Sig.push_back(IIT_F16);
- case MVT::bf16: return Sig.push_back(IIT_BF16);
- case MVT::f32: return Sig.push_back(IIT_F32);
- case MVT::f64: return Sig.push_back(IIT_F64);
- case MVT::f128: return Sig.push_back(IIT_F128);
- case MVT::ppcf128: return Sig.push_back(IIT_PPCF128);
- case MVT::token: return Sig.push_back(IIT_TOKEN);
- case MVT::Metadata: return Sig.push_back(IIT_METADATA);
- case MVT::x86mmx: return Sig.push_back(IIT_MMX);
- case MVT::x86amx: return Sig.push_back(IIT_AMX);
- // MVT::OtherVT is used to mean the empty struct type here.
- case MVT::Other: return Sig.push_back(IIT_EMPTYSTRUCT);
- // MVT::isVoid is used to represent varargs here.
- case MVT::isVoid: return Sig.push_back(IIT_VARARG);
- case MVT::externref:
- return Sig.push_back(IIT_EXTERNREF);
- case MVT::funcref:
- return Sig.push_back(IIT_FUNCREF);
- }
- // clang-format on
-}
-
-#if defined(_MSC_VER) && !defined(__clang__)
-#pragma optimize("",off) // MSVC 2015 optimizer can't deal with this function.
-#endif
-
-static void EncodeFixedType(Record *R, std::vector<unsigned char> &ArgCodes,
- unsigned &NextArgCode,
- std::vector<unsigned char> &Sig,
- ArrayRef<unsigned char> Mapping) {
-
- if (R->isSubClassOf("LLVMMatchType")) {
- unsigned Number = Mapping[R->getValueAsInt("Number")];
- assert(Number < ArgCodes.size() && "Invalid matching number!");
- if (R->isSubClassOf("LLVMExtendedType"))
- Sig.push_back(IIT_EXTEND_ARG);
- else if (R->isSubClassOf("LLVMTruncatedType"))
- Sig.push_back(IIT_TRUNC_ARG);
- else if (R->isSubClassOf("LLVMHalfElementsVectorType"))
- Sig.push_back(IIT_HALF_VEC_ARG);
- else if (R->isSubClassOf("LLVMScalarOrSameVectorWidth")) {
- Sig.push_back(IIT_SAME_VEC_WIDTH_ARG);
- Sig.push_back((Number << 3) | ArgCodes[Number]);
- MVT::SimpleValueType VT = getValueType(R->getValueAsDef("ElTy"));
- EncodeFixedValueType(VT, Sig);
- return;
- }
- else if (R->isSubClassOf("LLVMPointerTo"))
- Sig.push_back(IIT_PTR_TO_ARG);
- else if (R->isSubClassOf("LLVMVectorOfAnyPointersToElt")) {
- Sig.push_back(IIT_VEC_OF_ANYPTRS_TO_ELT);
- // Encode overloaded ArgNo
- Sig.push_back(NextArgCode++);
- // 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"))
- Sig.push_back(IIT_VEC_ELEMENT);
- else if (R->isSubClassOf("LLVMSubdivide2VectorType"))
- Sig.push_back(IIT_SUBDIVIDE2_ARG);
- else if (R->isSubClassOf("LLVMSubdivide4VectorType"))
- Sig.push_back(IIT_SUBDIVIDE4_ARG);
- else if (R->isSubClassOf("LLVMVectorOfBitcastsToInt"))
- Sig.push_back(IIT_VEC_OF_BITCASTS_TO_INT);
- else
- Sig.push_back(IIT_ARG);
- return Sig.push_back((Number << 3) | 7 /*IITDescriptor::AK_MatchType*/);
- }
-
- MVT::SimpleValueType VT = getValueType(R->getValueAsDef("VT"));
-
- unsigned Tmp = 0;
- switch (VT) {
- default: break;
- case MVT::iPTRAny: ++Tmp; [[fallthrough]];
- case MVT::vAny: ++Tmp; [[fallthrough]];
- case MVT::fAny: ++Tmp; [[fallthrough]];
- case MVT::iAny: ++Tmp; [[fallthrough]];
- case MVT::Any: {
- // If this is an "any" valuetype, then the type is the type of the next
- // type in the list specified to getIntrinsic().
- Sig.push_back(IIT_ARG);
-
- // Figure out what arg # this is consuming, and remember what kind it was.
- assert(NextArgCode < ArgCodes.size() && ArgCodes[NextArgCode] == Tmp &&
- "Invalid or no ArgCode associated with overloaded VT!");
- unsigned ArgNo = NextArgCode++;
-
- // Encode what sort of argument it must be in the low 3 bits of the ArgNo.
- return Sig.push_back((ArgNo << 3) | Tmp);
- }
-
- case MVT::iPTR: {
- unsigned AddrSpace = 0;
- if (R->isSubClassOf("LLVMQualPointerType")) {
- AddrSpace = R->getValueAsInt("AddrSpace");
- assert(AddrSpace < 256 && "Address space exceeds 255");
- }
- if (AddrSpace) {
- Sig.push_back(IIT_ANYPTR);
- Sig.push_back(AddrSpace);
- } else {
- Sig.push_back(IIT_PTR);
- }
- return EncodeFixedType(R->getValueAsDef("ElTy"), ArgCodes, NextArgCode, Sig,
- Mapping);
- }
- }
-
- if (MVT(VT).isVector()) {
- MVT VVT = VT;
- if (VVT.isScalableVector())
- Sig.push_back(IIT_SCALABLE_VEC);
- switch (VVT.getVectorMinNumElements()) {
- default: PrintFatalError("unhandled vector type width in intrinsic!");
- case 1: Sig.push_back(IIT_V1); break;
- case 2: Sig.push_back(IIT_V2); break;
- case 3: Sig.push_back(IIT_V3); break;
- case 4: Sig.push_back(IIT_V4); break;
- case 8: Sig.push_back(IIT_V8); break;
- case 16: Sig.push_back(IIT_V16); break;
- case 32: Sig.push_back(IIT_V32); break;
- case 64: Sig.push_back(IIT_V64); break;
- case 128: Sig.push_back(IIT_V128); break;
- case 256: Sig.push_back(IIT_V256); break;
- case 512: Sig.push_back(IIT_V512); break;
- case 1024: Sig.push_back(IIT_V1024); break;
- }
-
- return EncodeFixedValueType(VVT.getVectorElementType().SimpleTy, Sig);
- }
-
- EncodeFixedValueType(VT, Sig);
-}
-
-static void UpdateArgCodes(Record *R, std::vector<unsigned char> &ArgCodes,
- unsigned int &NumInserted,
- SmallVectorImpl<unsigned char> &Mapping) {
- if (R->isSubClassOf("LLVMMatchType")) {
- if (R->isSubClassOf("LLVMVectorOfAnyPointersToElt")) {
- ArgCodes.push_back(3 /*vAny*/);
- ++NumInserted;
- } else if (R->isSubClassOf("LLVMAnyPointerToElt")) {
- ArgCodes.push_back(4 /*iPTRAny*/);
- ++NumInserted;
- }
- return;
- }
-
- unsigned Tmp = 0;
- switch (getValueType(R->getValueAsDef("VT"))) {
- default: break;
- case MVT::iPTR:
- UpdateArgCodes(R->getValueAsDef("ElTy"), ArgCodes, NumInserted, Mapping);
- break;
- case MVT::iPTRAny:
- ++Tmp;
- [[fallthrough]];
- case MVT::vAny:
- ++Tmp;
- [[fallthrough]];
- case MVT::fAny:
- ++Tmp;
- [[fallthrough]];
- case MVT::iAny:
- ++Tmp;
- [[fallthrough]];
- case MVT::Any:
- unsigned OriginalIdx = ArgCodes.size() - NumInserted;
- assert(OriginalIdx >= Mapping.size());
- Mapping.resize(OriginalIdx+1);
- Mapping[OriginalIdx] = ArgCodes.size();
- ArgCodes.push_back(Tmp);
- break;
- }
-}
-
-#if defined(_MSC_VER) && !defined(__clang__)
-#pragma optimize("",on)
-#endif
-
/// ComputeFixedEncoding - If we can encode the type signature for this
/// intrinsic into 32 bits, return it. If not, return ~0U.
static void ComputeFixedEncoding(const CodeGenIntrinsic &Int,
std::vector<unsigned char> &TypeSig) {
- std::vector<unsigned char> ArgCodes;
-
- // Add codes for any overloaded result VTs.
- unsigned int NumInserted = 0;
- SmallVector<unsigned char, 8> ArgMapping;
- for (unsigned i = 0, e = Int.IS.RetVTs.size(); i != e; ++i)
- UpdateArgCodes(Int.IS.RetTypeDefs[i], ArgCodes, NumInserted, ArgMapping);
-
- // Add codes for any overloaded operand VTs.
- for (unsigned i = 0, e = Int.IS.ParamTypeDefs.size(); i != e; ++i)
- UpdateArgCodes(Int.IS.ParamTypeDefs[i], ArgCodes, NumInserted, ArgMapping);
-
- unsigned NextArgCode = 0;
- if (Int.IS.RetVTs.empty())
- TypeSig.push_back(IIT_Done);
- else if (Int.IS.RetVTs.size() == 1 &&
- Int.IS.RetVTs[0] == MVT::isVoid)
- TypeSig.push_back(IIT_Done);
- else {
- switch (Int.IS.RetVTs.size()) {
- case 1: break;
- case 2: TypeSig.push_back(IIT_STRUCT2); break;
- case 3: TypeSig.push_back(IIT_STRUCT3); break;
- case 4: TypeSig.push_back(IIT_STRUCT4); break;
- case 5: TypeSig.push_back(IIT_STRUCT5); break;
- case 6: TypeSig.push_back(IIT_STRUCT6); break;
- case 7: TypeSig.push_back(IIT_STRUCT7); break;
- case 8: TypeSig.push_back(IIT_STRUCT8); break;
- case 9: TypeSig.push_back(IIT_STRUCT9); break;
- default: llvm_unreachable("Unhandled case in struct");
+ if (auto *R = Int.TheDef->getValue("TypeSig")) {
+ for (auto &a : cast<ListInit>(R->getValue())->getValues()) {
+ for (auto &b : cast<ListInit>(a)->getValues())
+ TypeSig.push_back(cast<IntInit>(b)->getValue());
}
-
- for (unsigned i = 0, e = Int.IS.RetVTs.size(); i != e; ++i)
- EncodeFixedType(Int.IS.RetTypeDefs[i], ArgCodes, NextArgCode, TypeSig,
- ArgMapping);
}
-
- for (unsigned i = 0, e = Int.IS.ParamTypeDefs.size(); i != e; ++i)
- EncodeFixedType(Int.IS.ParamTypeDefs[i], ArgCodes, NextArgCode, TypeSig,
- ArgMapping);
}
static void printIITEntry(raw_ostream &OS, unsigned char X) {
@@ -640,6 +388,9 @@ std::optional<bool> compareFnAttributes(const CodeGenIntrinsic *L,
if (L->hasSideEffects != R->hasSideEffects)
return R->hasSideEffects;
+ if (L->isStrictFP != R->isStrictFP)
+ return R->isStrictFP;
+
// Try to order by readonly/readnone attribute.
uint32_t LK = L->ME.toIntValue();
uint32_t RK = R->ME.toIntValue();
@@ -726,6 +477,10 @@ void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints,
OS << " Attribute::get(C, Attribute::Alignment, "
<< Attr.Value << "),\n";
break;
+ case CodeGenIntrinsic::Dereferenceable:
+ OS << " Attribute::get(C, Attribute::Dereferenceable, "
+ << Attr.Value << "),\n";
+ break;
}
}
OS << " });\n";
@@ -770,6 +525,8 @@ void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints,
OS << " Attribute::get(C, Attribute::Convergent),\n";
if (Intrinsic.isSpeculatable)
OS << " Attribute::get(C, Attribute::Speculatable),\n";
+ if (Intrinsic.isStrictFP)
+ OS << " Attribute::get(C, Attribute::StrictFP),\n";
MemoryEffects ME = Intrinsic.ME;
// TODO: IntrHasSideEffects should affect not only readnone intrinsics.
@@ -842,7 +599,8 @@ void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints,
Intrinsic.isNoReturn || Intrinsic.isNoCallback || Intrinsic.isNoSync ||
Intrinsic.isNoFree || Intrinsic.isWillReturn || Intrinsic.isCold ||
Intrinsic.isNoDuplicate || Intrinsic.isNoMerge ||
- Intrinsic.isConvergent || Intrinsic.isSpeculatable) {
+ Intrinsic.isConvergent || Intrinsic.isSpeculatable ||
+ Intrinsic.isStrictFP) {
unsigned ID = UniqFnAttributes.find(&Intrinsic)->second;
OS << " AS[" << numAttrs++ << "] = {AttributeList::FunctionIndex, "
<< "getIntrinsicFnAttributeSet(C, " << ID << ")};\n";
@@ -952,10 +710,16 @@ void IntrinsicEmitter::EmitIntrinsicToBuiltinMap(
OS << "#endif\n\n";
}
-void llvm::EmitIntrinsicEnums(RecordKeeper &RK, raw_ostream &OS) {
+static void EmitIntrinsicEnums(RecordKeeper &RK, raw_ostream &OS) {
IntrinsicEmitter(RK).run(OS, /*Enums=*/true);
}
-void llvm::EmitIntrinsicImpl(RecordKeeper &RK, raw_ostream &OS) {
+static TableGen::Emitter::Opt X("gen-intrinsic-enums", EmitIntrinsicEnums,
+ "Generate intrinsic enums");
+
+static void EmitIntrinsicImpl(RecordKeeper &RK, raw_ostream &OS) {
IntrinsicEmitter(RK).run(OS, /*Enums=*/false);
}
+
+static TableGen::Emitter::Opt Y("gen-intrinsic-impl", EmitIntrinsicImpl,
+ "Generate intrinsic information");
diff --git a/llvm/utils/TableGen/OptParserEmitter.cpp b/llvm/utils/TableGen/OptParserEmitter.cpp
index d363191bd9b8..a04680b5d91e 100644
--- a/llvm/utils/TableGen/OptParserEmitter.cpp
+++ b/llvm/utils/TableGen/OptParserEmitter.cpp
@@ -64,7 +64,7 @@ class MarshallingInfo {
public:
static constexpr const char *MacroName = "OPTION_WITH_MARSHALLING";
const Record &R;
- bool ShouldAlwaysEmit;
+ bool ShouldAlwaysEmit = false;
StringRef MacroPrefix;
StringRef KeyPath;
StringRef DefaultValue;
@@ -212,8 +212,7 @@ static MarshallingInfo createMarshallingInfo(const Record &R) {
/// OptParserEmitter - This tablegen backend takes an input .td file
/// describing a list of options and emits a data structure for parsing and
/// working with those options when given an input command line.
-namespace llvm {
-void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
+static void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
// Get the option groups and options.
const std::vector<Record*> &Groups =
Records.getAllDerivedDefinitions("OptionGroup");
@@ -499,4 +498,6 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
OS << "\n";
}
-} // end namespace llvm
+
+static TableGen::Emitter::Opt X("gen-opt-parser-defs", EmitOptParser,
+ "Generate option definitions");
diff --git a/llvm/utils/TableGen/OptRSTEmitter.cpp b/llvm/utils/TableGen/OptRSTEmitter.cpp
index 03c7326e817a..87e755d943a1 100644
--- a/llvm/utils/TableGen/OptRSTEmitter.cpp
+++ b/llvm/utils/TableGen/OptRSTEmitter.cpp
@@ -10,13 +10,13 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
using namespace llvm;
/// OptParserEmitter - This tablegen backend takes an input .td file
/// describing a list of options and emits a RST man page.
-namespace llvm {
-void EmitOptRST(RecordKeeper &Records, raw_ostream &OS) {
+static void EmitOptRST(RecordKeeper &Records, raw_ostream &OS) {
llvm::StringMap<std::vector<Record *>> OptionsByGroup;
std::vector<Record *> OptionsWithoutGroup;
@@ -102,4 +102,6 @@ void EmitOptRST(RecordKeeper &Records, raw_ostream &OS) {
}
}
}
-} // end namespace llvm
+
+static TableGen::Emitter::Opt X("gen-opt-rst", EmitOptRST,
+ "Generate option RST");
diff --git a/llvm/utils/TableGen/PredicateExpander.cpp b/llvm/utils/TableGen/PredicateExpander.cpp
index b129401461b5..8f96d3307ded 100644
--- a/llvm/utils/TableGen/PredicateExpander.cpp
+++ b/llvm/utils/TableGen/PredicateExpander.cpp
@@ -12,6 +12,7 @@
#include "PredicateExpander.h"
#include "CodeGenSchedule.h" // Definition of STIPredicateFunction.
+#include "llvm/TableGen/Record.h"
namespace llvm {
diff --git a/llvm/utils/TableGen/PseudoLoweringEmitter.cpp b/llvm/utils/TableGen/PseudoLoweringEmitter.cpp
index 6a1e1332d767..e07fb9188098 100644
--- a/llvm/utils/TableGen/PseudoLoweringEmitter.cpp
+++ b/llvm/utils/TableGen/PseudoLoweringEmitter.cpp
@@ -313,10 +313,5 @@ void PseudoLoweringEmitter::run(raw_ostream &o) {
emitLoweringEmitter(o);
}
-namespace llvm {
-
-void EmitPseudoLowering(RecordKeeper &RK, raw_ostream &OS) {
- PseudoLoweringEmitter(RK).run(OS);
-}
-
-} // End llvm namespace
+static TableGen::Emitter::OptClass<PseudoLoweringEmitter>
+ X("gen-pseudo-lowering", "Generate pseudo instruction lowering");
diff --git a/llvm/utils/TableGen/RISCVTargetDefEmitter.cpp b/llvm/utils/TableGen/RISCVTargetDefEmitter.cpp
index fa6508cbfc69..12174fd83f56 100644
--- a/llvm/utils/TableGen/RISCVTargetDefEmitter.cpp
+++ b/llvm/utils/TableGen/RISCVTargetDefEmitter.cpp
@@ -1,4 +1,4 @@
-//===- RISCVTargetDefEmitter.cpp - Generate lists of RISCV CPUs -----------===//
+//===- RISCVTargetDefEmitter.cpp - Generate lists of RISC-V CPUs ----------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -11,23 +11,23 @@
//
//===----------------------------------------------------------------------===//
-#include "TableGenBackends.h"
#include "llvm/Support/RISCVISAInfo.h"
#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
using namespace llvm;
using ISAInfoTy = llvm::Expected<std::unique_ptr<RISCVISAInfo>>;
// We can generate march string from target features as what has been described
-// in RISCV ISA specification (version 20191213) 'Chapter 27. ISA Extension
+// in RISC-V ISA specification (version 20191213) 'Chapter 27. ISA Extension
// Naming Conventions'.
//
// This is almost the same as RISCVFeatures::parseFeatureBits, except that we
// get feature name from feature records instead of feature bits.
static std::string getMArch(const Record &Rec) {
std::vector<std::string> FeatureVector;
- int XLen = 32;
+ unsigned XLen = 32;
// Convert features to FeatureVector.
for (auto *Feature : Rec.getValueAsListOfDefs("Features")) {
@@ -47,12 +47,11 @@ static std::string getMArch(const Record &Rec) {
return (*ISAInfo)->toString();
}
-void llvm::EmitRISCVTargetDef(const RecordKeeper &RK, raw_ostream &OS) {
+static void EmitRISCVTargetDef(RecordKeeper &RK, raw_ostream &OS) {
OS << "#ifndef PROC\n"
<< "#define PROC(ENUM, NAME, DEFAULT_MARCH)\n"
<< "#endif\n\n";
- OS << "PROC(INVALID, {\"invalid\"}, {\"\"})\n";
// Iterate on all definition records.
for (const Record *Rec : RK.getAllDerivedDefinitions("RISCVProcessorModel")) {
std::string MArch = Rec->getValueAsString("DefaultMarch").str();
@@ -80,3 +79,6 @@ void llvm::EmitRISCVTargetDef(const RecordKeeper &RK, raw_ostream &OS) {
OS << "\n#undef TUNE_PROC\n";
}
+
+static TableGen::Emitter::Opt X("gen-riscv-target-def", EmitRISCVTargetDef,
+ "Generate the list of CPU for RISCV");
diff --git a/llvm/utils/TableGen/RegisterBankEmitter.cpp b/llvm/utils/TableGen/RegisterBankEmitter.cpp
index e6689b211a7d..2d23bf86b6ad 100644
--- a/llvm/utils/TableGen/RegisterBankEmitter.cpp
+++ b/llvm/utils/TableGen/RegisterBankEmitter.cpp
@@ -11,15 +11,15 @@
//
//===----------------------------------------------------------------------===//
+#include "CodeGenRegisters.h"
+#include "CodeGenTarget.h"
+#include "InfoByHwMode.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/Support/Debug.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
-#include "CodeGenRegisters.h"
-#include "CodeGenTarget.h"
-
#define DEBUG_TYPE "register-bank-emitter"
using namespace llvm;
@@ -37,11 +37,11 @@ private:
RegisterClassesTy RCs;
/// The register class with the largest register size.
- const CodeGenRegisterClass *RCWithLargestRegsSize;
+ std::vector<const CodeGenRegisterClass *> RCsWithLargestRegSize;
public:
- RegisterBank(const Record &TheDef)
- : TheDef(TheDef), RCWithLargestRegsSize(nullptr) {}
+ RegisterBank(const Record &TheDef, unsigned NumModeIds)
+ : TheDef(TheDef), RCsWithLargestRegSize(NumModeIds) {}
/// Get the human-readable name for the bank.
StringRef getName() const { return TheDef.getValueAsString("Name"); }
@@ -79,18 +79,21 @@ public:
// register size anywhere (we could sum the sizes of the subregisters
// but there may be additional bits too) and we can't derive it from
// the VT's reliably due to Untyped.
- if (RCWithLargestRegsSize == nullptr)
- RCWithLargestRegsSize = RC;
- else if (RCWithLargestRegsSize->RSI.get(DefaultMode).SpillSize <
- RC->RSI.get(DefaultMode).SpillSize)
- RCWithLargestRegsSize = RC;
- assert(RCWithLargestRegsSize && "RC was nullptr?");
+ unsigned NumModeIds = RCsWithLargestRegSize.size();
+ for (unsigned M = 0; M < NumModeIds; ++M) {
+ if (RCsWithLargestRegSize[M] == nullptr)
+ RCsWithLargestRegSize[M] = RC;
+ else if (RCsWithLargestRegSize[M]->RSI.get(M).SpillSize <
+ RC->RSI.get(M).SpillSize)
+ RCsWithLargestRegSize[M] = RC;
+ assert(RCsWithLargestRegSize[M] && "RC was nullptr?");
+ }
RCs.emplace_back(RC);
}
- const CodeGenRegisterClass *getRCWithLargestRegsSize() const {
- return RCWithLargestRegsSize;
+ const CodeGenRegisterClass *getRCWithLargestRegSize(unsigned HwMode) const {
+ return RCsWithLargestRegSize[HwMode];
}
iterator_range<typename RegisterClassesTy::const_iterator>
@@ -144,9 +147,10 @@ void RegisterBankEmitter::emitBaseClassDefinition(
raw_ostream &OS, const StringRef TargetName,
const std::vector<RegisterBank> &Banks) {
OS << "private:\n"
- << " static RegisterBank *RegBanks[];\n\n"
+ << " static const RegisterBank *RegBanks[];\n"
+ << " static const unsigned Sizes[];\n\n"
<< "protected:\n"
- << " " << TargetName << "GenRegisterBankInfo();\n"
+ << " " << TargetName << "GenRegisterBankInfo(unsigned HwMode = 0);\n"
<< "\n";
}
@@ -211,6 +215,7 @@ void RegisterBankEmitter::emitBaseClassImplementation(
raw_ostream &OS, StringRef TargetName,
std::vector<RegisterBank> &Banks) {
const CodeGenRegBank &RegisterClassHierarchy = Target.getRegBank();
+ const CodeGenHwModes &CGH = Target.getHwModes();
OS << "namespace llvm {\n"
<< "namespace " << TargetName << " {\n";
@@ -241,11 +246,8 @@ void RegisterBankEmitter::emitBaseClassImplementation(
for (const auto &Bank : Banks) {
std::string QualifiedBankID =
(TargetName + "::" + Bank.getEnumeratorName()).str();
- const CodeGenRegisterClass &RC = *Bank.getRCWithLargestRegsSize();
- unsigned Size = RC.RSI.get(DefaultMode).SpillSize;
- OS << "RegisterBank " << Bank.getInstanceVarName() << "(/* ID */ "
- << QualifiedBankID << ", /* Name */ \"" << Bank.getName()
- << "\", /* Size */ " << Size << ", "
+ OS << "const RegisterBank " << Bank.getInstanceVarName() << "(/* ID */ "
+ << QualifiedBankID << ", /* Name */ \"" << Bank.getName() << "\", "
<< "/* CoveredRegClasses */ " << Bank.getCoverageArrayName()
<< ", /* NumRegClasses */ "
<< RegisterClassHierarchy.getRegClasses().size() << ");\n";
@@ -253,16 +255,33 @@ void RegisterBankEmitter::emitBaseClassImplementation(
OS << "} // end namespace " << TargetName << "\n"
<< "\n";
- OS << "RegisterBank *" << TargetName
+ OS << "const RegisterBank *" << TargetName
<< "GenRegisterBankInfo::RegBanks[] = {\n";
for (const auto &Bank : Banks)
OS << " &" << TargetName << "::" << Bank.getInstanceVarName() << ",\n";
OS << "};\n\n";
+ unsigned NumModeIds = CGH.getNumModeIds();
+ OS << "const unsigned " << TargetName << "GenRegisterBankInfo::Sizes[] = {\n";
+ for (unsigned M = 0; M < NumModeIds; ++M) {
+ OS << " // Mode = " << M << " (";
+ if (M == DefaultMode)
+ OS << "Default";
+ else
+ OS << CGH.getMode(M).Name;
+ OS << ")\n";
+ for (const auto &Bank : Banks) {
+ const CodeGenRegisterClass &RC = *Bank.getRCWithLargestRegSize(M);
+ unsigned Size = RC.RSI.get(M).SpillSize;
+ OS << " " << Size << ",\n";
+ }
+ }
+ OS << "};\n\n";
+
OS << TargetName << "GenRegisterBankInfo::" << TargetName
- << "GenRegisterBankInfo()\n"
+ << "GenRegisterBankInfo(unsigned HwMode)\n"
<< " : RegisterBankInfo(RegBanks, " << TargetName
- << "::NumRegisterBanks) {\n"
+ << "::NumRegisterBanks, Sizes, HwMode) {\n"
<< " // Assert that RegBank indices match their ID's\n"
<< "#ifndef NDEBUG\n"
<< " for (auto RB : enumerate(RegBanks))\n"
@@ -275,12 +294,13 @@ void RegisterBankEmitter::emitBaseClassImplementation(
void RegisterBankEmitter::run(raw_ostream &OS) {
StringRef TargetName = Target.getName();
const CodeGenRegBank &RegisterClassHierarchy = Target.getRegBank();
+ const CodeGenHwModes &CGH = Target.getHwModes();
Records.startTimer("Analyze records");
std::vector<RegisterBank> Banks;
for (const auto &V : Records.getAllDerivedDefinitions("RegisterBank")) {
SmallPtrSet<const CodeGenRegisterClass *, 8> VisitedRCs;
- RegisterBank Bank(*V);
+ RegisterBank Bank(*V, CGH.getNumModeIds());
for (const CodeGenRegisterClass *RC :
Bank.getExplicitlySpecifiedRegisterClasses(RegisterClassHierarchy)) {
@@ -327,10 +347,5 @@ void RegisterBankEmitter::run(raw_ostream &OS) {
OS << "#endif // GET_TARGET_REGBANK_IMPL\n";
}
-namespace llvm {
-
-void EmitRegisterBank(RecordKeeper &RK, raw_ostream &OS) {
- RegisterBankEmitter(RK).run(OS);
-}
-
-} // end namespace llvm
+static TableGen::Emitter::OptClass<RegisterBankEmitter>
+ X("gen-register-bank", "Generate registers bank descriptions");
diff --git a/llvm/utils/TableGen/RegisterInfoEmitter.cpp b/llvm/utils/TableGen/RegisterInfoEmitter.cpp
index 113cebf8a08e..3101081114fb 100644
--- a/llvm/utils/TableGen/RegisterInfoEmitter.cpp
+++ b/llvm/utils/TableGen/RegisterInfoEmitter.cpp
@@ -12,8 +12,10 @@
//
//===----------------------------------------------------------------------===//
+#include "CodeGenHwModes.h"
#include "CodeGenRegisters.h"
#include "CodeGenTarget.h"
+#include "InfoByHwMode.h"
#include "SequenceToOffsetTable.h"
#include "Types.h"
#include "llvm/ADT/ArrayRef.h"
@@ -23,10 +25,10 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/SparseBitVector.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/CodeGen/MachineValueType.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Format.h"
-#include "llvm/Support/MachineValueType.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
@@ -633,17 +635,16 @@ static void printSubRegIndex(raw_ostream &OS, const CodeGenSubRegIndex *Idx) {
// The initial value depends on the specific list. The list is terminated by a
// 0 differential which means we can't encode repeated elements.
-typedef SmallVector<uint16_t, 4> DiffVec;
+typedef SmallVector<int16_t, 4> DiffVec;
typedef SmallVector<LaneBitmask, 4> MaskVec;
-// Differentially encode a sequence of numbers into V. The starting value and
-// terminating 0 are not added to V, so it will have the same size as List.
-static
-DiffVec &diffEncode(DiffVec &V, unsigned InitVal, SparseBitVector<> List) {
+// Fills V with differentials between every two consecutive elements of List.
+static DiffVec &diffEncode(DiffVec &V, SparseBitVector<> List) {
assert(V.empty() && "Clear DiffVec before diffEncode.");
- uint16_t Val = uint16_t(InitVal);
-
- for (uint16_t Cur : List) {
+ SparseBitVector<>::iterator I = List.begin(), E = List.end();
+ unsigned Val = *I;
+ while (++I != E) {
+ unsigned Cur = *I;
V.push_back(Cur - Val);
Val = Cur;
}
@@ -654,18 +655,16 @@ template<typename Iter>
static
DiffVec &diffEncode(DiffVec &V, unsigned InitVal, Iter Begin, Iter End) {
assert(V.empty() && "Clear DiffVec before diffEncode.");
- uint16_t Val = uint16_t(InitVal);
+ unsigned Val = InitVal;
for (Iter I = Begin; I != End; ++I) {
- uint16_t Cur = (*I)->EnumValue;
+ unsigned Cur = (*I)->EnumValue;
V.push_back(Cur - Val);
Val = Cur;
}
return V;
}
-static void printDiff16(raw_ostream &OS, uint16_t Val) {
- OS << Val;
-}
+static void printDiff16(raw_ostream &OS, int16_t Val) { OS << Val; }
static void printMask(raw_ostream &OS, LaneBitmask Val) {
OS << "LaneBitmask(0x" << PrintLaneMask(Val) << ')';
@@ -889,7 +888,6 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,
SmallVector<DiffVec, 4> SubRegLists(Regs.size());
SmallVector<DiffVec, 4> SuperRegLists(Regs.size());
SmallVector<DiffVec, 4> RegUnitLists(Regs.size());
- SmallVector<unsigned, 4> RegUnitInitScale(Regs.size());
// List of lane masks accompanying register unit sequences.
SequenceToOffsetTable<MaskVec> LaneMaskSeqs;
@@ -927,31 +925,8 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,
SuperRegList.end());
DiffSeqs.add(SuperRegLists[i]);
- // Differentially encode the register unit list, seeded by register number.
- // First compute a scale factor that allows more diff-lists to be reused:
- //
- // D0 -> (S0, S1)
- // D1 -> (S2, S3)
- //
- // A scale factor of 2 allows D0 and D1 to share a diff-list. The initial
- // value for the differential decoder is the register number multiplied by
- // the scale.
- //
- // Check the neighboring registers for arithmetic progressions.
- unsigned ScaleA = ~0u, ScaleB = ~0u;
- SparseBitVector<> RUs = Reg.getNativeRegUnits();
- if (I != Regs.begin() &&
- std::prev(I)->getNativeRegUnits().count() == RUs.count())
- ScaleB = *RUs.begin() - *std::prev(I)->getNativeRegUnits().begin();
- if (std::next(I) != Regs.end() &&
- std::next(I)->getNativeRegUnits().count() == RUs.count())
- ScaleA = *std::next(I)->getNativeRegUnits().begin() - *RUs.begin();
- unsigned Scale = std::min(ScaleB, ScaleA);
- // Default the scale to 0 if it can't be encoded in 4 bits.
- if (Scale >= 16)
- Scale = 0;
- RegUnitInitScale[i] = Scale;
- DiffSeqs.add(diffEncode(RegUnitLists[i], Scale * Reg.EnumValue, RUs));
+ const SparseBitVector<> &RUs = Reg.getNativeRegUnits();
+ DiffSeqs.add(diffEncode(RegUnitLists[i], RUs));
const auto &RUMasks = Reg.getRegUnitLaneMasks();
MaskVec &LaneMaskVec = RegUnitLaneMasks[i];
@@ -976,7 +951,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,
const std::string &TargetName = std::string(Target.getName());
// Emit the shared table of differential lists.
- OS << "extern const MCPhysReg " << TargetName << "RegDiffLists[] = {\n";
+ OS << "extern const int16_t " << TargetName << "RegDiffLists[] = {\n";
DiffSeqs.emit(OS, printDiff16);
OS << "};\n\n";
@@ -1012,10 +987,16 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,
// Emit the register descriptors now.
i = 0;
for (const auto &Reg : Regs) {
+ unsigned FirstRU = Reg.getNativeRegUnits().find_first();
+ unsigned Offset = DiffSeqs.get(RegUnitLists[i]);
+ // The value must be kept in sync with MCRegisterInfo.h.
+ constexpr unsigned RegUnitBits = 12;
+ assert(isUInt<RegUnitBits>(FirstRU) && "Too many regunits");
+ assert(isUInt<32 - RegUnitBits>(Offset) && "Offset is too big");
OS << " { " << RegStrings.get(std::string(Reg.getName())) << ", "
<< DiffSeqs.get(SubRegLists[i]) << ", " << DiffSeqs.get(SuperRegLists[i])
<< ", " << SubRegIdxSeqs.get(SubRegIdxLists[i]) << ", "
- << (DiffSeqs.get(RegUnitLists[i]) * 16 + RegUnitInitScale[i]) << ", "
+ << (Offset << RegUnitBits | FirstRU) << ", "
<< LaneMaskSeqs.get(RegUnitLaneMasks[i]) << " },\n";
++i;
}
@@ -1261,7 +1242,8 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
for (const auto &RC : RegisterClasses) {
std::vector<MVT::SimpleValueType> S;
for (const ValueTypeByHwMode &VVT : RC.VTs)
- S.push_back(VVT.get(M).SimpleTy);
+ if (VVT.hasDefault() || VVT.hasMode(M))
+ S.push_back(VVT.get(M).SimpleTy);
VTSeqs.add(S);
}
}
@@ -1311,7 +1293,8 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
<< RI.SpillAlignment;
std::vector<MVT::SimpleValueType> VTs;
for (const ValueTypeByHwMode &VVT : RC.VTs)
- VTs.push_back(VVT.get(M).SimpleTy);
+ if (VVT.hasDefault() || VVT.hasMode(M))
+ VTs.push_back(VVT.get(M).SimpleTy);
OS << ", VTLists+" << VTSeqs.get(VTs) << " }, // "
<< RC.getName() << '\n';
}
@@ -1649,7 +1632,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
// Emit the constructor of the class...
OS << "extern const MCRegisterDesc " << TargetName << "RegDesc[];\n";
- OS << "extern const MCPhysReg " << TargetName << "RegDiffLists[];\n";
+ OS << "extern const int16_t " << TargetName << "RegDiffLists[];\n";
OS << "extern const LaneBitmask " << TargetName << "LaneMaskLists[];\n";
OS << "extern const char " << TargetName << "RegStrings[];\n";
OS << "extern const char " << TargetName << "RegClassStrings[];\n";
@@ -1906,10 +1889,5 @@ void RegisterInfoEmitter::debugDump(raw_ostream &OS) {
}
}
-namespace llvm {
-
-void EmitRegisterInfo(RecordKeeper &RK, raw_ostream &OS) {
- RegisterInfoEmitter(RK).run(OS);
-}
-
-} // end namespace llvm
+static TableGen::Emitter::OptClass<RegisterInfoEmitter>
+ X("gen-register-info", "Generate registers and register classes info");
diff --git a/llvm/utils/TableGen/SearchableTableEmitter.cpp b/llvm/utils/TableGen/SearchableTableEmitter.cpp
index c88a2db55502..b6af02c28a80 100644
--- a/llvm/utils/TableGen/SearchableTableEmitter.cpp
+++ b/llvm/utils/TableGen/SearchableTableEmitter.cpp
@@ -19,6 +19,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
#include <algorithm>
#include <set>
#include <string>
@@ -173,6 +174,8 @@ private:
"' lookup method '" + Index.Name +
"', key field '" + Field.Name +
"' of type bits is too large");
+ } else if (isa<BitRecTy>(Field.RecType)) {
+ return "bool";
} else if (Field.Enum || Field.IsIntrinsic || Field.IsInstruction)
return "unsigned";
PrintFatalError(Index.Loc,
@@ -822,10 +825,5 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
OS << "#undef " << Guard << "\n";
}
-namespace llvm {
-
-void EmitSearchableTables(RecordKeeper &RK, raw_ostream &OS) {
- SearchableTableEmitter(RK).run(OS);
-}
-
-} // End llvm namespace.
+static TableGen::Emitter::OptClass<SearchableTableEmitter>
+ X("gen-searchable-tables", "Generate generic binary-searchable table");
diff --git a/llvm/utils/TableGen/SubtargetEmitter.cpp b/llvm/utils/TableGen/SubtargetEmitter.cpp
index 8afe6d37d0e0..e4eb23649e96 100644
--- a/llvm/utils/TableGen/SubtargetEmitter.cpp
+++ b/llvm/utils/TableGen/SubtargetEmitter.cpp
@@ -10,22 +10,23 @@
//
//===----------------------------------------------------------------------===//
+#include "CodeGenHwModes.h"
#include "CodeGenSchedule.h"
#include "CodeGenTarget.h"
#include "PredicateExpander.h"
-#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/MC/MCInstrItineraries.h"
#include "llvm/MC/MCSchedule.h"
-#include "llvm/MC/SubtargetFeature.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 "llvm/TargetParser/SubtargetFeature.h"
#include <algorithm>
#include <cassert>
#include <cstdint>
@@ -40,6 +41,15 @@ using namespace llvm;
namespace {
+/// Sorting predicate to sort record pointers by their
+/// FieldName field.
+struct LessRecordFieldFieldName {
+ bool operator()(const Record *Rec1, const Record *Rec2) const {
+ return Rec1->getValueAsString("FieldName") <
+ Rec2->getValueAsString("FieldName");
+ }
+};
+
class SubtargetEmitter {
// Each processor has a SchedClassDesc table with an entry for each SchedClass.
// The SchedClassDesc table indexes into a global write resource table, write
@@ -68,7 +78,7 @@ class SubtargetEmitter {
}
};
- const CodeGenTarget &TGT;
+ CodeGenTarget TGT;
RecordKeeper &Records;
CodeGenSchedModels &SchedModels;
std::string Target;
@@ -110,6 +120,7 @@ class SubtargetEmitter {
Record *FindReadAdvance(const CodeGenSchedRW &SchedRead,
const CodeGenProcModel &ProcModel);
void ExpandProcResources(RecVec &PRVec, std::vector<int64_t> &Cycles,
+ std::vector<int64_t> &StartAtCycles,
const CodeGenProcModel &ProcModel);
void GenSchedClassTables(const CodeGenProcModel &ProcModel,
SchedClassTables &SchedTables);
@@ -126,8 +137,8 @@ class SubtargetEmitter {
void ParseFeaturesFunction(raw_ostream &OS);
public:
- SubtargetEmitter(RecordKeeper &R, CodeGenTarget &TGT)
- : TGT(TGT), Records(R), SchedModels(TGT.getSchedModels()),
+ SubtargetEmitter(RecordKeeper &R)
+ : TGT(R), Records(R), SchedModels(TGT.getSchedModels()),
Target(TGT.getName()) {}
void run(raw_ostream &o);
@@ -200,15 +211,15 @@ void SubtargetEmitter::EmitSubtargetInfoMacroCalls(raw_ostream &OS) {
std::vector<Record *> FeatureList =
Records.getAllDerivedDefinitions("SubtargetFeature");
- llvm::sort(FeatureList, LessRecordFieldName());
+ llvm::sort(FeatureList, LessRecordFieldFieldName());
for (const Record *Feature : FeatureList) {
- const StringRef Attribute = Feature->getValueAsString("Attribute");
+ const StringRef FieldName = Feature->getValueAsString("FieldName");
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('[');
+ !StringRef(FieldName).contains('[');
if (!IsBool)
continue;
@@ -217,9 +228,9 @@ void SubtargetEmitter::EmitSubtargetInfoMacroCalls(raw_ostream &OS) {
// Define the getter with lowercased first char: xxxYyy() { return XxxYyy; }
const std::string Getter =
- Attribute.substr(0, 1).lower() + Attribute.substr(1).str();
+ FieldName.substr(0, 1).lower() + FieldName.substr(1).str();
- OS << "GET_SUBTARGETINFO_MACRO(" << Attribute << ", " << Default << ", "
+ OS << "GET_SUBTARGETINFO_MACRO(" << FieldName << ", " << Default << ", "
<< Getter << ")\n";
}
OS << "#undef GET_SUBTARGETINFO_MACRO\n";
@@ -967,6 +978,7 @@ Record *SubtargetEmitter::FindReadAdvance(const CodeGenSchedRW &SchedRead,
// resource groups and super resources that cover them.
void SubtargetEmitter::ExpandProcResources(RecVec &PRVec,
std::vector<int64_t> &Cycles,
+ std::vector<int64_t> &StartAtCycles,
const CodeGenProcModel &PM) {
assert(PRVec.size() == Cycles.size() && "failed precondition");
for (unsigned i = 0, e = PRVec.size(); i != e; ++i) {
@@ -989,6 +1001,7 @@ void SubtargetEmitter::ExpandProcResources(RecVec &PRVec,
SubDef->getLoc());
PRVec.push_back(SuperDef);
Cycles.push_back(Cycles[i]);
+ StartAtCycles.push_back(StartAtCycles[i]);
SubDef = SuperDef;
}
}
@@ -1005,6 +1018,7 @@ void SubtargetEmitter::ExpandProcResources(RecVec &PRVec,
if (SubI == SubE) {
PRVec.push_back(PR);
Cycles.push_back(Cycles[i]);
+ StartAtCycles.push_back(StartAtCycles[i]);
}
}
}
@@ -1139,22 +1153,48 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
std::vector<int64_t> Cycles =
WriteRes->getValueAsListOfInts("ResourceCycles");
- if (Cycles.empty()) {
- // If ResourceCycles is not provided, default to one cycle per
- // resource.
- Cycles.resize(PRVec.size(), 1);
- } else if (Cycles.size() != PRVec.size()) {
+ std::vector<int64_t> StartAtCycles =
+ WriteRes->getValueAsListOfInts("StartAtCycles");
+
+ // Check consistency of the two vectors carrying the start and
+ // stop cycles of the resources.
+ if (!Cycles.empty() && Cycles.size() != PRVec.size()) {
// If ResourceCycles is provided, check consistency.
PrintFatalError(
WriteRes->getLoc(),
- Twine("Inconsistent resource cycles: !size(ResourceCycles) != "
- "!size(ProcResources): ")
+ Twine("Inconsistent resource cycles: size(ResourceCycles) != "
+ "size(ProcResources): ")
.concat(Twine(PRVec.size()))
.concat(" vs ")
.concat(Twine(Cycles.size())));
}
- ExpandProcResources(PRVec, Cycles, ProcModel);
+ if (!StartAtCycles.empty() && StartAtCycles.size() != PRVec.size()) {
+ PrintFatalError(
+ WriteRes->getLoc(),
+ Twine("Inconsistent resource cycles: size(StartAtCycles) != "
+ "size(ProcResources): ")
+ .concat(Twine(StartAtCycles.size()))
+ .concat(" vs ")
+ .concat(Twine(PRVec.size())));
+ }
+
+ if (Cycles.empty()) {
+ // If ResourceCycles is not provided, default to one cycle
+ // per resource.
+ Cycles.resize(PRVec.size(), 1);
+ }
+
+ if (StartAtCycles.empty()) {
+ // If StartAtCycles is not provided, reserve the resource
+ // starting from cycle 0.
+ StartAtCycles.resize(PRVec.size(), 0);
+ }
+
+ assert(StartAtCycles.size() == Cycles.size());
+
+ ExpandProcResources(PRVec, Cycles, StartAtCycles, ProcModel);
+ assert(StartAtCycles.size() == Cycles.size());
for (unsigned PRIdx = 0, PREnd = PRVec.size();
PRIdx != PREnd; ++PRIdx) {
@@ -1162,6 +1202,17 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
WPREntry.ProcResourceIdx = ProcModel.getProcResourceIdx(PRVec[PRIdx]);
assert(WPREntry.ProcResourceIdx && "Bad ProcResourceIdx");
WPREntry.Cycles = Cycles[PRIdx];
+ WPREntry.StartAtCycle = StartAtCycles[PRIdx];
+ if (StartAtCycles[PRIdx] > Cycles[PRIdx]) {
+ PrintFatalError(WriteRes->getLoc(),
+ Twine("Inconsistent resource cycles: StartAtCycles "
+ "< Cycles must hold."));
+ }
+ if (StartAtCycles[PRIdx] < 0) {
+ PrintFatalError(WriteRes->getLoc(),
+ Twine("Invalid value: StartAtCycle "
+ "must be a non-negative value."));
+ }
// If this resource is already used in this sequence, add the current
// entry's cycles so that the same resource appears to be used
// serially, rather than multiple parallel uses. This is important for
@@ -1170,6 +1221,15 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
for( ; WPRIdx != WPREnd; ++WPRIdx) {
if (WriteProcResources[WPRIdx].ProcResourceIdx
== WPREntry.ProcResourceIdx) {
+ // TODO: multiple use of the same resources would
+ // require either 1. thinking of how to handle multiple
+ // intervals for the same resource in
+ // `<Target>WriteProcResTable` (see
+ // `SubtargetEmitter::EmitSchedClassTables`), or
+ // 2. thinking how to merge multiple intervals into a
+ // single interval.
+ assert(WPREntry.StartAtCycle == 0 &&
+ "multiple use ofthe same resource is not yet handled");
WriteProcResources[WPRIdx].Cycles += WPREntry.Cycles;
break;
}
@@ -1274,15 +1334,16 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables,
raw_ostream &OS) {
// Emit global WriteProcResTable.
- OS << "\n// {ProcResourceIdx, Cycles}\n"
- << "extern const llvm::MCWriteProcResEntry "
- << Target << "WriteProcResTable[] = {\n"
- << " { 0, 0}, // Invalid\n";
+ OS << "\n// {ProcResourceIdx, Cycles, StartAtCycle}\n"
+ << "extern const llvm::MCWriteProcResEntry " << Target
+ << "WriteProcResTable[] = {\n"
+ << " { 0, 0, 0 }, // Invalid\n";
for (unsigned WPRIdx = 1, WPREnd = SchedTables.WriteProcResources.size();
WPRIdx != WPREnd; ++WPRIdx) {
MCWriteProcResEntry &WPREntry = SchedTables.WriteProcResources[WPRIdx];
OS << " {" << format("%2d", WPREntry.ProcResourceIdx) << ", "
- << format("%2d", WPREntry.Cycles) << "}";
+ << format("%2d", WPREntry.Cycles) << ", "
+ << format("%2d", WPREntry.StartAtCycle) << "}";
if (WPRIdx + 1 < WPREnd)
OS << ',';
OS << " // #" << WPRIdx << '\n';
@@ -1401,6 +1462,12 @@ void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) {
OS << " " << (CompleteModel ? "true" : "false") << ", // "
<< "CompleteModel\n";
+ bool EnableIntervals =
+ (PM.ModelDef ? PM.ModelDef->getValueAsBit("EnableIntervals") : false);
+
+ OS << " " << (EnableIntervals ? "true" : "false") << ", // "
+ << "EnableIntervals\n";
+
OS << " " << PM.Index << ", // Processor ID\n";
if (PM.hasInstrSchedModel())
OS << " " << PM.ModelName << "ProcResources" << ",\n"
@@ -1746,17 +1813,17 @@ void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS) {
// Next record
StringRef Instance = R->getName();
StringRef Value = R->getValueAsString("Value");
- StringRef Attribute = R->getValueAsString("Attribute");
+ StringRef FieldName = R->getValueAsString("FieldName");
if (Value=="true" || Value=="false")
OS << " if (Bits[" << Target << "::"
<< Instance << "]) "
- << Attribute << " = " << Value << ";\n";
+ << FieldName << " = " << Value << ";\n";
else
OS << " if (Bits[" << Target << "::"
<< Instance << "] && "
- << Attribute << " < " << Value << ") "
- << Attribute << " = " << Value << ";\n";
+ << FieldName << " < " << Value << ") "
+ << FieldName << " = " << Value << ";\n";
}
OS << "}\n";
@@ -1983,11 +2050,5 @@ void SubtargetEmitter::run(raw_ostream &OS) {
EmitMCInstrAnalysisPredicateFunctions(OS);
}
-namespace llvm {
-
-void EmitSubtarget(RecordKeeper &RK, raw_ostream &OS) {
- CodeGenTarget CGTarget(RK);
- SubtargetEmitter(RK, CGTarget).run(OS);
-}
-
-} // end namespace llvm
+static TableGen::Emitter::OptClass<SubtargetEmitter>
+ X("gen-subtarget", "Generate subtarget enumerations");
diff --git a/llvm/utils/TableGen/SubtargetFeatureInfo.cpp b/llvm/utils/TableGen/SubtargetFeatureInfo.cpp
index 2a63fc490380..1db8c0bf430a 100644
--- a/llvm/utils/TableGen/SubtargetFeatureInfo.cpp
+++ b/llvm/utils/TableGen/SubtargetFeatureInfo.cpp
@@ -11,7 +11,6 @@
#include "llvm/Config/llvm-config.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
-#include <map>
using namespace llvm;
@@ -90,7 +89,7 @@ void SubtargetFeatureInfo::emitComputeAvailableFeatures(
StringRef TargetName, StringRef ClassName, StringRef FuncName,
SubtargetFeatureInfoMap &SubtargetFeatures, raw_ostream &OS,
StringRef ExtraParams) {
- OS << "PredicateBitset " << TargetName << ClassName << "::\n"
+ OS << "PredicateBitset " << ClassName << "::\n"
<< FuncName << "(const " << TargetName << "Subtarget *Subtarget";
if (!ExtraParams.empty())
OS << ", " << ExtraParams;
@@ -118,16 +117,19 @@ static bool emitFeaturesAux(StringRef TargetName, const Init &Val,
return false;
}
if (auto *D = dyn_cast<DagInit>(&Val)) {
- std::string Op = D->getOperator()->getAsString();
- if (Op == "not" && D->getNumArgs() == 1) {
+ auto *Op = dyn_cast<DefInit>(D->getOperator());
+ if (!Op)
+ return true;
+ StringRef OpName = Op->getDef()->getName();
+ if (OpName == "not" && D->getNumArgs() == 1) {
OS << '!';
return emitFeaturesAux(TargetName, *D->getArg(0), true, OS);
}
- if ((Op == "any_of" || Op == "all_of") && D->getNumArgs() > 0) {
+ if ((OpName == "any_of" || OpName == "all_of") && D->getNumArgs() > 0) {
bool Paren = D->getNumArgs() > 1 && std::exchange(ParenIfBinOp, true);
if (Paren)
OS << '(';
- ListSeparator LS(Op == "any_of" ? " || " : " && ");
+ ListSeparator LS(OpName == "any_of" ? " || " : " && ");
for (auto *Arg : D->getArgs()) {
OS << LS;
if (emitFeaturesAux(TargetName, *Arg, ParenIfBinOp, OS))
diff --git a/llvm/utils/TableGen/SubtargetFeatureInfo.h b/llvm/utils/TableGen/SubtargetFeatureInfo.h
index 8c8a4487934c..77703e8a87f8 100644
--- a/llvm/utils/TableGen/SubtargetFeatureInfo.h
+++ b/llvm/utils/TableGen/SubtargetFeatureInfo.h
@@ -9,9 +9,11 @@
#ifndef LLVM_UTIL_TABLEGEN_SUBTARGETFEATUREINFO_H
#define LLVM_UTIL_TABLEGEN_SUBTARGETFEATUREINFO_H
+#include "llvm/ADT/StringRef.h"
#include "llvm/TableGen/Record.h"
#include <map>
#include <string>
+#include <utility>
#include <vector>
namespace llvm {
@@ -67,8 +69,8 @@ struct SubtargetFeatureInfo {
///
/// \param TargetName The name of the target as used in class prefixes (e.g.
/// <TargetName>Subtarget)
- /// \param ClassName The name of the class (without the <Target> prefix)
- /// that will contain the generated functions.
+ /// \param ClassName The name of the class that will contain the generated
+ /// functions (including the target prefix.)
/// \param FuncName The name of the function to emit.
/// \param SubtargetFeatures A map of TableGen records to the
/// SubtargetFeatureInfo equivalent.
diff --git a/llvm/utils/TableGen/TableGen.cpp b/llvm/utils/TableGen/TableGen.cpp
index 746e2dd1db16..b2ed48cffe6b 100644
--- a/llvm/utils/TableGen/TableGen.cpp
+++ b/llvm/utils/TableGen/TableGen.cpp
@@ -10,57 +10,20 @@
//
//===----------------------------------------------------------------------===//
-#include "TableGenBackends.h" // Declares all backends.
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/TableGen/Main.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/SetTheory.h"
+#include "llvm/TableGen/TableGenBackend.h"
+#include <cassert>
+#include <string>
+#include <vector>
using namespace llvm;
-enum ActionType {
- PrintRecords,
- PrintDetailedRecords,
- NullBackend,
- DumpJSON,
- GenEmitter,
- GenRegisterInfo,
- GenInstrInfo,
- GenInstrDocs,
- GenAsmWriter,
- GenAsmMatcher,
- GenDisassembler,
- GenPseudoLowering,
- GenCompressInst,
- GenCallingConv,
- GenDAGISel,
- GenDFAPacketizer,
- GenFastISel,
- GenSubtarget,
- GenIntrinsicEnums,
- GenIntrinsicImpl,
- PrintEnums,
- PrintSets,
- GenOptParserDefs,
- GenOptRST,
- GenCTags,
- GenAttributes,
- GenSearchableTables,
- GenGlobalISel,
- GenGICombiner,
- GenX86EVEX2VEXTables,
- GenX86FoldTables,
- GenX86MnemonicTables,
- GenRegisterBank,
- GenExegesis,
- GenAutomata,
- GenDirectivesEnumDecl,
- GenDirectivesEnumImpl,
- GenDXILOperation,
- GenRISCVTargetDef,
-};
-
namespace llvm {
cl::opt<bool> EmitLongStrLiterals(
"long-string-literals",
@@ -71,229 +34,54 @@ cl::opt<bool> EmitLongStrLiterals(
} // end namespace llvm
namespace {
-cl::opt<ActionType> Action(
- cl::desc("Action to perform:"),
- cl::values(
- clEnumValN(PrintRecords, "print-records",
- "Print all records to stdout (default)"),
- clEnumValN(PrintDetailedRecords, "print-detailed-records",
- "Print full details of all records to stdout"),
- clEnumValN(NullBackend, "null-backend",
- "Do nothing after parsing (useful for timing)"),
- clEnumValN(DumpJSON, "dump-json",
- "Dump all records as machine-readable JSON"),
- clEnumValN(GenEmitter, "gen-emitter", "Generate machine code emitter"),
- clEnumValN(GenRegisterInfo, "gen-register-info",
- "Generate registers and register classes info"),
- clEnumValN(GenInstrInfo, "gen-instr-info",
- "Generate instruction descriptions"),
- clEnumValN(GenInstrDocs, "gen-instr-docs",
- "Generate instruction documentation"),
- clEnumValN(GenCallingConv, "gen-callingconv",
- "Generate calling convention descriptions"),
- clEnumValN(GenAsmWriter, "gen-asm-writer", "Generate assembly writer"),
- clEnumValN(GenDisassembler, "gen-disassembler",
- "Generate disassembler"),
- clEnumValN(GenPseudoLowering, "gen-pseudo-lowering",
- "Generate pseudo instruction lowering"),
- clEnumValN(GenCompressInst, "gen-compress-inst-emitter",
- "Generate RISCV compressed instructions."),
- clEnumValN(GenAsmMatcher, "gen-asm-matcher",
- "Generate assembly instruction matcher"),
- clEnumValN(GenDAGISel, "gen-dag-isel",
- "Generate a DAG instruction selector"),
- clEnumValN(GenDFAPacketizer, "gen-dfa-packetizer",
- "Generate DFA Packetizer for VLIW targets"),
- clEnumValN(GenFastISel, "gen-fast-isel",
- "Generate a \"fast\" instruction selector"),
- clEnumValN(GenSubtarget, "gen-subtarget",
- "Generate subtarget enumerations"),
- clEnumValN(GenIntrinsicEnums, "gen-intrinsic-enums",
- "Generate intrinsic enums"),
- clEnumValN(GenIntrinsicImpl, "gen-intrinsic-impl",
- "Generate intrinsic information"),
- clEnumValN(PrintEnums, "print-enums", "Print enum values for a class"),
- clEnumValN(PrintSets, "print-sets",
- "Print expanded sets for testing DAG exprs"),
- clEnumValN(GenOptParserDefs, "gen-opt-parser-defs",
- "Generate option definitions"),
- clEnumValN(GenOptRST, "gen-opt-rst", "Generate option RST"),
- clEnumValN(GenCTags, "gen-ctags", "Generate ctags-compatible index"),
- clEnumValN(GenAttributes, "gen-attrs", "Generate attributes"),
- clEnumValN(GenSearchableTables, "gen-searchable-tables",
- "Generate generic binary-searchable table"),
- clEnumValN(GenGlobalISel, "gen-global-isel",
- "Generate GlobalISel selector"),
- clEnumValN(GenGICombiner, "gen-global-isel-combiner",
- "Generate GlobalISel combiner"),
- clEnumValN(GenX86EVEX2VEXTables, "gen-x86-EVEX2VEX-tables",
- "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",
- "Generate llvm-exegesis tables"),
- clEnumValN(GenAutomata, "gen-automata", "Generate generic automata"),
- clEnumValN(GenDirectivesEnumDecl, "gen-directive-decl",
- "Generate directive related declaration code (header file)"),
- clEnumValN(GenDirectivesEnumImpl, "gen-directive-impl",
- "Generate directive related implementation code"),
- clEnumValN(GenDXILOperation, "gen-dxil-operation",
- "Generate DXIL operation information"),
- clEnumValN(GenRISCVTargetDef, "gen-riscv-target-def",
- "Generate the list of CPU for RISCV")));
+
cl::OptionCategory PrintEnumsCat("Options for -print-enums");
cl::opt<std::string> Class("class", cl::desc("Print Enum list for this class"),
cl::value_desc("class name"),
cl::cat(PrintEnumsCat));
-bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
- switch (Action) {
- case PrintRecords:
- OS << Records; // No argument, dump all contents
- break;
- case PrintDetailedRecords:
- EmitDetailedRecords(Records, OS);
- break;
- case NullBackend: // No backend at all.
- break;
- case DumpJSON:
- EmitJSON(Records, OS);
- break;
- case GenEmitter:
- EmitCodeEmitter(Records, OS);
- break;
- case GenRegisterInfo:
- EmitRegisterInfo(Records, OS);
- break;
- case GenInstrInfo:
- EmitInstrInfo(Records, OS);
- break;
- case GenInstrDocs:
- EmitInstrDocs(Records, OS);
- break;
- case GenCallingConv:
- EmitCallingConv(Records, OS);
- break;
- case GenAsmWriter:
- EmitAsmWriter(Records, OS);
- break;
- case GenAsmMatcher:
- EmitAsmMatcher(Records, OS);
- break;
- case GenDisassembler:
- EmitDisassembler(Records, OS);
- break;
- case GenPseudoLowering:
- EmitPseudoLowering(Records, OS);
- break;
- case GenCompressInst:
- EmitCompressInst(Records, OS);
- break;
- case GenDAGISel:
- EmitDAGISel(Records, OS);
- break;
- case GenDFAPacketizer:
- EmitDFAPacketizer(Records, OS);
- break;
- case GenFastISel:
- EmitFastISel(Records, OS);
- break;
- case GenSubtarget:
- EmitSubtarget(Records, OS);
- break;
- case GenIntrinsicEnums:
- EmitIntrinsicEnums(Records, OS);
- break;
- case GenIntrinsicImpl:
- EmitIntrinsicImpl(Records, OS);
- break;
- case GenOptParserDefs:
- EmitOptParser(Records, OS);
- break;
- case GenOptRST:
- EmitOptRST(Records, OS);
- break;
- case PrintEnums:
- {
- for (Record *Rec : Records.getAllDerivedDefinitions(Class))
- OS << Rec->getName() << ", ";
- OS << "\n";
- break;
- }
- case PrintSets:
- {
- SetTheory Sets;
- Sets.addFieldExpander("Set", "Elements");
- for (Record *Rec : Records.getAllDerivedDefinitions("Set")) {
- OS << Rec->getName() << " = [";
- const std::vector<Record*> *Elts = Sets.expand(Rec);
- assert(Elts && "Couldn't expand Set instance");
- for (Record *Elt : *Elts)
- OS << ' ' << Elt->getName();
- OS << " ]\n";
- }
- break;
- }
- case GenCTags:
- EmitCTags(Records, OS);
- break;
- case GenAttributes:
- EmitAttributes(Records, OS);
- break;
- case GenSearchableTables:
- EmitSearchableTables(Records, OS);
- break;
- case GenGlobalISel:
- EmitGlobalISel(Records, OS);
- break;
- case GenGICombiner:
- EmitGICombiner(Records, OS);
- break;
- case GenRegisterBank:
- EmitRegisterBank(Records, OS);
- break;
- case GenX86EVEX2VEXTables:
- EmitX86EVEX2VEXTables(Records, OS);
- break;
- case GenX86MnemonicTables:
- EmitX86MnemonicTables(Records, OS);
- break;
- case GenX86FoldTables:
- EmitX86FoldTables(Records, OS);
- break;
- case GenExegesis:
- EmitExegesis(Records, OS);
- break;
- case GenAutomata:
- EmitAutomata(Records, OS);
- break;
- case GenDirectivesEnumDecl:
- EmitDirectivesDecl(Records, OS);
- break;
- case GenDirectivesEnumImpl:
- EmitDirectivesImpl(Records, OS);
- break;
- case GenDXILOperation:
- EmitDXILOperation(Records, OS);
- break;
- case GenRISCVTargetDef:
- EmitRISCVTargetDef(Records, OS);
- break;
- }
+void PrintRecords(RecordKeeper &Records, raw_ostream &OS) {
+ OS << Records; // No argument, dump all contents
+}
- return false;
+void PrintEnums(RecordKeeper &Records, raw_ostream &OS) {
+ for (Record *Rec : Records.getAllDerivedDefinitions(Class))
+ OS << Rec->getName() << ", ";
+ OS << "\n";
}
+
+void PrintSets(RecordKeeper &Records, raw_ostream &OS) {
+ SetTheory Sets;
+ Sets.addFieldExpander("Set", "Elements");
+ for (Record *Rec : Records.getAllDerivedDefinitions("Set")) {
+ OS << Rec->getName() << " = [";
+ const std::vector<Record *> *Elts = Sets.expand(Rec);
+ assert(Elts && "Couldn't expand Set instance");
+ for (Record *Elt : *Elts)
+ OS << ' ' << Elt->getName();
+ OS << " ]\n";
+ }
}
+TableGen::Emitter::Opt X[] = {
+ {"print-records", PrintRecords, "Print all records to stdout (default)",
+ true},
+ {"print-detailed-records", EmitDetailedRecords,
+ "Print full details of all records to stdout"},
+ {"null-backend", [](RecordKeeper &Records, raw_ostream &OS) {},
+ "Do nothing after parsing (useful for timing)"},
+ {"dump-json", EmitJSON, "Dump all records as machine-readable JSON"},
+ {"print-enums", PrintEnums, "Print enum values for a class"},
+ {"print-sets", PrintSets, "Print expanded sets for testing DAG exprs"},
+};
+
+} // namespace
+
int main(int argc, char **argv) {
InitLLVM X(argc, argv);
cl::ParseCommandLineOptions(argc, argv);
- return TableGenMain(argv[0], &LLVMTableGenMain);
+ return TableGenMain(argv[0]);
}
#ifndef __has_feature
diff --git a/llvm/utils/TableGen/TableGenBackends.h b/llvm/utils/TableGen/TableGenBackends.h
index ac44babb1261..3afe6b01467b 100644
--- a/llvm/utils/TableGen/TableGenBackends.h
+++ b/llvm/utils/TableGen/TableGenBackends.h
@@ -15,6 +15,8 @@
#ifndef LLVM_UTILS_TABLEGEN_TABLEGENBACKENDS_H
#define LLVM_UTILS_TABLEGEN_TABLEGENBACKENDS_H
+#include <string>
+
// A TableGen backend is a function that looks like
//
// EmitFoo(RecordKeeper &RK, raw_ostream &OS /*, anything else you need */ )
@@ -61,41 +63,12 @@ namespace llvm {
class raw_ostream;
class RecordKeeper;
-void EmitIntrinsicEnums(RecordKeeper &RK, raw_ostream &OS);
-void EmitIntrinsicImpl(RecordKeeper &RK, raw_ostream &OS);
-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 EmitDAGISel(RecordKeeper &RK, raw_ostream &OS);
-void EmitDFAPacketizer(RecordKeeper &RK, raw_ostream &OS);
-void EmitDisassembler(RecordKeeper &RK, raw_ostream &OS);
-void EmitFastISel(RecordKeeper &RK, raw_ostream &OS);
-void EmitInstrInfo(RecordKeeper &RK, raw_ostream &OS);
-void EmitInstrDocs(RecordKeeper &RK, raw_ostream &OS);
-void EmitPseudoLowering(RecordKeeper &RK, raw_ostream &OS);
-void EmitCompressInst(RecordKeeper &RK, raw_ostream &OS);
-void EmitRegisterInfo(RecordKeeper &RK, raw_ostream &OS);
-void EmitSubtarget(RecordKeeper &RK, raw_ostream &OS);
void EmitMapTable(RecordKeeper &RK, raw_ostream &OS);
-void EmitOptParser(RecordKeeper &RK, raw_ostream &OS);
-void EmitOptRST(RecordKeeper &RK, raw_ostream &OS);
-void EmitCTags(RecordKeeper &RK, raw_ostream &OS);
-void EmitAttributes(RecordKeeper &RK, raw_ostream &OS);
-void EmitSearchableTables(RecordKeeper &RK, raw_ostream &OS);
-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);
-void EmitRISCVTargetDef(const RecordKeeper &RK, raw_ostream &OS);
-} // End llvm namespace
+// Defined in DecoderEmitter.cpp
+void EmitDecoder(RecordKeeper &RK, raw_ostream &OS,
+ const std::string &PredicateNamespace);
+
+} // namespace llvm
#endif
diff --git a/llvm/utils/TableGen/Types.cpp b/llvm/utils/TableGen/Types.cpp
index a6682da90e6b..aca8e36b683d 100644
--- a/llvm/utils/TableGen/Types.cpp
+++ b/llvm/utils/TableGen/Types.cpp
@@ -34,11 +34,3 @@ const char *llvm::getMinimalTypeForRange(uint64_t Range, unsigned MaxSize LLVM_A
return "uint16_t";
return "uint8_t";
}
-
-const char *llvm::getMinimalTypeForEnumBitfield(uint64_t Size) {
- uint64_t MaxIndex = Size;
- if (MaxIndex > 0)
- MaxIndex--;
- assert(MaxIndex <= 64 && "Too many bits");
- return getMinimalTypeForRange(1ULL << MaxIndex);
-}
diff --git a/llvm/utils/TableGen/Types.h b/llvm/utils/TableGen/Types.h
index 17c7742ccaac..f369d61785c4 100644
--- a/llvm/utils/TableGen/Types.h
+++ b/llvm/utils/TableGen/Types.h
@@ -16,9 +16,6 @@ namespace llvm {
/// MaxSize indicates the largest size of integer to consider (in bits) and only
/// supports values of at least 32.
const char *getMinimalTypeForRange(uint64_t Range, unsigned MaxSize = 64);
-
-/// Returns the smallest unsigned integer type that can hold the given bitfield.
-const char *getMinimalTypeForEnumBitfield(uint64_t Size);
}
#endif
diff --git a/llvm/utils/TableGen/VTEmitter.cpp b/llvm/utils/TableGen/VTEmitter.cpp
new file mode 100644
index 000000000000..d398a7e7b58f
--- /dev/null
+++ b/llvm/utils/TableGen/VTEmitter.cpp
@@ -0,0 +1,130 @@
+//===- VTEmitter.cpp - Generate properties from ValueTypes.td -------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
+#include <array>
+#include <cassert>
+#include <map>
+using namespace llvm;
+
+namespace {
+
+class VTEmitter {
+private:
+ RecordKeeper &Records;
+
+public:
+ VTEmitter(RecordKeeper &R) : Records(R) {}
+
+ void run(raw_ostream &OS);
+};
+
+} // End anonymous namespace.
+
+void VTEmitter::run(raw_ostream &OS) {
+ emitSourceFileHeader("ValueTypes Source Fragment", OS);
+
+ std::array<const Record *, 256> VTsByNumber = {};
+ auto ValueTypes = Records.getAllDerivedDefinitions("ValueType");
+ for (auto *VT : ValueTypes) {
+ auto Number = VT->getValueAsInt("Value");
+ assert(0 <= Number && Number < (int)VTsByNumber.size() &&
+ "ValueType should be uint8_t");
+ assert(!VTsByNumber[Number] && "Duplicate ValueType");
+ VTsByNumber[Number] = VT;
+ }
+
+ struct VTRange {
+ StringRef First;
+ StringRef Last;
+ bool Closed;
+ };
+
+ std::map<StringRef, VTRange> VTRanges;
+
+ auto UpdateVTRange = [&VTRanges](const char *Key, StringRef Name,
+ bool Valid) {
+ if (Valid) {
+ if (!VTRanges.count(Key))
+ VTRanges[Key].First = Name;
+ assert(!VTRanges[Key].Closed && "Gap detected!");
+ VTRanges[Key].Last = Name;
+ } else if (VTRanges.count(Key)) {
+ VTRanges[Key].Closed = true;
+ }
+ };
+
+ OS << "#ifdef GET_VT_ATTR // (Ty, n, sz, Any, Int, FP, Vec, Sc)\n";
+ for (const auto *VT : VTsByNumber) {
+ if (!VT)
+ continue;
+ auto Name = VT->getValueAsString("LLVMName");
+ auto Value = VT->getValueAsInt("Value");
+ bool IsInteger = VT->getValueAsInt("isInteger");
+ bool IsFP = VT->getValueAsInt("isFP");
+ bool IsVector = VT->getValueAsInt("isVector");
+ bool IsScalable = VT->getValueAsInt("isScalable");
+
+ UpdateVTRange("INTEGER_FIXEDLEN_VECTOR_VALUETYPE", Name,
+ IsInteger && IsVector && !IsScalable);
+ UpdateVTRange("INTEGER_SCALABLE_VECTOR_VALUETYPE", Name,
+ IsInteger && IsScalable);
+ UpdateVTRange("FP_FIXEDLEN_VECTOR_VALUETYPE", Name,
+ IsFP && IsVector && !IsScalable);
+ UpdateVTRange("FP_SCALABLE_VECTOR_VALUETYPE", Name, IsFP && IsScalable);
+ UpdateVTRange("FIXEDLEN_VECTOR_VALUETYPE", Name, IsVector && !IsScalable);
+ UpdateVTRange("SCALABLE_VECTOR_VALUETYPE", Name, IsScalable);
+ UpdateVTRange("VECTOR_VALUETYPE", Name, IsVector);
+ UpdateVTRange("INTEGER_VALUETYPE", Name, IsInteger && !IsVector);
+ UpdateVTRange("FP_VALUETYPE", Name, IsFP && !IsVector);
+ UpdateVTRange("VALUETYPE", Name, Value < 224);
+
+ // clang-format off
+ OS << " GET_VT_ATTR("
+ << Name << ", "
+ << Value << ", "
+ << VT->getValueAsInt("Size") << ", "
+ << VT->getValueAsInt("isOverloaded") << ", "
+ << (IsInteger ? Name[0] == 'i' ? 3 : 1 : 0) << ", "
+ << (IsFP ? Name[0] == 'f' ? 3 : 1 : 0) << ", "
+ << IsVector << ", "
+ << IsScalable << ")\n";
+ // clang-format on
+ }
+ OS << "#endif\n\n";
+
+ OS << "#ifdef GET_VT_RANGES\n";
+ for (const auto &KV : VTRanges) {
+ assert(KV.second.Closed);
+ OS << " FIRST_" << KV.first << " = " << KV.second.First << ",\n"
+ << " LAST_" << KV.first << " = " << KV.second.Last << ",\n";
+ }
+ OS << "#endif\n\n";
+
+ OS << "#ifdef GET_VT_VECATTR // (Ty, Sc, nElem, ElTy, ElSz)\n";
+ for (const auto *VT : VTsByNumber) {
+ if (!VT || !VT->getValueAsInt("isVector"))
+ continue;
+ const auto *ElTy = VT->getValueAsDef("ElementType");
+ assert(ElTy);
+ // clang-format off
+ OS << " GET_VT_VECATTR("
+ << VT->getValueAsString("LLVMName") << ", "
+ << VT->getValueAsInt("isScalable") << ", "
+ << VT->getValueAsInt("nElem") << ", "
+ << ElTy->getName() << ", "
+ << ElTy->getValueAsInt("Size") << ")\n";
+ // clang-format on
+ }
+ OS << "#endif\n\n";
+}
+
+static TableGen::Emitter::OptClass<VTEmitter> X("gen-vt", "Generate ValueType");
diff --git a/llvm/utils/TableGen/VarLenCodeEmitterGen.cpp b/llvm/utils/TableGen/VarLenCodeEmitterGen.cpp
index 2c1acd8d910c..85da547d04c1 100644
--- a/llvm/utils/TableGen/VarLenCodeEmitterGen.cpp
+++ b/llvm/utils/TableGen/VarLenCodeEmitterGen.cpp
@@ -58,6 +58,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TableGen/Error.h"
+#include "llvm/TableGen/Record.h"
using namespace llvm;
diff --git a/llvm/utils/TableGen/X86DisassemblerTables.cpp b/llvm/utils/TableGen/X86DisassemblerTables.cpp
index 601591d9f53d..708c92aecfc8 100644
--- a/llvm/utils/TableGen/X86DisassemblerTables.cpp
+++ b/llvm/utils/TableGen/X86DisassemblerTables.cpp
@@ -76,7 +76,7 @@ static inline const char* stringForOperandEncoding(OperandEncoding encoding) {
/// @return - True if child is a subset of parent, false otherwise.
static inline bool inheritsFrom(InstructionContext child,
InstructionContext parent, bool noPrefix = true,
- bool VEX_LIG = false, bool VEX_WIG = false,
+ bool VEX_LIG = false, bool WIG = false,
bool AdSize64 = false) {
if (child == parent)
return true;
@@ -144,20 +144,20 @@ static inline bool inheritsFrom(InstructionContext child,
case IC_64BIT_REXW_ADSIZE:
return false;
case IC_VEX:
- return (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_VEX_L_W)) ||
- (VEX_WIG && inheritsFrom(child, IC_VEX_W)) ||
+ return (VEX_LIG && WIG && inheritsFrom(child, IC_VEX_L_W)) ||
+ (WIG && inheritsFrom(child, IC_VEX_W)) ||
(VEX_LIG && inheritsFrom(child, IC_VEX_L));
case IC_VEX_XS:
- return (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_VEX_L_W_XS)) ||
- (VEX_WIG && inheritsFrom(child, IC_VEX_W_XS)) ||
+ return (VEX_LIG && WIG && inheritsFrom(child, IC_VEX_L_W_XS)) ||
+ (WIG && inheritsFrom(child, IC_VEX_W_XS)) ||
(VEX_LIG && inheritsFrom(child, IC_VEX_L_XS));
case IC_VEX_XD:
- return (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_VEX_L_W_XD)) ||
- (VEX_WIG && inheritsFrom(child, IC_VEX_W_XD)) ||
+ return (VEX_LIG && WIG && inheritsFrom(child, IC_VEX_L_W_XD)) ||
+ (WIG && inheritsFrom(child, IC_VEX_W_XD)) ||
(VEX_LIG && inheritsFrom(child, IC_VEX_L_XD));
case IC_VEX_OPSIZE:
- return (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_VEX_L_W_OPSIZE)) ||
- (VEX_WIG && inheritsFrom(child, IC_VEX_W_OPSIZE)) ||
+ return (VEX_LIG && WIG && inheritsFrom(child, IC_VEX_L_W_OPSIZE)) ||
+ (WIG && inheritsFrom(child, IC_VEX_W_OPSIZE)) ||
(VEX_LIG && inheritsFrom(child, IC_VEX_L_OPSIZE));
case IC_VEX_W:
return VEX_LIG && inheritsFrom(child, IC_VEX_L_W);
@@ -168,88 +168,88 @@ static inline bool inheritsFrom(InstructionContext child,
case IC_VEX_W_OPSIZE:
return VEX_LIG && inheritsFrom(child, IC_VEX_L_W_OPSIZE);
case IC_VEX_L:
- return VEX_WIG && inheritsFrom(child, IC_VEX_L_W);
+ return WIG && inheritsFrom(child, IC_VEX_L_W);
case IC_VEX_L_XS:
- return VEX_WIG && inheritsFrom(child, IC_VEX_L_W_XS);
+ return WIG && inheritsFrom(child, IC_VEX_L_W_XS);
case IC_VEX_L_XD:
- return VEX_WIG && inheritsFrom(child, IC_VEX_L_W_XD);
+ return WIG && inheritsFrom(child, IC_VEX_L_W_XD);
case IC_VEX_L_OPSIZE:
- return VEX_WIG && inheritsFrom(child, IC_VEX_L_W_OPSIZE);
+ return WIG && inheritsFrom(child, IC_VEX_L_W_OPSIZE);
case IC_VEX_L_W:
case IC_VEX_L_W_XS:
case IC_VEX_L_W_XD:
case IC_VEX_L_W_OPSIZE:
return false;
case IC_EVEX:
- return (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L_W)) ||
- (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W)) ||
- (VEX_WIG && inheritsFrom(child, IC_EVEX_W)) ||
+ return (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L_W)) ||
+ (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L2_W)) ||
+ (WIG && inheritsFrom(child, IC_EVEX_W)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L2));
case IC_EVEX_XS:
- return (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_XS)) ||
- (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_XS)) ||
- (VEX_WIG && inheritsFrom(child, IC_EVEX_W_XS)) ||
+ return (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L_W_XS)) ||
+ (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L2_W_XS)) ||
+ (WIG && inheritsFrom(child, IC_EVEX_W_XS)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L_XS)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L2_XS));
case IC_EVEX_XD:
- return (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_XD)) ||
- (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_XD)) ||
- (VEX_WIG && inheritsFrom(child, IC_EVEX_W_XD)) ||
+ return (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L_W_XD)) ||
+ (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L2_W_XD)) ||
+ (WIG && inheritsFrom(child, IC_EVEX_W_XD)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L_XD)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L2_XD));
case IC_EVEX_OPSIZE:
- return (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_OPSIZE)) ||
- (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_OPSIZE)) ||
- (VEX_WIG && inheritsFrom(child, IC_EVEX_W_OPSIZE)) ||
+ return (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L_W_OPSIZE)) ||
+ (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L2_W_OPSIZE)) ||
+ (WIG && inheritsFrom(child, IC_EVEX_W_OPSIZE)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L_OPSIZE)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L2_OPSIZE));
case IC_EVEX_K:
- return (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_K)) ||
- (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_K)) ||
- (VEX_WIG && inheritsFrom(child, IC_EVEX_W_K)) ||
+ return (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L_W_K)) ||
+ (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L2_W_K)) ||
+ (WIG && inheritsFrom(child, IC_EVEX_W_K)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L_K)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L2_K));
case IC_EVEX_XS_K:
- return (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_XS_K)) ||
- (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_XS_K)) ||
- (VEX_WIG && inheritsFrom(child, IC_EVEX_W_XS_K)) ||
+ return (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L_W_XS_K)) ||
+ (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L2_W_XS_K)) ||
+ (WIG && inheritsFrom(child, IC_EVEX_W_XS_K)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L_XS_K)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L2_XS_K));
case IC_EVEX_XD_K:
- return (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_XD_K)) ||
- (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_XD_K)) ||
- (VEX_WIG && inheritsFrom(child, IC_EVEX_W_XD_K)) ||
+ return (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L_W_XD_K)) ||
+ (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L2_W_XD_K)) ||
+ (WIG && inheritsFrom(child, IC_EVEX_W_XD_K)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L_XD_K)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L2_XD_K));
case IC_EVEX_OPSIZE_K:
- return (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_OPSIZE_K)) ||
- (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_OPSIZE_K)) ||
- (VEX_WIG && inheritsFrom(child, IC_EVEX_W_OPSIZE_K)) ||
+ return (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L_W_OPSIZE_K)) ||
+ (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L2_W_OPSIZE_K)) ||
+ (WIG && inheritsFrom(child, IC_EVEX_W_OPSIZE_K)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L_OPSIZE_K)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L2_OPSIZE_K));
case IC_EVEX_KZ:
- return (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_KZ)) ||
- (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_KZ)) ||
- (VEX_WIG && inheritsFrom(child, IC_EVEX_W_KZ)) ||
+ return (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L_W_KZ)) ||
+ (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L2_W_KZ)) ||
+ (WIG && inheritsFrom(child, IC_EVEX_W_KZ)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L_KZ)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L2_KZ));
case IC_EVEX_XS_KZ:
- return (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_XS_KZ)) ||
- (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_XS_KZ)) ||
- (VEX_WIG && inheritsFrom(child, IC_EVEX_W_XS_KZ)) ||
+ return (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L_W_XS_KZ)) ||
+ (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L2_W_XS_KZ)) ||
+ (WIG && inheritsFrom(child, IC_EVEX_W_XS_KZ)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L_XS_KZ)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L2_XS_KZ));
case IC_EVEX_XD_KZ:
- return (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_XD_KZ)) ||
- (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_XD_KZ)) ||
- (VEX_WIG && inheritsFrom(child, IC_EVEX_W_XD_KZ)) ||
+ return (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L_W_XD_KZ)) ||
+ (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L2_W_XD_KZ)) ||
+ (WIG && inheritsFrom(child, IC_EVEX_W_XD_KZ)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L_XD_KZ)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L2_XD_KZ));
case IC_EVEX_OPSIZE_KZ:
- return (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_OPSIZE_KZ)) ||
- (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_OPSIZE_KZ)) ||
- (VEX_WIG && inheritsFrom(child, IC_EVEX_W_OPSIZE_KZ)) ||
+ return (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L_W_OPSIZE_KZ)) ||
+ (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L2_W_OPSIZE_KZ)) ||
+ (WIG && inheritsFrom(child, IC_EVEX_W_OPSIZE_KZ)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L_OPSIZE_KZ)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L2_OPSIZE_KZ));
case IC_EVEX_W:
@@ -289,29 +289,29 @@ static inline bool inheritsFrom(InstructionContext child,
return (VEX_LIG && inheritsFrom(child, IC_EVEX_L_W_OPSIZE_KZ)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L2_W_OPSIZE_KZ));
case IC_EVEX_L:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L_W);
+ return WIG && inheritsFrom(child, IC_EVEX_L_W);
case IC_EVEX_L_XS:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_XS);
+ return WIG && inheritsFrom(child, IC_EVEX_L_W_XS);
case IC_EVEX_L_XD:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_XD);
+ return WIG && inheritsFrom(child, IC_EVEX_L_W_XD);
case IC_EVEX_L_OPSIZE:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_OPSIZE);
+ return WIG && inheritsFrom(child, IC_EVEX_L_W_OPSIZE);
case IC_EVEX_L_K:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_K);
+ return WIG && inheritsFrom(child, IC_EVEX_L_W_K);
case IC_EVEX_L_XS_K:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_XS_K);
+ return WIG && inheritsFrom(child, IC_EVEX_L_W_XS_K);
case IC_EVEX_L_XD_K:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_XD_K);
+ return WIG && inheritsFrom(child, IC_EVEX_L_W_XD_K);
case IC_EVEX_L_OPSIZE_K:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_OPSIZE_K);
+ return WIG && inheritsFrom(child, IC_EVEX_L_W_OPSIZE_K);
case IC_EVEX_L_KZ:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_KZ);
+ return WIG && inheritsFrom(child, IC_EVEX_L_W_KZ);
case IC_EVEX_L_XS_KZ:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_XS_KZ);
+ return WIG && inheritsFrom(child, IC_EVEX_L_W_XS_KZ);
case IC_EVEX_L_XD_KZ:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_XD_KZ);
+ return WIG && inheritsFrom(child, IC_EVEX_L_W_XD_KZ);
case IC_EVEX_L_OPSIZE_KZ:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_OPSIZE_KZ);
+ return WIG && inheritsFrom(child, IC_EVEX_L_W_OPSIZE_KZ);
case IC_EVEX_L_W:
case IC_EVEX_L_W_XS:
case IC_EVEX_L_W_XD:
@@ -328,29 +328,29 @@ static inline bool inheritsFrom(InstructionContext child,
case IC_EVEX_L_W_OPSIZE_KZ:
return false;
case IC_EVEX_L2:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W);
+ return WIG && inheritsFrom(child, IC_EVEX_L2_W);
case IC_EVEX_L2_XS:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_XS);
+ return WIG && inheritsFrom(child, IC_EVEX_L2_W_XS);
case IC_EVEX_L2_XD:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_XD);
+ return WIG && inheritsFrom(child, IC_EVEX_L2_W_XD);
case IC_EVEX_L2_OPSIZE:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_OPSIZE);
+ return WIG && inheritsFrom(child, IC_EVEX_L2_W_OPSIZE);
case IC_EVEX_L2_K:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_K);
+ return WIG && inheritsFrom(child, IC_EVEX_L2_W_K);
case IC_EVEX_L2_XS_K:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_XS_K);
+ return WIG && inheritsFrom(child, IC_EVEX_L2_W_XS_K);
case IC_EVEX_L2_XD_K:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_XD_K);
+ return WIG && inheritsFrom(child, IC_EVEX_L2_W_XD_K);
case IC_EVEX_L2_OPSIZE_K:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_OPSIZE_K);
+ return WIG && inheritsFrom(child, IC_EVEX_L2_W_OPSIZE_K);
case IC_EVEX_L2_KZ:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_KZ);
+ return WIG && inheritsFrom(child, IC_EVEX_L2_W_KZ);
case IC_EVEX_L2_XS_KZ:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_XS_KZ);
+ return WIG && inheritsFrom(child, IC_EVEX_L2_W_XS_KZ);
case IC_EVEX_L2_XD_KZ:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_XD_KZ);
+ return WIG && inheritsFrom(child, IC_EVEX_L2_W_XD_KZ);
case IC_EVEX_L2_OPSIZE_KZ:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_OPSIZE_KZ);
+ return WIG && inheritsFrom(child, IC_EVEX_L2_W_OPSIZE_KZ);
case IC_EVEX_L2_W:
case IC_EVEX_L2_W_XS:
case IC_EVEX_L2_W_XD:
@@ -367,79 +367,79 @@ static inline bool inheritsFrom(InstructionContext child,
case IC_EVEX_L2_W_OPSIZE_KZ:
return false;
case IC_EVEX_B:
- return (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_B)) ||
- (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_B)) ||
- (VEX_WIG && inheritsFrom(child, IC_EVEX_W_B)) ||
+ return (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L_W_B)) ||
+ (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L2_W_B)) ||
+ (WIG && inheritsFrom(child, IC_EVEX_W_B)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L_B)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L2_B));
case IC_EVEX_XS_B:
- return (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_XS_B)) ||
- (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_XS_B)) ||
- (VEX_WIG && inheritsFrom(child, IC_EVEX_W_XS_B)) ||
+ return (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L_W_XS_B)) ||
+ (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L2_W_XS_B)) ||
+ (WIG && inheritsFrom(child, IC_EVEX_W_XS_B)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L_XS_B)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L2_XS_B));
case IC_EVEX_XD_B:
- return (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_XD_B)) ||
- (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_XD_B)) ||
- (VEX_WIG && inheritsFrom(child, IC_EVEX_W_XD_B)) ||
+ return (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L_W_XD_B)) ||
+ (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L2_W_XD_B)) ||
+ (WIG && inheritsFrom(child, IC_EVEX_W_XD_B)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L_XD_B)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L2_XD_B));
case IC_EVEX_OPSIZE_B:
- return (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_OPSIZE_B)) ||
- (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_OPSIZE_B)) ||
- (VEX_WIG && inheritsFrom(child, IC_EVEX_W_OPSIZE_B)) ||
+ return (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L_W_OPSIZE_B)) ||
+ (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L2_W_OPSIZE_B)) ||
+ (WIG && inheritsFrom(child, IC_EVEX_W_OPSIZE_B)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L_OPSIZE_B)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L2_OPSIZE_B));
case IC_EVEX_K_B:
- return (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_K_B)) ||
- (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_K_B)) ||
- (VEX_WIG && inheritsFrom(child, IC_EVEX_W_K_B)) ||
+ return (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L_W_K_B)) ||
+ (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L2_W_K_B)) ||
+ (WIG && inheritsFrom(child, IC_EVEX_W_K_B)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L_K_B)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L2_K_B));
case IC_EVEX_XS_K_B:
- return (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_XS_K_B)) ||
- (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_XS_K_B)) ||
- (VEX_WIG && inheritsFrom(child, IC_EVEX_W_XS_K_B)) ||
+ return (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L_W_XS_K_B)) ||
+ (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L2_W_XS_K_B)) ||
+ (WIG && inheritsFrom(child, IC_EVEX_W_XS_K_B)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L_XS_K_B)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L2_XS_K_B));
case IC_EVEX_XD_K_B:
- return (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_XD_K_B)) ||
- (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_XD_K_B)) ||
- (VEX_WIG && inheritsFrom(child, IC_EVEX_W_XD_K_B)) ||
+ return (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L_W_XD_K_B)) ||
+ (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L2_W_XD_K_B)) ||
+ (WIG && inheritsFrom(child, IC_EVEX_W_XD_K_B)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L_XD_K_B)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L2_XD_K_B));
case IC_EVEX_OPSIZE_K_B:
- return (VEX_LIG && VEX_WIG &&
+ return (VEX_LIG && WIG &&
inheritsFrom(child, IC_EVEX_L_W_OPSIZE_K_B)) ||
- (VEX_LIG && VEX_WIG &&
+ (VEX_LIG && WIG &&
inheritsFrom(child, IC_EVEX_L2_W_OPSIZE_K_B)) ||
- (VEX_WIG && inheritsFrom(child, IC_EVEX_W_OPSIZE_K_B)) ||
+ (WIG && inheritsFrom(child, IC_EVEX_W_OPSIZE_K_B)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L_OPSIZE_K_B)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L2_OPSIZE_K_B));
case IC_EVEX_KZ_B:
- return (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_KZ_B)) ||
- (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_KZ_B)) ||
- (VEX_WIG && inheritsFrom(child, IC_EVEX_W_KZ_B)) ||
+ return (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L_W_KZ_B)) ||
+ (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L2_W_KZ_B)) ||
+ (WIG && inheritsFrom(child, IC_EVEX_W_KZ_B)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L_KZ_B)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L2_KZ_B));
case IC_EVEX_XS_KZ_B:
- return (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_XS_KZ_B)) ||
- (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_XS_KZ_B)) ||
- (VEX_WIG && inheritsFrom(child, IC_EVEX_W_XS_KZ_B)) ||
+ return (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L_W_XS_KZ_B)) ||
+ (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L2_W_XS_KZ_B)) ||
+ (WIG && inheritsFrom(child, IC_EVEX_W_XS_KZ_B)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L_XS_KZ_B)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L2_XS_KZ_B));
case IC_EVEX_XD_KZ_B:
- return (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_XD_KZ_B)) ||
- (VEX_LIG && VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_XD_KZ_B)) ||
- (VEX_WIG && inheritsFrom(child, IC_EVEX_W_XD_KZ_B)) ||
+ return (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L_W_XD_KZ_B)) ||
+ (VEX_LIG && WIG && inheritsFrom(child, IC_EVEX_L2_W_XD_KZ_B)) ||
+ (WIG && inheritsFrom(child, IC_EVEX_W_XD_KZ_B)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L_XD_KZ_B)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L2_XD_KZ_B));
case IC_EVEX_OPSIZE_KZ_B:
- return (VEX_LIG && VEX_WIG &&
+ return (VEX_LIG && WIG &&
inheritsFrom(child, IC_EVEX_L_W_OPSIZE_KZ_B)) ||
- (VEX_LIG && VEX_WIG &&
+ (VEX_LIG && WIG &&
inheritsFrom(child, IC_EVEX_L2_W_OPSIZE_KZ_B)) ||
- (VEX_WIG && inheritsFrom(child, IC_EVEX_W_OPSIZE_KZ_B)) ||
+ (WIG && inheritsFrom(child, IC_EVEX_W_OPSIZE_KZ_B)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L_OPSIZE_KZ_B)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L2_OPSIZE_KZ_B));
case IC_EVEX_W_B:
@@ -479,29 +479,29 @@ static inline bool inheritsFrom(InstructionContext child,
return (VEX_LIG && inheritsFrom(child, IC_EVEX_L_W_OPSIZE_KZ_B)) ||
(VEX_LIG && inheritsFrom(child, IC_EVEX_L2_W_OPSIZE_KZ_B));
case IC_EVEX_L_B:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_B);
+ return WIG && inheritsFrom(child, IC_EVEX_L_W_B);
case IC_EVEX_L_XS_B:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_XS_B);
+ return WIG && inheritsFrom(child, IC_EVEX_L_W_XS_B);
case IC_EVEX_L_XD_B:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_XD_B);
+ return WIG && inheritsFrom(child, IC_EVEX_L_W_XD_B);
case IC_EVEX_L_OPSIZE_B:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_OPSIZE_B);
+ return WIG && inheritsFrom(child, IC_EVEX_L_W_OPSIZE_B);
case IC_EVEX_L_K_B:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_K_B);
+ return WIG && inheritsFrom(child, IC_EVEX_L_W_K_B);
case IC_EVEX_L_XS_K_B:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_XS_K_B);
+ return WIG && inheritsFrom(child, IC_EVEX_L_W_XS_K_B);
case IC_EVEX_L_XD_K_B:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_XD_K_B);
+ return WIG && inheritsFrom(child, IC_EVEX_L_W_XD_K_B);
case IC_EVEX_L_OPSIZE_K_B:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_OPSIZE_K_B);
+ return WIG && inheritsFrom(child, IC_EVEX_L_W_OPSIZE_K_B);
case IC_EVEX_L_KZ_B:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_KZ_B);
+ return WIG && inheritsFrom(child, IC_EVEX_L_W_KZ_B);
case IC_EVEX_L_XS_KZ_B:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_XS_KZ_B);
+ return WIG && inheritsFrom(child, IC_EVEX_L_W_XS_KZ_B);
case IC_EVEX_L_XD_KZ_B:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_XD_KZ_B);
+ return WIG && inheritsFrom(child, IC_EVEX_L_W_XD_KZ_B);
case IC_EVEX_L_OPSIZE_KZ_B:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L_W_OPSIZE_KZ_B);
+ return WIG && inheritsFrom(child, IC_EVEX_L_W_OPSIZE_KZ_B);
case IC_EVEX_L_W_B:
case IC_EVEX_L_W_XS_B:
case IC_EVEX_L_W_XD_B:
@@ -518,29 +518,29 @@ static inline bool inheritsFrom(InstructionContext child,
case IC_EVEX_L_W_OPSIZE_KZ_B:
return false;
case IC_EVEX_L2_B:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_B);
+ return WIG && inheritsFrom(child, IC_EVEX_L2_W_B);
case IC_EVEX_L2_XS_B:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_XS_B);
+ return WIG && inheritsFrom(child, IC_EVEX_L2_W_XS_B);
case IC_EVEX_L2_XD_B:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_XD_B);
+ return WIG && inheritsFrom(child, IC_EVEX_L2_W_XD_B);
case IC_EVEX_L2_OPSIZE_B:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_OPSIZE_B);
+ return WIG && inheritsFrom(child, IC_EVEX_L2_W_OPSIZE_B);
case IC_EVEX_L2_K_B:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_K_B);
+ return WIG && inheritsFrom(child, IC_EVEX_L2_W_K_B);
case IC_EVEX_L2_XS_K_B:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_XS_K_B);
+ return WIG && inheritsFrom(child, IC_EVEX_L2_W_XS_K_B);
case IC_EVEX_L2_XD_K_B:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_XD_K_B);
+ return WIG && inheritsFrom(child, IC_EVEX_L2_W_XD_K_B);
case IC_EVEX_L2_OPSIZE_K_B:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_OPSIZE_K_B);
+ return WIG && inheritsFrom(child, IC_EVEX_L2_W_OPSIZE_K_B);
case IC_EVEX_L2_KZ_B:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_KZ_B);
+ return WIG && inheritsFrom(child, IC_EVEX_L2_W_KZ_B);
case IC_EVEX_L2_XS_KZ_B:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_XS_KZ_B);
+ return WIG && inheritsFrom(child, IC_EVEX_L2_W_XS_KZ_B);
case IC_EVEX_L2_XD_KZ_B:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_XD_KZ_B);
+ return WIG && inheritsFrom(child, IC_EVEX_L2_W_XD_KZ_B);
case IC_EVEX_L2_OPSIZE_KZ_B:
- return VEX_WIG && inheritsFrom(child, IC_EVEX_L2_W_OPSIZE_KZ_B);
+ return WIG && inheritsFrom(child, IC_EVEX_L2_W_OPSIZE_KZ_B);
case IC_EVEX_L2_W_B:
case IC_EVEX_L2_W_XS_B:
case IC_EVEX_L2_W_XD_B:
@@ -1068,7 +1068,7 @@ void DisassemblerTables::setTableFields(OpcodeType type,
bool is32bit,
bool noPrefix,
bool ignoresVEX_L,
- bool ignoresVEX_W,
+ bool ignoresW,
unsigned addressSize) {
ContextDecision &decision = *Tables[type];
@@ -1080,7 +1080,7 @@ void DisassemblerTables::setTableFields(OpcodeType type,
bool adSize64 = addressSize == 64;
if (inheritsFrom((InstructionContext)index,
InstructionSpecifiers[uid].insnContext, noPrefix,
- ignoresVEX_L, ignoresVEX_W, adSize64))
+ ignoresVEX_L, ignoresW, adSize64))
setTableFields(decision.opcodeDecisions[index].modRMDecisions[opcode],
filter,
uid,
diff --git a/llvm/utils/TableGen/X86EVEX2VEXTablesEmitter.cpp b/llvm/utils/TableGen/X86EVEX2VEXTablesEmitter.cpp
index 1384330ee8a1..35792ab67a4f 100644
--- a/llvm/utils/TableGen/X86EVEX2VEXTablesEmitter.cpp
+++ b/llvm/utils/TableGen/X86EVEX2VEXTablesEmitter.cpp
@@ -15,6 +15,7 @@
#include "CodeGenTarget.h"
#include "X86RecognizableInstr.h"
#include "llvm/TableGen/Error.h"
+#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
using namespace llvm;
@@ -113,10 +114,10 @@ public:
bool operator()(const CodeGenInstruction *VEXInst) {
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 VEX_W = VEXRI.HasREX_W;
+ bool EVEX_W = EVEXRI.HasREX_W;
+ bool VEX_WIG = VEXRI.IgnoresW;
+ bool EVEX_WIG = EVEXRI.IgnoresW;
bool EVEX_W1_VEX_W0 = EVEXInst->TheDef->getValueAsBit("EVEX_W1_VEX_W0");
if (VEXRI.IsCodeGenOnly != EVEXRI.IsCodeGenOnly ||
@@ -237,10 +238,7 @@ void X86EVEX2VEXTablesEmitter::run(raw_ostream &OS) {
// Print CheckVEXInstPredicate function.
printCheckPredicate(EVEX2VEXPredicates, OS);
}
-}
+} // namespace
-namespace llvm {
-void EmitX86EVEX2VEXTables(RecordKeeper &RK, raw_ostream &OS) {
- X86EVEX2VEXTablesEmitter(RK).run(OS);
-}
-}
+static TableGen::Emitter::OptClass<X86EVEX2VEXTablesEmitter>
+ X("gen-x86-EVEX2VEX-tables", "Generate X86 EVEX to VEX compress tables");
diff --git a/llvm/utils/TableGen/X86FoldTablesEmitter.cpp b/llvm/utils/TableGen/X86FoldTablesEmitter.cpp
index 5b3f11848de6..89d93e4d3cbc 100644
--- a/llvm/utils/TableGen/X86FoldTablesEmitter.cpp
+++ b/llvm/utils/TableGen/X86FoldTablesEmitter.cpp
@@ -11,34 +11,24 @@
//
//===----------------------------------------------------------------------===//
+#include "CodeGenInstruction.h"
#include "CodeGenTarget.h"
#include "X86RecognizableInstr.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/FormattedStream.h"
-#include "llvm/TableGen/Error.h"
+#include "llvm/Support/X86FoldTablesUtils.h"
+#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
using namespace llvm;
using namespace X86Disassembler;
namespace {
-
-// 3 possible strategies for the unfolding flag (TB_NO_REVERSE) of the
-// manual added entries.
-enum UnfoldStrategy {
- UNFOLD, // Allow unfolding
- NO_UNFOLD, // Prevent unfolding
- NO_STRATEGY // Make decision according to operands' sizes
-};
-
// Represents an entry in the manual mapped instructions set.
struct ManualMapEntry {
const char *RegInstStr;
const char *MemInstStr;
- UnfoldStrategy Strategy;
-
- ManualMapEntry(const char *RegInstStr, const char *MemInstStr,
- UnfoldStrategy Strategy = NO_STRATEGY)
- : RegInstStr(RegInstStr), MemInstStr(MemInstStr), Strategy(Strategy) {}
+ uint16_t Strategy;
};
// List of instructions requiring explicitly aligned memory.
@@ -50,36 +40,15 @@ const char *ExplicitUnalign[] = {"MOVDQU", "MOVUPS", "MOVUPD",
"PCMPESTRM", "PCMPESTRI",
"PCMPISTRM", "PCMPISTRI" };
-// 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 },
- { "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 },
+#define ENTRY(REG, MEM, FLAGS) {#REG, #MEM, FLAGS},
+#include "X86ManualFoldTables.def"
};
+const std::set<StringRef> NoFoldSet= {
+#define NOFOLD(INSN) #INSN,
+#include "X86ManualFoldTables.def"
+};
static bool isExplicitAlign(const CodeGenInstruction *Inst) {
return any_of(ExplicitAlign, [Inst](const char *InstStr) {
@@ -103,51 +72,76 @@ class X86FoldTablesEmitter {
const CodeGenInstruction *MemInst;
public:
- bool CannotUnfold = false;
- bool IsLoad = false;
- bool IsStore = false;
- bool IsAligned = false;
- unsigned int Alignment = 0;
+ bool NoReverse = false;
+ bool NoForward = false;
+ bool FoldLoad = false;
+ bool FoldStore = false;
+ Align Alignment;
+ X86FoldTableEntry() = default;
X86FoldTableEntry(const CodeGenInstruction *RegInst,
const CodeGenInstruction *MemInst)
: RegInst(RegInst), MemInst(MemInst) {}
void print(formatted_raw_ostream &OS) const {
OS.indent(2);
- OS << "{ X86::" << RegInst->TheDef->getName() << ",";
- OS.PadToColumn(40);
- OS << "X86::" << MemInst->TheDef->getName() << ",";
- OS.PadToColumn(75);
+ OS << "{X86::" << RegInst->TheDef->getName() << ", ";
+ OS << "X86::" << MemInst->TheDef->getName() << ", ";
std::string Attrs;
- if (IsLoad)
- Attrs += "TB_FOLDED_LOAD | ";
- if (IsStore)
- Attrs += "TB_FOLDED_STORE | ";
- if (CannotUnfold)
- Attrs += "TB_NO_REVERSE | ";
- if (IsAligned)
- Attrs += "TB_ALIGN_" + std::to_string(Alignment) + " | ";
+ if (FoldLoad)
+ Attrs += "TB_FOLDED_LOAD|";
+ if (FoldStore)
+ Attrs += "TB_FOLDED_STORE|";
+ if (NoReverse)
+ Attrs += "TB_NO_REVERSE|";
+ if (NoForward)
+ Attrs += "TB_NO_FORWARD|";
+ if (Alignment != Align(1))
+ Attrs += "TB_ALIGN_" + std::to_string(Alignment.value()) + "|";
- StringRef SimplifiedAttrs = StringRef(Attrs).rtrim("| ");
+ StringRef SimplifiedAttrs = StringRef(Attrs).rtrim("|");
if (SimplifiedAttrs.empty())
SimplifiedAttrs = "0";
- OS << SimplifiedAttrs << " },\n";
+ OS << SimplifiedAttrs << "},\n";
}
- bool operator<(const X86FoldTableEntry &RHS) const {
- bool LHSpseudo = RegInst->TheDef->getValueAsBit("isPseudo");
- bool RHSpseudo = RHS.RegInst->TheDef->getValueAsBit("isPseudo");
- if (LHSpseudo != RHSpseudo)
- return LHSpseudo;
+#ifndef NDEBUG
+ // Check that Uses and Defs are same after memory fold.
+ void checkCorrectness() const {
+ auto &RegInstRec = *RegInst->TheDef;
+ auto &MemInstRec = *MemInst->TheDef;
+ auto ListOfUsesReg = RegInstRec.getValueAsListOfDefs("Uses");
+ auto ListOfUsesMem = MemInstRec.getValueAsListOfDefs("Uses");
+ auto ListOfDefsReg = RegInstRec.getValueAsListOfDefs("Defs");
+ auto ListOfDefsMem = MemInstRec.getValueAsListOfDefs("Defs");
+ if (ListOfUsesReg != ListOfUsesMem || ListOfDefsReg != ListOfDefsMem)
+ report_fatal_error("Uses/Defs couldn't be changed after folding " +
+ RegInstRec.getName() + " to " +
+ MemInstRec.getName());
+ }
+#endif
+ };
- return RegInst->TheDef->getName() < RHS.RegInst->TheDef->getName();
+ // NOTE: We check the fold tables are sorted in X86InstrFoldTables.cpp by the enum of the
+ // instruction, which is computed in CodeGenTarget::ComputeInstrsByEnum. So we should
+ // use the same comparator here.
+ // FIXME: Could we share the code with CodeGenTarget::ComputeInstrsByEnum?
+ struct CompareInstrsByEnum {
+ bool operator()(const CodeGenInstruction *LHS,
+ const CodeGenInstruction *RHS) const {
+ assert(LHS && RHS && "LHS and RHS shouldn't be nullptr");
+ const auto &D1 = *LHS->TheDef;
+ const auto &D2 = *RHS->TheDef;
+ return std::make_tuple(!D1.getValueAsBit("isPseudo"), D1.getName()) <
+ std::make_tuple(!D2.getValueAsBit("isPseudo"), D2.getName());
}
};
- typedef std::vector<X86FoldTableEntry> FoldTable;
+ typedef std::map<const CodeGenInstruction *, X86FoldTableEntry,
+ CompareInstrsByEnum>
+ FoldTable;
// std::vector for each folding table.
// Table2Addr - Holds instructions which their memory form performs load+store
// Table#i - Holds instructions which the their memory form perform a load OR
@@ -163,20 +157,20 @@ public:
X86FoldTablesEmitter(RecordKeeper &R) : Records(R), Target(R) {}
// run - Generate the 6 X86 memory fold tables.
- void run(formatted_raw_ostream &OS);
+ void run(raw_ostream &OS);
private:
// Decides to which table to add the entry with the given instructions.
// S sets the strategy of adding the TB_NO_REVERSE flag.
void updateTables(const CodeGenInstruction *RegInstr,
- const CodeGenInstruction *MemInstr,
- const UnfoldStrategy S = NO_STRATEGY);
+ const CodeGenInstruction *MemInstr, uint16_t S = 0,
+ bool IsManual = false);
// Generates X86FoldTableEntry with the given instructions and fill it with
// the appropriate flags - then adds it to Table.
void addEntryWithFlags(FoldTable &Table, const CodeGenInstruction *RegInstr,
- const CodeGenInstruction *MemInstr,
- const UnfoldStrategy S, const unsigned int FoldedInd);
+ const CodeGenInstruction *MemInstr, uint16_t S,
+ unsigned FoldedIdx, bool isManual);
// Print the given table as a static const C++ array of type
// X86MemoryFoldTableEntry.
@@ -185,8 +179,8 @@ private:
OS << "static const X86MemoryFoldTableEntry MemoryFold" << TableName
<< "[] = {\n";
- for (const X86FoldTableEntry &E : Table)
- E.print(OS);
+ for (auto &E : Table)
+ E.second.print(OS);
OS << "};\n\n";
}
@@ -206,76 +200,110 @@ static bool hasPtrTailcallRegClass(const CodeGenInstruction *Inst) {
});
}
-// Calculates the integer value representing the BitsInit object
-static inline uint64_t getValueFromBitsInit(const BitsInit *B) {
- assert(B->getNumBits() <= sizeof(uint64_t) * 8 && "BitInits' too long!");
+static uint8_t byteFromBitsInit(const BitsInit *B) {
+ unsigned N = B->getNumBits();
+ assert(N <= 8 && "Field is too large for uint8_t!");
- uint64_t Value = 0;
- for (unsigned i = 0, e = B->getNumBits(); i != e; ++i) {
- BitInit *Bit = cast<BitInit>(B->getBit(i));
- Value |= uint64_t(Bit->getValue()) << i;
+ uint8_t Value = 0;
+ for (unsigned I = 0; I != N; ++I) {
+ BitInit *Bit = cast<BitInit>(B->getBit(I));
+ Value |= Bit->getValue() << I;
}
return Value;
}
-// Return true if the instruction defined as a register flavor.
-static inline bool hasRegisterFormat(const Record *Inst) {
- const BitsInit *FormBits = Inst->getValueAsBitsInit("FormBits");
- uint64_t FormBitsNum = getValueFromBitsInit(FormBits);
-
- // Values from X86Local namespace defined in X86RecognizableInstr.cpp
- return FormBitsNum >= X86Local::MRMDestReg && FormBitsNum <= X86Local::MRM7r;
+static bool mayFoldFromForm(uint8_t Form) {
+ switch (Form) {
+ default:
+ return Form >= X86Local::MRM0r && Form <= X86Local::MRM7r;
+ case X86Local::MRMXr:
+ case X86Local::MRMXrCC:
+ case X86Local::MRMDestReg:
+ case X86Local::MRMSrcReg:
+ case X86Local::MRMSrcReg4VOp3:
+ case X86Local::MRMSrcRegOp4:
+ case X86Local::MRMSrcRegCC:
+ return true;
+ }
}
-// Return true if the instruction defined as a memory flavor.
-static inline bool hasMemoryFormat(const Record *Inst) {
- const BitsInit *FormBits = Inst->getValueAsBitsInit("FormBits");
- uint64_t FormBitsNum = getValueFromBitsInit(FormBits);
-
- // Values from X86Local namespace defined in X86RecognizableInstr.cpp
- return FormBitsNum >= X86Local::MRMDestMem && FormBitsNum <= X86Local::MRM7m;
+static bool mayFoldToForm(uint8_t Form) {
+ switch (Form) {
+ default:
+ return Form >= X86Local::MRM0m && Form <= X86Local::MRM7m;
+ case X86Local::MRMXm:
+ case X86Local::MRMXmCC:
+ case X86Local::MRMDestMem:
+ case X86Local::MRMSrcMem:
+ case X86Local::MRMSrcMem4VOp3:
+ case X86Local::MRMSrcMemOp4:
+ case X86Local::MRMSrcMemCC:
+ return true;
+ }
}
-static inline bool isNOREXRegClass(const Record *Op) {
- return Op->getName().contains("_NOREX");
+static bool mayFoldFromLeftToRight(uint8_t LHS, uint8_t RHS) {
+ switch (LHS) {
+ default:
+ llvm_unreachable("Unexpected Form!");
+ case X86Local::MRM0r:
+ return RHS == X86Local::MRM0m;
+ case X86Local::MRM1r:
+ return RHS == X86Local::MRM1m;
+ case X86Local::MRM2r:
+ return RHS == X86Local::MRM2m;
+ case X86Local::MRM3r:
+ return RHS == X86Local::MRM3m;
+ case X86Local::MRM4r:
+ return RHS == X86Local::MRM4m;
+ case X86Local::MRM5r:
+ return RHS == X86Local::MRM5m;
+ case X86Local::MRM6r:
+ return RHS == X86Local::MRM6m;
+ case X86Local::MRM7r:
+ return RHS == X86Local::MRM7m;
+ case X86Local::MRMXr:
+ return RHS == X86Local::MRMXm;
+ case X86Local::MRMXrCC:
+ return RHS == X86Local::MRMXmCC;
+ case X86Local::MRMDestReg:
+ return RHS == X86Local::MRMDestMem;
+ case X86Local::MRMSrcReg:
+ return RHS == X86Local::MRMSrcMem;
+ case X86Local::MRMSrcReg4VOp3:
+ return RHS == X86Local::MRMSrcMem4VOp3;
+ case X86Local::MRMSrcRegOp4:
+ return RHS == X86Local::MRMSrcMemOp4;
+ case X86Local::MRMSrcRegCC:
+ return RHS == X86Local::MRMSrcMemCC;
+ }
}
-// Get the alternative instruction pointed by "FoldGenRegForm" field.
-static inline const CodeGenInstruction *
-getAltRegInst(const CodeGenInstruction *I, const RecordKeeper &Records,
- const CodeGenTarget &Target) {
-
- StringRef AltRegInstStr = I->TheDef->getValueAsString("FoldGenRegForm");
- Record *AltRegInstRec = Records.getDef(AltRegInstStr);
- assert(AltRegInstRec &&
- "Alternative register form instruction def not found");
- CodeGenInstruction &AltRegInst = Target.getInstruction(AltRegInstRec);
- return &AltRegInst;
+static bool isNOREXRegClass(const Record *Op) {
+ return Op->getName().contains("_NOREX");
}
-// Function object - Operator() returns true if the given VEX instruction
-// matches the EVEX instruction of this object.
+// Function object - Operator() returns true if the given Reg instruction
+// matches the Mem instruction of this object.
class IsMatch {
const CodeGenInstruction *MemInst;
- unsigned Variant;
+ const X86Disassembler::RecognizableInstrBase MemRI;
+ const unsigned Variant;
public:
IsMatch(const CodeGenInstruction *Inst, unsigned V)
- : MemInst(Inst), Variant(V) {}
+ : MemInst(Inst), MemRI(*MemInst), Variant(V) {}
bool operator()(const CodeGenInstruction *RegInst) {
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)
+ if (RegRI.HasEVEX_B || MemRI.HasEVEX_B)
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))
+ if (!mayFoldFromLeftToRight(RegRI.Form, MemRI.Form))
return false;
// X86 encoding is crazy, e.g
@@ -288,38 +316,32 @@ public:
X86Disassembler::getMnemonic(RegInst, Variant))
return false;
- // Return false if one (at least) of the encoding fields of both
- // instructions do not match.
- 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("hasLockPrefix") !=
- MemRec->getValueAsBit("hasLockPrefix") ||
- RegRec->getValueAsBit("hasNoTrackPrefix") !=
- MemRec->getValueAsBit("hasNoTrackPrefix") ||
- RegRec->getValueAsBit("EVEX_W1_VEX_W0") !=
- MemRec->getValueAsBit("EVEX_W1_VEX_W0"))
+ // Return false if any of the following fields of does not match.
+ if (std::make_tuple(RegRI.Encoding, RegRI.Opcode, RegRI.OpPrefix,
+ RegRI.OpMap, RegRI.OpSize, RegRI.AdSize, RegRI.HasREX_W,
+ RegRI.HasVEX_4V, RegRI.HasVEX_L, RegRI.IgnoresVEX_L,
+ RegRI.IgnoresW, RegRI.HasEVEX_K, RegRI.HasEVEX_KZ,
+ RegRI.HasEVEX_L2, RegRec->getValueAsBit("hasEVEX_RC"),
+ RegRec->getValueAsBit("hasLockPrefix"),
+ RegRec->getValueAsBit("hasNoTrackPrefix"),
+ RegRec->getValueAsBit("EVEX_W1_VEX_W0")) !=
+ std::make_tuple(MemRI.Encoding, MemRI.Opcode, MemRI.OpPrefix,
+ MemRI.OpMap, MemRI.OpSize, MemRI.AdSize, MemRI.HasREX_W,
+ MemRI.HasVEX_4V, MemRI.HasVEX_L, MemRI.IgnoresVEX_L,
+ MemRI.IgnoresW, MemRI.HasEVEX_K, MemRI.HasEVEX_KZ,
+ MemRI.HasEVEX_L2, MemRec->getValueAsBit("hasEVEX_RC"),
+ MemRec->getValueAsBit("hasLockPrefix"),
+ MemRec->getValueAsBit("hasNoTrackPrefix"),
+ MemRec->getValueAsBit("EVEX_W1_VEX_W0")))
return false;
// Make sure the sizes of the operands of both instructions suit each other.
// This is needed for instructions with intrinsic version (_Int).
// Where the only difference is the size of the operands.
- // For example: VUCOMISDZrm and Int_VUCOMISDrm
+ // For example: VUCOMISDZrm and VUCOMISDrm_Int
// Also for instructions that their EVEX version was upgraded to work with
// k-registers. For example VPCMPEQBrm (xmm output register) and
// VPCMPEQBZ128rm (k register output register).
- bool ArgFolded = false;
unsigned MemOutSize = MemRec->getValueAsDag("OutOperandList")->getNumArgs();
unsigned RegOutSize = RegRec->getValueAsDag("OutOperandList")->getNumArgs();
unsigned MemInSize = MemRec->getValueAsDag("InOperandList")->getNumArgs();
@@ -330,59 +352,36 @@ public:
unsigned RegStartIdx =
(MemOutSize + 1 == RegOutSize) && (MemInSize == RegInSize) ? 1 : 0;
- for (unsigned i = 0, e = MemInst->Operands.size(); i < e; i++) {
- Record *MemOpRec = MemInst->Operands[i].Rec;
- Record *RegOpRec = RegInst->Operands[i + RegStartIdx].Rec;
+ bool FoundFoldedOp = false;
+ for (unsigned I = 0, E = MemInst->Operands.size(); I != E; I++) {
+ Record *MemOpRec = MemInst->Operands[I].Rec;
+ Record *RegOpRec = RegInst->Operands[I + RegStartIdx].Rec;
if (MemOpRec == RegOpRec)
continue;
- if (isRegisterOperand(MemOpRec) && isRegisterOperand(RegOpRec)) {
- if (getRegOperandSize(MemOpRec) != getRegOperandSize(RegOpRec) ||
- isNOREXRegClass(MemOpRec) != isNOREXRegClass(RegOpRec))
- return false;
- } else if (isMemoryOperand(MemOpRec) && isMemoryOperand(RegOpRec)) {
- if (getMemOperandSize(MemOpRec) != getMemOperandSize(RegOpRec))
- return false;
- } else if (isImmediateOperand(MemOpRec) && isImmediateOperand(RegOpRec)) {
- if (MemOpRec->getValueAsDef("Type") != RegOpRec->getValueAsDef("Type"))
- return false;
- } else {
- // Only one operand can be folded.
- if (ArgFolded)
- return false;
+ if (isRegisterOperand(MemOpRec) && isRegisterOperand(RegOpRec) &&
+ ((getRegOperandSize(MemOpRec) != getRegOperandSize(RegOpRec)) ||
+ (isNOREXRegClass(MemOpRec) != isNOREXRegClass(RegOpRec))))
+ return false;
- assert(isRegisterOperand(RegOpRec) && isMemoryOperand(MemOpRec));
- ArgFolded = true;
- }
- }
+ if (isMemoryOperand(MemOpRec) && isMemoryOperand(RegOpRec) &&
+ (getMemOperandSize(MemOpRec) != getMemOperandSize(RegOpRec)))
+ return false;
- return true;
- }
+ if (isImmediateOperand(MemOpRec) && isImmediateOperand(RegOpRec) &&
+ (MemOpRec->getValueAsDef("Type") != RegOpRec->getValueAsDef("Type")))
+ return false;
-private:
- // Return true of the 2 given forms are the opposite of each other.
- 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;
+ // Only one operand can be folded.
+ if (FoundFoldedOp)
+ return false;
- return false;
+ assert(isRegisterOperand(RegOpRec) && isMemoryOperand(MemOpRec));
+ FoundFoldedOp = true;
+ }
+
+ return FoundFoldedOp;
}
};
@@ -391,13 +390,23 @@ private:
void X86FoldTablesEmitter::addEntryWithFlags(FoldTable &Table,
const CodeGenInstruction *RegInstr,
const CodeGenInstruction *MemInstr,
- const UnfoldStrategy S,
- const unsigned int FoldedInd) {
+ uint16_t S, unsigned FoldedIdx,
+ bool isManual) {
X86FoldTableEntry Result = X86FoldTableEntry(RegInstr, MemInstr);
Record *RegRec = RegInstr->TheDef;
Record *MemRec = MemInstr->TheDef;
+ if (isManual) {
+ Result.NoReverse = S & TB_NO_REVERSE;
+ Result.NoForward = S & TB_NO_FORWARD;
+ Result.FoldLoad = S & TB_FOLDED_LOAD;
+ Result.FoldStore = S & TB_FOLDED_STORE;
+ Result.Alignment = Align(1ULL << ((S & TB_ALIGN_MASK) >> TB_ALIGN_SHIFT));
+ Table[RegInstr] = Result;
+ return;
+ }
+
// Only table0 entries should explicitly specify a load or store flag.
if (&Table == &Table0) {
unsigned MemInOpsNum = MemRec->getValueAsDag("InOperandList")->getNumArgs();
@@ -408,48 +417,62 @@ void X86FoldTablesEmitter::addEntryWithFlags(FoldTable &Table,
// If the instruction reads from the folded operand, it well appear as in
// input in both forms.
if (MemInOpsNum == RegInOpsNum)
- Result.IsLoad = true;
+ Result.FoldLoad = true;
else
- Result.IsStore = true;
+ Result.FoldStore = true;
}
- Record *RegOpRec = RegInstr->Operands[FoldedInd].Rec;
- Record *MemOpRec = MemInstr->Operands[FoldedInd].Rec;
+ Record *RegOpRec = RegInstr->Operands[FoldedIdx].Rec;
+ Record *MemOpRec = MemInstr->Operands[FoldedIdx].Rec;
// Unfolding code generates a load/store instruction according to the size of
// the register in the register form instruction.
// If the register's size is greater than the memory's operand size, do not
// allow unfolding.
- if (S == UNFOLD)
- Result.CannotUnfold = false;
- else if (S == NO_UNFOLD)
- Result.CannotUnfold = true;
- else if (getRegOperandSize(RegOpRec) > getMemOperandSize(MemOpRec))
- Result.CannotUnfold = true; // S == NO_STRATEGY
- uint64_t Enc = getValueFromBitsInit(RegRec->getValueAsBitsInit("OpEncBits"));
+ // the unfolded load size will be based on the register size. If that’s bigger
+ // than the memory operand size, the unfolded load will load more memory and
+ // potentially cause a memory fault.
+ if (getRegOperandSize(RegOpRec) > getMemOperandSize(MemOpRec))
+ Result.NoReverse = true;
+
+ // Check no-kz version's isMoveReg
+ StringRef RegInstName = RegRec->getName();
+ unsigned DropLen =
+ RegInstName.endswith("rkz") ? 2 : (RegInstName.endswith("rk") ? 1 : 0);
+ Record *BaseDef =
+ DropLen ? Records.getDef(RegInstName.drop_back(DropLen)) : nullptr;
+ bool IsMoveReg =
+ BaseDef ? Target.getInstruction(BaseDef).isMoveReg : RegInstr->isMoveReg;
+ // A masked load can not be unfolded to a full load, otherwise it would access
+ // unexpected memory. A simple store can not be unfolded.
+ if (IsMoveReg && (BaseDef || Result.FoldStore))
+ Result.NoReverse = true;
+
+ uint8_t Enc = byteFromBitsInit(RegRec->getValueAsBitsInit("OpEncBits"));
if (isExplicitAlign(RegInstr)) {
// The instruction require explicitly aligned memory.
BitsInit *VectSize = RegRec->getValueAsBitsInit("VectSize");
- uint64_t Value = getValueFromBitsInit(VectSize);
- Result.IsAligned = true;
- Result.Alignment = Value;
- } else if (Enc != X86Local::XOP && Enc != X86Local::VEX &&
- Enc != X86Local::EVEX) {
- // Instructions with VEX encoding do not require alignment.
- if (!isExplicitUnalign(RegInstr) && getMemOperandSize(MemOpRec) > 64) {
- // SSE packed vector instructions require a 16 byte alignment.
- Result.IsAligned = true;
- Result.Alignment = 16;
- }
+ Result.Alignment = Align(byteFromBitsInit(VectSize));
+ } else if (!Enc && !isExplicitUnalign(RegInstr) &&
+ getMemOperandSize(MemOpRec) > 64) {
+ // Instructions with XOP/VEX/EVEX encoding do not require alignment while
+ // SSE packed vector instructions require a 16 byte alignment.
+ Result.Alignment = Align(16);
}
+ // Expand is only ever created as a masked instruction. It is not safe to
+ // unfold a masked expand because we don't know if it came from an expand load
+ // intrinsic or folding a plain load. If it is from a expand load intrinsic,
+ // Unfolding to plain load would read more elements and could trigger a fault.
+ if (RegRec->getName().contains("EXPAND"))
+ Result.NoReverse = true;
- Table.push_back(Result);
+ Table[RegInstr] = Result;
}
void X86FoldTablesEmitter::updateTables(const CodeGenInstruction *RegInstr,
const CodeGenInstruction *MemInstr,
- const UnfoldStrategy S) {
+ uint16_t S, bool IsManual) {
Record *RegRec = RegInstr->TheDef;
Record *MemRec = MemInstr->TheDef;
@@ -459,8 +482,8 @@ void X86FoldTablesEmitter::updateTables(const CodeGenInstruction *RegInstr,
unsigned RegInSize = RegRec->getValueAsDag("InOperandList")->getNumArgs();
// Instructions which Read-Modify-Write should be added to Table2Addr.
- if (MemOutSize != RegOutSize && MemInSize == RegInSize) {
- addEntryWithFlags(Table2Addr, RegInstr, MemInstr, S, 0);
+ if (!MemOutSize && RegOutSize == 1 && MemInSize == RegInSize) {
+ addEntryWithFlags(Table2Addr, RegInstr, MemInstr, S, 0, IsManual);
return;
}
@@ -477,19 +500,19 @@ void X86FoldTablesEmitter::updateTables(const CodeGenInstruction *RegInstr,
isMemoryOperand(MemOpRec)) {
switch (i) {
case 0:
- addEntryWithFlags(Table0, RegInstr, MemInstr, S, 0);
+ addEntryWithFlags(Table0, RegInstr, MemInstr, S, 0, IsManual);
return;
case 1:
- addEntryWithFlags(Table1, RegInstr, MemInstr, S, 1);
+ addEntryWithFlags(Table1, RegInstr, MemInstr, S, 1, IsManual);
return;
case 2:
- addEntryWithFlags(Table2, RegInstr, MemInstr, S, 2);
+ addEntryWithFlags(Table2, RegInstr, MemInstr, S, 2, IsManual);
return;
case 3:
- addEntryWithFlags(Table3, RegInstr, MemInstr, S, 3);
+ addEntryWithFlags(Table3, RegInstr, MemInstr, S, 3, IsManual);
return;
case 4:
- addEntryWithFlags(Table4, RegInstr, MemInstr, S, 4);
+ addEntryWithFlags(Table4, RegInstr, MemInstr, S, 4, IsManual);
return;
}
}
@@ -506,12 +529,12 @@ void X86FoldTablesEmitter::updateTables(const CodeGenInstruction *RegInstr,
Record *MemOpRec = MemInstr->Operands[RegOutSize - 1].Rec;
if (isRegisterOperand(RegOpRec) && isMemoryOperand(MemOpRec) &&
getRegOperandSize(RegOpRec) == getMemOperandSize(MemOpRec))
- addEntryWithFlags(Table0, RegInstr, MemInstr, S, 0);
+ addEntryWithFlags(Table0, RegInstr, MemInstr, S, 0, IsManual);
}
}
-void X86FoldTablesEmitter::run(formatted_raw_ostream &OS) {
- emitSourceFileHeader("X86 fold tables", OS);
+void X86FoldTablesEmitter::run(raw_ostream &o) {
+ formatted_raw_ostream OS(o);
// Holds all memory instructions
std::vector<const CodeGenInstruction *> MemInsts;
@@ -526,7 +549,9 @@ void X86FoldTablesEmitter::run(formatted_raw_ostream &OS) {
if (!Rec->isSubClassOf("X86Inst") || Rec->getValueAsBit("isAsmParserOnly"))
continue;
- // - Do not proceed if the instruction is marked as notMemoryFoldable.
+ if (NoFoldSet.find(Rec->getName()) != NoFoldSet.end())
+ continue;
+
// - Instructions including RST register class operands are not relevant
// for memory folding (for further details check the explanation in
// lib/Target/X86/X86InstrFPStack.td file).
@@ -534,17 +559,18 @@ void X86FoldTablesEmitter::run(formatted_raw_ostream &OS) {
// class ptr_rc_tailcall, which can be of a size 32 or 64, to ensure
// safe mapping of these instruction we manually map them and exclude
// them from the automation.
- if (Rec->getValueAsBit("isMemoryFoldable") == false ||
- hasRSTRegClass(Inst) || hasPtrTailcallRegClass(Inst))
+ if (hasRSTRegClass(Inst) || hasPtrTailcallRegClass(Inst))
continue;
// Add all the memory form instructions to MemInsts, and all the register
- // form instructions to RegInsts[Opc], where Opc in the opcode of each
+ // form instructions to RegInsts[Opc], where Opc is the opcode of each
// instructions. this helps reducing the runtime of the backend.
- if (hasMemoryFormat(Rec))
+ const BitsInit *FormBits = Rec->getValueAsBitsInit("FormBits");
+ uint8_t Form = byteFromBitsInit(FormBits);
+ if (mayFoldToForm(Form))
MemInsts.push_back(Inst);
- else if (hasRegisterFormat(Rec)) {
- uint8_t Opc = getValueFromBitsInit(Rec->getValueAsBitsInit("Opcode"));
+ else if (mayFoldFromForm(Form)) {
+ uint8_t Opc = byteFromBitsInit(Rec->getValueAsBitsInit("Opcode"));
RegInsts[Opc].push_back(Inst);
}
}
@@ -555,7 +581,7 @@ void X86FoldTablesEmitter::run(formatted_raw_ostream &OS) {
// instruction.
for (const CodeGenInstruction *MemInst : MemInsts) {
uint8_t Opc =
- getValueFromBitsInit(MemInst->TheDef->getValueAsBitsInit("Opcode"));
+ byteFromBitsInit(MemInst->TheDef->getValueAsBitsInit("Opcode"));
auto RegInstsIt = RegInsts.find(Opc);
if (RegInstsIt == RegInsts.end())
@@ -569,16 +595,13 @@ void X86FoldTablesEmitter::run(formatted_raw_ostream &OS) {
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
- // memory form instruction to the register form instruction pointed by
- // this field
- if (RegInst->TheDef->isValueUnset("FoldGenRegForm")) {
- updateTables(RegInst, MemInst);
- } else {
- const CodeGenInstruction *AltRegInst =
- getAltRegInst(RegInst, Records, Target);
- updateTables(AltRegInst, MemInst);
+ StringRef RegInstName = RegInst->TheDef->getName();
+ if (RegInstName.endswith("_REV") || RegInstName.endswith("_alt")) {
+ if (auto *RegAltRec = Records.getDef(RegInstName.drop_back(4))) {
+ RegInst = &Target.getInstruction(RegAltRec);
+ }
}
+ updateTables(RegInst, MemInst);
OpcRegInsts.erase(Match);
}
}
@@ -589,17 +612,23 @@ void X86FoldTablesEmitter::run(formatted_raw_ostream &OS) {
Record *MemInstIter = Records.getDef(Entry.MemInstStr);
updateTables(&(Target.getInstruction(RegInstIter)),
- &(Target.getInstruction(MemInstIter)), Entry.Strategy);
+ &(Target.getInstruction(MemInstIter)), Entry.Strategy, true);
}
- // Sort the tables before printing.
- llvm::sort(Table2Addr);
- llvm::sort(Table0);
- llvm::sort(Table1);
- llvm::sort(Table2);
- llvm::sort(Table3);
- llvm::sort(Table4);
-
+#ifndef NDEBUG
+ auto CheckMemFoldTable = [](const FoldTable &Table) -> void {
+ for (const auto &Record : Table) {
+ auto &FoldEntry = Record.second;
+ FoldEntry.checkCorrectness();
+ }
+ };
+ CheckMemFoldTable(Table2Addr);
+ CheckMemFoldTable(Table0);
+ CheckMemFoldTable(Table1);
+ CheckMemFoldTable(Table2);
+ CheckMemFoldTable(Table3);
+ CheckMemFoldTable(Table4);
+#endif
// Print all tables.
printTable(Table2Addr, "Table2Addr", OS);
printTable(Table0, "Table0", OS);
@@ -609,10 +638,5 @@ void X86FoldTablesEmitter::run(formatted_raw_ostream &OS) {
printTable(Table4, "Table4", OS);
}
-namespace llvm {
-
-void EmitX86FoldTables(RecordKeeper &RK, raw_ostream &o) {
- formatted_raw_ostream OS(o);
- X86FoldTablesEmitter(RK).run(OS);
-}
-} // namespace llvm
+static TableGen::Emitter::OptClass<X86FoldTablesEmitter>
+ X("gen-x86-fold-tables", "Generate X86 fold tables");
diff --git a/llvm/utils/TableGen/X86ManualFoldTables.def b/llvm/utils/TableGen/X86ManualFoldTables.def
new file mode 100644
index 000000000000..d949830b0988
--- /dev/null
+++ b/llvm/utils/TableGen/X86ManualFoldTables.def
@@ -0,0 +1,288 @@
+//===- X86ManualFoldTables.def ----------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+// \file
+// This file defines all the entries in X86 memory folding tables that need
+// special handling.
+//===----------------------------------------------------------------------===//
+
+#ifndef NOFOLD
+#define NOFOLD(INSN)
+#endif
+NOFOLD(BTC16rr)
+NOFOLD(BTC32rr)
+NOFOLD(BTC64rr)
+NOFOLD(BTR16rr)
+NOFOLD(BTR32rr)
+NOFOLD(BTR64rr)
+NOFOLD(BTS16rr)
+NOFOLD(BTS32rr)
+NOFOLD(BTS64rr)
+NOFOLD(VCOMPRESSPDZ128rrk)
+NOFOLD(VCOMPRESSPDZ256rrk)
+NOFOLD(VCOMPRESSPDZrrk)
+NOFOLD(VCOMPRESSPSZ128rrk)
+NOFOLD(VCOMPRESSPSZ256rrk)
+NOFOLD(VCOMPRESSPSZrrk)
+NOFOLD(VCVTPS2PHZ128rrk)
+NOFOLD(VCVTPS2PHZ256rrk)
+NOFOLD(VCVTPS2PHZrrk)
+NOFOLD(VEXTRACTF32x4Z256rrk)
+NOFOLD(VEXTRACTF32x4Zrrk)
+NOFOLD(VEXTRACTF32x8Zrrk)
+NOFOLD(VEXTRACTF64x2Z256rrk)
+NOFOLD(VEXTRACTF64x2Zrrk)
+NOFOLD(VEXTRACTF64x4Zrrk)
+NOFOLD(VEXTRACTI32x4Z256rrk)
+NOFOLD(VEXTRACTI32x4Zrrk)
+NOFOLD(VEXTRACTI32x8Zrrk)
+NOFOLD(VEXTRACTI64x2Z256rrk)
+NOFOLD(VEXTRACTI64x2Zrrk)
+NOFOLD(VEXTRACTI64x4Zrrk)
+NOFOLD(VMOVAPDZ128mrk)
+NOFOLD(VMOVAPDZ256mrk)
+NOFOLD(VMOVAPDZmrk)
+NOFOLD(VMOVAPSZ128mrk)
+NOFOLD(VMOVAPSZ256mrk)
+NOFOLD(VMOVAPSZmrk)
+NOFOLD(VMOVDQA32Z128mrk)
+NOFOLD(VMOVDQA32Z256mrk)
+NOFOLD(VMOVDQA32Zmrk)
+NOFOLD(VMOVDQA64Z128mrk)
+NOFOLD(VMOVDQA64Z256mrk)
+NOFOLD(VMOVDQA64Zmrk)
+NOFOLD(VMOVDQU16Z128mrk)
+NOFOLD(VMOVDQU16Z256mrk)
+NOFOLD(VMOVDQU16Zmrk)
+NOFOLD(VMOVDQU32Z128mrk)
+NOFOLD(VMOVDQU32Z256mrk)
+NOFOLD(VMOVDQU32Zmrk)
+NOFOLD(VMOVDQU64Z128mrk)
+NOFOLD(VMOVDQU64Z256mrk)
+NOFOLD(VMOVDQU64Zmrk)
+NOFOLD(VMOVDQU8Z128mrk)
+NOFOLD(VMOVDQU8Z256mrk)
+NOFOLD(VMOVDQU8Zmrk)
+NOFOLD(VMOVUPDZ128mrk)
+NOFOLD(VMOVUPDZ256mrk)
+NOFOLD(VMOVUPDZmrk)
+NOFOLD(VMOVUPSZ128mrk)
+NOFOLD(VMOVUPSZ256mrk)
+NOFOLD(VMOVUPSZmrk)
+NOFOLD(VPCOMPRESSBZ128rrk)
+NOFOLD(VPCOMPRESSBZ256rrk)
+NOFOLD(VPCOMPRESSBZrrk)
+NOFOLD(VPCOMPRESSDZ128rrk)
+NOFOLD(VPCOMPRESSDZ256rrk)
+NOFOLD(VPCOMPRESSDZrrk)
+NOFOLD(VPCOMPRESSQZ128rrk)
+NOFOLD(VPCOMPRESSQZ256rrk)
+NOFOLD(VPCOMPRESSQZrrk)
+NOFOLD(VPCOMPRESSWZ128rrk)
+NOFOLD(VPCOMPRESSWZ256rrk)
+NOFOLD(VPCOMPRESSWZrrk)
+NOFOLD(VPMOVDBZ128rrk)
+NOFOLD(VPMOVDBZ256rrk)
+NOFOLD(VPMOVDBZrrk)
+NOFOLD(VPMOVDWZ128rrk)
+NOFOLD(VPMOVDWZ256rrk)
+NOFOLD(VPMOVDWZrrk)
+NOFOLD(VPMOVQBZ128rrk)
+NOFOLD(VPMOVQBZ256rrk)
+NOFOLD(VPMOVQBZrrk)
+NOFOLD(VPMOVQDZ128rrk)
+NOFOLD(VPMOVQDZ256rrk)
+NOFOLD(VPMOVQDZrrk)
+NOFOLD(VPMOVQWZ128rrk)
+NOFOLD(VPMOVQWZ256rrk)
+NOFOLD(VPMOVQWZrrk)
+NOFOLD(VPMOVSDBZ128rrk)
+NOFOLD(VPMOVSDBZ256rrk)
+NOFOLD(VPMOVSDBZrrk)
+NOFOLD(VPMOVSDWZ128rrk)
+NOFOLD(VPMOVSDWZ256rrk)
+NOFOLD(VPMOVSDWZrrk)
+NOFOLD(VPMOVSQBZ128rrk)
+NOFOLD(VPMOVSQBZ256rrk)
+NOFOLD(VPMOVSQBZrrk)
+NOFOLD(VPMOVSQDZ128rrk)
+NOFOLD(VPMOVSQDZ256rrk)
+NOFOLD(VPMOVSQDZrrk)
+NOFOLD(VPMOVSQWZ128rrk)
+NOFOLD(VPMOVSQWZ256rrk)
+NOFOLD(VPMOVSQWZrrk)
+NOFOLD(VPMOVSWBZ128rrk)
+NOFOLD(VPMOVSWBZ256rrk)
+NOFOLD(VPMOVSWBZrrk)
+NOFOLD(VPMOVUSDBZ128rrk)
+NOFOLD(VPMOVUSDBZ256rrk)
+NOFOLD(VPMOVUSDBZrrk)
+NOFOLD(VPMOVUSDWZ128rrk)
+NOFOLD(VPMOVUSDWZ256rrk)
+NOFOLD(VPMOVUSDWZrrk)
+NOFOLD(VPMOVUSQBZ128rrk)
+NOFOLD(VPMOVUSQBZ256rrk)
+NOFOLD(VPMOVUSQBZrrk)
+NOFOLD(VPMOVUSQDZ128rrk)
+NOFOLD(VPMOVUSQDZ256rrk)
+NOFOLD(VPMOVUSQDZrrk)
+NOFOLD(VPMOVUSQWZ128rrk)
+NOFOLD(VPMOVUSQWZ256rrk)
+NOFOLD(VPMOVUSQWZrrk)
+NOFOLD(VPMOVUSWBZ128rrk)
+NOFOLD(VPMOVUSWBZ256rrk)
+NOFOLD(VPMOVUSWBZrrk)
+NOFOLD(VPMOVWBZ128rrk)
+NOFOLD(VPMOVWBZ256rrk)
+NOFOLD(VPMOVWBZrrk)
+NOFOLD(ARPL16rr)
+NOFOLD(BT16rr)
+NOFOLD(BT32rr)
+NOFOLD(BT64rr)
+NOFOLD(CMPXCHG16rr)
+NOFOLD(CMPXCHG32rr)
+NOFOLD(CMPXCHG64rr)
+NOFOLD(CMPXCHG8rr)
+NOFOLD(LLDT16r)
+NOFOLD(LMSW16r)
+NOFOLD(LTRr)
+NOFOLD(NOOPLr)
+NOFOLD(NOOPQr)
+NOFOLD(NOOPWr)
+NOFOLD(POP16rmr)
+NOFOLD(POP32rmr)
+NOFOLD(POP64rmr)
+NOFOLD(PUSH16rmr)
+NOFOLD(PUSH32rmr)
+NOFOLD(PUSH64rmr)
+NOFOLD(VCOMPRESSPDZ128rr)
+NOFOLD(VCOMPRESSPDZ256rr)
+NOFOLD(VCOMPRESSPDZrr)
+NOFOLD(VCOMPRESSPSZ128rr)
+NOFOLD(VCOMPRESSPSZ256rr)
+NOFOLD(VCOMPRESSPSZrr)
+NOFOLD(VERRr)
+NOFOLD(VERWr)
+NOFOLD(VMREAD32rr)
+NOFOLD(VMREAD64rr)
+NOFOLD(VPCOMPRESSBZ128rr)
+NOFOLD(VPCOMPRESSBZ256rr)
+NOFOLD(VPCOMPRESSBZrr)
+NOFOLD(VPCOMPRESSDZ128rr)
+NOFOLD(VPCOMPRESSDZ256rr)
+NOFOLD(VPCOMPRESSDZrr)
+NOFOLD(VPCOMPRESSQZ128rr)
+NOFOLD(VPCOMPRESSQZ256rr)
+NOFOLD(VPCOMPRESSQZrr)
+NOFOLD(VPCOMPRESSWZ128rr)
+NOFOLD(VPCOMPRESSWZ256rr)
+NOFOLD(VPCOMPRESSWZrr)
+NOFOLD(LAR16rr)
+NOFOLD(LAR32rr)
+NOFOLD(LAR64rr)
+NOFOLD(LSL16rr)
+NOFOLD(LSL32rr)
+NOFOLD(LSL64rr)
+NOFOLD(MOVSX16rr16)
+NOFOLD(MOVZX16rr16)
+NOFOLD(VMWRITE32rr)
+NOFOLD(VMWRITE64rr)
+NOFOLD(VBLENDMPDZ128rrkz)
+NOFOLD(VBLENDMPDZ256rrkz)
+NOFOLD(VBLENDMPDZrrkz)
+NOFOLD(VBLENDMPSZ128rrkz)
+NOFOLD(VBLENDMPSZ256rrkz)
+NOFOLD(VBLENDMPSZrrkz)
+NOFOLD(VPBLENDMBZ128rrkz)
+NOFOLD(VPBLENDMBZ256rrkz)
+NOFOLD(VPBLENDMBZrrkz)
+NOFOLD(VPBLENDMDZ128rrkz)
+NOFOLD(VPBLENDMDZ256rrkz)
+NOFOLD(VPBLENDMDZrrkz)
+NOFOLD(VPBLENDMQZ128rrkz)
+NOFOLD(VPBLENDMQZ256rrkz)
+NOFOLD(VPBLENDMQZrrkz)
+NOFOLD(VPBLENDMWZ128rrkz)
+NOFOLD(VPBLENDMWZ256rrkz)
+NOFOLD(VPBLENDMWZrrkz)
+NOFOLD(UD1Lr)
+NOFOLD(UD1Qr)
+NOFOLD(UD1Wr)
+// Exclude these two b/c they would conflict with {MMX_MOVD64from64rr, MMX_MOVQ64mr} in unfolding table
+NOFOLD(MMX_MOVQ64rr)
+NOFOLD(MMX_MOVQ64rr_REV)
+// INSERTPSrm has no count_s while INSERTPSrr has count_s.
+// count_s is to indicate which element in dst vector is inserted.
+// if count_s!=0, we can not fold INSERTPSrr into INSERTPSrm
+//
+// the following folding can happen when count_s==0
+// load xmm0, m32
+// insertpsrr xmm1, xmm0, imm
+// =>
+// insertpsrm xmm1, m32, imm
+NOFOLD(INSERTPSrr)
+#undef NOFOLD
+
+#ifndef ENTRY
+#define ENTRY(REG, MEM, FLAGS)
+#endif
+// The following entries are added manually b/c the encodings of reg form does not match the
+// encoding of memory form
+ENTRY(ADD16ri_DB, ADD16mi, TB_NO_REVERSE)
+ENTRY(ADD16rr_DB, ADD16mr, TB_NO_REVERSE)
+ENTRY(ADD32ri_DB, ADD32mi, TB_NO_REVERSE)
+ENTRY(ADD32rr_DB, ADD32mr, TB_NO_REVERSE)
+ENTRY(ADD64ri32_DB, ADD64mi32, TB_NO_REVERSE)
+ENTRY(ADD64rr_DB, ADD64mr, TB_NO_REVERSE)
+ENTRY(ADD8ri_DB, ADD8mi, TB_NO_REVERSE)
+ENTRY(ADD8rr_DB, ADD8mr, TB_NO_REVERSE)
+ENTRY(ADD16rr_DB, ADD16rm, TB_NO_REVERSE)
+ENTRY(ADD32rr_DB, ADD32rm, TB_NO_REVERSE)
+ENTRY(ADD64rr_DB, ADD64rm, TB_NO_REVERSE)
+ENTRY(ADD8rr_DB, ADD8rm, TB_NO_REVERSE)
+ENTRY(MMX_MOVD64from64rr, MMX_MOVQ64mr, TB_FOLDED_STORE)
+ENTRY(MMX_MOVD64grr, MMX_MOVD64mr, TB_FOLDED_STORE)
+ENTRY(MOV64toSDrr, MOV64mr, TB_FOLDED_STORE | TB_NO_REVERSE)
+ENTRY(MOVDI2SSrr, MOV32mr, TB_FOLDED_STORE | TB_NO_REVERSE)
+ENTRY(MOVPQIto64rr, MOVPQI2QImr, TB_FOLDED_STORE | TB_NO_REVERSE)
+ENTRY(MOVSDto64rr, MOVSDmr, TB_FOLDED_STORE | TB_NO_REVERSE)
+ENTRY(MOVSS2DIrr, MOVSSmr, TB_FOLDED_STORE)
+ENTRY(MOVLHPSrr, MOVHPSrm, TB_NO_REVERSE)
+ENTRY(PUSH16r, PUSH16rmm, TB_FOLDED_LOAD)
+ENTRY(PUSH32r, PUSH32rmm, TB_FOLDED_LOAD)
+ENTRY(PUSH64r, PUSH64rmm, TB_FOLDED_LOAD)
+ENTRY(TAILJMPr, TAILJMPm, TB_FOLDED_LOAD)
+ENTRY(TAILJMPr64, TAILJMPm64, TB_FOLDED_LOAD)
+ENTRY(TAILJMPr64_REX, TAILJMPm64_REX, TB_FOLDED_LOAD)
+ENTRY(TCRETURNri, TCRETURNmi, TB_FOLDED_LOAD | TB_NO_FORWARD)
+ENTRY(TCRETURNri64, TCRETURNmi64, TB_FOLDED_LOAD | TB_NO_FORWARD)
+ENTRY(VMOVLHPSZrr, VMOVHPSZ128rm, TB_NO_REVERSE)
+ENTRY(VMOVLHPSrr, VMOVHPSrm, TB_NO_REVERSE)
+ENTRY(VMOV64toSDZrr, MOV64mr, TB_FOLDED_STORE | TB_NO_REVERSE)
+ENTRY(VMOV64toSDrr, MOV64mr, TB_FOLDED_STORE | TB_NO_REVERSE)
+ENTRY(VMOVDI2SSZrr, MOV32mr, TB_FOLDED_STORE | TB_NO_REVERSE)
+ENTRY(VMOVDI2SSrr, MOV32mr, TB_FOLDED_STORE | TB_NO_REVERSE)
+ENTRY(VMOVPQIto64Zrr, VMOVPQI2QIZmr, TB_FOLDED_STORE | TB_NO_REVERSE)
+ENTRY(VMOVPQIto64rr, VMOVPQI2QImr, TB_FOLDED_STORE | TB_NO_REVERSE)
+ENTRY(VMOVSDto64Zrr, VMOVSDZmr, TB_FOLDED_STORE | TB_NO_REVERSE)
+ENTRY(VMOVSDto64rr, VMOVSDmr, TB_FOLDED_STORE | TB_NO_REVERSE)
+ENTRY(VMOVSS2DIZrr, VMOVSSZmr, TB_FOLDED_STORE)
+ENTRY(VMOVSS2DIrr, VMOVSSmr, TB_FOLDED_STORE)
+ENTRY(MMX_MOVD64to64rr, MMX_MOVQ64rm, 0)
+ENTRY(MOV64toPQIrr, MOVQI2PQIrm, TB_NO_REVERSE)
+ENTRY(MOV64toSDrr, MOVSDrm_alt, TB_NO_REVERSE)
+ENTRY(MOVDI2SSrr, MOVSSrm_alt, 0)
+ENTRY(VMOV64toPQIZrr, VMOVQI2PQIZrm, TB_NO_REVERSE)
+ENTRY(VMOV64toPQIrr, VMOVQI2PQIrm, TB_NO_REVERSE)
+ENTRY(VMOV64toSDZrr, VMOVSDZrm_alt, TB_NO_REVERSE)
+ENTRY(VMOV64toSDrr, VMOVSDrm_alt, TB_NO_REVERSE)
+ENTRY(VMOVDI2SSZrr, VMOVSSZrm_alt, 0)
+ENTRY(VMOVDI2SSrr, VMOVSSrm_alt, 0)
+ENTRY(MOVSDrr, MOVLPDrm, TB_NO_REVERSE)
+ENTRY(VMOVSDZrr, VMOVLPDZ128rm, TB_NO_REVERSE)
+ENTRY(VMOVSDrr, VMOVLPDrm, TB_NO_REVERSE)
+#undef ENTRY
diff --git a/llvm/utils/TableGen/X86MnemonicTables.cpp b/llvm/utils/TableGen/X86MnemonicTables.cpp
index f405e051e355..aeafee157462 100644
--- a/llvm/utils/TableGen/X86MnemonicTables.cpp
+++ b/llvm/utils/TableGen/X86MnemonicTables.cpp
@@ -14,7 +14,7 @@
#include "CodeGenInstruction.h"
#include "CodeGenTarget.h"
#include "X86RecognizableInstr.h"
-#include "llvm/TableGen/Error.h"
+#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
using namespace llvm;
@@ -87,8 +87,5 @@ void X86MnemonicTablesEmitter::run(raw_ostream &OS) {
} // namespace
-namespace llvm {
-void EmitX86MnemonicTables(RecordKeeper &RK, raw_ostream &OS) {
- X86MnemonicTablesEmitter(RK).run(OS);
-}
-} // namespace llvm
+static TableGen::Emitter::OptClass<X86MnemonicTablesEmitter>
+ X("gen-x86-mnemonic-tables", "Generate X86 mnemonic tables");
diff --git a/llvm/utils/TableGen/X86ModRMFilters.h b/llvm/utils/TableGen/X86ModRMFilters.h
index e2d0907b4f8b..d2169a8e879b 100644
--- a/llvm/utils/TableGen/X86ModRMFilters.h
+++ b/llvm/utils/TableGen/X86ModRMFilters.h
@@ -17,7 +17,7 @@
#ifndef LLVM_UTILS_TABLEGEN_X86MODRMFILTERS_H
#define LLVM_UTILS_TABLEGEN_X86MODRMFILTERS_H
-#include "llvm/Support/DataTypes.h"
+#include <cstdint>
namespace llvm {
diff --git a/llvm/utils/TableGen/X86RecognizableInstr.cpp b/llvm/utils/TableGen/X86RecognizableInstr.cpp
index e5c1e53936f6..b2f51ba01689 100644
--- a/llvm/utils/TableGen/X86RecognizableInstr.cpp
+++ b/llvm/utils/TableGen/X86RecognizableInstr.cpp
@@ -118,8 +118,7 @@ RecognizableInstrBase::RecognizableInstrBase(const CodeGenInstruction &insn) {
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");
+ IgnoresW = Rec->getValueAsBit("IgnoresW");
IgnoresVEX_L = Rec->getValueAsBit("ignoresVEX_L");
HasEVEX_L2 = Rec->getValueAsBit("hasEVEX_L2");
HasEVEX_K = Rec->getValueAsBit("hasEVEX_K");
@@ -189,7 +188,7 @@ InstructionContext RecognizableInstr::insnContext() const {
llvm_unreachable("Don't support VEX.L if EVEX_L2 is enabled");
}
// VEX_L & VEX_W
- if (!EncodeRC && HasVEX_L && HasVEX_W) {
+ if (!EncodeRC && HasVEX_L && HasREX_W) {
if (OpPrefix == X86Local::PD)
insnContext = EVEX_KB(IC_EVEX_L_W_OPSIZE);
else if (OpPrefix == X86Local::XS)
@@ -216,7 +215,7 @@ InstructionContext RecognizableInstr::insnContext() const {
errs() << "Instruction does not use a prefix: " << Name << "\n";
llvm_unreachable("Invalid prefix");
}
- } else if (!EncodeRC && HasEVEX_L2 && HasVEX_W) {
+ } else if (!EncodeRC && HasEVEX_L2 && HasREX_W) {
// EVEX_L2 & VEX_W
if (OpPrefix == X86Local::PD)
insnContext = EVEX_KB(IC_EVEX_L2_W_OPSIZE);
@@ -245,7 +244,7 @@ InstructionContext RecognizableInstr::insnContext() const {
llvm_unreachable("Invalid prefix");
}
}
- else if (HasVEX_W) {
+ else if (HasREX_W) {
// VEX_W
if (OpPrefix == X86Local::PD)
insnContext = EVEX_KB(IC_EVEX_W_OPSIZE);
@@ -275,7 +274,7 @@ InstructionContext RecognizableInstr::insnContext() const {
}
/// eof EVEX
} else if (Encoding == X86Local::VEX || Encoding == X86Local::XOP) {
- if (HasVEX_L && HasVEX_W) {
+ if (HasVEX_L && HasREX_W) {
if (OpPrefix == X86Local::PD)
insnContext = IC_VEX_L_W_OPSIZE;
else if (OpPrefix == X86Local::XS)
@@ -290,7 +289,7 @@ InstructionContext RecognizableInstr::insnContext() const {
}
} else if (OpPrefix == X86Local::PD && HasVEX_L)
insnContext = IC_VEX_L_OPSIZE;
- else if (OpPrefix == X86Local::PD && HasVEX_W)
+ else if (OpPrefix == X86Local::PD && HasREX_W)
insnContext = IC_VEX_W_OPSIZE;
else if (OpPrefix == X86Local::PD)
insnContext = IC_VEX_OPSIZE;
@@ -298,11 +297,11 @@ InstructionContext RecognizableInstr::insnContext() const {
insnContext = IC_VEX_L_XS;
else if (HasVEX_L && OpPrefix == X86Local::XD)
insnContext = IC_VEX_L_XD;
- else if (HasVEX_W && OpPrefix == X86Local::XS)
+ else if (HasREX_W && OpPrefix == X86Local::XS)
insnContext = IC_VEX_W_XS;
- else if (HasVEX_W && OpPrefix == X86Local::XD)
+ else if (HasREX_W && OpPrefix == X86Local::XD)
insnContext = IC_VEX_W_XD;
- else if (HasVEX_W && OpPrefix == X86Local::PS)
+ else if (HasREX_W && OpPrefix == X86Local::PS)
insnContext = IC_VEX_W;
else if (HasVEX_L && OpPrefix == X86Local::PS)
insnContext = IC_VEX_L;
@@ -532,7 +531,7 @@ void RecognizableInstr::emitInstructionSpecifier() {
// Operand 3 (optional) is an immediate.
assert(numPhysicalOperands >= 2 + additionalOperands &&
numPhysicalOperands <= 3 + additionalOperands &&
- "Unexpected number of operands for MRMDestRegFrm");
+ "Unexpected number of operands for MRMDestReg");
HANDLE_OPERAND(rmRegister)
if (HasEVEX_K)
@@ -883,11 +882,11 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const {
tables.setTableFields(*opcodeType, insnContext(), currentOpcode, *filter,
UID, Is32Bit, OpPrefix == 0,
IgnoresVEX_L || EncodeRC,
- IgnoresVEX_W, AddressSize);
+ IgnoresW, AddressSize);
} else {
tables.setTableFields(*opcodeType, insnContext(), opcodeToSet, *filter, UID,
Is32Bit, OpPrefix == 0, IgnoresVEX_L || EncodeRC,
- IgnoresVEX_W, AddressSize);
+ IgnoresW, AddressSize);
}
#undef MAP
@@ -955,6 +954,9 @@ OperandType RecognizableInstr::typeFromString(const std::string &s,
TYPE("i128mem", TYPE_M)
TYPE("i256mem", TYPE_M)
TYPE("i512mem", TYPE_M)
+ TYPE("i512mem_GR16", TYPE_M)
+ TYPE("i512mem_GR32", TYPE_M)
+ TYPE("i512mem_GR64", TYPE_M)
TYPE("i64i32imm_brtarget", TYPE_REL)
TYPE("i16imm_brtarget", TYPE_REL)
TYPE("i32imm_brtarget", TYPE_REL)
@@ -1221,6 +1223,9 @@ RecognizableInstr::memoryEncodingFromString(const std::string &s,
ENCODING("i128mem", ENCODING_RM)
ENCODING("i256mem", ENCODING_RM)
ENCODING("i512mem", ENCODING_RM)
+ ENCODING("i512mem_GR16", ENCODING_RM)
+ ENCODING("i512mem_GR32", ENCODING_RM)
+ ENCODING("i512mem_GR64", ENCODING_RM)
ENCODING("f80mem", ENCODING_RM)
ENCODING("lea64_32mem", ENCODING_RM)
ENCODING("lea64mem", ENCODING_RM)
diff --git a/llvm/utils/TableGen/X86RecognizableInstr.h b/llvm/utils/TableGen/X86RecognizableInstr.h
index ea56a9d7d994..5efacdb27465 100644
--- a/llvm/utils/TableGen/X86RecognizableInstr.h
+++ b/llvm/utils/TableGen/X86RecognizableInstr.h
@@ -17,8 +17,10 @@
#define LLVM_UTILS_TABLEGEN_X86RECOGNIZABLEINSTR_H
#include "CodeGenInstruction.h"
-#include "llvm/Support/DataTypes.h"
#include "llvm/Support/X86DisassemblerDecoderCommon.h"
+#include <cstdint>
+#include <string>
+#include <vector>
struct InstructionSpecifier;
@@ -180,10 +182,8 @@ struct RecognizableInstrBase {
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;
+ /// The IgnoresW field from the record
+ bool IgnoresW;
/// The hasVEX_L field from the record
bool HasVEX_L;
/// The ignoreVEX_L field from the record