diff --git a/llvm/test/TableGen/GlobalISelEmitter.td b/llvm/test/TableGen/GlobalISelEmitter.td --- a/llvm/test/TableGen/GlobalISelEmitter.td +++ b/llvm/test/TableGen/GlobalISelEmitter.td @@ -88,6 +88,17 @@ // 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 @@ // 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 @@ // 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 @@ // 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 @@ // 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 @@ // 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 --- 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 --- a/llvm/utils/TableGen/CMakeLists.txt +++ b/llvm/utils/TableGen/CMakeLists.txt @@ -62,6 +62,7 @@ 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 --- 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 @@ 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 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 @@ /// This adds compatibility for RuleMatchers to use this for ordering rules. DenseMap RuleMatcherScores; - // Map of predicates to their subtarget features. - SubtargetFeatureInfoMap SubtargetFeatures; - // Rule coverage information. std::optional RuleCoverage; @@ -392,16 +405,6 @@ importImplicitDefRenderers(BuildMIAction &DstMIBuilder, const std::vector &ImplicitDefs) const; - void emitCxxPredicateFns(raw_ostream &OS, StringRef CodeFieldName, - StringRef TypeIdentifier, StringRef ArgType, - StringRef ArgName, StringRef AdditionalArgs, - StringRef AdditionalDeclarations, - std::function Filter); - void emitImmPredicateFns(raw_ostream &OS, StringRef TypeIdentifier, - StringRef ArgType, - std::function 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 runOnPattern(const PatternToMatch &P); @@ -448,6 +451,8 @@ InstructionMatcher &InsnMatcher, bool &HasAddedMatcher); }; +StringRef getPatFragPredicateEnumName(Record *R) { return R->getName(); } + void GlobalISelEmitter::gatherOpcodeValues() { InstructionOpcodeMatcher::initOpcodeValuesMap(Target); } @@ -507,8 +512,10 @@ } 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 @@ 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 Filter) { - std::vector 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 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 Rules, bool Optimize, bool WithCoverage) { @@ -2329,6 +2264,88 @@ 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 MatchedRecords; + std::copy_if(AllPatFrags.begin(), AllPatFrags.end(), + std::back_inserter(MatchedRecords), [&](Record *R) { + return !R->getValueAsString("GISelPredicateCode").empty(); + }); + emitMIPredicateFnsImpl( + 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(MatchedRecords), &getPatFragPredicateEnumName, + [&](Record *R) { return R->getValueAsString("GISelPredicateCode"); }, + "PatFrag predicates."); +} + +void GlobalISelEmitter::emitI64ImmPredicateFns(raw_ostream &OS) { + std::vector 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( + OS, "I64", "int64_t", ArrayRef(MatchedRecords), + &getPatFragPredicateEnumName, + [&](Record *R) { return R->getValueAsString("ImmediateCode"); }, + "PatFrag predicates."); +} + +void GlobalISelEmitter::emitAPFloatImmPredicateFns(raw_ostream &OS) { + std::vector 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( + OS, "APFloat", "const APFloat &", ArrayRef(MatchedRecords), + &getPatFragPredicateEnumName, + [&](Record *R) { return R->getValueAsString("ImmediateCode"); }, + "PatFrag predicates."); +} + +void GlobalISelEmitter::emitAPIntImmPredicateFns(raw_ostream &OS) { + std::vector MatchedRecords; + std::copy_if(AllPatFrags.begin(), AllPatFrags.end(), + std::back_inserter(MatchedRecords), [&](Record *R) { + return !R->getValueAsString("ImmediateCode").empty() && + R->getValueAsBit("IsAPInt"); + }); + emitImmPredicateFnsImpl( + OS, "APInt", "const APInt &", ArrayRef(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 @@ // Track the GINodeEquiv definitions. gatherNodeEquivs(); + AllPatFrags = RK.getAllDerivedDefinitions("PatFrags"); + emitSourceFileHeader( ("Global Instruction Selector for the " + Target.getName() + " target") .str(), @@ -2407,205 +2426,13 @@ 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;\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 " - "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 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> FeatureBitsets; - FeatureBitsets.reserve(Rules.size()); - for (auto &Rule : Rules) - FeatureBitsets.push_back(Rule.getRequiredFeatures()); - llvm::sort(FeatureBitsets, [&](const std::vector &A, - const std::vector &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 @@ 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.h b/llvm/utils/TableGen/GlobalISelMatchTableExecutorEmitter.h new file mode 100644 --- /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 +#include + +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 Rules); + + /// Emits an enum + an array that stores references to + /// \p ComplexOperandMatchers. + void emitComplexPredicates(raw_ostream &OS, + ArrayRef ComplexOperandMatchers); + + /// Emits an enum + an array that stores references to + /// \p CustomOperandRenderers. + void emitCustomOperandRenderers(raw_ostream &OS, + ArrayRef CustomOperandRenderers); + + /// Emits an enum + an array to reference \p TypeObjects (LLTs) in the match + /// table. + void emitTypeObjects(raw_ostream &OS, ArrayRef 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 + void emitCxxPredicateFns( + raw_ostream &OS, StringRef TypeIdentifier, StringRef ArgType, + StringRef ArgName, StringRef AdditionalArgs, + StringRef AdditionalDeclarations, ArrayRef Predicates, + std::function GetPredEnumName, + std::function 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 + void emitMIPredicateFnsImpl( + raw_ostream &OS, StringRef AdditionalDecls, + ArrayRef Predicates, + std::function GetPredEnumName, + std::function 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 + void emitImmPredicateFnsImpl( + raw_ostream &OS, StringRef TypeIdentifier, StringRef ArgType, + ArrayRef Predicates, + std::function GetPredEnumName, + std::function 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 TypeObjects, + ArrayRef Rules, + ArrayRef ComplexOperandMatchers, + ArrayRef 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/GlobalISelMatchTableExecutorEmitter.cpp b/llvm/utils/TableGen/GlobalISelMatchTableExecutorEmitter.cpp new file mode 100644 --- /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 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> FeatureBitsets; + FeatureBitsets.reserve(Rules.size()); + for (auto &Rule : Rules) + FeatureBitsets.push_back(Rule.getRequiredFeatures()); + llvm::sort(FeatureBitsets, [&](const std::vector &A, + const std::vector &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 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 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 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 TypeObjects, + ArrayRef Rules, ArrayRef ComplexOperandMatchers, + ArrayRef 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;\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 " + "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/SubtargetFeatureInfo.h b/llvm/utils/TableGen/SubtargetFeatureInfo.h --- a/llvm/utils/TableGen/SubtargetFeatureInfo.h +++ b/llvm/utils/TableGen/SubtargetFeatureInfo.h @@ -69,8 +69,8 @@ /// /// \param TargetName The name of the target as used in class prefixes (e.g. /// Subtarget) - /// \param ClassName The name of the class (without the 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/SubtargetFeatureInfo.cpp b/llvm/utils/TableGen/SubtargetFeatureInfo.cpp --- a/llvm/utils/TableGen/SubtargetFeatureInfo.cpp +++ b/llvm/utils/TableGen/SubtargetFeatureInfo.cpp @@ -89,7 +89,7 @@ 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;