From b9f235e5ced0a8119da0fe3e8e624e5b9a04d33d Mon Sep 17 00:00:00 2001 From: Tom Stellard Date: Fri, 5 Feb 2016 19:59:33 +0000 Subject: [PATCH] TableGen: Add IsOptional field to AsmOperandClass Summary: This makes it possible to specify some operands as optional to the AsmMatcher. Setting this field to true will prevent the AsmMatcher from emitting 'too few operands' errors when there are missing optional operands. Reviewers: olista01, ab Subscribers: nhaustov, arsenm, llvm-commits Differential Revision: http://reviews.llvm.org/D15755 llvm-svn: 259913 --- llvm/include/llvm/Target/Target.td | 9 +++++++++ llvm/utils/TableGen/AsmMatcherEmitter.cpp | 16 +++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td index 275be5902210..562bbfb8a981 100644 --- a/llvm/include/llvm/Target/Target.td +++ b/llvm/include/llvm/Target/Target.td @@ -605,6 +605,15 @@ class AsmOperandClass { // 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 { diff --git a/llvm/utils/TableGen/AsmMatcherEmitter.cpp b/llvm/utils/TableGen/AsmMatcherEmitter.cpp index 07dbd2853055..103ed99e35c5 100644 --- a/llvm/utils/TableGen/AsmMatcherEmitter.cpp +++ b/llvm/utils/TableGen/AsmMatcherEmitter.cpp @@ -200,6 +200,10 @@ struct ClassInfo { /// 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 @@ ClassInfo *AsmMatcherInfo::getTokenClass(StringRef Token) { Entry->RenderMethod = ""; Entry->ParserMethod = ""; Entry->DiagnosticType = ""; + Entry->IsOptional = false; } return Entry; @@ -1249,6 +1254,7 @@ buildRegisterClasses(SmallPtrSetImpl &SingletonRegisters) { CI->Registers = RS; // FIXME: diagnostic type. CI->DiagnosticType = ""; + CI->IsOptional = false; RegisterSetClasses.insert(std::make_pair(RS, CI)); ++Index; } @@ -1363,6 +1369,10 @@ void AsmMatcherInfo::buildOperandClasses() { 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 @@ static void emitMatchClassEnumeration(CodeGenTarget &Target, << "/// 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 @@ static void emitIsSubclass(CodeGenTarget &Target, 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 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { 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";