[llvm] 7b8bb9d - [TableGen] Expose remapRegClassByHwMode() helper in AsmMatcher
via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 14 11:12:11 PDT 2026
Author: Alexander Richardson
Date: 2026-09-14T11:12:05-07:00
New Revision: 7b8bb9d1f379da437eacfa7f4de96957e41956c6
URL: https://github.com/llvm/llvm-project/commit/7b8bb9d1f379da437eacfa7f4de96957e41956c6
DIFF: https://github.com/llvm/llvm-project/commit/7b8bb9d1f379da437eacfa7f4de96957e41956c6.diff
LOG: [TableGen] Expose remapRegClassByHwMode() helper in AsmMatcher
This is useful to map from a ByHwMode MCK_* value to the actual resolved
MCK_* type. This is needed for #177073 where we would otherwise have to
add the manual logic to do this remapping (which is the approach I
previously used). Move RegClassByHwModeMatchTable to file scope and
provide a remapRegClassByHwMode() helper function in the generated
AsmMatcher. Currently only used for RISC-V, but I assume other targets
could also make use of this in the future. But even if not, I think it's
cleaner to have this as a helper rather than an inline array inside the
matcher function.
This change was created with the help of AI tools.
Reviewed By: arsenm
Pull Request: https://github.com/llvm/llvm-project/pull/223302
Added:
Modified:
llvm/test/TableGen/RegClassByHwMode.td
llvm/utils/TableGen/AsmMatcherEmitter.cpp
Removed:
################################################################################
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 35c06e9141e16..4a619883bfefc 100644
--- a/llvm/utils/TableGen/AsmMatcherEmitter.cpp
+++ b/llvm/utils/TableGen/AsmMatcherEmitter.cpp
@@ -2652,6 +2652,68 @@ 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) {
@@ -2700,69 +2762,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");
@@ -3677,6 +3687,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-commits
mailing list