[llvm-branch-commits] [llvm] [TableGen] Expose remapRegClassByHwMode() helper in AsmMatcher (PR #223302)

Alexander Richardson via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Sun Sep 13 21:46:16 PDT 2026


https://github.com/arichardson updated https://github.com/llvm/llvm-project/pull/223302

>From 75cb490c08be8643e6018e739ec477d7d2edf7d2 Mon Sep 17 00:00:00 2001
From: Alex Richardson <alexrichardson at google.com>
Date: Sun, 13 Sep 2026 21:41:45 -0700
Subject: [PATCH] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20initia?=
 =?UTF-8?q?l=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Created using spr 1.3.8-beta.1
---
 llvm/test/TableGen/RegClassByHwMode.td    |  64 +++++++-----
 llvm/utils/TableGen/AsmMatcherEmitter.cpp | 122 ++++++++++++----------
 2 files changed, 103 insertions(+), 83 deletions(-)

diff --git a/llvm/test/TableGen/RegClassByHwMode.td b/llvm/test/TableGen/RegClassByHwMode.td
index a9acc154ad933..d03c1e4246d33 100644
--- a/llvm/test/TableGen/RegClassByHwMode.td
+++ b/llvm/test/TableGen/RegClassByHwMode.td
@@ -97,39 +97,47 @@ include "Common/RegClassByHwModeCommon.td"
 // ASMMATCHER-NEXT:   MCK_LAST_REGCLASS_BY_HWMODE = MCK_RegByHwMode_YRegs_EvenIfRequired,
 // ASMMATCHER-NEXT:   MCK_Imm, // user defined class 'ImmAsmOperand'
 
+// ASMMATCHER:      static constexpr MatchClassKind RegClassByHwModeMatchTable[4][3] = {
+// ASMMATCHER-NEXT:   { // DefaultMode
+// ASMMATCHER-NEXT:     MCK_PtrRegs32, // MyPtrRC
+// ASMMATCHER-NEXT:     MCK_XRegs, // XRegs_EvenIfRequired
+// ASMMATCHER-NEXT:     MCK_YRegs, // YRegs_EvenIfRequired
+// ASMMATCHER-NEXT:   },
+// ASMMATCHER-NEXT:   { // EvenMode
+// ASMMATCHER-NEXT:     InvalidMatchClass, // Missing mode entry for MyPtrRC
+// ASMMATCHER-NEXT:     MCK_XRegs_Even, // XRegs_EvenIfRequired
+// ASMMATCHER-NEXT:     MCK_YRegs_Even, // YRegs_EvenIfRequired
+// ASMMATCHER-NEXT:   },
+// ASMMATCHER-NEXT:   { // OddMode
+// ASMMATCHER-NEXT:     InvalidMatchClass, // Missing mode entry for MyPtrRC
+// ASMMATCHER-NEXT:     MCK_XRegs_Odd, // XRegs_EvenIfRequired
+// ASMMATCHER-NEXT:     InvalidMatchClass, // Missing mode entry for YRegs_EvenIfRequired
+// ASMMATCHER-NEXT:   },
+// ASMMATCHER-NEXT:   { // Ptr64
+// ASMMATCHER-NEXT:     MCK_PtrRegs64, // MyPtrRC
+// ASMMATCHER-NEXT:     InvalidMatchClass, // Missing mode entry for XRegs_EvenIfRequired
+// ASMMATCHER-NEXT:     InvalidMatchClass, // Missing mode entry for YRegs_EvenIfRequired
+// ASMMATCHER-NEXT:   },
+// ASMMATCHER-NEXT: };
+// ASMMATCHER-EMPTY:
+// ASMMATCHER-NEXT: static_assert(MCK_LAST_REGCLASS_BY_HWMODE - MCK_LAST_REGISTER == 3);
+// ASMMATCHER-EMPTY:
+// ASMMATCHER-NEXT: {{\[\[}}maybe_unused{{\]\]}} static inline MatchClassKind
+// ASMMATCHER-NEXT: remapRegClassByHwMode(unsigned Kind, const MCSubtargetInfo &STI) {
+// ASMMATCHER-NEXT:   if (Kind > MCK_LAST_REGISTER && Kind <= MCK_LAST_REGCLASS_BY_HWMODE) {
+// ASMMATCHER-NEXT:     unsigned HwMode = STI.getHwMode(MCSubtargetInfo::HwMode_RegInfo);
+// ASMMATCHER-NEXT:     assert(HwMode < 4 && "Invalid HwMode");
+// ASMMATCHER-NEXT:     return RegClassByHwModeMatchTable[HwMode][Kind - (MCK_LAST_REGISTER + 1)];
+// ASMMATCHER-NEXT:   }
+// ASMMATCHER-NEXT:   return static_cast<MatchClassKind>(Kind);
+// ASMMATCHER-NEXT: }
+
 // ASMMATCHER: static unsigned validateOperandClass(MCParsedAsmOperand &GOp, MatchClassKind Kind, const MCSubtargetInfo &STI) {
 // ASMMATCHER: if (Kind <= MCK_LAST_TOKEN) {
 
 // ASMMATCHER: switch (Kind) {
 
-// ASMMATCHER: if (Kind > MCK_LAST_REGISTER && Kind <= MCK_LAST_REGCLASS_BY_HWMODE) {
-// ASMMATCHER-NEXT:    static constexpr MatchClassKind RegClassByHwModeMatchTable[4][3] = {
-// ASMMATCHER-NEXT:      { // DefaultMode
-// ASMMATCHER-NEXT:        MCK_PtrRegs32, // MyPtrRC
-// ASMMATCHER-NEXT:        MCK_XRegs, // XRegs_EvenIfRequired
-// ASMMATCHER-NEXT:        MCK_YRegs, // YRegs_EvenIfRequired
-// ASMMATCHER-NEXT:      },
-// ASMMATCHER-NEXT:      { // EvenMode
-// ASMMATCHER-NEXT:        InvalidMatchClass, // Missing mode entry for MyPtrRC
-// ASMMATCHER-NEXT:        MCK_XRegs_Even, // XRegs_EvenIfRequired
-// ASMMATCHER-NEXT:        MCK_YRegs_Even, // YRegs_EvenIfRequired
-// ASMMATCHER-NEXT:      },
-// ASMMATCHER-NEXT:      { // OddMode
-// ASMMATCHER-NEXT:        InvalidMatchClass, // Missing mode entry for MyPtrRC
-// ASMMATCHER-NEXT:        MCK_XRegs_Odd, // XRegs_EvenIfRequired
-// ASMMATCHER-NEXT:        InvalidMatchClass, // Missing mode entry for YRegs_EvenIfRequired
-// ASMMATCHER-NEXT:      },
-// ASMMATCHER-NEXT:      { // Ptr64
-// ASMMATCHER-NEXT:        MCK_PtrRegs64, // MyPtrRC
-// ASMMATCHER-NEXT:        InvalidMatchClass, // Missing mode entry for XRegs_EvenIfRequired
-// ASMMATCHER-NEXT:        InvalidMatchClass, // Missing mode entry for YRegs_EvenIfRequired
-// ASMMATCHER-NEXT:      },
-// ASMMATCHER-NEXT:    };
-// ASMMATCHER-EMPTY:
-// ASMMATCHER-NEXT:    static_assert(MCK_LAST_REGCLASS_BY_HWMODE - MCK_LAST_REGISTER == 3);
-// ASMMATCHER-NEXT:    const unsigned HwMode = STI.getHwMode(MCSubtargetInfo::HwMode_RegInfo);
-// ASMMATCHER-NEXT:    Kind = RegClassByHwModeMatchTable[HwMode][Kind - (MCK_LAST_REGISTER + 1)];
-// ASMMATCHER-NEXT:  }
+// ASMMATCHER:   Kind = remapRegClassByHwMode(Kind, STI);
 
 // ASMMATCHER: if (Operand.isReg()) {
 
diff --git a/llvm/utils/TableGen/AsmMatcherEmitter.cpp b/llvm/utils/TableGen/AsmMatcherEmitter.cpp
index 5e2127d139081..34ebb34edb055 100644
--- a/llvm/utils/TableGen/AsmMatcherEmitter.cpp
+++ b/llvm/utils/TableGen/AsmMatcherEmitter.cpp
@@ -2624,6 +2624,67 @@ static void emitGetRegClassFromMatchKindFunc(AsmMatcherInfo &Info,
   OS << "}\n\n";
 }
 
+/// emitRegClassByHwModeMatchTable - Emit the RegClassByHwMode match table and
+/// helper functions for remapping match classes by hardware mode.
+static void emitRegClassByHwModeMatchTable(const CodeGenTarget &Target,
+                                           AsmMatcherInfo &Info,
+                                           raw_ostream &OS) {
+  ArrayRef<const Record *> RegClassesByHwMode = Target.getAllRegClassByHwMode();
+  if (RegClassesByHwMode.empty())
+    return;
+
+  const CodeGenHwModes &CGH = Target.getHwModes();
+  const CodeGenRegBank &RegBank = Target.getRegBank();
+  unsigned NumModes = CGH.getNumModeIds();
+  unsigned NumClassesByHwMode = RegClassesByHwMode.size();
+
+  OS << "static constexpr MatchClassKind RegClassByHwModeMatchTable["
+     << NumModes << "][" << NumClassesByHwMode << "] = {\n";
+
+  // TODO: If the instruction predicates can statically resolve which hwmode,
+  // directly match the register class
+  for (unsigned M = 0; M < NumModes; ++M) {
+    OS << "  { // " << CGH.getModeName(M, /*IncludeDefault=*/true) << '\n';
+    for (unsigned I = 0; I != NumClassesByHwMode; ++I) {
+      const Record *Class = RegClassesByHwMode[I];
+      const HwModeSelect &ModeSelect = CGH.getHwModeSelect(Class);
+
+      auto FoundMode =
+          find_if(ModeSelect.Items, [=](const HwModeSelect::PairType P) {
+            return P.first == M;
+          });
+
+      if (FoundMode == ModeSelect.Items.end()) {
+        OS << "    InvalidMatchClass, // Missing mode entry for "
+           << Class->getName() << "\n";
+      } else {
+        const CodeGenRegisterClass *RegClass =
+            RegBank.getRegClass(FoundMode->second);
+        const ClassInfo *CI =
+            Info.RegisterClassClasses.at(RegClass->getDef());
+        OS << "    " << CI->Name << ", // " << Class->getName() << "\n";
+      }
+    }
+
+    OS << "  },\n";
+  }
+
+  OS << "};\n\n";
+
+  OS << "static_assert(MCK_LAST_REGCLASS_BY_HWMODE - MCK_LAST_REGISTER == "
+     << NumClassesByHwMode << ");\n\n";
+
+  OS << "[[maybe_unused]] static inline MatchClassKind\n"
+     << "remapRegClassByHwMode(unsigned Kind, const MCSubtargetInfo &STI) {\n"
+     << "  if (Kind > MCK_LAST_REGISTER && Kind <= MCK_LAST_REGCLASS_BY_HWMODE) {\n"
+     << "    unsigned HwMode = STI.getHwMode(MCSubtargetInfo::HwMode_RegInfo);\n"
+     << "    assert(HwMode < " << NumModes << " && \"Invalid HwMode\");\n"
+     << "    return RegClassByHwModeMatchTable[HwMode][Kind - (MCK_LAST_REGISTER + 1)];\n"
+     << "  }\n"
+     << "  return static_cast<MatchClassKind>(Kind);\n"
+     << "}\n\n";
+}
+
 /// emitValidateOperandClass - Emit the function to validate an operand class.
 static void emitValidateOperandClass(const CodeGenTarget &Target,
                                      AsmMatcherInfo &Info, raw_ostream &OS) {
@@ -2672,69 +2733,17 @@ static void emitValidateOperandClass(const CodeGenTarget &Target,
   }
   OS << "  } // end switch (Kind)\n\n";
 
-  const CodeGenRegBank &RegBank = Target.getRegBank();
   ArrayRef<const Record *> RegClassesByHwMode = Target.getAllRegClassByHwMode();
-  unsigned NumClassesByHwMode = RegClassesByHwMode.size();
-
   if (!RegClassesByHwMode.empty()) {
     // Resolve RegClassByHwMode kinds to their concrete class regardless of
     // whether Operand is actually a register, so that the diagnostic
     // fallback paths below (for both register and non-register operands)
     // see a concrete class rather than an unresolved by-hwmode one.
-    OS << "  if (Kind > MCK_LAST_REGISTER &&"
-          " Kind <= MCK_LAST_REGCLASS_BY_HWMODE) {\n";
-
-    const CodeGenHwModes &CGH = Target.getHwModes();
-    unsigned NumModes = CGH.getNumModeIds();
-
-    OS << indent(4)
-       << "static constexpr MatchClassKind RegClassByHwModeMatchTable["
-       << NumModes << "][" << RegClassesByHwMode.size() << "] = {\n";
-
-    // TODO: If the instruction predicates can statically resolve which hwmode,
-    // directly match the register class
-    for (unsigned M = 0; M < NumModes; ++M) {
-      OS << indent(6) << "{ // " << CGH.getModeName(M, /*IncludeDefault=*/true)
-         << '\n';
-      for (unsigned I = 0; I != NumClassesByHwMode; ++I) {
-        const Record *Class = RegClassesByHwMode[I];
-        const HwModeSelect &ModeSelect = CGH.getHwModeSelect(Class);
-
-        auto FoundMode =
-            find_if(ModeSelect.Items, [=](const HwModeSelect::PairType P) {
-              return P.first == M;
-            });
-
-        if (FoundMode == ModeSelect.Items.end()) {
-          OS << indent(8) << "InvalidMatchClass, // Missing mode entry for "
-             << Class->getName() << "\n";
-        } else {
-          const CodeGenRegisterClass *RegClass =
-              RegBank.getRegClass(FoundMode->second);
-          const ClassInfo *CI =
-              Info.RegisterClassClasses.at(RegClass->getDef());
-          OS << indent(8) << CI->Name << ", // " << Class->getName() << "\n";
-        }
-      }
-
-      OS << indent(6) << "},\n";
-    }
-
-    OS << indent(4) << "};\n\n";
-
-    OS << indent(4)
-       << "static_assert(MCK_LAST_REGCLASS_BY_HWMODE - MCK_LAST_REGISTER == "
-       << NumClassesByHwMode << ");\n";
-
-    OS << indent(4)
-       << "const unsigned HwMode = "
-          "STI.getHwMode(MCSubtargetInfo::HwMode_RegInfo);\n"
-       << indent(4)
-       << "Kind = RegClassByHwModeMatchTable[HwMode][Kind - (MCK_LAST_REGISTER "
-          "+ 1)];\n"
-          "  }\n\n";
+    OS << "  Kind = remapRegClassByHwMode(Kind, STI);\n\n";
   }
 
+  const CodeGenRegBank &RegBank = Target.getRegBank();
+
   // Check for register operands, including sub-classes.
   const auto &Regs = RegBank.getRegisters();
   StringRef Namespace = Regs.front().TheDef->getValueAsString("Namespace");
@@ -3649,6 +3658,9 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
   if (AsmParser->getValueAsBit("EmitTokenDiagnosticTypes"))
     emitTokenDiagFunction(Info, OS);
 
+  // Emit the RegClassByHwMode match table and remap helper functions.
+  emitRegClassByHwModeMatchTable(Target, Info, OS);
+
   // Emit the routine to validate an operand against a match class.
   emitValidateOperandClass(Target, Info, OS);
 



More information about the llvm-branch-commits mailing list