[llvm-branch-commits] [TableGen] Generate `getRegClassFromMatchKind()` for AsmMatchers (PR #200453)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri May 29 09:47:09 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-tablegen
Author: Alexander Richardson (arichardson)
<details>
<summary>Changes</summary>
This helper can be useful in validateTargetOperandClass to get the
MCRegisterClass for the MCK_* enum.
Migrate the RVY logic to use this new generated function. Checking all
register classes instead of just the RVY ones will marginally slow down
validateTargetOperandClass, but since this is already a slow path it
should not matter.
---
Full diff: https://github.com/llvm/llvm-project/pull/200453.diff
3 Files Affected:
- (modified) llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp (-21)
- (added) llvm/test/TableGen/getRegClassFromMatchKind.td (+104)
- (modified) llvm/utils/TableGen/AsmMatcherEmitter.cpp (+35)
``````````diff
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index 19b724e481f69..98f7f4b6ec1a7 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -1394,27 +1394,6 @@ static MatchClassKind remapRegClassByHwMode(MatchClassKind Kind, bool Purecap) {
}
}
-static const MCRegisterClass *getRegClassFromMatchKind(MatchClassKind K) {
- // TODO: it would be nice to have tablegen generate this.
- switch (K) {
- case MCK_GPR:
- return &RISCVMCRegisterClasses[RISCV::GPRRegClassID];
- case MCK_GPRC:
- return &RISCVMCRegisterClasses[RISCV::GPRCRegClassID];
- case MCK_GPRSP:
- return &RISCVMCRegisterClasses[RISCV::GPRSPRegClassID];
- case MCK_YGPR:
- return &RISCVMCRegisterClasses[RISCV::YGPRRegClassID];
- case MCK_YGPRC:
- return &RISCVMCRegisterClasses[RISCV::YGPRCRegClassID];
- case MCK_YGPRNoX0:
- return &RISCVMCRegisterClasses[RISCV::YGPRNoX0RegClassID];
- case MCK_YGPRSP:
- return &RISCVMCRegisterClasses[RISCV::YGPRSPRegClassID];
- default:
- return nullptr;
- }
-}
unsigned RISCVAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
unsigned _Kind) {
diff --git a/llvm/test/TableGen/getRegClassFromMatchKind.td b/llvm/test/TableGen/getRegClassFromMatchKind.td
new file mode 100644
index 0000000000000..6c629f6e11ac4
--- /dev/null
+++ b/llvm/test/TableGen/getRegClassFromMatchKind.td
@@ -0,0 +1,104 @@
+// RUN: llvm-tblgen -gen-asm-matcher -I %p/../../include %s | FileCheck %s --check-prefix=ASMMATCHER
+// RUN: llvm-tblgen -gen-register-info -I %p/../../include %s -o %t.inc
+// RUN: FileCheck %s --check-prefix=REGINFO-ENUM --input-file=%tEnums.inc
+// RUN: FileCheck %s --check-prefix=REGINFO-DESC --input-file=%tMCDesc.inc
+
+/// This test verifies that TableGen's AsmMatcherEmitter correctly generates
+/// the target-independent `getRegClassFromMatchKind` mapping function.
+///
+/// It specifically verifies that:
+/// - Explicit named target RegisterClasses (like `RegClass`) are mapped.
+/// - Singleton registers (like `Reg` used literally in `bar` instruction)
+/// which generate implicit `MCK_Reg` match classes are NOT mapped.
+/// - Non-register class operands (like the custom immediate `MyImmOp`
+/// in `baz` instruction) are NOT mapped.
+/// - All register classes are covered by the generated function (checking enums)
+
+
+include "llvm/Target/Target.td"
+
+def ArchInstrInfo : InstrInfo { }
+
+def ArchAsmParserVariant : AsmParserVariant {
+ let Variant = 0;
+ let Name = "Arch";
+}
+
+def Arch : Target {
+ let InstructionSet = ArchInstrInfo;
+ let AssemblyParserVariants = [ArchAsmParserVariant];
+}
+
+let Namespace = "Arch" in {
+ def Reg : Register<"reg">;
+ def Reg2 : Register<"reg2">;
+}
+
+/// Use "Arch" as namespace to match the Target name.
+def RegClass : RegisterClass<"Arch", [i32], 0, (add Reg, Reg2)>;
+
+def MyImmAsmOperand : AsmOperandClass {
+ let Name = "MyImm";
+}
+
+def MyImmOp : Operand<i32> {
+ let ParserMatchClass = MyImmAsmOperand;
+}
+
+def foo : Instruction {
+ let Size = 2;
+ let OutOperandList = (outs);
+ let InOperandList = (ins RegClass:$src);
+ let AsmString = "foo $src";
+ let Namespace = "Arch";
+}
+
+def bar : Instruction {
+ let Size = 2;
+ let OutOperandList = (outs);
+ let InOperandList = (ins);
+ let AsmString = "bar reg"; // uses Reg literally, making it a singleton register
+ let Namespace = "Arch";
+}
+
+def baz : Instruction {
+ let Size = 2;
+ let OutOperandList = (outs);
+ let InOperandList = (ins MyImmOp:$imm);
+ let AsmString = "baz $imm"; // uses MyImmAsmOperand
+ let Namespace = "Arch";
+}
+
+// ASMMATCHER: enum MatchClassKind {
+// ASMMATCHER-NEXT: InvalidMatchClass = 0,
+// ASMMATCHER-NEXT: OptionalMatchClass = 1,
+// ASMMATCHER-NEXT: MCK_LAST_TOKEN = OptionalMatchClass,
+// ASMMATCHER-NEXT: MCK_Reg, // register class 'Reg'
+// ASMMATCHER-NEXT: MCK_RegClass, // register class 'RegClass'
+// ASMMATCHER-NEXT: MCK_LAST_REGISTER = MCK_RegClass,
+// ASMMATCHER-NEXT: MCK_Imm, // user defined class 'ImmAsmOperand'
+// ASMMATCHER-NEXT: MCK_MyImm, // user defined class 'MyImmAsmOperand'
+// ASMMATCHER-NEXT: NumMatchClassKinds
+// ASMMATCHER-NEXT: };
+
+// ASMMATCHER: {{\[\[}}maybe_unused]] static const MCRegisterClass *getRegClassFromMatchKind(MatchClassKind Kind) {
+// ASMMATCHER-NEXT: switch (Kind) {
+// ASMMATCHER-NEXT: case MCK_RegClass:
+// ASMMATCHER-NEXT: return &ArchMCRegisterClasses[Arch::RegClassRegClassID];
+// ASMMATCHER-NEXT: default:
+// ASMMATCHER-NEXT: return nullptr;
+// ASMMATCHER-NEXT: }
+// ASMMATCHER-NEXT: }
+
+// REGINFO-ENUM: // Register classes
+// REGINFO-ENUM-EMPTY:
+// REGINFO-ENUM-NEXT: namespace Arch {
+// REGINFO-ENUM-EMPTY:
+// REGINFO-ENUM-NEXT: enum {
+// REGINFO-ENUM-NEXT: RegClassRegClassID = 0,
+// REGINFO-ENUM-EMPTY:
+// REGINFO-ENUM-NEXT: };
+
+// REGINFO-DESC: extern const MCRegisterClass ArchMCRegisterClasses[] = {
+// REGINFO-DESC-NEXT: { RegClass, RegClassBits, 0, 2, sizeof(RegClassBits), Arch::RegClassRegClassID, 32, 1, true, false },
+// REGINFO-DESC-NEXT: };
diff --git a/llvm/utils/TableGen/AsmMatcherEmitter.cpp b/llvm/utils/TableGen/AsmMatcherEmitter.cpp
index 4c61d64ec215a..9eee31d0f0018 100644
--- a/llvm/utils/TableGen/AsmMatcherEmitter.cpp
+++ b/llvm/utils/TableGen/AsmMatcherEmitter.cpp
@@ -2520,6 +2520,37 @@ static void emitRegisterMatchErrorFunc(AsmMatcherInfo &Info, raw_ostream &OS) {
OS << "}\n\n";
}
+// Returns true if ClassName corresponds to a RegisterClass defined in the
+// target description (and thus has a generated RegClassID), rather than a
+// singleton register or an anonymous derived register class.
+static bool isDefinedRegisterClass(const AsmMatcherInfo &Info,
+ StringRef ClassName) {
+ for (const auto &RC : Info.Target.getRegBank().getRegClasses()) {
+ if (RC.getName() == ClassName)
+ return true;
+ }
+ return false;
+}
+
+static void emitGetRegClassFromMatchKindFunc(AsmMatcherInfo &Info,
+ raw_ostream &OS) {
+ OS << "[[maybe_unused]] static const MCRegisterClass "
+ "*getRegClassFromMatchKind(MatchClassKind Kind) {\n";
+ OS << " switch (Kind) {\n";
+ for (const auto &CI : Info.Classes) {
+ if (CI.isRegisterClass() && !CI.ValueName.empty() &&
+ isDefinedRegisterClass(Info, CI.ClassName)) {
+ OS << " case " << CI.Name << ":\n";
+ OS << " return &" << Info.Target.getName() << "MCRegisterClasses["
+ << Info.Target.getName() << "::" << CI.ClassName << "RegClassID];\n";
+ }
+ }
+ OS << " default:\n";
+ OS << " return nullptr;\n";
+ OS << " }\n";
+ OS << "}\n\n";
+}
+
/// emitValidateOperandClass - Emit the function to validate an operand class.
static void emitValidateOperandClass(const CodeGenTarget &Target,
AsmMatcherInfo &Info, raw_ostream &OS) {
@@ -3507,6 +3538,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << "\n#ifdef GET_MATCHER_IMPLEMENTATION\n";
OS << "#undef GET_MATCHER_IMPLEMENTATION\n\n";
+ OS << "#include \"llvm/MC/MCRegisterInfo.h\"\n\n";
// Generate the function that remaps for mnemonic aliases.
bool HasMnemonicAliases = emitMnemonicAliases(OS, Info, Target);
@@ -3528,6 +3560,9 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
// Emit a function to map register classes to operand match failure codes.
emitRegisterMatchErrorFunc(Info, OS);
+ // Emit a function to map MatchClassKind to MCRegisterClass.
+ emitGetRegClassFromMatchKindFunc(Info, OS);
+
// Emit the routine to match token strings to their match class.
emitMatchTokenString(Target, Info.Classes, OS);
``````````
</details>
https://github.com/llvm/llvm-project/pull/200453
More information about the llvm-branch-commits
mailing list