Index: include/llvm/Target/Target.td =================================================================== --- include/llvm/Target/Target.td +++ include/llvm/Target/Target.td @@ -605,6 +605,15 @@ // match failure error message. By default, use a generic "invalid operand" // diagnostic. The target AsmParser maps these codes to text. string DiagnosticType = ""; + + /// Set to 1 if this operand is optional and not always required. Typically, + /// the AsmParser will emit an error when it finishes parsing an + /// instruction if it hasn't matched all the operands yet. However, this + /// error will be surppressed if all of the remaining unmatched operands are + /// marked as IsOptional. + /// + /// Optional arguments must be at the end of the operand list. + bit IsOptional = 0; } def ImmAsmOperand : AsmOperandClass { Index: utils/TableGen/AsmMatcherEmitter.cpp =================================================================== --- utils/TableGen/AsmMatcherEmitter.cpp +++ utils/TableGen/AsmMatcherEmitter.cpp @@ -199,6 +199,10 @@ /// For custom match classes: the diagnostic kind for when the predicate fails. std::string DiagnosticType; + + /// Is this operand optional and not always required. + bool IsOptional; + public: /// isRegisterClass() - Check if this is a register class. bool isRegisterClass() const { @@ -1116,6 +1120,7 @@ Entry->RenderMethod = ""; Entry->ParserMethod = ""; Entry->DiagnosticType = ""; + Entry->IsOptional = false; } return Entry; @@ -1251,6 +1256,7 @@ CI->Registers = RS; // FIXME: diagnostic type. CI->DiagnosticType = ""; + CI->IsOptional = false; RegisterSetClasses.insert(std::make_pair(RS, CI)); ++Index; } @@ -1365,6 +1371,10 @@ if (StringInit *SI = dyn_cast(DiagnosticType)) CI->DiagnosticType = SI->getValue(); + Init *IsOptional = Rec->getValueInit("IsOptional"); + if (BitInit *BI = dyn_cast(IsOptional)) + CI->IsOptional = BI->getValue(); + ++Index; } } @@ -2106,6 +2116,7 @@ << "/// instruction matching.\n"; OS << "enum MatchClassKind {\n"; OS << " InvalidMatchClass = 0,\n"; + OS << " OptionalMatchClass = 1,\n"; for (const auto &CI : Infos) { OS << " " << CI.Name << ", // "; if (CI.Kind == ClassInfo::Token) { @@ -2192,6 +2203,8 @@ bool EmittedSwitch = false; for (const auto &A : Infos) { std::vector SuperClasses; + if (A.IsOptional) + SuperClasses.push_back("OptionalMatchClass"); for (const auto &B : Infos) { if (&A != &B && A.isSubsetOf(B)) SuperClasses.push_back(B.Name); @@ -3072,7 +3085,8 @@ OS << " auto Formal = static_cast(it->Classes[i]);\n"; OS << " if (i" << (HasMnemonicFirst ? "+1" : "") << " >= Operands.size()) {\n"; - OS << " OperandsValid = (Formal == " <<"InvalidMatchClass);\n"; + OS << " OperandsValid = (Formal == " <<"InvalidMatchClass) || " + << "isSubclass(Formal, OptionalMatchClass);\n"; OS << " if (!OperandsValid) ErrorInfo = i" << (HasMnemonicFirst ? "+1" : "") << ";\n"; OS << " break;\n";