[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.
This commit is contained in:
woruyu 2026-01-27 13:54:26 +08:00 committed by GitHub
parent f5de33dbf5
commit 170ad2335e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 81 additions and 11 deletions

View File

@ -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<i32> {
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: }

View File

@ -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";
}