[llvm] [NFC][TableGen] Reorganize GlobalISelMatchTable.h (PR #200153)

Pierre van Houtryve via llvm-commits llvm-commits at lists.llvm.org
Thu May 28 03:25:53 PDT 2026


https://github.com/Pierre-vh created https://github.com/llvm/llvm-project/pull/200153

This file was a bit of a kitchen sink, and the implementation of the
match table is sufficiently difficult to get comfortable with already.
I spent the past few weeks looking at it, finding improvements, etc. and
I think a nice way to make it a bit easier to approach is to split up
the file a bit so that the main implementation (Matchers.h/.cpp) only
contains the code pertaining to the Matchers (RuleMatchers, Preds, etc.).

We now have 3 files:

- One for type (LLT) related utilities.
- One for the MatchTable emission logic, which is generic and should not
  be tied to any specific implementation. It just has the tools to emit
  the opcodes for the table.
- One for the entire Matcher system, including PredicateMatchers and so on.

>From aa0d012d0478686ca3929abc024f8fef82306199 Mon Sep 17 00:00:00 2001
From: pvanhout <pierre.vanhoutryve at amd.com>
Date: Thu, 28 May 2026 12:13:12 +0200
Subject: [PATCH] [NFC][TableGen] Reorganize GlobalISelMatchTable.h

This file was a bit of a kitchen sink, and the implementation of the
match table is sufficiently difficult to get comfortable with already.
I spent the past few weeks looking at it, finding improvements, etc. and
I think a nice way to make it a bit easier to approach is to split up
the file a bit so that the main implementation (Matchers.h/.cpp) only
contains the code pertaining to the Matchers (RuleMatchers, Preds, etc.).

We now have 3 files:

- One for type (LLT) related utilities.
- One for the MatchTable emission logic, which is generic and should not
  be tied to any specific implementation. It just has the tools to emit
  the opcodes for the table.
- One for the entire Matcher system, including PredicateMatchers and so on.
---
 llvm/utils/TableGen/Common/CMakeLists.txt     |   4 +-
 .../GlobalISelMatchTableExecutorEmitter.cpp   |   2 +-
 .../GlobalISel/MatchTable/MatchTable.cpp      | 253 +++++++++++
 .../Common/GlobalISel/MatchTable/MatchTable.h | 180 ++++++++
 .../Matchers.cpp}                             | 409 +-----------------
 .../Matchers.h}                               | 234 +---------
 .../Common/GlobalISel/MatchTable/Types.cpp    | 160 +++++++
 .../Common/GlobalISel/MatchTable/Types.h      |  86 ++++
 .../TableGen/GlobalISelCombinerEmitter.cpp    |   6 +-
 llvm/utils/TableGen/GlobalISelEmitter.cpp     |   6 +-
 10 files changed, 721 insertions(+), 619 deletions(-)
 create mode 100644 llvm/utils/TableGen/Common/GlobalISel/MatchTable/MatchTable.cpp
 create mode 100644 llvm/utils/TableGen/Common/GlobalISel/MatchTable/MatchTable.h
 rename llvm/utils/TableGen/Common/GlobalISel/{GlobalISelMatchTable.cpp => MatchTable/Matchers.cpp} (86%)
 rename llvm/utils/TableGen/Common/GlobalISel/{GlobalISelMatchTable.h => MatchTable/Matchers.h} (90%)
 create mode 100644 llvm/utils/TableGen/Common/GlobalISel/MatchTable/Types.cpp
 create mode 100644 llvm/utils/TableGen/Common/GlobalISel/MatchTable/Types.h

