[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