From 170ad2335e5c4a3bf53fdd5bfeeb9fe8350398b4 Mon Sep 17 00:00:00 2001 From: woruyu <1214539920@qq.com> Date: Tue, 27 Jan 2026 13:54:26 +0800 Subject: [PATCH] [TableGen][AsmMatcher] Fix optional operand mask indexing when HasMnemonicFirst is false (#176868) ### Summary Fix optional operand mask indexing in the generated asm matcher when HasMnemonicFirst is false. --- llvm/test/TableGen/NotFirstMnemonic.td | 64 +++++++++++++++++++++++ llvm/utils/TableGen/AsmMatcherEmitter.cpp | 28 ++++++---- 2 files changed, 81 insertions(+), 11 deletions(-) create mode 100644 llvm/test/TableGen/NotFirstMnemonic.td diff --git a/llvm/test/TableGen/NotFirstMnemonic.td b/llvm/test/TableGen/NotFirstMnemonic.td new file mode 100644 index 000000000000..2e481b3bcded --- /dev/null +++ b/llvm/test/TableGen/NotFirstMnemonic.td @@ -0,0 +1,64 @@ +// RUN: llvm-tblgen -gen-asm-matcher -I %p/../../include %s | FileCheck %s + +// Check that specifying AsmVariant works correctly + +include "llvm/Target/Target.td" + +def ArchParser : AsmParser { + let HasMnemonicFirst = 0; +} + +def Arch : Target { + let AssemblyParsers = [ArchParser]; +} + +def Reg : Register<"reg">; + +def RegClass : RegisterClass<"foo", [i32], 0, (add Reg)>; + +def OptinalAsmOperand :AsmOperandClass { + let Name = "OptinalAsmOperand"; + let RenderMethod = "addOptinalAsmOperand"; + let IsOptional = 1; +} + +def OptinalOperand : Operand { + let OperandNamespace = "Arch"; + let OperandType = "OPERAND_INPUT_MODS"; + let PrintMethod = "printOptinalOperand"; + let ParserMatchClass = OptinalAsmOperand; +} + +class InstCommonBase { + field bits<64> Inst; +} + +def foo : Instruction, InstCommonBase { + bits<32> optinalOp; + + let Size = 2; + let OutOperandList = (outs); + let InOperandList = (ins OptinalOperand:$optinalOp); + let AsmString = "$optinalOp\tfoo"; + let Namespace = "Arch"; + + let Inst{22 - 10} = optinalOp{12 - 0}; +} + +// CHECK: if (OptionalOperandsMask[*(p + 1)]) { + +// CHECK: SmallBitVector OptionalOperandsMask(2); + +// CHECK: OptionalOperandsMask.reset(0, 2); + +// CHECK: if (Formal == InvalidMatchClass) { +// CHECK-NEXT: OptionalOperandsMask.set(FormalIdx, 2); +// CHECK: if (isSubclass(Formal, OptionalMatchClass)) { +// CHECK-NEXT: OptionalOperandsMask.set(FormalIdx); +// CHECK: if (Diag == Match_InvalidOperand && isSubclass(Formal, OptionalMatchClass)) { +// CHECK-NEXT: OptionalOperandsMask.set(FormalIdx); + +// CHECK: for (unsigned i = 0, NumDefaults = 0; i < 2; ++i) { +// CHECK-NEXT: NumDefaults += (OptionalOperandsMask[i] ? 1 : 0); +// CHECK-NEXT: DefaultsOffset[i + 1] = NumDefaults; +// CHECK-NEXT: } diff --git a/llvm/utils/TableGen/AsmMatcherEmitter.cpp b/llvm/utils/TableGen/AsmMatcherEmitter.cpp index e6085af5aa91..5610123f3323 100644 --- a/llvm/utils/TableGen/AsmMatcherEmitter.cpp +++ b/llvm/utils/TableGen/AsmMatcherEmitter.cpp @@ -2183,7 +2183,7 @@ emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, // If optional operand is not present in actual instruction then we // should call its DefaultMethod before RenderMethod assert(HasOptionalOperands); - CvtOS << " if (OptionalOperandsMask[*(p + 1) - 1]) {\n" + CvtOS << " if (OptionalOperandsMask[*(p + 1)]) {\n" << " " << Op.Class->DefaultMethod << "()" << "->" << Op.Class->RenderMethod << "(Inst, " << OpInfo.MINumOperands << ");\n" @@ -3733,7 +3733,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { } if (HasOptionalOperands) - OS << " SmallBitVector OptionalOperandsMask(" << MaxNumOperands << ");\n"; + OS << " SmallBitVector OptionalOperandsMask(" + << MaxNumOperands + HasMnemonicFirst << ");\n"; // Emit code to search the table. OS << " // Find the appropriate table for this asm variant.\n"; @@ -3802,7 +3803,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { if (!ReportMultipleNearMisses) OS << " bool OperandsValid = true;\n"; if (HasOptionalOperands) - OS << " OptionalOperandsMask.reset(0, " << MaxNumOperands << ");\n"; + OS << " OptionalOperandsMask.reset(0, " + << MaxNumOperands + HasMnemonicFirst << ");\n"; OS << " for (unsigned FormalIdx = " << (HasMnemonicFirst ? "0" : "SIndex") << ", ActualIdx = " << (HasMnemonicFirst ? "1" : "SIndex") << "; FormalIdx != " << MaxNumOperands << "; ++FormalIdx) {\n"; @@ -3850,21 +3852,24 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"but formal " "operand not required\\n\");\n"; OS << " if (isSubclass(Formal, OptionalMatchClass)) {\n"; - OS << " OptionalOperandsMask.set(FormalIdx);\n"; + OS << " OptionalOperandsMask.set(" + << (HasMnemonicFirst ? "FormalIdx + 1" : "FormalIdx") << ");\n"; OS << " }\n"; OS << " }\n"; OS << " continue;\n"; } else { OS << " if (Formal == InvalidMatchClass) {\n"; if (HasOptionalOperands) { - OS << " OptionalOperandsMask.set(FormalIdx, " << MaxNumOperands - << ");\n"; + OS << " OptionalOperandsMask.set(" + << (HasMnemonicFirst ? "FormalIdx + 1, " : "FormalIdx, ") + << MaxNumOperands + HasMnemonicFirst << ");\n"; } OS << " break;\n"; OS << " }\n"; OS << " if (isSubclass(Formal, OptionalMatchClass)) {\n"; if (HasOptionalOperands) - OS << " OptionalOperandsMask.set(FormalIdx);\n"; + OS << " OptionalOperandsMask.set(" + << (HasMnemonicFirst ? "FormalIdx + 1" : "FormalIdx") << ");\n"; OS << " continue;\n"; OS << " }\n"; OS << " OperandsValid = false;\n"; @@ -3904,7 +3909,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " if (Diag == Match_InvalidOperand " << "&& isSubclass(Formal, OptionalMatchClass)) {\n"; if (HasOptionalOperands) - OS << " OptionalOperandsMask.set(FormalIdx);\n"; + OS << " OptionalOperandsMask.set(" + << (HasMnemonicFirst ? "FormalIdx + 1" : "FormalIdx") << ");\n"; OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"ignoring " "optional operand\\n\");\n"; OS << " continue;\n"; @@ -4059,12 +4065,12 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { if (HasOptionalOperands) { OS << " unsigned DefaultsOffset[" << (MaxNumOperands + 1) << "] = { 0 };\n"; - OS << " assert(OptionalOperandsMask.size() == " << (MaxNumOperands) - << ");\n"; + OS << " assert(OptionalOperandsMask.size() == " + << (MaxNumOperands + HasMnemonicFirst) << ");\n"; OS << " for (unsigned i = 0, NumDefaults = 0; i < " << (MaxNumOperands) << "; ++i) {\n"; - OS << " DefaultsOffset[i + 1] = NumDefaults;\n"; OS << " NumDefaults += (OptionalOperandsMask[i] ? 1 : 0);\n"; + OS << " DefaultsOffset[i + 1] = NumDefaults;\n"; OS << " }\n\n"; }