[llvm] 908d0d5 - [TableGen][GlobalISel] Add Generic MatchTableExecutor Emitter
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 11 00:42:48 PDT 2023
Author: pvanhout
Date: 2023-07-11T09:42:35+02:00
New Revision: 908d0d54b82deef971754bbf3e67fb6bf72f6193
URL: https://github.com/llvm/llvm-project/commit/908d0d54b82deef971754bbf3e67fb6bf72f6193
DIFF: https://github.com/llvm/llvm-project/commit/908d0d54b82deef971754bbf3e67fb6bf72f6193.diff
LOG: [TableGen][GlobalISel] Add Generic MatchTableExecutor Emitter
Move all of the reusable logic out of `GlobalISelEmitter.cpp` into a `GlobalISelMatchTableExecutorEmitter` class so the future combiner backend can use it as well.
Depends on D153755
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D153756
Added:
llvm/utils/TableGen/GlobalISelMatchTableExecutorEmitter.cpp
llvm/utils/TableGen/GlobalISelMatchTableExecutorEmitter.h
Modified:
llvm/test/TableGen/GlobalISelEmitter.td
llvm/test/TableGen/GlobalISelEmitterCustomPredicate.td
llvm/utils/TableGen/CMakeLists.txt
llvm/utils/TableGen/GlobalISelEmitter.cpp
llvm/utils/TableGen/SubtargetFeatureInfo.cpp
llvm/utils/TableGen/SubtargetFeatureInfo.h
Removed:
################################################################################
diff --git a/llvm/test/TableGen/GlobalISelEmitter.td b/llvm/test/TableGen/GlobalISelEmitter.td
index a2284513cfb752..ddd757e1018a4a 100644
--- a/llvm/test/TableGen/GlobalISelEmitter.td
+++ b/llvm/test/TableGen/GlobalISelEmitter.td
@@ -88,6 +88,17 @@ def HasC : Predicate<"Subtarget->hasC()"> { let RecomputePerFunction = 1; }
// CHECK-NEXT: ExecInfo(TypeObjects, NumTypeObjects, FeatureBitsets, ComplexPredicateFns, CustomRenderers)
// CHECK-NEXT: #endif // ifdef GET_GLOBALISEL_TEMPORARIES_INIT
+// CHECK-LABEL: // LLT Objects.
+// CHECK-NEXT: enum {
+// CHECK-NEXT: GILLT_p0s32
+// CHECK-NEXT: GILLT_s32,
+// CHECK-NEXT: }
+// CHECK-NEXT: const static size_t NumTypeObjects = 2;
+// CHECK-NEXT: const static LLT TypeObjects[] = {
+// CHECK-NEXT: LLT::pointer(0, 32),
+// CHECK-NEXT: LLT::scalar(32),
+// CHECK-NEXT: };
+
// CHECK-LABEL: enum SubtargetFeatureBits : uint8_t {
// CHECK-NEXT: Feature_HasABit = 0,
// CHECK-NEXT: Feature_HasBBit = 1,
@@ -112,17 +123,6 @@ def HasC : Predicate<"Subtarget->hasC()"> { let RecomputePerFunction = 1; }
// CHECK-NEXT: return Features;
// CHECK-NEXT: }
-// CHECK-LABEL: // LLT Objects.
-// CHECK-NEXT: enum {
-// CHECK-NEXT: GILLT_p0s32
-// CHECK-NEXT: GILLT_s32,
-// CHECK-NEXT: }
-// CHECK-NEXT: const static size_t NumTypeObjects = 2;
-// CHECK-NEXT: const static LLT TypeObjects[] = {
-// CHECK-NEXT: LLT::pointer(0, 32),
-// CHECK-NEXT: LLT::scalar(32),
-// CHECK-NEXT: };
-
// CHECK-LABEL: // Feature bitsets.
// CHECK-NEXT: enum {
// CHECK-NEXT: GIFBS_Invalid,
@@ -142,24 +142,31 @@ def HasC : Predicate<"Subtarget->hasC()"> { let RecomputePerFunction = 1; }
// CHECK-NEXT: GICP_gi_complex_rr,
// CHECK-NEXT: };
+// CHECK-LABEL: MyTargetInstructionSelector::ComplexMatcherMemFn
+// CHECK-NEXT: MyTargetInstructionSelector::ComplexPredicateFns[] = {
+// CHECK-NEXT: nullptr, // GICP_Invalid
+// CHECK-NEXT: &MyTargetInstructionSelector::selectComplexPattern, // gi_complex
+// CHECK-NEXT: &MyTargetInstructionSelector::selectComplexPatternRR, // gi_complex_rr
+// CHECK-NEXT: }
+
+// CHECK-LABEL: // PatFrag predicates.
+// CHECK-NEXT: enum {
+// CHECK-NEXT: GICXXPred_MI_Predicate_frag = GICXXPred_MI_Invalid + 1,
+// CHECK-NEXT: };
+
// CHECK-LABEL: // PatFrag predicates.
// CHECK-NEXT: enum {
// CHECK-NEXT: GICXXPred_I64_Predicate_cimm8 = GICXXPred_I64_Invalid + 1,
// CHECK-NEXT: GICXXPred_I64_Predicate_simm8,
// CHECK-NEXT: };
-
// CHECK-NEXT: bool MyTargetInstructionSelector::testImmPredicate_I64(unsigned PredicateID, int64_t Imm) const {
// CHECK-NEXT: switch (PredicateID) {
// CHECK-NEXT: case GICXXPred_I64_Predicate_cimm8: {
// CHECK-NEXT: return isInt<8>(Imm);
-// CHECK-NEXT: llvm_unreachable("ImmediateCode should have returned");
-// CHECK-NEXT: return false;
// CHECK-NEXT: }
// CHECK-NEXT: case GICXXPred_I64_Predicate_simm8: {
-// CHECK-NEXT: return isInt<8>(Imm);
-// CHECK-NEXT: llvm_unreachable("ImmediateCode should have returned");
-// CHECK-NEXT: return false;
+// CHECK-NEXT: return isInt<8>(Imm);
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: llvm_unreachable("Unknown predicate");
@@ -174,8 +181,6 @@ def HasC : Predicate<"Subtarget->hasC()"> { let RecomputePerFunction = 1; }
// CHECK-NEXT: switch (PredicateID) {
// CHECK-NEXT: case GICXXPred_APFloat_Predicate_fpimmz: {
// CHECK-NEXT: return Imm->isExactlyValue(0.0);
-// CHECK-NEXT: llvm_unreachable("ImmediateCode should have returned");
-// CHECK-NEXT: return false;
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: llvm_unreachable("Unknown predicate");
@@ -190,21 +195,12 @@ def HasC : Predicate<"Subtarget->hasC()"> { let RecomputePerFunction = 1; }
// CHECK-NEXT: switch (PredicateID) {
// CHECK-NEXT: case GICXXPred_APInt_Predicate_simm9: {
// CHECK-NEXT: return isInt<9>(Imm->getSExtValue());
-// CHECK-NEXT: llvm_unreachable("ImmediateCode should have returned");
-// CHECK-NEXT: return false;
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: llvm_unreachable("Unknown predicate");
// CHECK-NEXT: return false;
// CHECK-NEXT: }
-// CHECK-LABEL: MyTargetInstructionSelector::ComplexMatcherMemFn
-// CHECK-NEXT: MyTargetInstructionSelector::ComplexPredicateFns[] = {
-// CHECK-NEXT: nullptr, // GICP_Invalid
-// CHECK-NEXT: &MyTargetInstructionSelector::selectComplexPattern, // gi_complex
-// CHECK-NEXT: &MyTargetInstructionSelector::selectComplexPatternRR, // gi_complex_rr
-// CHECK-NEXT: }
-
// CHECK-LABEL: // Custom renderers.
// CHECK-NEXT: enum {
// CHECK-NEXT: GICR_Invalid,
@@ -217,8 +213,7 @@ def HasC : Predicate<"Subtarget->hasC()"> { let RecomputePerFunction = 1; }
// CHECK-NEXT: };
// CHECK: bool MyTargetInstructionSelector::selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const {
-// CHECK-NEXT: MachineFunction &MF = *I.getParent()->getParent();
-// CHECK-NEXT: MachineRegisterInfo &MRI = MF.getRegInfo();
+// CHECK-NEXT: MachineRegisterInfo &MRI = MF->getRegInfo();
// CHECK-NEXT: const PredicateBitset AvailableFeatures = getAvailableFeatures();
// CHECK-NEXT: NewMIVector OutMIs;
// CHECK-NEXT: State.MIs.clear();
diff --git a/llvm/test/TableGen/GlobalISelEmitterCustomPredicate.td b/llvm/test/TableGen/GlobalISelEmitterCustomPredicate.td
index 49e8f4fdfe7de7..b0cbd2e103320f 100644
--- a/llvm/test/TableGen/GlobalISelEmitterCustomPredicate.td
+++ b/llvm/test/TableGen/GlobalISelEmitterCustomPredicate.td
@@ -14,13 +14,13 @@
//
// CHECK: bool MyTargetInstructionSelector::testMIPredicate_MI(
// CHECK: case GICXXPred_MI_Predicate_and_or_pat: {
-// CHECK: llvm_unreachable("GISelPredicateCode should have returned");
+// CHECK: return doesComplexCheck(MI);
// CHECK: case GICXXPred_MI_Predicate_or_oneuse: {
-// CHECK: llvm_unreachable("GISelPredicateCode should have returned");
+// CHECK: return MRI.hasOneNonDBGUse(MI.getOperand(0).getReg());
// CHECK: case GICXXPred_MI_Predicate_patfrags_test_pat: {
-// CHECK: llvm_unreachable("GISelPredicateCode should have returned");
+// CHECK: return doesComplexCheck(MI);
// CHECK: case GICXXPred_MI_Predicate_sub3_pat: {
-// CHECK: llvm_unreachable("GISelPredicateCode should have returned");
+// CHECK: return doesComplexCheck(MI);
include "llvm/Target/Target.td"
include "GlobalISelEmitterCommon.td"
diff --git a/llvm/utils/TableGen/CMakeLists.txt b/llvm/utils/TableGen/CMakeLists.txt
index 53aeb8c22d314d..bf5d2cc56c934c 100644
--- a/llvm/utils/TableGen/CMakeLists.txt
+++ b/llvm/utils/TableGen/CMakeLists.txt
@@ -62,6 +62,7 @@ add_tablegen(llvm-tblgen LLVM
GICombinerEmitter.cpp
GlobalISelEmitter.cpp
GlobalISelMatchTable.cpp
+ GlobalISelMatchTableExecutorEmitter.cpp
InfoByHwMode.cpp
InstrInfoEmitter.cpp
InstrDocsEmitter.cpp
diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp
index 59fa2833b05d9f..c7d3b06f1b497f 100644
--- a/llvm/utils/TableGen/GlobalISelEmitter.cpp
+++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp
@@ -35,6 +35,7 @@
#include "CodeGenRegisters.h"
#include "CodeGenTarget.h"
#include "GlobalISelMatchTable.h"
+#include "GlobalISelMatchTableExecutorEmitter.h"
#include "InfoByHwMode.h"
#include "SubtargetFeatureInfo.h"
#include "llvm/ADT/Statistic.h"
@@ -298,17 +299,32 @@ 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;
+
+ 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.
@@ -329,9 +345,6 @@ class GlobalISelEmitter {
/// 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;
@@ -392,16 +405,6 @@ class GlobalISelEmitter {
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);
@@ -448,6 +451,8 @@ class GlobalISelEmitter {
InstructionMatcher &InsnMatcher, bool &HasAddedMatcher);
};
+StringRef getPatFragPredicateEnumName(Record *R) { return R->getName(); }
+
void GlobalISelEmitter::gatherOpcodeValues() {
InstructionOpcodeMatcher::initOpcodeValuesMap(Target);
}
@@ -507,8 +512,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 ------------------------------------------------------------===//
@@ -2215,78 +2222,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 =
- (" = GICXXPred_" + TypeIdentifier + "_Invalid + 1,\n").str();
- for (const auto *Record : MatchedRecords) {
- OS << " GICXXPred_" << 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 GICXXPred_" << 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 MatcherState &State",
- " const MachineFunction &MF = *MI.getParent()->getParent();\n"
- " const MachineRegisterInfo &MRI = MF.getRegInfo();\n"
- " const auto &Operands = State.RecordedOperands;\n"
- " (void)Operands;\n"
- " (void)MRI;",
- [](const Record *R) { return true; });
-}
-
MatchTable
GlobalISelEmitter::buildMatchTable(MutableArrayRef<RuleMatcher> Rules,
bool Optimize, bool WithCoverage) {
@@ -2329,6 +2264,88 @@ GlobalISelEmitter::buildMatchTable(MutableArrayRef<RuleMatcher> Rules,
return MatchTable::buildTable(OptRules, WithCoverage);
}
+void GlobalISelEmitter::emitAdditionalImpl(raw_ostream &OS) {
+ OS << "bool " << getClassName()
+ << "::selectImpl(MachineInstr &I, CodeGenCoverage "
+ "&CoverageInfo) const {\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, ExecInfo"
+ << ", getMatchTable(), TII, MRI, 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::run(raw_ostream &OS) {
if (!UseCoverageFile.empty()) {
RuleCoverage = CodeGenCoverage();
@@ -2352,6 +2369,8 @@ void GlobalISelEmitter::run(raw_ostream &OS) {
// Track the GINodeEquiv definitions.
gatherNodeEquivs();
+ AllPatFrags = RK.getAllDerivedDefinitions("PatFrags");
+
emitSourceFileHeader(
("Global Instruction Selector for the " + Target.getName() + " target")
.str(),
@@ -2407,205 +2426,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 ExecInfoTy<PredicateBitset, ComplexMatcherMemFn, "
- "CustomRendererFn> "
- "ExecInfo;\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 MatcherState &State) "
- "const override;\n"
- << "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_DECL\n\n";
-
- OS << "#ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n"
- << ", State(" << MaxTemporaries << "),\n"
- << "ExecInfo(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()];
@@ -2622,53 +2449,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, ExecInfo"
- << ", 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) {
diff --git a/llvm/utils/TableGen/GlobalISelMatchTableExecutorEmitter.cpp b/llvm/utils/TableGen/GlobalISelMatchTableExecutorEmitter.cpp
new file mode 100644
index 00000000000000..46c95f22649bb3
--- /dev/null
+++ b/llvm/utils/TableGen/GlobalISelMatchTableExecutorEmitter.cpp
@@ -0,0 +1,262 @@
+//===- 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);
+ emitCustomOperandRenderers(OS, CustomOperandRenderers);
+ emitAdditionalImpl(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";
+ 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 00000000000000..d1573da290ed1b
--- /dev/null
+++ b/llvm/utils/TableGen/GlobalISelMatchTableExecutorEmitter.h
@@ -0,0 +1,227 @@
+//===- 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";
+ std::string EnumeratorSeparator =
+ (" = GICXXPred_" + TypeIdentifier + "_Invalid + 1,\n").str();
+ 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";
+ }
+ if (!Predicates.empty())
+ 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;
+
+ 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/SubtargetFeatureInfo.cpp b/llvm/utils/TableGen/SubtargetFeatureInfo.cpp
index 7579fabfbb2c20..1db8c0bf430a7a 100644
--- a/llvm/utils/TableGen/SubtargetFeatureInfo.cpp
+++ b/llvm/utils/TableGen/SubtargetFeatureInfo.cpp
@@ -89,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;
diff --git a/llvm/utils/TableGen/SubtargetFeatureInfo.h b/llvm/utils/TableGen/SubtargetFeatureInfo.h
index e6a3f82d9bb83f..77703e8a87f858 100644
--- a/llvm/utils/TableGen/SubtargetFeatureInfo.h
+++ b/llvm/utils/TableGen/SubtargetFeatureInfo.h
@@ -69,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.
More information about the llvm-commits
mailing list