diff options
Diffstat (limited to 'utils/TableGen/AsmMatcherEmitter.cpp')
-rw-r--r-- | utils/TableGen/AsmMatcherEmitter.cpp | 246 |
1 files changed, 165 insertions, 81 deletions
diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp index 5b4229e64682..146d10835b8d 100644 --- a/utils/TableGen/AsmMatcherEmitter.cpp +++ b/utils/TableGen/AsmMatcherEmitter.cpp @@ -1,9 +1,8 @@ //===- AsmMatcherEmitter.cpp - Generate an assembly matcher ---------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -1073,8 +1072,9 @@ bool MatchableInfo::validate(StringRef CommentDelimiter, bool IsAlias) const { // handle, the target should be refactored to use operands instead of // modifiers. // - // Also, check for instructions which reference the operand multiple times; - // this implies a constraint we would not honor. + // Also, check for instructions which reference the operand multiple times, + // if they don't define a custom AsmMatcher: this implies a constraint that + // the built-in matching code would not honor. std::set<std::string> OperandNames; for (const AsmOperand &Op : AsmOperands) { StringRef Tok = Op.Token; @@ -1084,7 +1084,8 @@ bool MatchableInfo::validate(StringRef CommentDelimiter, bool IsAlias) const { "' not supported by asm matcher. Mark isCodeGenOnly!"); // Verify that any operand is only mentioned once. // We reject aliases and ignore instructions for now. - if (!IsAlias && Tok[0] == '$' && !OperandNames.insert(Tok).second) { + if (!IsAlias && TheDef->getValueAsString("AsmMatchConverter").empty() && + Tok[0] == '$' && !OperandNames.insert(Tok).second) { LLVM_DEBUG({ errs() << "warning: '" << TheDef->getName() << "': " << "ignoring instruction with tied operand '" @@ -1160,8 +1161,9 @@ AsmMatcherInfo::getOperandClass(Record *Rec, int SubOpIdx) { // use it, else just fall back to the underlying register class. const RecordVal *R = Rec->getValue("ParserMatchClass"); if (!R || !R->getValue()) - PrintFatalError("Record `" + Rec->getName() + - "' does not have a ParserMatchClass!\n"); + PrintFatalError(Rec->getLoc(), + "Record `" + Rec->getName() + + "' does not have a ParserMatchClass!\n"); if (DefInit *DI= dyn_cast<DefInit>(R->getValue())) { Record *MatchClass = DI->getDef(); @@ -1473,7 +1475,6 @@ void AsmMatcherInfo::buildInfo() { for (const auto &Pair : SubtargetFeatures) LLVM_DEBUG(Pair.second.dump()); #endif // NDEBUG - assert(SubtargetFeatures.size() <= 64 && "Too many subtarget features!"); bool HasMnemonicFirst = AsmParser->getValueAsBit("HasMnemonicFirst"); bool ReportMultipleNearMisses = @@ -1928,10 +1929,11 @@ getConverterOperandID(const std::string &Name, return ID; } -static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, - std::vector<std::unique_ptr<MatchableInfo>> &Infos, - bool HasMnemonicFirst, bool HasOptionalOperands, - raw_ostream &OS) { +static unsigned +emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, + std::vector<std::unique_ptr<MatchableInfo>> &Infos, + bool HasMnemonicFirst, bool HasOptionalOperands, + raw_ostream &OS) { SmallSetVector<CachedHashString, 16> OperandConversionKinds; SmallSetVector<CachedHashString, 16> InstructionConversionKinds; std::vector<std::vector<uint8_t> > ConversionTable; @@ -2337,6 +2339,8 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, // Spit out the operand number lookup function. OS << OpOS.str(); + + return ConversionTable.size(); } /// emitMatchClassEnumeration - Emit the enumeration for match class kinds. @@ -2675,7 +2679,7 @@ static void emitGetSubtargetFeatureName(AsmMatcherInfo &Info, raw_ostream &OS) { for (const auto &SF : Info.SubtargetFeatures) { const SubtargetFeatureInfo &SFI = SF.second; // FIXME: Totally just a placeholder name to get the algorithm working. - OS << " case " << SFI.getEnumName() << ": return \"" + OS << " case " << SFI.getEnumBitName() << ": return \"" << SFI.TheDef->getValueAsString("PredicateName") << "\";\n"; } OS << " default: return \"(unknown)\";\n"; @@ -2691,7 +2695,10 @@ static std::string GetAliasRequiredFeatures(Record *R, const AsmMatcherInfo &Info) { std::vector<Record*> ReqFeatures = R->getValueAsListOfDefs("Predicates"); std::string Result; - unsigned NumFeatures = 0; + + if (ReqFeatures.empty()) + return Result; + for (unsigned i = 0, e = ReqFeatures.size(); i != e; ++i) { const SubtargetFeatureInfo *F = Info.getSubtargetFeature(ReqFeatures[i]); @@ -2699,15 +2706,12 @@ static std::string GetAliasRequiredFeatures(Record *R, PrintFatalError(R->getLoc(), "Predicate '" + ReqFeatures[i]->getName() + "' is not marked as an AssemblerPredicate!"); - if (NumFeatures) - Result += '|'; + if (i) + Result += " && "; - Result += F->getEnumName(); - ++NumFeatures; + Result += "Features.test(" + F->getEnumBitName() + ')'; } - if (NumFeatures > 1) - Result = '(' + Result + ')'; return Result; } @@ -2763,7 +2767,7 @@ static void emitMnemonicAliasVariant(raw_ostream &OS,const AsmMatcherInfo &Info, if (!MatchCode.empty()) MatchCode += "else "; - MatchCode += "if ((Features & " + FeatureMask + ") == "+FeatureMask+")\n"; + MatchCode += "if (" + FeatureMask + ")\n"; MatchCode += " Mnemonic = \""; MatchCode += R->getValueAsString("ToMnemonic"); MatchCode += "\";\n"; @@ -2798,7 +2802,7 @@ static bool emitMnemonicAliases(raw_ostream &OS, const AsmMatcherInfo &Info, if (Aliases.empty()) return false; OS << "static void applyMnemonicAliases(StringRef &Mnemonic, " - "uint64_t Features, unsigned VariantID) {\n"; + "const FeatureBitset &Features, unsigned VariantID) {\n"; OS << " switch (VariantID) {\n"; unsigned VariantCount = Target.getAsmParserVariantCount(); for (unsigned VC = 0; VC != VariantCount; ++VC) { @@ -2823,7 +2827,9 @@ 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, bool HasMnemonicFirst) { + unsigned MaxMnemonicIndex, + unsigned MaxFeaturesIndex, + bool HasMnemonicFirst) { unsigned MaxMask = 0; for (const OperandMatchEntry &OMI : Info.OperandMatchInfo) { MaxMask |= OMI.OperandMask; @@ -2832,14 +2838,14 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target, // Emit the static custom operand parsing table; OS << "namespace {\n"; OS << " struct OperandMatchEntry {\n"; - OS << " " << getMinimalTypeForEnumBitfield(Info.SubtargetFeatures.size()) - << " RequiredFeatures;\n"; OS << " " << getMinimalTypeForRange(MaxMnemonicIndex) << " Mnemonic;\n"; + OS << " " << getMinimalTypeForRange(MaxMask) + << " OperandMask;\n"; OS << " " << getMinimalTypeForRange(std::distance( Info.Classes.begin(), Info.Classes.end())) << " Class;\n"; - OS << " " << getMinimalTypeForRange(MaxMask) - << " OperandMask;\n\n"; + OS << " " << getMinimalTypeForRange(MaxFeaturesIndex) + << " RequiredFeaturesIdx;\n\n"; OS << " StringRef getMnemonic() const {\n"; OS << " return StringRef(MnemonicTable + Mnemonic + 1,\n"; OS << " MnemonicTable[Mnemonic]);\n"; @@ -2865,29 +2871,18 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target, OS << "static const OperandMatchEntry OperandMatchTable[" << Info.OperandMatchInfo.size() << "] = {\n"; - OS << " /* Operand List Mask, Mnemonic, Operand Class, Features */\n"; + OS << " /* Operand List Mnemonic, Mask, Operand Class, Features */\n"; for (const OperandMatchEntry &OMI : Info.OperandMatchInfo) { const MatchableInfo &II = *OMI.MI; OS << " { "; - // Write the required features mask. - if (!II.RequiredFeatures.empty()) { - for (unsigned i = 0, e = II.RequiredFeatures.size(); i != e; ++i) { - if (i) OS << "|"; - OS << II.RequiredFeatures[i]->getEnumName(); - } - } else - OS << "0"; - // Store a pascal-style length byte in the mnemonic. std::string LenMnemonic = char(II.Mnemonic.size()) + II.Mnemonic.str(); - OS << ", " << StringTable.GetOrAddStringOffset(LenMnemonic, false) + OS << StringTable.GetOrAddStringOffset(LenMnemonic, false) << " /* " << II.Mnemonic << " */, "; - OS << OMI.CI->Name; - - OS << ", " << OMI.OperandMask; + OS << OMI.OperandMask; OS << " /* "; bool printComma = false; for (int i = 0, e = 31; i !=e; ++i) @@ -2897,7 +2892,17 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target, OS << i; printComma = true; } - OS << " */"; + OS << " */, "; + + OS << OMI.CI->Name; + + // Write the required features mask. + OS << ", AMFBS"; + if (II.RequiredFeatures.empty()) + OS << "_None"; + else + for (unsigned i = 0, e = II.RequiredFeatures.size(); i != e; ++i) + OS << '_' << II.RequiredFeatures[i]->TheDef->getName(); OS << " },\n"; } @@ -2933,7 +2938,7 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target, // Emit code to get the available features. OS << " // Get the current feature set.\n"; - OS << " uint64_t AvailableFeatures = getAvailableFeatures();\n\n"; + OS << " const FeatureBitset &AvailableFeatures = getAvailableFeatures();\n\n"; OS << " // Get the next operand index.\n"; OS << " unsigned NextOpNum = Operands.size()" @@ -2967,8 +2972,10 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target, // Emit check that the required features are available. OS << " // check if the available features match\n"; + OS << " const FeatureBitset &RequiredFeatures = " + "FeatureBitsets[it->RequiredFeaturesIdx];\n"; OS << " if (!ParseForAllFeatures && (AvailableFeatures & " - "it->RequiredFeatures) != it->RequiredFeatures)\n"; + "RequiredFeatures) != RequiredFeatures)\n"; OS << " continue;\n\n"; // Emit check to ensure the operand number matches. @@ -3034,7 +3041,8 @@ static void emitAsmTiedOperandConstraints(CodeGenTarget &Target, static void emitMnemonicSpellChecker(raw_ostream &OS, CodeGenTarget &Target, unsigned VariantCount) { OS << "static std::string " << Target.getName() - << "MnemonicSpellCheck(StringRef S, uint64_t FBS, unsigned VariantID) {\n"; + << "MnemonicSpellCheck(StringRef S, const FeatureBitset &FBS," + << " unsigned VariantID) {\n"; if (!VariantCount) OS << " return \"\";"; else { @@ -3055,7 +3063,9 @@ static void emitMnemonicSpellChecker(raw_ostream &OS, CodeGenTarget &Target, OS << " }\n\n"; OS << " for (auto I = Start; I < End; I++) {\n"; OS << " // Ignore unsupported instructions.\n"; - OS << " if ((FBS & I->RequiredFeatures) != I->RequiredFeatures)\n"; + OS << " const FeatureBitset &RequiredFeatures = " + "FeatureBitsets[I->RequiredFeaturesIdx];\n"; + OS << " if ((FBS & RequiredFeatures) != RequiredFeatures)\n"; OS << " continue;\n"; OS << "\n"; OS << " StringRef T = I->getMnemonic();\n"; @@ -3103,6 +3113,14 @@ static void emitMatchClassKindNames(std::forward_list<ClassInfo> &Infos, OS << "#endif // NDEBUG\n"; } +static std::string +getNameForFeatureBitset(const std::vector<Record *> &FeatureBitset) { + std::string Name = "AMFBS"; + for (const auto &Feature : FeatureBitset) + Name += ("_" + Feature->getName()).str(); + return Name; +} + void AsmMatcherEmitter::run(raw_ostream &OS) { CodeGenTarget Target(Records); Record *AsmParser = Target.getAsmParser(); @@ -3115,10 +3133,10 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { // Sort the instruction table using the partial order on classes. We use // stable_sort to ensure that ambiguous instructions are still // deterministically ordered. - std::stable_sort(Info.Matchables.begin(), Info.Matchables.end(), - [](const std::unique_ptr<MatchableInfo> &a, - const std::unique_ptr<MatchableInfo> &b){ - return *a < *b;}); + llvm::stable_sort( + Info.Matchables, + [](const std::unique_ptr<MatchableInfo> &a, + const std::unique_ptr<MatchableInfo> &b) { return *a < *b; }); #ifdef EXPENSIVE_CHECKS // Verify that the table is sorted and operator < works transitively. @@ -3174,7 +3192,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << "#undef GET_ASSEMBLER_HEADER\n"; OS << " // This should be included into the middle of the declaration of\n"; OS << " // your subclasses implementation of MCTargetAsmParser.\n"; - OS << " uint64_t ComputeAvailableFeatures(const FeatureBitset& FB) const;\n"; + OS << " FeatureBitset ComputeAvailableFeatures(const FeatureBitset& FB) const;\n"; if (HasOptionalOperands) { OS << " void convertToMCInst(unsigned Kind, MCInst &Inst, " << "unsigned Opcode,\n" @@ -3192,9 +3210,21 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { if (ReportMultipleNearMisses) OS << " SmallVectorImpl<NearMissInfo> *NearMisses,\n"; else - OS << " uint64_t &ErrorInfo,\n"; + OS << " uint64_t &ErrorInfo,\n" + << " FeatureBitset &MissingFeatures,\n"; OS << " bool matchingInlineAsm,\n" << " unsigned VariantID = 0);\n"; + if (!ReportMultipleNearMisses) + OS << " unsigned MatchInstructionImpl(const OperandVector &Operands,\n" + << " MCInst &Inst,\n" + << " uint64_t &ErrorInfo,\n" + << " bool matchingInlineAsm,\n" + << " unsigned VariantID = 0) {\n" + << " FeatureBitset MissingFeatures;\n" + << " return MatchInstructionImpl(Operands, Inst, ErrorInfo, MissingFeatures,\n" + << " matchingInlineAsm, VariantID);\n" + << " }\n\n"; + if (!Info.OperandMatchInfo.empty()) { OS << " OperandMatchResultTy MatchOperandParserImpl(\n"; @@ -3219,7 +3249,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << "#undef GET_REGISTER_MATCHER\n\n"; // Emit the subtarget feature enumeration. - SubtargetFeatureInfo::emitSubtargetFeatureFlagEnumeration( + SubtargetFeatureInfo::emitSubtargetFeatureBitEnumeration( Info.SubtargetFeatures, OS); // Emit the function to match a register name to number. @@ -3249,8 +3279,9 @@ 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, HasMnemonicFirst, - HasOptionalOperands, OS); + unsigned NumConverters = emitConvertFuncs(Target, ClassName, Info.Matchables, + HasMnemonicFirst, + HasOptionalOperands, OS); // Emit the enumeration for classes which participate in matching. emitMatchClassEnumeration(Target, Info.Classes, OS); @@ -3300,6 +3331,56 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { StringTable.EmitString(OS); OS << ";\n\n"; + std::vector<std::vector<Record *>> FeatureBitsets; + for (const auto &MI : Info.Matchables) { + if (MI->RequiredFeatures.empty()) + continue; + FeatureBitsets.emplace_back(); + for (unsigned I = 0, E = MI->RequiredFeatures.size(); I != E; ++I) + FeatureBitsets.back().push_back(MI->RequiredFeatures[I]->TheDef); + } + + llvm::sort(FeatureBitsets, [&](const std::vector<Record *> &A, + const std::vector<Record *> &B) { + if (A.size() < B.size()) + return true; + if (A.size() > B.size()) + return false; + for (const auto &Pair : zip(A, B)) { + if (std::get<0>(Pair)->getName() < std::get<1>(Pair)->getName()) + return true; + if (std::get<0>(Pair)->getName() > std::get<1>(Pair)->getName()) + return false; + } + return false; + }); + FeatureBitsets.erase( + std::unique(FeatureBitsets.begin(), FeatureBitsets.end()), + FeatureBitsets.end()); + OS << "// Feature bitsets.\n" + << "enum : " << getMinimalTypeForRange(FeatureBitsets.size()) << " {\n" + << " AMFBS_None,\n"; + for (const auto &FeatureBitset : FeatureBitsets) { + if (FeatureBitset.empty()) + continue; + OS << " " << getNameForFeatureBitset(FeatureBitset) << ",\n"; + } + OS << "};\n\n" + << "const static FeatureBitset FeatureBitsets[] {\n" + << " {}, // AMFBS_None\n"; + for (const auto &FeatureBitset : FeatureBitsets) { + if (FeatureBitset.empty()) + continue; + OS << " {"; + for (const auto &Feature : FeatureBitset) { + const auto &I = Info.SubtargetFeatures.find(Feature); + assert(I != Info.SubtargetFeatures.end() && "Didn't import predicate?"); + OS << I->second.getEnumBitName() << ", "; + } + OS << "},\n"; + } + OS << "};\n\n"; + // Emit the static match table; unused classes get initialized to 0 which is // guaranteed to be InvalidMatchClass. // @@ -3315,10 +3396,10 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " " << getMinimalTypeForRange(MaxMnemonicIndex) << " Mnemonic;\n"; OS << " uint16_t Opcode;\n"; - OS << " " << getMinimalTypeForRange(Info.Matchables.size()) + OS << " " << getMinimalTypeForRange(NumConverters) << " ConvertFn;\n"; - OS << " " << getMinimalTypeForEnumBitfield(Info.SubtargetFeatures.size()) - << " RequiredFeatures;\n"; + OS << " " << getMinimalTypeForRange(FeatureBitsets.size()) + << " RequiredFeaturesIdx;\n"; OS << " " << getMinimalTypeForRange( std::distance(Info.Classes.begin(), Info.Classes.end())) << " Classes[" << MaxNumOperands << "];\n"; @@ -3363,13 +3444,12 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { << MI->ConversionFnKind << ", "; // Write the required features mask. - if (!MI->RequiredFeatures.empty()) { - for (unsigned i = 0, e = MI->RequiredFeatures.size(); i != e; ++i) { - if (i) OS << "|"; - OS << MI->RequiredFeatures[i]->getEnumName(); - } - } else - OS << "0"; + OS << "AMFBS"; + if (MI->RequiredFeatures.empty()) + OS << "_None"; + else + for (unsigned i = 0, e = MI->RequiredFeatures.size(); i != e; ++i) + OS << '_' << MI->RequiredFeatures[i]->TheDef->getName(); OS << ", { "; for (unsigned i = 0, e = MI->AsmOperands.size(); i != e; ++i) { @@ -3394,7 +3474,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { if (ReportMultipleNearMisses) OS << " SmallVectorImpl<NearMissInfo> *NearMisses,\n"; else - OS << " uint64_t &ErrorInfo,\n"; + OS << " uint64_t &ErrorInfo,\n" + << " FeatureBitset &MissingFeatures,\n"; OS << " bool matchingInlineAsm, unsigned VariantID) {\n"; if (!ReportMultipleNearMisses) { @@ -3409,7 +3490,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { // Emit code to get the available features. OS << " // Get the current feature set.\n"; - OS << " uint64_t AvailableFeatures = getAvailableFeatures();\n\n"; + OS << " const FeatureBitset &AvailableFeatures = getAvailableFeatures();\n\n"; OS << " // Get the instruction mnemonic, which is the first token.\n"; if (HasMnemonicFirst) { @@ -3433,7 +3514,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " bool HadMatchOtherThanFeatures = false;\n"; OS << " bool HadMatchOtherThanPredicate = false;\n"; OS << " unsigned RetCode = Match_InvalidOperand;\n"; - OS << " uint64_t MissingFeatures = ~0ULL;\n"; + OS << " MissingFeatures.set();\n"; OS << " // Set ErrorInfo to the operand that mismatches if it is\n"; OS << " // wrong for all instances of the instruction.\n"; OS << " ErrorInfo = ~0ULL;\n"; @@ -3479,9 +3560,10 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " for (const MatchEntry *it = MnemonicRange.first, " << "*ie = MnemonicRange.second;\n"; OS << " it != ie; ++it) {\n"; + OS << " const FeatureBitset &RequiredFeatures = " + "FeatureBitsets[it->RequiredFeaturesIdx];\n"; OS << " bool HasRequiredFeatures =\n"; - OS << " (AvailableFeatures & it->RequiredFeatures) == " - "it->RequiredFeatures;\n"; + OS << " (AvailableFeatures & RequiredFeatures) == RequiredFeatures;\n"; OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"Trying to match opcode \"\n"; OS << " << MII.getName(it->Opcode) << \"\\n\");\n"; @@ -3640,16 +3722,18 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " if (!HasRequiredFeatures) {\n"; if (!ReportMultipleNearMisses) OS << " HadMatchOtherThanFeatures = true;\n"; - OS << " uint64_t NewMissingFeatures = it->RequiredFeatures & " + OS << " FeatureBitset NewMissingFeatures = RequiredFeatures & " "~AvailableFeatures;\n"; - OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"Missing target features: \"\n"; - OS << " << format_hex(NewMissingFeatures, 18)\n"; - OS << " << \"\\n\");\n"; + OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"Missing target features:\";\n"; + OS << " for (unsigned I = 0, E = NewMissingFeatures.size(); I != E; ++I)\n"; + OS << " if (NewMissingFeatures[I])\n"; + OS << " dbgs() << ' ' << I;\n"; + OS << " dbgs() << \"\\n\");\n"; if (ReportMultipleNearMisses) { OS << " FeaturesNearMiss = NearMissInfo::getMissedFeature(NewMissingFeatures);\n"; } else { - OS << " if (countPopulation(NewMissingFeatures) <=\n" - " countPopulation(MissingFeatures))\n"; + OS << " if (NewMissingFeatures.count() <=\n" + " MissingFeatures.count())\n"; OS << " MissingFeatures = NewMissingFeatures;\n"; OS << " continue;\n"; } @@ -3804,15 +3888,15 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " // Okay, we had no match. Try to return a useful error code.\n"; OS << " if (HadMatchOtherThanPredicate || !HadMatchOtherThanFeatures)\n"; OS << " return RetCode;\n\n"; - OS << " // Missing feature matches return which features were missing\n"; - OS << " ErrorInfo = MissingFeatures;\n"; + OS << " ErrorInfo = 0;\n"; OS << " return Match_MissingFeature;\n"; } OS << "}\n\n"; if (!Info.OperandMatchInfo.empty()) emitCustomOperandParsing(OS, Target, Info, ClassName, StringTable, - MaxMnemonicIndex, HasMnemonicFirst); + MaxMnemonicIndex, FeatureBitsets.size(), + HasMnemonicFirst); OS << "#endif // GET_MATCHER_IMPLEMENTATION\n\n"; |