diff --git a/llvm/utils/TableGen/Common/CMakeLists.txt b/llvm/utils/TableGen/Common/CMakeLists.txt
index 7b33c2a6e02a0..84e5e53f9fade 100644
--- a/llvm/utils/TableGen/Common/CMakeLists.txt
+++ b/llvm/utils/TableGen/Common/CMakeLists.txt
@@ -11,10 +11,12 @@ set(LLVM_LINK_COMPONENTS
   )
 
 add_llvm_library(LLVMTableGenCommon STATIC OBJECT EXCLUDE_FROM_ALL DISABLE_LLVM_LINK_LLVM_DYLIB
+  GlobalISel/MatchTable/MatchTable.cpp
+  GlobalISel/MatchTable/Matchers.cpp
+  GlobalISel/MatchTable/Types.cpp
   GlobalISel/CodeExpander.cpp
   GlobalISel/CombinerUtils.cpp
   GlobalISel/CXXPredicates.cpp
-  GlobalISel/GlobalISelMatchTable.cpp
   GlobalISel/GlobalISelMatchTableExecutorEmitter.cpp
   GlobalISel/PatternParser.cpp
   GlobalISel/Patterns.cpp
diff --git a/llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTableExecutorEmitter.cpp b/llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTableExecutorEmitter.cpp
index e9608bb7a9a7a..e59f0d8c0a7ad 100644
--- a/llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTableExecutorEmitter.cpp
+++ b/llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTableExecutorEmitter.cpp
@@ -7,7 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "GlobalISelMatchTableExecutorEmitter.h"
-#include "GlobalISelMatchTable.h"
+#include "MatchTable/Matchers.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/TableGen/CodeGenHelpers.h"
 
diff --git a/llvm/utils/TableGen/Common/GlobalISel/MatchTable/MatchTable.cpp b/llvm/utils/TableGen/Common/GlobalISel/MatchTable/MatchTable.cpp
new file mode 100644
index 0000000000000..7bebeee0db7df
--- /dev/null
+++ b/llvm/utils/TableGen/Common/GlobalISel/MatchTable/MatchTable.cpp
@@ -0,0 +1,253 @@
+//===- MatchTable.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 "MatchTable.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/TableGen/Record.h"
+
+#define DEBUG_TYPE "gi-match-table"
+
+namespace llvm {
+namespace gi {
+// GIMT_Encode2/4/8
+constexpr StringLiteral EncodeMacroName = "GIMT_Encode";
+
+//===- Helpers ------------------------------------------------------------===//
+
+void emitEncodingMacrosDef(raw_ostream &OS) {
+  OS << "#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__\n"
+     << "#define " << EncodeMacroName << "2(Val)"
+     << " uint8_t(Val), uint8_t((Val) >> 8)\n"
+     << "#define " << EncodeMacroName << "4(Val)"
+     << " uint8_t(Val), uint8_t((Val) >> 8), "
+        "uint8_t((Val) >> 16), uint8_t((Val) >> 24)\n"
+     << "#define " << EncodeMacroName << "8(Val)"
+     << " uint8_t(Val), uint8_t((Val) >> 8), "
+        "uint8_t((Val) >> 16), uint8_t((Val) >> 24),  "
+        "uint8_t(uint64_t(Val) >> 32), uint8_t(uint64_t(Val) >> 40), "
+        "uint8_t(uint64_t(Val) >> 48), uint8_t(uint64_t(Val) >> 56)\n"
+     << "#else\n"
+     << "#define " << EncodeMacroName << "2(Val)"
+     << " uint8_t((Val) >> 8), uint8_t(Val)\n"
+     << "#define " << EncodeMacroName << "4(Val)"
+     << " uint8_t((Val) >> 24), uint8_t((Val) >> 16), "
+        "uint8_t((Val) >> 8), uint8_t(Val)\n"
+     << "#define " << EncodeMacroName << "8(Val)"
+     << " uint8_t(uint64_t(Val) >> 56), uint8_t(uint64_t(Val) >> 48), "
+        "uint8_t(uint64_t(Val) >> 40), uint8_t(uint64_t(Val) >> 32),  "
+        "uint8_t((Val) >> 24), uint8_t((Val) >> 16), "
+        "uint8_t((Val) >> 8), uint8_t(Val)\n"
+     << "#endif\n";
+}
+
+void emitEncodingMacrosUndef(raw_ostream &OS) {
+  OS << "#undef " << EncodeMacroName << "2\n"
+     << "#undef " << EncodeMacroName << "4\n"
+     << "#undef " << EncodeMacroName << "8\n";
+}
+
+std::string getNameForFeatureBitset(ArrayRef<const Record *> FeatureBitset,
+                                    int HwModeIdx) {
+  std::string Name = "GIFBS";
+  for (const Record *Feature : FeatureBitset)
+    Name += ("_" + Feature->getName()).str();
+  if (HwModeIdx >= 0)
+    Name += ("_HwMode" + std::to_string(HwModeIdx));
+  return Name;
+}
+
+static std::string getEncodedEmitStr(StringRef NamedValue, unsigned NumBytes) {
+  if (NumBytes == 2 || NumBytes == 4 || NumBytes == 8)
+    return (EncodeMacroName + Twine(NumBytes) + "(" + NamedValue + ")").str();
+  llvm_unreachable("Unsupported number of bytes!");
+}
+
+//===- MatchTableRecord ---------------------------------------------------===//
+
+void MatchTableRecord::emit(raw_ostream &OS, bool LineBreakIsNextAfterThis,
+                            const MatchTable &Table) const {
+  bool UseLineComment =
+      LineBreakIsNextAfterThis || (Flags & MTRF_LineBreakFollows);
+  if (Flags & (MTRF_JumpTarget | MTRF_CommaFollows))
+    UseLineComment = false;
+
+  if (Flags & MTRF_Comment)
+    OS << (UseLineComment ? "// " : "/*");
+
+  if (NumElements > 1 && !(Flags & (MTRF_PreEncoded | MTRF_Comment)))
+    OS << getEncodedEmitStr(EmitStr, NumElements);
+  else
+    OS << EmitStr;
+
+  if (Flags & MTRF_Label)
+    OS << ": @" << Table.getLabelIndex(LabelID);
+
+  if ((Flags & MTRF_Comment) && !UseLineComment)
+    OS << "*/";
+
+  if (Flags & MTRF_JumpTarget) {
+    if (Flags & MTRF_Comment)
+      OS << " ";
+    // TODO: Could encode this AOT to speed up build of generated file
+    OS << getEncodedEmitStr(llvm::to_string(Table.getLabelIndex(LabelID)),
+                            NumElements);
+  }
+
+  if (Flags & MTRF_CommaFollows) {
+    OS << ",";
+    if (!LineBreakIsNextAfterThis && !(Flags & MTRF_LineBreakFollows))
+      OS << " ";
+  }
+
+  if (Flags & MTRF_LineBreakFollows)
+    OS << "\n";
+}
+
+//===- MatchTable ---------------------------------------------------------===//
+
+MatchTableRecord MatchTable::LineBreak = {
+    std::nullopt, "" /* Emit String */, 0 /* Elements */,
+    MatchTableRecord::MTRF_LineBreakFollows};
+
+MatchTableRecord MatchTable::Comment(StringRef Comment) {
+  return MatchTableRecord(std::nullopt, Comment, 0,
+                          MatchTableRecord::MTRF_Comment);
+}
+
+MatchTableRecord MatchTable::Opcode(StringRef Opcode, int IndentAdjust) {
+  unsigned ExtraFlags = 0;
+  if (IndentAdjust > 0)
+    ExtraFlags |= MatchTableRecord::MTRF_Indent;
+  if (IndentAdjust < 0)
+    ExtraFlags |= MatchTableRecord::MTRF_Outdent;
+
+  return MatchTableRecord(std::nullopt, Opcode, 1,
+                          MatchTableRecord::MTRF_CommaFollows | ExtraFlags);
+}
+
+MatchTableRecord MatchTable::NamedValue(unsigned NumBytes,
+                                        StringRef NamedValue) {
+  return MatchTableRecord(std::nullopt, NamedValue, NumBytes,
+                          MatchTableRecord::MTRF_CommaFollows);
+}
+
+MatchTableRecord MatchTable::NamedValue(unsigned NumBytes, StringRef Namespace,
+                                        StringRef NamedValue) {
+  return MatchTableRecord(std::nullopt, (Namespace + "::" + NamedValue).str(),
+                          NumBytes, MatchTableRecord::MTRF_CommaFollows);
+}
+
+MatchTableRecord MatchTable::IntValue(unsigned NumBytes, int64_t IntValue) {
+  assert(isUIntN(NumBytes * 8, IntValue) || isIntN(NumBytes * 8, IntValue));
+  uint64_t UIntValue = IntValue;
+  if (NumBytes < 8)
+    UIntValue &= (UINT64_C(1) << NumBytes * 8) - 1;
+  std::string Str = llvm::to_string(UIntValue);
+  if (UIntValue > INT64_MAX)
+    Str += 'u';
+  // TODO: Could optimize this directly to save the compiler some work when
+  // building the file
+  return MatchTableRecord(std::nullopt, Str, NumBytes,
+                          MatchTableRecord::MTRF_CommaFollows);
+}
+
+MatchTableRecord MatchTable::ULEB128Value(uint64_t IntValue) {
+  uint8_t Buffer[10];
+  unsigned Len = encodeULEB128(IntValue, Buffer);
+
+  // Simple case (most common)
+  if (Len == 1) {
+    return MatchTableRecord(std::nullopt, llvm::to_string((unsigned)Buffer[0]),
+                            1, MatchTableRecord::MTRF_CommaFollows);
+  }
+
+  // Print it as, e.g. /* -123456 (*/, 0xC0, 0xBB, 0x78 /*)*/
+  std::string Str;
+  raw_string_ostream OS(Str);
+  OS << "/* " << llvm::to_string(IntValue) << "(*/";
+  for (unsigned K = 0; K < Len; ++K) {
+    if (K)
+      OS << ", ";
+    OS << "0x" << llvm::toHex({Buffer[K]});
+  }
+  OS << "/*)*/";
+  return MatchTableRecord(std::nullopt, Str, Len,
+                          MatchTableRecord::MTRF_CommaFollows |
+                              MatchTableRecord::MTRF_PreEncoded);
+}
+
+MatchTableRecord MatchTable::Label(unsigned LabelID) {
+  return MatchTableRecord(LabelID, "Label " + llvm::to_string(LabelID), 0,
+                          MatchTableRecord::MTRF_Label |
+                              MatchTableRecord::MTRF_Comment |
+                              MatchTableRecord::MTRF_LineBreakFollows);
+}
+
+MatchTableRecord MatchTable::JumpTarget(unsigned LabelID) {
+  return MatchTableRecord(LabelID, "Label " + llvm::to_string(LabelID), 4,
+                          MatchTableRecord::MTRF_JumpTarget |
+                              MatchTableRecord::MTRF_Comment |
+                              MatchTableRecord::MTRF_CommaFollows);
+}
+
+void MatchTable::emitUse(raw_ostream &OS) const { OS << "MatchTable" << ID; }
+
+void MatchTable::emitDeclaration(raw_ostream &OS) const {
+  static constexpr unsigned BaseIndent = 4;
+  unsigned Indentation = 0;
+  OS << "  constexpr static uint8_t MatchTable" << ID << "[] = {";
+  LineBreak.emit(OS, true, *this);
+
+  // We want to display the table index of each line in a consistent
+  // manner. It has to appear as a column on the left side of the table.
+  // To determine how wide the column needs to be, check how many characters
+  // we need to fit the largest possible index in the current table.
+  const unsigned NumColsForIdx = llvm::to_string(CurrentSize).size();
+
+  unsigned CurIndex = 0;
+  const auto BeginLine = [&]() {
+    OS.indent(BaseIndent);
+    std::string IdxStr = llvm::to_string(CurIndex);
+    // Pad the string with spaces to keep the size of the prefix consistent.
+    OS << " /* ";
+    OS.indent(NumColsForIdx - IdxStr.size()) << IdxStr << " */ ";
+    OS.indent(Indentation);
+  };
+
+  BeginLine();
+  for (auto I = Contents.begin(), E = Contents.end(); I != E; ++I) {
+    bool LineBreakIsNext = false;
+    const auto &NextI = std::next(I);
+
+    if (NextI != E) {
+      if (NextI->EmitStr == "" &&
+          NextI->Flags == MatchTableRecord::MTRF_LineBreakFollows)
+        LineBreakIsNext = true;
+    }
+
+    if (I->Flags & MatchTableRecord::MTRF_Indent)
+      Indentation += 2;
+
+    I->emit(OS, LineBreakIsNext, *this);
+    if (I->Flags & MatchTableRecord::MTRF_LineBreakFollows)
+      BeginLine();
+
+    if (I->Flags & MatchTableRecord::MTRF_Outdent)
+      Indentation -= 2;
+
+    CurIndex += I->size();
+  }
+  assert(CurIndex == CurrentSize);
+  OS << "}; // Size: " << CurrentSize << " bytes\n";
+}
+
+} // namespace gi
+} // namespace llvm
diff --git a/llvm/utils/TableGen/Common/GlobalISel/MatchTable/MatchTable.h b/llvm/utils/TableGen/Common/GlobalISel/MatchTable/MatchTable.h
new file mode 100644
index 0000000000000..59c6173fd0445
--- /dev/null
+++ b/llvm/utils/TableGen/Common/GlobalISel/MatchTable/MatchTable.h
@@ -0,0 +1,180 @@
+//===- MatchTable.h -------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// This file contains the generic emitter for the GlobalISel Match Table
+/// system. This file only contains the code used to emit the table itself.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_UTILS_TABLEGEN_COMMON_GLOBALISEL_MATCHTABLE_MATCHTABLE_H
+#define LLVM_UTILS_TABLEGEN_COMMON_GLOBALISEL_MATCHTABLE_MATCHTABLE_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
+#include <string>
+
+namespace llvm {
+class raw_ostream;
+class Record;
+namespace gi {
+class Matcher;
+class MatchTable;
+
+//===- Helper functions ---------------------------------------------------===//
+
+void emitEncodingMacrosDef(raw_ostream &OS);
+void emitEncodingMacrosUndef(raw_ostream &OS);
+
+std::string getNameForFeatureBitset(ArrayRef<const Record *> FeatureBitset,
+                                    int HwModeIdx);
+
+/// A record to be stored in a MatchTable.
+///
+/// This class represents any and all output that may be required to emit the
+/// MatchTable. Instances  are most often configured to represent an opcode or
+/// value that will be emitted to the table with some formatting but it can also
+/// represent commas, comments, and other formatting instructions.
+struct MatchTableRecord {
+  enum RecordFlagsBits {
+    MTRF_None = 0x0,
+    /// Causes EmitStr to be formatted as comment when emitted.
+    MTRF_Comment = 0x1,
+    /// Causes the record value to be followed by a comma when emitted.
+    MTRF_CommaFollows = 0x2,
+    /// Causes the record value to be followed by a line break when emitted.
+    MTRF_LineBreakFollows = 0x4,
+    /// Indicates that the record defines a label and causes an additional
+    /// comment to be emitted containing the index of the label.
+    MTRF_Label = 0x8,
+    /// Causes the record to be emitted as the index of the label specified by
+    /// LabelID along with a comment indicating where that label is.
+    MTRF_JumpTarget = 0x10,
+    /// Causes the formatter to add a level of indentation before emitting the
+    /// record.
+    MTRF_Indent = 0x20,
+    /// Causes the formatter to remove a level of indentation after emitting the
+    /// record.
+    MTRF_Outdent = 0x40,
+    /// Causes the formatter to not use encoding macros to emit this multi-byte
+    /// value.
+    MTRF_PreEncoded = 0x80,
+  };
+
+  /// When MTRF_Label or MTRF_JumpTarget is used, indicates a label id to
+  /// reference or define.
+  unsigned LabelID;
+  /// The string to emit. Depending on the MTRF_* flags it may be a comment, a
+  /// value, a label name.
+  std::string EmitStr;
+
+private:
+  /// The number of MatchTable elements described by this record. Comments are 0
+  /// while values are typically 1. Values >1 may occur when we need to emit
+  /// values that exceed the size of a MatchTable element.
+  unsigned NumElements;
+
+public:
+  /// A bitfield of RecordFlagsBits flags.
+  unsigned Flags;
+
+  MatchTableRecord(std::optional<unsigned> LabelID_, StringRef EmitStr,
+                   unsigned NumElements, unsigned Flags)
+      : LabelID(LabelID_.value_or(~0u)), EmitStr(EmitStr),
+        NumElements(NumElements), Flags(Flags) {
+    assert((!LabelID_ || LabelID != ~0u) &&
+           "This value is reserved for non-labels");
+  }
+  MatchTableRecord(const MatchTableRecord &Other) = default;
+  MatchTableRecord(MatchTableRecord &&Other) = default;
+
+  /// Useful if a Match Table Record gets optimized out
+  void turnIntoComment() {
+    Flags |= MTRF_Comment;
+    Flags &= ~MTRF_CommaFollows;
+    NumElements = 0;
+  }
+
+  void emit(raw_ostream &OS, bool LineBreakNextAfterThis,
+            const MatchTable &Table) const;
+  unsigned size() const { return NumElements; }
+};
+
+/// Holds the contents of a generated MatchTable to enable formatting and the
+/// necessary index tracking needed to support GIM_Try.
+class MatchTable {
+  /// An unique identifier for the table. The generated table will be named
+  /// MatchTable${ID}.
+  unsigned ID;
+  /// The records that make up the table. Also includes comments describing the
+  /// values being emitted and line breaks to format it.
+  std::vector<MatchTableRecord> Contents;
+  /// The currently defined labels.
+  DenseMap<unsigned, unsigned> LabelMap;
+  /// Tracks the sum of MatchTableRecord::NumElements as the table is built.
+  unsigned CurrentSize = 0;
+  /// A unique identifier for a MatchTable label.
+  unsigned CurrentLabelID = 0;
+  /// Determines if the table should be instrumented for rule coverage tracking.
+  bool IsWithCoverage;
+  /// Whether this table is for the GISel combiner.
+  bool IsCombinerTable;
+
+public:
+  static MatchTableRecord LineBreak;
+  static MatchTableRecord Comment(StringRef Comment);
+  static MatchTableRecord Opcode(StringRef Opcode, int IndentAdjust = 0);
+  static MatchTableRecord NamedValue(unsigned NumBytes, StringRef NamedValue);
+  static MatchTableRecord NamedValue(unsigned NumBytes, StringRef Namespace,
+                                     StringRef NamedValue);
+  static MatchTableRecord IntValue(unsigned NumBytes, int64_t IntValue);
+  static MatchTableRecord ULEB128Value(uint64_t IntValue);
+  static MatchTableRecord Label(unsigned LabelID);
+  static MatchTableRecord JumpTarget(unsigned LabelID);
+
+  MatchTable(bool WithCoverage, bool IsCombinerTable, unsigned ID = 0)
+      : ID(ID), IsWithCoverage(WithCoverage), IsCombinerTable(IsCombinerTable) {
+  }
+
+  bool isWithCoverage() const { return IsWithCoverage; }
+  bool isCombiner() const { return IsCombinerTable; }
+
+  void push_back(const MatchTableRecord &Value) {
+    if (Value.Flags & MatchTableRecord::MTRF_Label)
+      defineLabel(Value.LabelID);
+    Contents.push_back(Value);
+    CurrentSize += Value.size();
+  }
+
+  unsigned allocateLabelID() { return CurrentLabelID++; }
+
+  void defineLabel(unsigned LabelID) {
+    LabelMap.try_emplace(LabelID, CurrentSize);
+  }
+
+  unsigned getLabelIndex(unsigned LabelID) const {
+    const auto I = LabelMap.find(LabelID);
+    assert(I != LabelMap.end() && "Use of undeclared label");
+    return I->second;
+  }
+
+  void emitUse(raw_ostream &OS) const;
+  void emitDeclaration(raw_ostream &OS) const;
+};
+
+inline MatchTable &operator<<(MatchTable &Table,
+                              const MatchTableRecord &Value) {
+  Table.push_back(Value);
+  return Table;
+}
+
+} // namespace gi
+} // namespace llvm
+
+#endif
diff --git a/llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.cpp b/llvm/utils/TableGen/Common/GlobalISel/MatchTable/Matchers.cpp
similarity index 86%
rename from llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.cpp
rename to llvm/utils/TableGen/Common/GlobalISel/MatchTable/Matchers.cpp
index 9b7584c00ddd3..92fa3c224a497 100644
--- a/llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.cpp
+++ b/llvm/utils/TableGen/Common/GlobalISel/MatchTable/Matchers.cpp
@@ -1,4 +1,4 @@
-//===- GlobalISelMatchTable.cpp -------------------------------------------===//
+//===- Matchers.cpp -------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -6,7 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "GlobalISelMatchTable.h"
+#include "Matchers.h"
 #include "Common/CodeGenInstruction.h"
 #include "Common/CodeGenRegisters.h"
 #include "llvm/ADT/Statistic.h"
@@ -17,7 +17,7 @@
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/TableGen/Error.h"
 
-#define DEBUG_TYPE "gi-match-table"
+#define DEBUG_TYPE "gi-match-table-matchers"
 
 STATISTIC(NumPatternEmitted, "Number of patterns emitted");
 
@@ -44,54 +44,8 @@ getMatchOpcodeForImmPredicate(const TreePredicateFn &Predicate) {
   return "GIM_Check" + Predicate.getImmTypeIdentifier().str() + "ImmPredicate";
 }
 
-// GIMT_Encode2/4/8
-constexpr StringLiteral EncodeMacroName = "GIMT_Encode";
-
 //===- Helpers ------------------------------------------------------------===//
 
-void llvm::gi::emitEncodingMacrosDef(raw_ostream &OS) {
-  OS << "#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__\n"
-     << "#define " << EncodeMacroName << "2(Val)"
-     << " uint8_t(Val), uint8_t((Val) >> 8)\n"
-     << "#define " << EncodeMacroName << "4(Val)"
-     << " uint8_t(Val), uint8_t((Val) >> 8), "
-        "uint8_t((Val) >> 16), uint8_t((Val) >> 24)\n"
-     << "#define " << EncodeMacroName << "8(Val)"
-     << " uint8_t(Val), uint8_t((Val) >> 8), "
-        "uint8_t((Val) >> 16), uint8_t((Val) >> 24),  "
-        "uint8_t(uint64_t(Val) >> 32), uint8_t(uint64_t(Val) >> 40), "
-        "uint8_t(uint64_t(Val) >> 48), uint8_t(uint64_t(Val) >> 56)\n"
-     << "#else\n"
-     << "#define " << EncodeMacroName << "2(Val)"
-     << " uint8_t((Val) >> 8), uint8_t(Val)\n"
-     << "#define " << EncodeMacroName << "4(Val)"
-     << " uint8_t((Val) >> 24), uint8_t((Val) >> 16), "
-        "uint8_t((Val) >> 8), uint8_t(Val)\n"
-     << "#define " << EncodeMacroName << "8(Val)"
-     << " uint8_t(uint64_t(Val) >> 56), uint8_t(uint64_t(Val) >> 48), "
-        "uint8_t(uint64_t(Val) >> 40), uint8_t(uint64_t(Val) >> 32),  "
-        "uint8_t((Val) >> 24), uint8_t((Val) >> 16), "
-        "uint8_t((Val) >> 8), uint8_t(Val)\n"
-     << "#endif\n";
-}
-
-void llvm::gi::emitEncodingMacrosUndef(raw_ostream &OS) {
-  OS << "#undef " << EncodeMacroName << "2\n"
-     << "#undef " << EncodeMacroName << "4\n"
-     << "#undef " << EncodeMacroName << "8\n";
-}
-
-std::string
-llvm::gi::getNameForFeatureBitset(ArrayRef<const Record *> FeatureBitset,
-                                  int HwModeIdx) {
-  std::string Name = "GIFBS";
-  for (const Record *Feature : FeatureBitset)
-    Name += ("_" + Feature->getName()).str();
-  if (HwModeIdx >= 0)
-    Name += ("_HwMode" + std::to_string(HwModeIdx));
-  return Name;
-}
-
 template <class GroupT>
 static std::vector<Matcher *>
 optimizeRules(ArrayRef<Matcher *> Rules,
@@ -181,201 +135,8 @@ std::vector<Matcher *> llvm::gi::optimizeRuleset(
   return OptRules;
 }
 
-static std::string getEncodedEmitStr(StringRef NamedValue, unsigned NumBytes) {
-  if (NumBytes == 2 || NumBytes == 4 || NumBytes == 8)
-    return (EncodeMacroName + Twine(NumBytes) + "(" + NamedValue + ")").str();
-  llvm_unreachable("Unsupported number of bytes!");
-}
-
-template <class Range> static bool matchersRecordOperand(Range &&R) {
-  return any_of(R, [](const auto &I) { return I->recordsOperand(); });
-}
-
-//===- Global Data --------------------------------------------------------===//
-
-std::set<LLTCodeGen> llvm::gi::KnownTypes;
-
-//===- MatchTableRecord ---------------------------------------------------===//
-
-void MatchTableRecord::emit(raw_ostream &OS, bool LineBreakIsNextAfterThis,
-                            const MatchTable &Table) const {
-  bool UseLineComment =
-      LineBreakIsNextAfterThis || (Flags & MTRF_LineBreakFollows);
-  if (Flags & (MTRF_JumpTarget | MTRF_CommaFollows))
-    UseLineComment = false;
-
-  if (Flags & MTRF_Comment)
-    OS << (UseLineComment ? "// " : "/*");
-
-  if (NumElements > 1 && !(Flags & (MTRF_PreEncoded | MTRF_Comment)))
-    OS << getEncodedEmitStr(EmitStr, NumElements);
-  else
-    OS << EmitStr;
-
-  if (Flags & MTRF_Label)
-    OS << ": @" << Table.getLabelIndex(LabelID);
-
-  if ((Flags & MTRF_Comment) && !UseLineComment)
-    OS << "*/";
-
-  if (Flags & MTRF_JumpTarget) {
-    if (Flags & MTRF_Comment)
-      OS << " ";
-    // TODO: Could encode this AOT to speed up build of generated file
-    OS << getEncodedEmitStr(llvm::to_string(Table.getLabelIndex(LabelID)),
-                            NumElements);
-  }
-
-  if (Flags & MTRF_CommaFollows) {
-    OS << ",";
-    if (!LineBreakIsNextAfterThis && !(Flags & MTRF_LineBreakFollows))
-      OS << " ";
-  }
-
-  if (Flags & MTRF_LineBreakFollows)
-    OS << "\n";
-}
-
-//===- MatchTable ---------------------------------------------------------===//
-
-MatchTableRecord MatchTable::LineBreak = {
-    std::nullopt, "" /* Emit String */, 0 /* Elements */,
-    MatchTableRecord::MTRF_LineBreakFollows};
-
-MatchTableRecord MatchTable::Comment(StringRef Comment) {
-  return MatchTableRecord(std::nullopt, Comment, 0,
-                          MatchTableRecord::MTRF_Comment);
-}
-
-MatchTableRecord MatchTable::Opcode(StringRef Opcode, int IndentAdjust) {
-  unsigned ExtraFlags = 0;
-  if (IndentAdjust > 0)
-    ExtraFlags |= MatchTableRecord::MTRF_Indent;
-  if (IndentAdjust < 0)
-    ExtraFlags |= MatchTableRecord::MTRF_Outdent;
-
-  return MatchTableRecord(std::nullopt, Opcode, 1,
-                          MatchTableRecord::MTRF_CommaFollows | ExtraFlags);
-}
-
-MatchTableRecord MatchTable::NamedValue(unsigned NumBytes,
-                                        StringRef NamedValue) {
-  return MatchTableRecord(std::nullopt, NamedValue, NumBytes,
-                          MatchTableRecord::MTRF_CommaFollows);
-}
-
-MatchTableRecord MatchTable::NamedValue(unsigned NumBytes, StringRef Namespace,
-                                        StringRef NamedValue) {
-  return MatchTableRecord(std::nullopt, (Namespace + "::" + NamedValue).str(),
-                          NumBytes, MatchTableRecord::MTRF_CommaFollows);
-}
-
-MatchTableRecord MatchTable::IntValue(unsigned NumBytes, int64_t IntValue) {
-  assert(isUIntN(NumBytes * 8, IntValue) || isIntN(NumBytes * 8, IntValue));
-  uint64_t UIntValue = IntValue;
-  if (NumBytes < 8)
-    UIntValue &= (UINT64_C(1) << NumBytes * 8) - 1;
-  std::string Str = llvm::to_string(UIntValue);
-  if (UIntValue > INT64_MAX)
-    Str += 'u';
-  // TODO: Could optimize this directly to save the compiler some work when
-  // building the file
-  return MatchTableRecord(std::nullopt, Str, NumBytes,
-                          MatchTableRecord::MTRF_CommaFollows);
-}
-
-MatchTableRecord MatchTable::ULEB128Value(uint64_t IntValue) {
-  uint8_t Buffer[10];
-  unsigned Len = encodeULEB128(IntValue, Buffer);
-
-  // Simple case (most common)
-  if (Len == 1) {
-    return MatchTableRecord(std::nullopt, llvm::to_string((unsigned)Buffer[0]),
-                            1, MatchTableRecord::MTRF_CommaFollows);
-  }
-
-  // Print it as, e.g. /* -123456 (*/, 0xC0, 0xBB, 0x78 /*)*/
-  std::string Str;
-  raw_string_ostream OS(Str);
-  OS << "/* " << llvm::to_string(IntValue) << "(*/";
-  for (unsigned K = 0; K < Len; ++K) {
-    if (K)
-      OS << ", ";
-    OS << "0x" << llvm::toHex({Buffer[K]});
-  }
-  OS << "/*)*/";
-  return MatchTableRecord(std::nullopt, Str, Len,
-                          MatchTableRecord::MTRF_CommaFollows |
-                              MatchTableRecord::MTRF_PreEncoded);
-}
-
-MatchTableRecord MatchTable::Label(unsigned LabelID) {
-  return MatchTableRecord(LabelID, "Label " + llvm::to_string(LabelID), 0,
-                          MatchTableRecord::MTRF_Label |
-                              MatchTableRecord::MTRF_Comment |
-                              MatchTableRecord::MTRF_LineBreakFollows);
-}
-
-MatchTableRecord MatchTable::JumpTarget(unsigned LabelID) {
-  return MatchTableRecord(LabelID, "Label " + llvm::to_string(LabelID), 4,
-                          MatchTableRecord::MTRF_JumpTarget |
-                              MatchTableRecord::MTRF_Comment |
-                              MatchTableRecord::MTRF_CommaFollows);
-}
-
-void MatchTable::emitUse(raw_ostream &OS) const { OS << "MatchTable" << ID; }
-
-void MatchTable::emitDeclaration(raw_ostream &OS) const {
-  static constexpr unsigned BaseIndent = 4;
-  unsigned Indentation = 0;
-  OS << "  constexpr static uint8_t MatchTable" << ID << "[] = {";
-  LineBreak.emit(OS, true, *this);
-
-  // We want to display the table index of each line in a consistent
-  // manner. It has to appear as a column on the left side of the table.
-  // To determine how wide the column needs to be, check how many characters
-  // we need to fit the largest possible index in the current table.
-  const unsigned NumColsForIdx = llvm::to_string(CurrentSize).size();
-
-  unsigned CurIndex = 0;
-  const auto BeginLine = [&]() {
-    OS.indent(BaseIndent);
-    std::string IdxStr = llvm::to_string(CurIndex);
-    // Pad the string with spaces to keep the size of the prefix consistent.
-    OS << " /* ";
-    OS.indent(NumColsForIdx - IdxStr.size()) << IdxStr << " */ ";
-    OS.indent(Indentation);
-  };
-
-  BeginLine();
-  for (auto I = Contents.begin(), E = Contents.end(); I != E; ++I) {
-    bool LineBreakIsNext = false;
-    const auto &NextI = std::next(I);
-
-    if (NextI != E) {
-      if (NextI->EmitStr == "" &&
-          NextI->Flags == MatchTableRecord::MTRF_LineBreakFollows)
-        LineBreakIsNext = true;
-    }
-
-    if (I->Flags & MatchTableRecord::MTRF_Indent)
-      Indentation += 2;
-
-    I->emit(OS, LineBreakIsNext, *this);
-    if (I->Flags & MatchTableRecord::MTRF_LineBreakFollows)
-      BeginLine();
-
-    if (I->Flags & MatchTableRecord::MTRF_Outdent)
-      Indentation -= 2;
-
-    CurIndex += I->size();
-  }
-  assert(CurIndex == CurrentSize);
-  OS << "}; // Size: " << CurrentSize << " bytes\n";
-}
-
-MatchTable MatchTable::buildTable(ArrayRef<Matcher *> Rules, bool WithCoverage,
-                                  bool IsCombiner) {
+MatchTable llvm::gi::buildMatchTable(ArrayRef<Matcher *> Rules,
+                                     bool WithCoverage, bool IsCombiner) {
   MatchTable Table(WithCoverage, IsCombiner);
   for (Matcher *Rule : Rules)
     Rule->emit(Table);
@@ -383,146 +144,15 @@ MatchTable MatchTable::buildTable(ArrayRef<Matcher *> Rules, bool WithCoverage,
   return Table << MatchTable::Opcode("GIM_Reject") << MatchTable::LineBreak;
 }
 
-//===- LLTCodeGen ---------------------------------------------------------===//
-
-std::string LLTCodeGen::getCxxEnumValue() const {
-  std::string Str;
-  raw_string_ostream OS(Str);
-
-  emitCxxEnumValue(OS);
-  return Str;
-}
-
-void LLTCodeGen::emitCxxEnumValue(raw_ostream &OS) const {
-  if (Ty.isScalar()) {
-    if (Ty.isBFloat16())
-      OS << "GILLT_bf16";
-    else if (Ty.isPPCF128())
-      OS << "GILLT_ppcf128";
-    else if (Ty.isX86FP80())
-      OS << "GILLT_x86fp80";
-    else if (Ty.isFloat())
-      OS << "GILLT_f" << Ty.getSizeInBits();
-    else if (Ty.isInteger())
-      OS << "GILLT_i" << Ty.getSizeInBits();
-    else
-      OS << "GILLT_s" << Ty.getSizeInBits();
-    return;
-  }
-  if (Ty.isVector()) {
-    OS << (Ty.isScalable() ? "GILLT_nxv" : "GILLT_v")
-       << Ty.getElementCount().getKnownMinValue();
-
-    LLT ElemTy = Ty.getElementType();
-    if (ElemTy.isBFloat16())
-      OS << "bf16";
-    else if (ElemTy.isPPCF128())
-      OS << "ppcf128";
-    else if (ElemTy.isX86FP80())
-      OS << "x86fp80";
-    else if (ElemTy.isFloat())
-      OS << "f" << ElemTy.getSizeInBits();
-    else if (ElemTy.isInteger())
-      OS << "i" << ElemTy.getSizeInBits();
-    else
-      OS << "s" << ElemTy.getSizeInBits();
-    return;
-  }
-
-  if (Ty.isPointer()) {
-    OS << "GILLT_p" << Ty.getAddressSpace();
-    if (Ty.getSizeInBits() > 0)
-      OS << "s" << Ty.getSizeInBits();
-    return;
-  }
-
-  llvm_unreachable("Unhandled LLT");
-}
-
-void LLTCodeGen::emitCxxConstructorCall(raw_ostream &OS) const {
-  auto EmitScalarType = [&OS](LLT T) {
-    if (T.isInteger())
-      OS << "LLT(LLT::Kind::INTEGER, ElementCount::getFixed(0), "
-         << T.getScalarSizeInBits() << ")";
-    else if (T.isBFloat16())
-      OS << "LLT(LLT::Kind::FLOAT, ElementCount::getFixed(0), 16, "
-            "LLT::FpSemantics::S_BFloat)";
-    else if (T.isPPCF128())
-      OS << "LLT(LLT::Kind::FLOAT, ElementCount::getFixed(0), 128, "
-            "LLT::FpSemantics::S_PPCDoubleDouble)";
-    else if (T.isX86FP80())
-      OS << "LLT(LLT::Kind::FLOAT, ElementCount::getFixed(0), 80, "
-            "LLT::FpSemantics::S_x87DoubleExtended)";
-    else if (T.isFloat(16))
-      OS << "LLT(LLT::Kind::FLOAT, ElementCount::getFixed(0), 16, "
-            "LLT::FpSemantics::S_IEEEhalf)";
-    else if (T.isFloat(32))
-      OS << "LLT(LLT::Kind::FLOAT, ElementCount::getFixed(0), 32, "
-            "LLT::FpSemantics::S_IEEEsingle)";
-    else if (T.isFloat(64))
-      OS << "LLT(LLT::Kind::FLOAT, ElementCount::getFixed(0), 64, "
-            "LLT::FpSemantics::S_IEEEdouble)";
-    else if (T.isFloat(128))
-      OS << "LLT(LLT::Kind::FLOAT, ElementCount::getFixed(0), 128, "
-            "LLT::FpSemantics::S_IEEEquad)";
-    else
-      OS << "LLT::scalar(" << T.getScalarSizeInBits() << ")";
-  };
-
-  if (Ty.isScalar()) {
-    EmitScalarType(Ty);
-    return;
-  }
-
-  if (Ty.isVector()) {
-    OS << "LLT::vector("
-       << (Ty.isScalable() ? "ElementCount::getScalable("
-                           : "ElementCount::getFixed(")
-       << Ty.getElementCount().getKnownMinValue() << "), ";
-    EmitScalarType(Ty.getElementType());
-    OS << ")";
-    return;
-  }
-
-  if (Ty.isPointer() && Ty.getSizeInBits() > 0) {
-    OS << "LLT::pointer(" << Ty.getAddressSpace() << ", " << Ty.getSizeInBits()
-       << ")";
-    return;
-  }
-
-  llvm_unreachable("Unhandled LLT");
-}
-
-/// This ordering is used for std::unique() and llvm::sort(). There's no
-/// particular logic behind the order but either A < B or B < A must be
-/// true if A != B.
-bool LLTCodeGen::operator<(const LLTCodeGen &Other) const {
-  return Ty.getUniqueRAWLLTData() < Other.Ty.getUniqueRAWLLTData();
-}
-
-//===- LLTCodeGen Helpers -------------------------------------------------===//
-
-std::optional<LLTCodeGen> llvm::gi::MVTToLLT(MVT VT) {
-  if (VT.isVector() && !VT.getVectorElementCount().isScalar())
-    return LLTCodeGen(LLT(VT));
-
-  if (VT.isInteger() || VT.isFloatingPoint())
-    return LLTCodeGen(LLT(VT));
-
-  return std::nullopt;
+template <class Range> static bool matchersRecordOperand(Range &&R) {
+  return any_of(R, [](const auto &I) { return I->recordsOperand(); });
 }
 
-std::optional<LLTCodeGen> llvm::gi::MVTToGenericLLT(MVT VT) {
-  if (VT.isVector() && !VT.getVectorElementCount().isScalar()) {
-    unsigned ElemBits = VT.getVectorElementType().getSizeInBits();
-    return LLTCodeGen(
-        LLT::vector(VT.getVectorElementCount(), LLT::scalar(ElemBits)));
-  }
-
-  if (VT.isInteger() || VT.isFloatingPoint())
-    return LLTCodeGen(LLT::scalar(VT.getSizeInBits()));
-
-  return std::nullopt;
+static void emitType(MatchTable &Table, const LLTCodeGenOrTempType &Ty) {
+  if (Ty.isLLTCodeGen())
+    Table << MatchTable::NamedValue(1, Ty.getLLTCodeGen().getCxxEnumValue());
+  else
+    Table << MatchTable::IntValue(1, Ty.getTempTypeIdx());
 }
 
 //===- Matcher ------------------------------------------------------------===//
@@ -1503,8 +1133,7 @@ void OperandImmPredicateMatcher::emitPredicateOpcodes(MatchTable &Table,
         << MatchTable::LineBreak;
 }
 
-//===- OperandLeafPredicateMatcher
-//-----------------------------------------===//
+//===- OperandLeafPredicateMatcher ----------------------------------------===//
 
 void OperandLeafPredicateMatcher::emitPredicateOpcodes(
     MatchTable &Table, RuleMatcher &Rule) const {
@@ -2274,9 +1903,10 @@ void ImmRenderer::emitRenderOpcodes(MatchTable &Table,
     assert(Table.isCombiner() &&
            "ConstantInt immediate are only for combiners!");
     Table << MatchTable::Opcode("GIR_AddCImm") << MatchTable::Comment("InsnID")
-          << MatchTable::ULEB128Value(InsnID) << MatchTable::Comment("Type")
-          << *CImmLLT << MatchTable::Comment("Imm")
-          << MatchTable::IntValue(8, Imm) << MatchTable::LineBreak;
+          << MatchTable::ULEB128Value(InsnID) << MatchTable::Comment("Type");
+    emitType(Table, *CImmLLT);
+    Table << MatchTable::Comment("Imm") << MatchTable::IntValue(8, Imm)
+          << MatchTable::LineBreak;
   } else {
     emitAddImm(Table, Rule, InsnID, Imm);
   }
@@ -2614,6 +2244,7 @@ void MakeTempRegisterAction::emitActionOpcodes(MatchTable &Table,
                                                RuleMatcher &Rule) const {
   Table << MatchTable::Opcode("GIR_MakeTempReg")
         << MatchTable::Comment("TempRegID")
-        << MatchTable::ULEB128Value(TempRegID) << MatchTable::Comment("TypeID")
-        << Ty << MatchTable::LineBreak;
+        << MatchTable::ULEB128Value(TempRegID) << MatchTable::Comment("TypeID");
+  emitType(Table, Ty);
+  Table << MatchTable::LineBreak;
 }
diff --git a/llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.h b/llvm/utils/TableGen/Common/GlobalISel/MatchTable/Matchers.h
similarity index 90%
rename from llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.h
rename to llvm/utils/TableGen/Common/GlobalISel/MatchTable/Matchers.h
index 5d1dc889f8523..d300a846cbb41 100644
--- a/llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.h
+++ b/llvm/utils/TableGen/Common/GlobalISel/MatchTable/Matchers.h
@@ -1,4 +1,4 @@
-//===- GlobalISelMatchTable.h ---------------------------------------------===//
+//===- Matchers.h ---------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -7,16 +7,18 @@
 //===----------------------------------------------------------------------===//
 //
 /// \file
-/// This file contains the code related to the GlobalISel Match Table emitted by
-/// GlobalISelEmitter.cpp. The generated match table is interpreted at runtime
-/// by `GIMatchTableExecutorImpl.h` to match & apply ISel patterns.
+/// This file contains the code related to the GlobalISel Matchers, which
+/// are the data structures used to model amd optimize state machines that
+/// can be emitted as "match tables" (see MatchTable.h/.cpp).
 ///
 //===----------------------------------------------------------------------===//
 
-#ifndef LLVM_UTILS_TABLEGEN_COMMON_GLOBALISEL_GLOBALISELMATCHTABLE_H
-#define LLVM_UTILS_TABLEGEN_COMMON_GLOBALISEL_GLOBALISELMATCHTABLE_H
+#ifndef LLVM_UTILS_TABLEGEN_COMMON_GLOBALISEL_MATCHTABLE_MATCHERS_H
+#define LLVM_UTILS_TABLEGEN_COMMON_GLOBALISEL_MATCHTABLE_MATCHERS_H
 
 #include "Common/CodeGenDAGPatterns.h"
+#include "MatchTable.h"
+#include "Types.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/MapVector.h"
@@ -42,8 +44,6 @@ class Record;
 class SMLoc;
 class CodeGenRegisterClass;
 
-// Use a namespace to avoid conflicts because there's some fairly generic names
-// in there (e.g. Matcher).
 namespace gi {
 class MatchTable;
 class Matcher;
@@ -61,12 +61,6 @@ using GISelFlags = std::uint32_t;
 
 //===- Helper functions ---------------------------------------------------===//
 
-void emitEncodingMacrosDef(raw_ostream &OS);
-void emitEncodingMacrosUndef(raw_ostream &OS);
-
-std::string getNameForFeatureBitset(ArrayRef<const Record *> FeatureBitset,
-                                    int HwModeIdx);
-
 /// Takes a sequence of \p Rules and group them based on the predicates
 /// they share. \p MatcherStorage is used as a memory container
 /// for the group that are created as part of this process.
@@ -95,213 +89,9 @@ std::vector<Matcher *>
 optimizeRuleset(MutableArrayRef<RuleMatcher> Rules,
                 std::vector<std::unique_ptr<Matcher>> &MatcherStorage);
 
-/// A record to be stored in a MatchTable.
-///
-/// This class represents any and all output that may be required to emit the
-/// MatchTable. Instances  are most often configured to represent an opcode or
-/// value that will be emitted to the table with some formatting but it can also
-/// represent commas, comments, and other formatting instructions.
-struct MatchTableRecord {
-  enum RecordFlagsBits {
-    MTRF_None = 0x0,
-    /// Causes EmitStr to be formatted as comment when emitted.
-    MTRF_Comment = 0x1,
-    /// Causes the record value to be followed by a comma when emitted.
-    MTRF_CommaFollows = 0x2,
-    /// Causes the record value to be followed by a line break when emitted.
-    MTRF_LineBreakFollows = 0x4,
-    /// Indicates that the record defines a label and causes an additional
-    /// comment to be emitted containing the index of the label.
-    MTRF_Label = 0x8,
-    /// Causes the record to be emitted as the index of the label specified by
-    /// LabelID along with a comment indicating where that label is.
-    MTRF_JumpTarget = 0x10,
-    /// Causes the formatter to add a level of indentation before emitting the
-    /// record.
-    MTRF_Indent = 0x20,
-    /// Causes the formatter to remove a level of indentation after emitting the
-    /// record.
-    MTRF_Outdent = 0x40,
-    /// Causes the formatter to not use encoding macros to emit this multi-byte
-    /// value.
-    MTRF_PreEncoded = 0x80,
-  };
-
-  /// When MTRF_Label or MTRF_JumpTarget is used, indicates a label id to
-  /// reference or define.
-  unsigned LabelID;
-  /// The string to emit. Depending on the MTRF_* flags it may be a comment, a
-  /// value, a label name.
-  std::string EmitStr;
-
-private:
-  /// The number of MatchTable elements described by this record. Comments are 0
-  /// while values are typically 1. Values >1 may occur when we need to emit
-  /// values that exceed the size of a MatchTable element.
-  unsigned NumElements;
-
-public:
-  /// A bitfield of RecordFlagsBits flags.
-  unsigned Flags;
-
-  MatchTableRecord(std::optional<unsigned> LabelID_, StringRef EmitStr,
-                   unsigned NumElements, unsigned Flags)
-      : LabelID(LabelID_.value_or(~0u)), EmitStr(EmitStr),
-        NumElements(NumElements), Flags(Flags) {
-    assert((!LabelID_ || LabelID != ~0u) &&
-           "This value is reserved for non-labels");
-  }
-  MatchTableRecord(const MatchTableRecord &Other) = default;
-  MatchTableRecord(MatchTableRecord &&Other) = default;
-
-  /// Useful if a Match Table Record gets optimized out
-  void turnIntoComment() {
-    Flags |= MTRF_Comment;
-    Flags &= ~MTRF_CommaFollows;
-    NumElements = 0;
-  }
-
-  void emit(raw_ostream &OS, bool LineBreakNextAfterThis,
-            const MatchTable &Table) const;
-  unsigned size() const { return NumElements; }
-};
-
-/// Holds the contents of a generated MatchTable to enable formatting and the
-/// necessary index tracking needed to support GIM_Try.
-class MatchTable {
-  /// An unique identifier for the table. The generated table will be named
-  /// MatchTable${ID}.
-  unsigned ID;
-  /// The records that make up the table. Also includes comments describing the
-  /// values being emitted and line breaks to format it.
-  std::vector<MatchTableRecord> Contents;
-  /// The currently defined labels.
-  DenseMap<unsigned, unsigned> LabelMap;
-  /// Tracks the sum of MatchTableRecord::NumElements as the table is built.
-  unsigned CurrentSize = 0;
-  /// A unique identifier for a MatchTable label.
-  unsigned CurrentLabelID = 0;
-  /// Determines if the table should be instrumented for rule coverage tracking.
-  bool IsWithCoverage;
-  /// Whether this table is for the GISel combiner.
-  bool IsCombinerTable;
-
-public:
-  static MatchTableRecord LineBreak;
-  static MatchTableRecord Comment(StringRef Comment);
-  static MatchTableRecord Opcode(StringRef Opcode, int IndentAdjust = 0);
-  static MatchTableRecord NamedValue(unsigned NumBytes, StringRef NamedValue);
-  static MatchTableRecord NamedValue(unsigned NumBytes, StringRef Namespace,
-                                     StringRef NamedValue);
-  static MatchTableRecord IntValue(unsigned NumBytes, int64_t IntValue);
-  static MatchTableRecord ULEB128Value(uint64_t IntValue);
-  static MatchTableRecord Label(unsigned LabelID);
-  static MatchTableRecord JumpTarget(unsigned LabelID);
-
-  static MatchTable buildTable(ArrayRef<Matcher *> Rules, bool WithCoverage,
-                               bool IsCombiner = false);
-
-  MatchTable(bool WithCoverage, bool IsCombinerTable, unsigned ID = 0)
-      : ID(ID), IsWithCoverage(WithCoverage), IsCombinerTable(IsCombinerTable) {
-  }
-
-  bool isWithCoverage() const { return IsWithCoverage; }
-  bool isCombiner() const { return IsCombinerTable; }
-
-  void push_back(const MatchTableRecord &Value) {
-    if (Value.Flags & MatchTableRecord::MTRF_Label)
-      defineLabel(Value.LabelID);
-    Contents.push_back(Value);
-    CurrentSize += Value.size();
-  }
-
-  unsigned allocateLabelID() { return CurrentLabelID++; }
-
-  void defineLabel(unsigned LabelID) {
-    LabelMap.try_emplace(LabelID, CurrentSize);
-  }
-
-  unsigned getLabelIndex(unsigned LabelID) const {
-    const auto I = LabelMap.find(LabelID);
-    assert(I != LabelMap.end() && "Use of undeclared label");
-    return I->second;
-  }
-
-  void emitUse(raw_ostream &OS) const;
-  void emitDeclaration(raw_ostream &OS) const;
-};
-
-inline MatchTable &operator<<(MatchTable &Table,
-                              const MatchTableRecord &Value) {
-  Table.push_back(Value);
-  return Table;
-}
-
-/// This class stands in for LLT wherever we want to tablegen-erate an
-/// equivalent at compiler run-time.
-class LLTCodeGen {
-private:
-  LLT Ty;
-
-public:
-  LLTCodeGen() = default;
-  LLTCodeGen(const LLT &Ty) : Ty(Ty) {}
-
-  std::string getCxxEnumValue() const;
-
-  void emitCxxEnumValue(raw_ostream &OS) const;
-  void emitCxxConstructorCall(raw_ostream &OS) const;
-
-  const LLT &get() const { return Ty; }
-
-  /// This ordering is used for std::unique() and llvm::sort(). There's no
-  /// particular logic behind the order but either A < B or B < A must be
-  /// true if A != B.
-  bool operator<(const LLTCodeGen &Other) const;
-  bool operator==(const LLTCodeGen &B) const { return Ty == B.Ty; }
-};
-
-// Track all types that are used so we can emit the corresponding enum.
-extern std::set<LLTCodeGen> KnownTypes;
-
-/// Convert an MVT to an equivalent LLT if possible, or the invalid LLT() for
-/// MVTs that don't map cleanly to an LLT (e.g., iPTR, *any, ...).
-std::optional<LLTCodeGen> MVTToLLT(MVT VT);
-std::optional<LLTCodeGen> MVTToGenericLLT(MVT VT);
-
-using TempTypeIdx = int64_t;
-class LLTCodeGenOrTempType {
-public:
-  LLTCodeGenOrTempType(const LLTCodeGen &LLT) : Data(LLT) {}
-  LLTCodeGenOrTempType(TempTypeIdx TempTy) : Data(TempTy) {}
-
-  bool isLLTCodeGen() const { return std::holds_alternative<LLTCodeGen>(Data); }
-  bool isTempTypeIdx() const {
-    return std::holds_alternative<TempTypeIdx>(Data);
-  }
-
-  const LLTCodeGen &getLLTCodeGen() const {
-    assert(isLLTCodeGen());
-    return std::get<LLTCodeGen>(Data);
-  }
-
-  TempTypeIdx getTempTypeIdx() const {
-    assert(isTempTypeIdx());
-    return std::get<TempTypeIdx>(Data);
-  }
-
-private:
-  std::variant<LLTCodeGen, TempTypeIdx> Data;
-};
-
-inline MatchTable &operator<<(MatchTable &Table,
-                              const LLTCodeGenOrTempType &Ty) {
-  if (Ty.isLLTCodeGen())
-    Table << MatchTable::NamedValue(1, Ty.getLLTCodeGen().getCxxEnumValue());
-  else
-    Table << MatchTable::IntValue(1, Ty.getTempTypeIdx());
-  return Table;
-}
+/// Build a MatchTable for emission from \p Rules
+MatchTable buildMatchTable(ArrayRef<Matcher *> Rules, bool WithCoverage,
+                           bool IsCombiner = false);
 
 //===- Matchers -----------------------------------------------------------===//
 class Matcher {
@@ -2621,4 +2411,4 @@ class MakeTempRegisterAction : public MatchAction {
 } // namespace gi
 } // namespace llvm
 
-#endif // LLVM_UTILS_TABLEGEN_COMMON_GLOBALISEL_GLOBALISELMATCHTABLE_H
+#endif // LLVM_UTILS_TABLEGEN_COMMON_GLOBALISEL_GLOBALISELMATCHERS_H
diff --git a/llvm/utils/TableGen/Common/GlobalISel/MatchTable/Types.cpp b/llvm/utils/TableGen/Common/GlobalISel/MatchTable/Types.cpp
new file mode 100644
index 0000000000000..1b969f209a0b6
--- /dev/null
+++ b/llvm/utils/TableGen/Common/GlobalISel/MatchTable/Types.cpp
@@ -0,0 +1,160 @@
+//===- Types.cpp ------------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Types.h"
+
+namespace llvm {
+namespace gi {
+
+//===- Global Data --------------------------------------------------------===//
+
+std::set<LLTCodeGen> KnownTypes;
+
+//===- LLTCodeGen ---------------------------------------------------------===//
+
+std::string LLTCodeGen::getCxxEnumValue() const {
+  std::string Str;
+  raw_string_ostream OS(Str);
+
+  emitCxxEnumValue(OS);
+  return Str;
+}
+
+void LLTCodeGen::emitCxxEnumValue(raw_ostream &OS) const {
+  if (Ty.isScalar()) {
+    if (Ty.isBFloat16())
+      OS << "GILLT_bf16";
+    else if (Ty.isPPCF128())
+      OS << "GILLT_ppcf128";
+    else if (Ty.isX86FP80())
+      OS << "GILLT_x86fp80";
+    else if (Ty.isFloat())
+      OS << "GILLT_f" << Ty.getSizeInBits();
+    else if (Ty.isInteger())
+      OS << "GILLT_i" << Ty.getSizeInBits();
+    else
+      OS << "GILLT_s" << Ty.getSizeInBits();
+    return;
+  }
+  if (Ty.isVector()) {
+    OS << (Ty.isScalable() ? "GILLT_nxv" : "GILLT_v")
+       << Ty.getElementCount().getKnownMinValue();
+
+    LLT ElemTy = Ty.getElementType();
+    if (ElemTy.isBFloat16())
+      OS << "bf16";
+    else if (ElemTy.isPPCF128())
+      OS << "ppcf128";
+    else if (ElemTy.isX86FP80())
+      OS << "x86fp80";
+    else if (ElemTy.isFloat())
+      OS << "f" << ElemTy.getSizeInBits();
+    else if (ElemTy.isInteger())
+      OS << "i" << ElemTy.getSizeInBits();
+    else
+      OS << "s" << ElemTy.getSizeInBits();
+    return;
+  }
+
+  if (Ty.isPointer()) {
+    OS << "GILLT_p" << Ty.getAddressSpace();
+    if (Ty.getSizeInBits() > 0)
+      OS << "s" << Ty.getSizeInBits();
+    return;
+  }
+
+  llvm_unreachable("Unhandled LLT");
+}
+
+void LLTCodeGen::emitCxxConstructorCall(raw_ostream &OS) const {
+  auto EmitScalarType = [&OS](LLT T) {
+    if (T.isInteger())
+      OS << "LLT(LLT::Kind::INTEGER, ElementCount::getFixed(0), "
+         << T.getScalarSizeInBits() << ")";
+    else if (T.isBFloat16())
+      OS << "LLT(LLT::Kind::FLOAT, ElementCount::getFixed(0), 16, "
+            "LLT::FpSemantics::S_BFloat)";
+    else if (T.isPPCF128())
+      OS << "LLT(LLT::Kind::FLOAT, ElementCount::getFixed(0), 128, "
+            "LLT::FpSemantics::S_PPCDoubleDouble)";
+    else if (T.isX86FP80())
+      OS << "LLT(LLT::Kind::FLOAT, ElementCount::getFixed(0), 80, "
+            "LLT::FpSemantics::S_x87DoubleExtended)";
+    else if (T.isFloat(16))
+      OS << "LLT(LLT::Kind::FLOAT, ElementCount::getFixed(0), 16, "
+            "LLT::FpSemantics::S_IEEEhalf)";
+    else if (T.isFloat(32))
+      OS << "LLT(LLT::Kind::FLOAT, ElementCount::getFixed(0), 32, "
+            "LLT::FpSemantics::S_IEEEsingle)";
+    else if (T.isFloat(64))
+      OS << "LLT(LLT::Kind::FLOAT, ElementCount::getFixed(0), 64, "
+            "LLT::FpSemantics::S_IEEEdouble)";
+    else if (T.isFloat(128))
+      OS << "LLT(LLT::Kind::FLOAT, ElementCount::getFixed(0), 128, "
+            "LLT::FpSemantics::S_IEEEquad)";
+    else
+      OS << "LLT::scalar(" << T.getScalarSizeInBits() << ")";
+  };
+
+  if (Ty.isScalar()) {
+    EmitScalarType(Ty);
+    return;
+  }
+
+  if (Ty.isVector()) {
+    OS << "LLT::vector("
+       << (Ty.isScalable() ? "ElementCount::getScalable("
+                           : "ElementCount::getFixed(")
+       << Ty.getElementCount().getKnownMinValue() << "), ";
+    EmitScalarType(Ty.getElementType());
+    OS << ")";
+    return;
+  }
+
+  if (Ty.isPointer() && Ty.getSizeInBits() > 0) {
+    OS << "LLT::pointer(" << Ty.getAddressSpace() << ", " << Ty.getSizeInBits()
+       << ")";
+    return;
+  }
+
+  llvm_unreachable("Unhandled LLT");
+}
+
+/// This ordering is used for std::unique() and llvm::sort(). There's no
+/// particular logic behind the order but either A < B or B < A must be
+/// true if A != B.
+bool LLTCodeGen::operator<(const LLTCodeGen &Other) const {
+  return Ty.getUniqueRAWLLTData() < Other.Ty.getUniqueRAWLLTData();
+}
+
+//===- LLTCodeGen Helpers -------------------------------------------------===//
+
+std::optional<LLTCodeGen> MVTToLLT(MVT VT) {
+  if (VT.isVector() && !VT.getVectorElementCount().isScalar())
+    return LLTCodeGen(LLT(VT));
+
+  if (VT.isInteger() || VT.isFloatingPoint())
+    return LLTCodeGen(LLT(VT));
+
+  return std::nullopt;
+}
+
+std::optional<LLTCodeGen> MVTToGenericLLT(MVT VT) {
+  if (VT.isVector() && !VT.getVectorElementCount().isScalar()) {
+    unsigned ElemBits = VT.getVectorElementType().getSizeInBits();
+    return LLTCodeGen(
+        LLT::vector(VT.getVectorElementCount(), LLT::scalar(ElemBits)));
+  }
+
+  if (VT.isInteger() || VT.isFloatingPoint())
+    return LLTCodeGen(LLT::scalar(VT.getSizeInBits()));
+
+  return std::nullopt;
+}
+} // namespace gi
+} // namespace llvm
diff --git a/llvm/utils/TableGen/Common/GlobalISel/MatchTable/Types.h b/llvm/utils/TableGen/Common/GlobalISel/MatchTable/Types.h
new file mode 100644
index 0000000000000..4b0fdcd66c9f6
--- /dev/null
+++ b/llvm/utils/TableGen/Common/GlobalISel/MatchTable/Types.h
@@ -0,0 +1,86 @@
+//===- Types.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 utilities used to represent LLTs for MatchTable-related
+/// components.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_UTILS_TABLEGEN_COMMON_GLOBALISEL_MATCHTABLE_TYPES_H
+#define LLVM_UTILS_TABLEGEN_COMMON_GLOBALISEL_MATCHTABLE_TYPES_H
+
+#include "llvm/CodeGenTypes/LowLevelType.h"
+#include <set>
+#include <string>
+#include <variant>
+
+namespace llvm {
+namespace gi {
+
+/// This class stands in for LLT wherever we want to tablegen-erate an
+/// equivalent at compiler run-time.
+class LLTCodeGen {
+private:
+  LLT Ty;
+
+public:
+  LLTCodeGen() = default;
+  LLTCodeGen(const LLT &Ty) : Ty(Ty) {}
+
+  std::string getCxxEnumValue() const;
+
+  void emitCxxEnumValue(raw_ostream &OS) const;
+  void emitCxxConstructorCall(raw_ostream &OS) const;
+
+  const LLT &get() const { return Ty; }
+
+  /// This ordering is used for std::unique() and llvm::sort(). There's no
+  /// particular logic behind the order but either A < B or B < A must be
+  /// true if A != B.
+  bool operator<(const LLTCodeGen &Other) const;
+  bool operator==(const LLTCodeGen &B) const { return Ty == B.Ty; }
+};
+
+// Track all types that are used so we can emit the corresponding enum.
+extern std::set<LLTCodeGen> KnownTypes;
+
+/// Convert an MVT to an equivalent LLT if possible, or the invalid LLT() for
+/// MVTs that don't map cleanly to an LLT (e.g., iPTR, *any, ...).
+std::optional<LLTCodeGen> MVTToLLT(MVT VT);
+std::optional<LLTCodeGen> MVTToGenericLLT(MVT VT);
+
+using TempTypeIdx = int64_t;
+class LLTCodeGenOrTempType {
+public:
+  LLTCodeGenOrTempType(const LLTCodeGen &LLT) : Data(LLT) {}
+  LLTCodeGenOrTempType(TempTypeIdx TempTy) : Data(TempTy) {}
+
+  bool isLLTCodeGen() const { return std::holds_alternative<LLTCodeGen>(Data); }
+  bool isTempTypeIdx() const {
+    return std::holds_alternative<TempTypeIdx>(Data);
+  }
+
+  const LLTCodeGen &getLLTCodeGen() const {
+    assert(isLLTCodeGen());
+    return std::get<LLTCodeGen>(Data);
+  }
+
+  TempTypeIdx getTempTypeIdx() const {
+    assert(isTempTypeIdx());
+    return std::get<TempTypeIdx>(Data);
+  }
+
+private:
+  std::variant<LLTCodeGen, TempTypeIdx> Data;
+};
+
+} // namespace gi
+} // namespace llvm
+
+#endif
diff --git a/llvm/utils/TableGen/GlobalISelCombinerEmitter.cpp b/llvm/utils/TableGen/GlobalISelCombinerEmitter.cpp
index deb126cbd716a..129034f81d082 100644
--- a/llvm/utils/TableGen/GlobalISelCombinerEmitter.cpp
+++ b/llvm/utils/TableGen/GlobalISelCombinerEmitter.cpp
@@ -33,8 +33,8 @@
 #include "Common/GlobalISel/CodeExpander.h"
 #include "Common/GlobalISel/CodeExpansions.h"
 #include "Common/GlobalISel/CombinerUtils.h"
-#include "Common/GlobalISel/GlobalISelMatchTable.h"
 #include "Common/GlobalISel/GlobalISelMatchTableExecutorEmitter.h"
+#include "Common/GlobalISel/MatchTable/Matchers.h"
 #include "Common/GlobalISel/PatternParser.h"
 #include "Common/GlobalISel/Patterns.h"
 #include "Common/SubtargetFeatureInfo.h"
@@ -2714,8 +2714,8 @@ MatchTable
 GICombinerEmitter::buildMatchTable(MutableArrayRef<RuleMatcher> Rules) {
   std::vector<std::unique_ptr<Matcher>> MatcherStorage;
   std::vector<Matcher *> OptRules = optimizeRuleset(Rules, MatcherStorage);
-  return MatchTable::buildTable(OptRules, /*WithCoverage*/ false,
-                                /*IsCombiner*/ true);
+  return ::buildMatchTable(OptRules, /*WithCoverage*/ false,
+                           /*IsCombiner*/ true);
 }
 
 /// Recurse into GICombineGroup's and flatten the ruleset into a simple list.
diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp
index 813cf0f6c087b..a6266e62012e4 100644
--- a/llvm/utils/TableGen/GlobalISelEmitter.cpp
+++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp
@@ -35,8 +35,8 @@
 #include "Common/CodeGenInstruction.h"
 #include "Common/CodeGenRegisters.h"
 #include "Common/CodeGenTarget.h"
-#include "Common/GlobalISel/GlobalISelMatchTable.h"
 #include "Common/GlobalISel/GlobalISelMatchTableExecutorEmitter.h"
+#include "Common/GlobalISel/MatchTable/Matchers.h"
 #include "Common/InfoByHwMode.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/CodeGenTypes/LowLevelType.h"
@@ -2311,12 +2311,12 @@ GlobalISelEmitter::buildMatchTable(MutableArrayRef<RuleMatcher> Rules,
                                    bool Optimize, bool WithCoverage) {
   if (!Optimize) {
     SmallVector<Matcher *> InputRules(make_pointer_range(Rules));
-    return MatchTable::buildTable(InputRules, WithCoverage);
+    return ::buildMatchTable(InputRules, WithCoverage);
   }
 
   std::vector<std::unique_ptr<Matcher>> MatcherStorage;
   std::vector<Matcher *> OptRules = optimizeRuleset(Rules, MatcherStorage);
-  return MatchTable::buildTable(OptRules, WithCoverage);
+  return ::buildMatchTable(OptRules, WithCoverage);
 }
 
 void GlobalISelEmitter::emitAdditionalImpl(raw_ostream &OS) {



More information about the llvm-commits mailing list