X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=utils%2FTableGen%2FAsmMatcherEmitter.cpp;h=2ec65442a330b4689feb541a67739fde6104fbbe;hp=45e3ef829fe24bf737002a1abf50ae7e3d8f29bd;hb=8dd99ee81de8af8f0500e2baeacd29bf24b7f02c;hpb=a1a9b688803a4d17af6a183f208470ddbc9c4a8d diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp index 45e3ef829fe..2ec65442a33 100644 --- a/utils/TableGen/AsmMatcherEmitter.cpp +++ b/utils/TableGen/AsmMatcherEmitter.cpp @@ -296,9 +296,11 @@ public: class AsmVariantInfo { public: + std::string RegisterPrefix; std::string TokenizingCharacters; std::string SeparatorCharacters; std::string BreakCharacters; + int AsmVariantNo; }; /// MatchableInfo - Helper class for storing the necessary information for an @@ -491,8 +493,8 @@ struct MatchableInfo { void initialize(const AsmMatcherInfo &Info, SmallPtrSetImpl &SingletonRegisters, - int AsmVariantNo, StringRef RegisterPrefix, - AsmVariantInfo const &Variant); + AsmVariantInfo const &Variant, + bool HasMnemonicFirst); /// validate - Return true if this matchable is a valid thing to match against /// and perform a bunch of validity checking. @@ -594,8 +596,7 @@ struct MatchableInfo { private: void tokenizeAsmString(AsmMatcherInfo const &Info, AsmVariantInfo const &Variant); - void addAsmOperand(size_t Start, size_t End, - std::string const &SeparatorCharacters); + void addAsmOperand(StringRef Token, bool IsIsolatedToken = false); }; /// SubtargetFeatureInfo - Helper class for storing information on a subtarget @@ -836,14 +837,33 @@ extractSingletonRegisterForAsmOperand(MatchableInfo::AsmOperand &Op, void MatchableInfo::initialize(const AsmMatcherInfo &Info, SmallPtrSetImpl &SingletonRegisters, - int AsmVariantNo, StringRef RegisterPrefix, - AsmVariantInfo const &Variant) { - AsmVariantID = AsmVariantNo; + AsmVariantInfo const &Variant, + bool HasMnemonicFirst) { + AsmVariantID = Variant.AsmVariantNo; AsmString = - CodeGenInstruction::FlattenAsmStringVariants(AsmString, AsmVariantNo); + CodeGenInstruction::FlattenAsmStringVariants(AsmString, + Variant.AsmVariantNo); tokenizeAsmString(Info, Variant); + // The first token of the instruction is the mnemonic, which must be a + // simple string, not a $foo variable or a singleton register. + if (AsmOperands.empty()) + PrintFatalError(TheDef->getLoc(), + "Instruction '" + TheDef->getName() + "' has no tokens"); + + assert(!AsmOperands[0].Token.empty()); + if (HasMnemonicFirst) { + Mnemonic = AsmOperands[0].Token; + if (Mnemonic[0] == '$') + PrintFatalError(TheDef->getLoc(), + "Invalid instruction mnemonic '" + Mnemonic + "'!"); + + // Remove the first operand, it is tracked in the mnemonic field. + AsmOperands.erase(AsmOperands.begin()); + } else if (AsmOperands[0].Token[0] != '$') + Mnemonic = AsmOperands[0].Token; + // Compute the require features. for (Record *Predicate : TheDef->getValueAsListOfDefs("Predicates")) if (const SubtargetFeatureInfo *Feature = @@ -852,7 +872,7 @@ void MatchableInfo::initialize(const AsmMatcherInfo &Info, // Collect singleton registers, if used. for (MatchableInfo::AsmOperand &Op : AsmOperands) { - extractSingletonRegisterForAsmOperand(Op, Info, RegisterPrefix); + extractSingletonRegisterForAsmOperand(Op, Info, Variant.RegisterPrefix); if (Record *Reg = Op.SingletonReg) SingletonRegisters.insert(Reg); } @@ -866,16 +886,8 @@ void MatchableInfo::initialize(const AsmMatcherInfo &Info, } /// Append an AsmOperand for the given substring of AsmString. -void MatchableInfo::addAsmOperand(size_t Start, size_t End, - std::string const &Separators) { - StringRef String = AsmString; - // Look for separators before and after to figure out is this token is - // isolated. Accept '$$' as that's how we escape '$'. - bool IsIsolatedToken = - (!Start || Separators.find(String[Start - 1]) != StringRef::npos || - String.substr(Start - 1, 2) == "$$") && - (End >= String.size() || Separators.find(String[End]) != StringRef::npos); - AsmOperands.push_back(AsmOperand(IsIsolatedToken, String.slice(Start, End))); +void MatchableInfo::addAsmOperand(StringRef Token, bool IsIsolatedToken) { + AsmOperands.push_back(AsmOperand(IsIsolatedToken, Token)); } /// tokenizeAsmString - Tokenize a simplified assembly string. @@ -884,50 +896,58 @@ void MatchableInfo::tokenizeAsmString(const AsmMatcherInfo &Info, StringRef String = AsmString; size_t Prev = 0; bool InTok = false; - std::string Separators = Variant.TokenizingCharacters + - Variant.SeparatorCharacters; + bool IsIsolatedToken = true; for (size_t i = 0, e = String.size(); i != e; ++i) { - if(Variant.BreakCharacters.find(String[i]) != std::string::npos) { - if(InTok) { - addAsmOperand(Prev, i, Separators); + char Char = String[i]; + if (Variant.BreakCharacters.find(Char) != std::string::npos) { + if (InTok) { + addAsmOperand(String.slice(Prev, i), false); Prev = i; + IsIsolatedToken = false; } InTok = true; continue; } - if(Variant.TokenizingCharacters.find(String[i]) != std::string::npos) { - if(InTok) { - addAsmOperand(Prev, i, Separators); + if (Variant.TokenizingCharacters.find(Char) != std::string::npos) { + if (InTok) { + addAsmOperand(String.slice(Prev, i), IsIsolatedToken); InTok = false; + IsIsolatedToken = false; } - addAsmOperand(i, i + 1, Separators); + addAsmOperand(String.slice(i, i + 1), IsIsolatedToken); Prev = i + 1; + IsIsolatedToken = true; continue; } - if(Variant.SeparatorCharacters.find(String[i]) != std::string::npos) { - if(InTok) { - addAsmOperand(Prev, i, Separators); + if (Variant.SeparatorCharacters.find(Char) != std::string::npos) { + if (InTok) { + addAsmOperand(String.slice(Prev, i), IsIsolatedToken); InTok = false; } Prev = i + 1; + IsIsolatedToken = true; continue; } - switch (String[i]) { + + switch (Char) { case '\\': if (InTok) { - addAsmOperand(Prev, i, Separators); + addAsmOperand(String.slice(Prev, i), false); InTok = false; + IsIsolatedToken = false; } ++i; assert(i != String.size() && "Invalid quoted character"); - addAsmOperand(i, i + 1, Separators); + addAsmOperand(String.slice(i, i + 1), IsIsolatedToken); Prev = i + 1; + IsIsolatedToken = false; break; case '$': { - if (InTok && Prev != i) { - addAsmOperand(Prev, i, Separators); + if (InTok) { + addAsmOperand(String.slice(Prev, i), false); InTok = false; + IsIsolatedToken = false; } // If this isn't "${", start new identifier looking like "$xxx" @@ -939,26 +959,20 @@ void MatchableInfo::tokenizeAsmString(const AsmMatcherInfo &Info, size_t EndPos = String.find('}', i); assert(EndPos != StringRef::npos && "Missing brace in operand reference!"); - addAsmOperand(i, EndPos+1, Separators); + addAsmOperand(String.slice(i, EndPos+1), IsIsolatedToken); Prev = EndPos + 1; i = EndPos; + IsIsolatedToken = false; break; } + default: InTok = true; + break; } } if (InTok && Prev != String.size()) - addAsmOperand(Prev, StringRef::npos, Separators); - - // The first token of the instruction is the mnemonic, which must be a - // simple string, not a $foo variable or a singleton register. - if (AsmOperands.empty()) - PrintFatalError(TheDef->getLoc(), - "Instruction '" + TheDef->getName() + "' has no tokens"); - assert(!AsmOperands[0].Token.empty()); - if (AsmOperands[0].Token[0] != '$') - Mnemonic = AsmOperands[0].Token; + addAsmOperand(String.substr(Prev), IsIsolatedToken); } bool MatchableInfo::validate(StringRef CommentDelimiter, bool Hack) const { @@ -988,8 +1002,8 @@ bool MatchableInfo::validate(StringRef CommentDelimiter, bool Hack) const { // Also, check for instructions which reference the operand multiple times; // this implies a constraint we would not honor. std::set OperandNames; - for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i) { - StringRef Tok = AsmOperands[i].Token; + for (const AsmOperand &Op : AsmOperands) { + StringRef Tok = Op.Token; if (Tok[0] == '$' && Tok.find(':') != StringRef::npos) PrintFatalError(TheDef->getLoc(), "matchable with operand modifier '" + Tok + @@ -1351,8 +1365,7 @@ void AsmMatcherInfo::buildInfo() { // Build information about all of the AssemblerPredicates. std::vector AllPredicates = Records.getAllDerivedDefinitions("Predicate"); - for (unsigned i = 0, e = AllPredicates.size(); i != e; ++i) { - Record *Pred = AllPredicates[i]; + for (Record *Pred : AllPredicates) { // Ignore predicates that are not intended for the assembler. if (!Pred->getValueAsBit("AssemblerMatcherPredicate")) continue; @@ -1366,6 +1379,8 @@ void AsmMatcherInfo::buildInfo() { assert(SubtargetFeatures.size() <= 64 && "Too many subtarget features!"); } + bool HasMnemonicFirst = AsmParser->getValueAsBit("HasMnemonicFirst"); + // Parse the instructions; we need to do this first so that we can gather the // singleton register classes. SmallPtrSet SingletonRegisters; @@ -1374,15 +1389,15 @@ void AsmMatcherInfo::buildInfo() { Record *AsmVariant = Target.getAsmParserVariant(VC); std::string CommentDelimiter = AsmVariant->getValueAsString("CommentDelimiter"); - std::string RegisterPrefix = AsmVariant->getValueAsString("RegisterPrefix"); AsmVariantInfo Variant; + Variant.RegisterPrefix = AsmVariant->getValueAsString("RegisterPrefix"); Variant.TokenizingCharacters = AsmVariant->getValueAsString("TokenizingCharacters"); Variant.SeparatorCharacters = AsmVariant->getValueAsString("SeparatorCharacters"); Variant.BreakCharacters = AsmVariant->getValueAsString("BreakCharacters"); - int AsmVariantNo = AsmVariant->getValueAsInt("Variant"); + Variant.AsmVariantNo = AsmVariant->getValueAsInt("Variant"); for (const CodeGenInstruction *CGI : Target.instructions()) { @@ -1397,8 +1412,7 @@ void AsmMatcherInfo::buildInfo() { auto II = llvm::make_unique(*CGI); - II->initialize(*this, SingletonRegisters, AsmVariantNo, RegisterPrefix, - Variant); + II->initialize(*this, SingletonRegisters, Variant, HasMnemonicFirst); // Ignore instructions which shouldn't be matched and diagnose invalid // instruction definitions with an error. @@ -1414,7 +1428,8 @@ void AsmMatcherInfo::buildInfo() { Records.getAllDerivedDefinitions("InstAlias"); for (unsigned i = 0, e = AllInstAliases.size(); i != e; ++i) { auto Alias = llvm::make_unique(AllInstAliases[i], - AsmVariantNo, Target); + Variant.AsmVariantNo, + Target); // If the tblgen -match-prefix option is specified (for tblgen hackers), // filter the set of instruction aliases we consider, based on the target @@ -1425,8 +1440,7 @@ void AsmMatcherInfo::buildInfo() { auto II = llvm::make_unique(std::move(Alias)); - II->initialize(*this, SingletonRegisters, AsmVariantNo, RegisterPrefix, - Variant); + II->initialize(*this, SingletonRegisters, Variant, HasMnemonicFirst); // Validate the alias definitions. II->validate(CommentDelimiter, false); @@ -1732,7 +1746,7 @@ static unsigned getConverterOperandID(const std::string &Name, static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, std::vector> &Infos, - raw_ostream &OS) { + bool HasMnemonicFirst, raw_ostream &OS) { SmallSetVector OperandConversionKinds; SmallSetVector InstructionConversionKinds; std::vector > ConversionTable; @@ -1866,7 +1880,7 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, // Add the operand entry to the instruction kind conversion row. ConversionRow.push_back(ID); - ConversionRow.push_back(OpInfo.AsmOperandNum); + ConversionRow.push_back(OpInfo.AsmOperandNum + HasMnemonicFirst); if (!IsNewConverter) break; @@ -1988,8 +2002,8 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, // Output the operand conversion kind enum. OS << "enum OperatorConversionKind {\n"; - for (unsigned i = 0, e = OperandConversionKinds.size(); i != e; ++i) - OS << " " << OperandConversionKinds[i] << ",\n"; + for (const std::string &Converter : OperandConversionKinds) + OS << " " << Converter << ",\n"; OS << " CVT_NUM_CONVERTERS\n"; OS << "};\n\n"; @@ -2119,12 +2133,7 @@ static void emitIsSubclass(CodeGenTarget &Target, OS << " if (A == B)\n"; OS << " return true;\n\n"; - std::string OStr; - raw_string_ostream SS(OStr); - unsigned Count = 0; - SS << " switch (A) {\n"; - SS << " default:\n"; - SS << " return false;\n"; + bool EmittedSwitch = false; for (const auto &A : Infos) { std::vector SuperClasses; for (const auto &B : Infos) { @@ -2134,32 +2143,38 @@ static void emitIsSubclass(CodeGenTarget &Target, if (SuperClasses.empty()) continue; - ++Count; - SS << "\n case " << A.Name << ":\n"; + // If this is the first SuperClass, emit the switch header. + if (!EmittedSwitch) { + OS << " switch (A) {\n"; + OS << " default:\n"; + OS << " return false;\n"; + EmittedSwitch = true; + } + + OS << "\n case " << A.Name << ":\n"; if (SuperClasses.size() == 1) { - SS << " return B == " << SuperClasses.back().str() << ";\n"; + OS << " return B == " << SuperClasses.back() << ";\n"; continue; } if (!SuperClasses.empty()) { - SS << " switch (B) {\n"; - SS << " default: return false;\n"; - for (unsigned i = 0, e = SuperClasses.size(); i != e; ++i) - SS << " case " << SuperClasses[i].str() << ": return true;\n"; - SS << " }\n"; + OS << " switch (B) {\n"; + OS << " default: return false;\n"; + for (StringRef SC : SuperClasses) + OS << " case " << SC << ": return true;\n"; + OS << " }\n"; } else { // No case statement to emit - SS << " return false;\n"; + OS << " return false;\n"; } } - SS << " }\n"; - // If there were case statements emitted into the string stream, write them - // to the output stream, otherwise write the default. - if (Count) - OS << SS.str(); + // If there were case statements emitted into the string stream write the + // default. + if (EmittedSwitch) + OS << " }\n"; else OS << " return false;\n"; @@ -2247,19 +2262,16 @@ static void emitSubtargetFeatureFlagEnumeration(AsmMatcherInfo &Info, static void emitOperandDiagnosticTypes(AsmMatcherInfo &Info, raw_ostream &OS) { // Get the set of diagnostic types from all of the operand classes. std::set Types; - for (std::map::const_iterator - I = Info.AsmOperandClasses.begin(), - E = Info.AsmOperandClasses.end(); I != E; ++I) { - if (!I->second->DiagnosticType.empty()) - Types.insert(I->second->DiagnosticType); + for (const auto &OpClassEntry : Info.AsmOperandClasses) { + if (!OpClassEntry.second->DiagnosticType.empty()) + Types.insert(OpClassEntry.second->DiagnosticType); } if (Types.empty()) return; // Now emit the enum entries. - for (std::set::const_iterator I = Types.begin(), E = Types.end(); - I != E; ++I) - OS << " Match_" << *I << ",\n"; + for (StringRef Type : Types) + OS << " Match_" << Type << ",\n"; OS << " END_OPERAND_DIAGNOSTIC_TYPES\n"; } @@ -2367,8 +2379,7 @@ static void emitMnemonicAliasVariant(raw_ostream &OS,const AsmMatcherInfo &Info, // iteration order of the map is stable. std::map > AliasesFromMnemonic; - for (unsigned i = 0, e = Aliases.size(); i != e; ++i) { - Record *R = Aliases[i]; + for (Record *R : Aliases) { // FIXME: Allow AssemblerVariantName to be a comma separated list. std::string AsmVariantName = R->getValueAsString("AsmVariantName"); if (AsmVariantName != AsmParserVariantName) @@ -2381,10 +2392,8 @@ static void emitMnemonicAliasVariant(raw_ostream &OS,const AsmMatcherInfo &Info, // Process each alias a "from" mnemonic at a time, building the code executed // by the string remapper. std::vector Cases; - for (std::map >::iterator - I = AliasesFromMnemonic.begin(), E = AliasesFromMnemonic.end(); - I != E; ++I) { - const std::vector &ToVec = I->second; + for (const auto &AliasEntry : AliasesFromMnemonic) { + const std::vector &ToVec = AliasEntry.second; // Loop through each alias and emit code that handles each case. If there // are two instructions without predicates, emit an error. If there is one, @@ -2409,7 +2418,7 @@ static void emitMnemonicAliasVariant(raw_ostream &OS,const AsmMatcherInfo &Info, AliasWithNoPredicate = i; continue; } - if (R->getValueAsString("ToMnemonic") == I->first) + if (R->getValueAsString("ToMnemonic") == AliasEntry.first) PrintFatalError(R->getLoc(), "MnemonicAlias to the same string"); if (!MatchCode.empty()) @@ -2427,7 +2436,7 @@ static void emitMnemonicAliasVariant(raw_ostream &OS,const AsmMatcherInfo &Info, MatchCode += "return;"; - Cases.push_back(std::make_pair(I->first, MatchCode)); + Cases.push_back(std::make_pair(AliasEntry.first, MatchCode)); } StringMatcher("Mnemonic", Cases, OS).Emit(Indent); } @@ -2470,12 +2479,10 @@ static bool emitMnemonicAliases(raw_ostream &OS, const AsmMatcherInfo &Info, static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target, const AsmMatcherInfo &Info, StringRef ClassName, StringToOffsetTable &StringTable, - unsigned MaxMnemonicIndex) { + unsigned MaxMnemonicIndex, bool HasMnemonicFirst) { unsigned MaxMask = 0; - for (std::vector::const_iterator it = - Info.OperandMatchInfo.begin(), ie = Info.OperandMatchInfo.end(); - it != ie; ++it) { - MaxMask |= it->OperandMask; + for (const OperandMatchEntry &OMI : Info.OperandMatchInfo) { + MaxMask |= OMI.OperandMask; } // Emit the static custom operand parsing table; @@ -2515,10 +2522,7 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target, << Info.OperandMatchInfo.size() << "] = {\n"; OS << " /* Operand List Mask, Mnemonic, Operand Class, Features */\n"; - for (std::vector::const_iterator it = - Info.OperandMatchInfo.begin(), ie = Info.OperandMatchInfo.end(); - it != ie; ++it) { - const OperandMatchEntry &OMI = *it; + for (const OperandMatchEntry &OMI : Info.OperandMatchInfo) { const MatchableInfo &II = *OMI.MI; OS << " { "; @@ -2589,19 +2593,25 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target, OS << " uint64_t AvailableFeatures = getAvailableFeatures();\n\n"; OS << " // Get the next operand index.\n"; - OS << " unsigned NextOpNum = Operands.size();\n"; + OS << " unsigned NextOpNum = Operands.size()" + << (HasMnemonicFirst ? " - 1" : "") << ";\n"; // Emit code to search the table. OS << " // Search the table.\n"; - OS << " std::pair"; - OS << " MnemonicRange\n"; - OS << " (OperandMatchTable, OperandMatchTable+"; - OS << Info.OperandMatchInfo.size() << ");\n"; - OS << " if(!Mnemonic.empty())\n"; - OS << " MnemonicRange = std::equal_range(OperandMatchTable,"; - OS << " OperandMatchTable+" - << Info.OperandMatchInfo.size() << ", Mnemonic,\n" - << " LessOpcodeOperand());\n\n"; + if (HasMnemonicFirst) { + OS << " auto MnemonicRange =\n"; + OS << " std::equal_range(std::begin(OperandMatchTable), " + "std::end(OperandMatchTable),\n"; + OS << " Mnemonic, LessOpcodeOperand());\n\n"; + } else { + OS << " auto MnemonicRange = std::make_pair(std::begin(OperandMatchTable)," + " std::end(OperandMatchTable));\n"; + OS << " if (!Mnemonic.empty())\n"; + OS << " MnemonicRange =\n"; + OS << " std::equal_range(std::begin(OperandMatchTable), " + "std::end(OperandMatchTable),\n"; + OS << " Mnemonic, LessOpcodeOperand());\n\n"; + } OS << " if (MnemonicRange.first == MnemonicRange.second)\n"; OS << " return MatchOperand_NoMatch;\n\n"; @@ -2686,6 +2696,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { // Compute the information on the custom operand parsing. Info.buildOperandMatchInfo(); + bool HasMnemonicFirst = AsmParser->getValueAsBit("HasMnemonicFirst"); + // Write the output. // Information for the class declaration. @@ -2700,7 +2712,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { << "&Operands);\n"; OS << " void convertToMapAndConstraints(unsigned Kind,\n "; OS << " const OperandVector &Operands) override;\n"; - OS << " bool mnemonicIsValid(StringRef Mnemonic, unsigned VariantID);\n"; + if (HasMnemonicFirst) + OS << " bool mnemonicIsValid(StringRef Mnemonic, unsigned VariantID);\n"; OS << " unsigned MatchInstructionImpl(const OperandVector &Operands,\n" << " MCInst &Inst,\n" << " uint64_t &ErrorInfo," @@ -2761,7 +2774,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { // Generate the convertToMCInst function to convert operands into an MCInst. // Also, generate the convertToMapAndConstraints function for MS-style inline // assembly. The latter doesn't actually generate a MCInst. - emitConvertFuncs(Target, ClassName, Info.Matchables, OS); + emitConvertFuncs(Target, ClassName, Info.Matchables, HasMnemonicFirst, OS); // Emit the enumeration for classes which participate in matching. emitMatchClassEnumeration(Target, Info.Classes, OS); @@ -2883,24 +2896,26 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { } // A method to determine if a mnemonic is in the list. - OS << "bool " << Target.getName() << ClassName << "::\n" - << "mnemonicIsValid(StringRef Mnemonic, unsigned VariantID) {\n"; - OS << " // Find the appropriate table for this asm variant.\n"; - OS << " const MatchEntry *Start, *End;\n"; - OS << " switch (VariantID) {\n"; - OS << " default: llvm_unreachable(\"invalid variant!\");\n"; - for (unsigned VC = 0; VC != VariantCount; ++VC) { - Record *AsmVariant = Target.getAsmParserVariant(VC); - int AsmVariantNo = AsmVariant->getValueAsInt("Variant"); - OS << " case " << AsmVariantNo << ": Start = std::begin(MatchTable" << VC - << "); End = std::end(MatchTable" << VC << "); break;\n"; + if (HasMnemonicFirst) { + OS << "bool " << Target.getName() << ClassName << "::\n" + << "mnemonicIsValid(StringRef Mnemonic, unsigned VariantID) {\n"; + OS << " // Find the appropriate table for this asm variant.\n"; + OS << " const MatchEntry *Start, *End;\n"; + OS << " switch (VariantID) {\n"; + OS << " default: llvm_unreachable(\"invalid variant!\");\n"; + for (unsigned VC = 0; VC != VariantCount; ++VC) { + Record *AsmVariant = Target.getAsmParserVariant(VC); + int AsmVariantNo = AsmVariant->getValueAsInt("Variant"); + OS << " case " << AsmVariantNo << ": Start = std::begin(MatchTable" << VC + << "); End = std::end(MatchTable" << VC << "); break;\n"; + } + OS << " }\n"; + OS << " // Search the table.\n"; + OS << " auto MnemonicRange = "; + OS << "std::equal_range(Start, End, Mnemonic, LessOpcode());\n"; + OS << " return MnemonicRange.first != MnemonicRange.second;\n"; + OS << "}\n\n"; } - OS << " }\n"; - OS << " // Search the table.\n"; - OS << " std::pair MnemonicRange =\n"; - OS << " std::equal_range(Start, End, Mnemonic, LessOpcode());\n"; - OS << " return MnemonicRange.first != MnemonicRange.second;\n"; - OS << "}\n\n"; // Finally, build the match function. OS << "unsigned " << Target.getName() << ClassName << "::\n" @@ -2909,8 +2924,10 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { << " bool matchingInlineAsm, unsigned VariantID) {\n"; OS << " // Eliminate obvious mismatches.\n"; - OS << " if (Operands.size() > " << MaxNumOperands << ") {\n"; - OS << " ErrorInfo = " << MaxNumOperands << ";\n"; + OS << " if (Operands.size() > " + << (MaxNumOperands + HasMnemonicFirst) << ") {\n"; + OS << " ErrorInfo = " + << (MaxNumOperands + HasMnemonicFirst) << ";\n"; OS << " return Match_InvalidOperand;\n"; OS << " }\n\n"; @@ -2919,10 +2936,15 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " uint64_t AvailableFeatures = getAvailableFeatures();\n\n"; OS << " // Get the instruction mnemonic, which is the first token.\n"; - OS << " StringRef Mnemonic;\n"; - OS << " if (Operands[0]->isToken())\n"; - OS << " Mnemonic = ((" << Target.getName() - << "Operand&)*Operands[0]).getToken();\n\n"; + if (HasMnemonicFirst) { + OS << " StringRef Mnemonic = ((" << Target.getName() + << "Operand&)*Operands[0]).getToken();\n\n"; + } else { + OS << " StringRef Mnemonic;\n"; + OS << " if (Operands[0]->isToken())\n"; + OS << " Mnemonic = ((" << Target.getName() + << "Operand&)*Operands[0]).getToken();\n\n"; + } if (HasMnemonicAliases) { OS << " // Process all MnemonicAliases to remap the mnemonic.\n"; @@ -2951,12 +2973,18 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { << "); End = std::end(MatchTable" << VC << "); break;\n"; } OS << " }\n"; + OS << " // Search the table.\n"; - OS << " std::pair " - "MnemonicRange(Start, End);\n"; - OS << " unsigned SIndex = Mnemonic.empty() ? 0 : 1;\n"; - OS << " if (!Mnemonic.empty())\n"; - OS << " MnemonicRange = std::equal_range(Start, End, Mnemonic.lower(), LessOpcode());\n\n"; + if (HasMnemonicFirst) { + OS << " auto MnemonicRange = " + "std::equal_range(Start, End, Mnemonic, LessOpcode());\n\n"; + } else { + OS << " auto MnemonicRange = std::make_pair(Start, End);\n"; + OS << " unsigned SIndex = Mnemonic.empty() ? 0 : 1;\n"; + OS << " if (!Mnemonic.empty())\n"; + OS << " MnemonicRange = " + "std::equal_range(Start, End, Mnemonic.lower(), LessOpcode());\n\n"; + } OS << " // Return a more specific error code if no mnemonics match.\n"; OS << " if (MnemonicRange.first == MnemonicRange.second)\n"; @@ -2966,16 +2994,25 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { << "*ie = MnemonicRange.second;\n"; OS << " it != ie; ++it) {\n"; + if (HasMnemonicFirst) { + OS << " // equal_range guarantees that instruction mnemonic matches.\n"; + OS << " assert(Mnemonic == it->getMnemonic());\n"; + } + // Emit check that the subclasses match. OS << " bool OperandsValid = true;\n"; - OS << " for (unsigned i = SIndex; i != " << MaxNumOperands << "; ++i) {\n"; + OS << " for (unsigned i = " << (HasMnemonicFirst ? "0" : "SIndex") + << "; i != " << MaxNumOperands << "; ++i) {\n"; OS << " auto Formal = static_cast(it->Classes[i]);\n"; - OS << " if (i >= Operands.size()) {\n"; + OS << " if (i" << (HasMnemonicFirst ? "+1" : "") + << " >= Operands.size()) {\n"; OS << " OperandsValid = (Formal == " <<"InvalidMatchClass);\n"; - OS << " if (!OperandsValid) ErrorInfo = i;\n"; + OS << " if (!OperandsValid) ErrorInfo = i" + << (HasMnemonicFirst ? "+1" : "") << ";\n"; OS << " break;\n"; OS << " }\n"; - OS << " MCParsedAsmOperand &Actual = *Operands[i];\n"; + OS << " MCParsedAsmOperand &Actual = *Operands[i" + << (HasMnemonicFirst ? "+1" : "") << "];\n"; OS << " unsigned Diag = validateOperandClass(Actual, Formal);\n"; OS << " if (Diag == Match_Success)\n"; OS << " continue;\n"; @@ -2991,8 +3028,9 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " // If we already had a match that only failed due to a\n"; OS << " // target predicate, that diagnostic is preferred.\n"; OS << " if (!HadMatchOtherThanPredicate &&\n"; - OS << " (it == MnemonicRange.first || ErrorInfo <= i)) {\n"; - OS << " ErrorInfo = i;\n"; + OS << " (it == MnemonicRange.first || ErrorInfo <= i" + << (HasMnemonicFirst ? "+1" : "") << ")) {\n"; + OS << " ErrorInfo = i" << (HasMnemonicFirst ? "+1" : "") << ";\n"; OS << " // InvalidOperand is the default. Prefer specificity.\n"; OS << " if (Diag != Match_InvalidOperand)\n"; OS << " RetCode = Diag;\n"; @@ -3067,7 +3105,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { if (!Info.OperandMatchInfo.empty()) emitCustomOperandParsing(OS, Target, Info, ClassName, StringTable, - MaxMnemonicIndex); + MaxMnemonicIndex, HasMnemonicFirst); OS << "#endif // GET_MATCHER_IMPLEMENTATION\n\n"; }