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,
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,9 +299,22 @@
   return *MaybeOpTy;
 }
 
-class GlobalISelEmitter {
+class GlobalISelEmitter : 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; }
+  std::string getClassName() const override {
+    return Target.getName().str() + "InstructionSelector";
+  }
+
   void run(raw_ostream &OS);
 
 private:
@@ -309,6 +323,8 @@
   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 @@
   /// 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 @@
   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,10 @@
                        InstructionMatcher &InsnMatcher, bool &HasAddedMatcher);
 };
 
+std::string getPatFragPredicateEnumName(Record *R) {
+  return R->getName().str();
+}
+
 void GlobalISelEmitter::gatherOpcodeValues() {
   InstructionOpcodeMatcher::initOpcodeValuesMap(Target);
 }
@@ -507,8 +514,8 @@
 }
 
 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()) {}
 
 //===- 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<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,91 @@
   return MatchTable::buildTable(OptRules, WithCoverage);
 }
 
+void GlobalISelEmitter::emitAdditionalImpl(raw_ostream &OS) {
+  OS << "bool " << getClassName()
+     << "::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";
+}
+
+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").str();
+      },
+      "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").str(); },
+      "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").str(); },
+      "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").str(); },
+      "PatFrag predicates.");
+}
+
 void GlobalISelEmitter::run(raw_ostream &OS) {
   if (!UseCoverageFile.empty()) {
     RuleCoverage = CodeGenCoverage();
@@ -2352,6 +2372,8 @@
   // Track the GINodeEquiv definitions.
   gatherNodeEquivs();
 
+  AllPatFrags = RK.getAllDerivedDefinitions("PatFrags");
+
   emitSourceFileHeader(
       ("Global Instruction Selector for the " + Target.getName() + " target")
           .str(),
@@ -2407,205 +2429,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<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 +2452,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 <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<std::string(PredicateObject)> GetPredEnumName,
+      std::function<std::string(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<std::string(PredicateObject)> GetPredEnumName,
+      std::function<std::string(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<std::string(PredicateObject)> GetPredEnumName,
+      std::function<std::string(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 std::string 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/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<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 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";
+}
+
+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/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.
   ///                   <TargetName>Subtarget)
-  /// \param ClassName  The name of the class (without the <Target> prefix)
-  ///                   that will contain the generated functions.
+  /// \param ClassName  The name of the class that will contain the generated
+  ///                   functions (including the target prefix.)
   /// \param FuncName   The name of the function to emit.
   /// \param SubtargetFeatures A map of TableGen records to the
   ///                          SubtargetFeatureInfo equivalent.
diff --git a/llvm/utils/TableGen/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;