Index: llvm/trunk/include/llvm/Target/Target.td =================================================================== --- llvm/trunk/include/llvm/Target/Target.td +++ llvm/trunk/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 suppressed 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: llvm/trunk/utils/TableGen/AsmMatcherEmitter.cpp =================================================================== --- llvm/trunk/utils/TableGen/AsmMatcherEmitter.cpp +++ llvm/trunk/utils/TableGen/AsmMatcherEmitter.cpp @@ -200,6 +200,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 { @@ -1115,6 +1119,7 @@ Entry->RenderMethod = ""; Entry->ParserMethod = ""; Entry->DiagnosticType = ""; + Entry->IsOptional = false; } return Entry; @@ -1249,6 +1254,7 @@ CI->Registers = RS; // FIXME: diagnostic type. CI->DiagnosticType = ""; + CI->IsOptional = false; RegisterSetClasses.insert(std::make_pair(RS, CI)); ++Index; } @@ -1363,6 +1369,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; } } @@ -2102,6 +2112,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) { @@ -2188,6 +2199,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); @@ -3100,7 +3113,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";