diff options
Diffstat (limited to 'utils/TableGen/AsmMatcherEmitter.cpp')
-rw-r--r-- | utils/TableGen/AsmMatcherEmitter.cpp | 307 |
1 files changed, 182 insertions, 125 deletions
diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp index 5ef0db9..cdcc496 100644 --- a/utils/TableGen/AsmMatcherEmitter.cpp +++ b/utils/TableGen/AsmMatcherEmitter.cpp @@ -99,6 +99,7 @@ #include "AsmMatcherEmitter.h" #include "CodeGenTarget.h" #include "StringMatcher.h" +#include "StringToOffsetTable.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/SmallPtrSet.h" @@ -107,6 +108,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" #include <map> @@ -251,7 +253,7 @@ public: switch (Kind) { case Invalid: - assert(0 && "Invalid kind!"); + llvm_unreachable("Invalid kind!"); default: // This class precedes the RHS if it is a proper subset of the RHS. @@ -282,7 +284,11 @@ struct MatchableInfo { /// The suboperand index within SrcOpName, or -1 for the entire operand. int SubOpIdx; - explicit AsmOperand(StringRef T) : Token(T), Class(0), SubOpIdx(-1) {} + /// Register record if this token is singleton register. + Record *SingletonReg; + + explicit AsmOperand(StringRef T) : Token(T), Class(0), SubOpIdx(-1), + SingletonReg(0) {} }; /// ResOperand - This represents a single operand in the result instruction @@ -361,6 +367,9 @@ struct MatchableInfo { } }; + /// AsmVariantID - Target's assembly syntax variant no. + int AsmVariantID; + /// TheDef - This is the definition of the instruction or InstAlias that this /// matchable came from. Record *const TheDef; @@ -401,24 +410,28 @@ struct MatchableInfo { std::string ConversionFnKind; MatchableInfo(const CodeGenInstruction &CGI) - : TheDef(CGI.TheDef), DefRec(&CGI), AsmString(CGI.AsmString) { + : AsmVariantID(0), TheDef(CGI.TheDef), DefRec(&CGI), + AsmString(CGI.AsmString) { } MatchableInfo(const CodeGenInstAlias *Alias) - : TheDef(Alias->TheDef), DefRec(Alias), AsmString(Alias->AsmString) { + : AsmVariantID(0), TheDef(Alias->TheDef), DefRec(Alias), + AsmString(Alias->AsmString) { } void Initialize(const AsmMatcherInfo &Info, - SmallPtrSet<Record*, 16> &SingletonRegisters); + SmallPtrSet<Record*, 16> &SingletonRegisters, + int AsmVariantNo, std::string &RegisterPrefix); /// Validate - Return true if this matchable is a valid thing to match against /// and perform a bunch of validity checking. bool Validate(StringRef CommentDelimiter, bool Hack) const; - /// getSingletonRegisterForAsmOperand - If the specified token is a singleton - /// register, return the Record for it, otherwise return null. - Record *getSingletonRegisterForAsmOperand(unsigned i, - const AsmMatcherInfo &Info) const; + /// extractSingletonRegisterForAsmOperand - Extract singleton register, + /// if present, from specified token. + void + extractSingletonRegisterForAsmOperand(unsigned i, const AsmMatcherInfo &Info, + std::string &RegisterPrefix); /// FindAsmOperand - Find the AsmOperand with the specified name and /// suboperand index. @@ -552,9 +565,6 @@ public: /// Target - The target information. CodeGenTarget &Target; - /// The AsmParser "RegisterPrefix" value. - std::string RegisterPrefix; - /// The classes which are needed for matching. std::vector<ClassInfo*> Classes; @@ -641,9 +651,11 @@ void MatchableInfo::dump() { } void MatchableInfo::Initialize(const AsmMatcherInfo &Info, - SmallPtrSet<Record*, 16> &SingletonRegisters) { - // TODO: Eventually support asmparser for Variant != 0. - AsmString = CodeGenInstruction::FlattenAsmStringVariants(AsmString, 0); + SmallPtrSet<Record*, 16> &SingletonRegisters, + int AsmVariantNo, std::string &RegisterPrefix) { + AsmVariantID = AsmVariantNo; + AsmString = + CodeGenInstruction::FlattenAsmStringVariants(AsmString, AsmVariantNo); TokenizeAsmString(Info); @@ -656,7 +668,8 @@ void MatchableInfo::Initialize(const AsmMatcherInfo &Info, // Collect singleton registers, if used. for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i) { - if (Record *Reg = getSingletonRegisterForAsmOperand(i, Info)) + extractSingletonRegisterForAsmOperand(i, Info, RegisterPrefix); + if (Record *Reg = AsmOperands[i].SingletonReg) SingletonRegisters.insert(Reg); } } @@ -736,7 +749,8 @@ void MatchableInfo::TokenizeAsmString(const AsmMatcherInfo &Info) { throw TGError(TheDef->getLoc(), "Instruction '" + TheDef->getName() + "' has no tokens"); Mnemonic = AsmOperands[0].Token; - if (Mnemonic[0] == '$' || getSingletonRegisterForAsmOperand(0, Info)) + // FIXME : Check and raise an error if it is a register. + if (Mnemonic[0] == '$') throw TGError(TheDef->getLoc(), "Invalid instruction mnemonic '" + Mnemonic.str() + "'!"); @@ -799,28 +813,30 @@ bool MatchableInfo::Validate(StringRef CommentDelimiter, bool Hack) const { return true; } -/// getSingletonRegisterForAsmOperand - If the specified token is a singleton -/// register, return the register name, otherwise return a null StringRef. -Record *MatchableInfo:: -getSingletonRegisterForAsmOperand(unsigned i, const AsmMatcherInfo &Info) const{ - StringRef Tok = AsmOperands[i].Token; - if (!Tok.startswith(Info.RegisterPrefix)) - return 0; +/// extractSingletonRegisterForAsmOperand - Extract singleton register, +/// if present, from specified token. +void MatchableInfo:: +extractSingletonRegisterForAsmOperand(unsigned OperandNo, + const AsmMatcherInfo &Info, + std::string &RegisterPrefix) { + StringRef Tok = AsmOperands[OperandNo].Token; + if (RegisterPrefix.empty()) { + std::string LoweredTok = Tok.lower(); + if (const CodeGenRegister *Reg = Info.Target.getRegisterByName(LoweredTok)) + AsmOperands[OperandNo].SingletonReg = Reg->TheDef; + return; + } + + if (!Tok.startswith(RegisterPrefix)) + return; - StringRef RegName = Tok.substr(Info.RegisterPrefix.size()); + StringRef RegName = Tok.substr(RegisterPrefix.size()); if (const CodeGenRegister *Reg = Info.Target.getRegisterByName(RegName)) - return Reg->TheDef; + AsmOperands[OperandNo].SingletonReg = Reg->TheDef; // If there is no register prefix (i.e. "%" in "%eax"), then this may // be some random non-register token, just ignore it. - if (Info.RegisterPrefix.empty()) - return 0; - - // Otherwise, we have something invalid prefixed with the register prefix, - // such as %foo. - std::string Err = "unable to find register for '" + RegName.str() + - "' (which matches register prefix)"; - throw TGError(TheDef->getLoc(), Err); + return; } static std::string getEnumNameForToken(StringRef Str) { @@ -1104,8 +1120,7 @@ void AsmMatcherInfo::BuildOperandClasses() { AsmMatcherInfo::AsmMatcherInfo(Record *asmParser, CodeGenTarget &target, RecordKeeper &records) - : Records(records), AsmParser(asmParser), Target(target), - RegisterPrefix(AsmParser->getValueAsString("RegisterPrefix")) { + : Records(records), AsmParser(asmParser), Target(target) { } /// BuildOperandMatchInfo - Build the necessary information to handle user @@ -1160,86 +1175,92 @@ void AsmMatcherInfo::BuildInfo() { assert(FeatureNo < 32 && "Too many subtarget features!"); } - std::string CommentDelimiter = AsmParser->getValueAsString("CommentDelimiter"); - // Parse the instructions; we need to do this first so that we can gather the // singleton register classes. SmallPtrSet<Record*, 16> SingletonRegisters; - for (CodeGenTarget::inst_iterator I = Target.inst_begin(), - E = Target.inst_end(); I != E; ++I) { - const CodeGenInstruction &CGI = **I; - - // If the tblgen -match-prefix option is specified (for tblgen hackers), - // filter the set of instructions we consider. - if (!StringRef(CGI.TheDef->getName()).startswith(MatchPrefix)) - continue; - - // Ignore "codegen only" instructions. - if (CGI.TheDef->getValueAsBit("isCodeGenOnly")) - continue; - - // Validate the operand list to ensure we can handle this instruction. - for (unsigned i = 0, e = CGI.Operands.size(); i != e; ++i) { - const CGIOperandList::OperandInfo &OI = CGI.Operands[i]; - - // Validate tied operands. - if (OI.getTiedRegister() != -1) { - // If we have a tied operand that consists of multiple MCOperands, - // reject it. We reject aliases and ignore instructions for now. - if (OI.MINumOperands != 1) { - // FIXME: Should reject these. The ARM backend hits this with $lane - // in a bunch of instructions. It is unclear what the right answer is. - DEBUG({ - errs() << "warning: '" << CGI.TheDef->getName() << "': " - << "ignoring instruction with multi-operand tied operand '" - << OI.Name << "'\n"; - }); - continue; - } + unsigned VariantCount = Target.getAsmParserVariantCount(); + for (unsigned VC = 0; VC != VariantCount; ++VC) { + Record *AsmVariant = Target.getAsmParserVariant(VC); + std::string CommentDelimiter = AsmVariant->getValueAsString("CommentDelimiter"); + std::string RegisterPrefix = AsmVariant->getValueAsString("RegisterPrefix"); + int AsmVariantNo = AsmVariant->getValueAsInt("Variant"); + + for (CodeGenTarget::inst_iterator I = Target.inst_begin(), + E = Target.inst_end(); I != E; ++I) { + const CodeGenInstruction &CGI = **I; + + // If the tblgen -match-prefix option is specified (for tblgen hackers), + // filter the set of instructions we consider. + if (!StringRef(CGI.TheDef->getName()).startswith(MatchPrefix)) + continue; + + // Ignore "codegen only" instructions. + if (CGI.TheDef->getValueAsBit("isCodeGenOnly")) + continue; + + // Validate the operand list to ensure we can handle this instruction. + for (unsigned i = 0, e = CGI.Operands.size(); i != e; ++i) { + const CGIOperandList::OperandInfo &OI = CGI.Operands[i]; + + // Validate tied operands. + if (OI.getTiedRegister() != -1) { + // If we have a tied operand that consists of multiple MCOperands, + // reject it. We reject aliases and ignore instructions for now. + if (OI.MINumOperands != 1) { + // FIXME: Should reject these. The ARM backend hits this with $lane + // in a bunch of instructions. It is unclear what the right answer is. + DEBUG({ + errs() << "warning: '" << CGI.TheDef->getName() << "': " + << "ignoring instruction with multi-operand tied operand '" + << OI.Name << "'\n"; + }); + continue; + } + } } - } - OwningPtr<MatchableInfo> II(new MatchableInfo(CGI)); + OwningPtr<MatchableInfo> II(new MatchableInfo(CGI)); - II->Initialize(*this, SingletonRegisters); + II->Initialize(*this, SingletonRegisters, AsmVariantNo, RegisterPrefix); - // Ignore instructions which shouldn't be matched and diagnose invalid - // instruction definitions with an error. - if (!II->Validate(CommentDelimiter, true)) - continue; + // Ignore instructions which shouldn't be matched and diagnose invalid + // instruction definitions with an error. + if (!II->Validate(CommentDelimiter, true)) + continue; - // Ignore "Int_*" and "*_Int" instructions, which are internal aliases. - // - // FIXME: This is a total hack. - if (StringRef(II->TheDef->getName()).startswith("Int_") || - StringRef(II->TheDef->getName()).endswith("_Int")) - continue; + // Ignore "Int_*" and "*_Int" instructions, which are internal aliases. + // + // FIXME: This is a total hack. + if (StringRef(II->TheDef->getName()).startswith("Int_") || + StringRef(II->TheDef->getName()).endswith("_Int")) + continue; - Matchables.push_back(II.take()); - } + Matchables.push_back(II.take()); + } - // Parse all of the InstAlias definitions and stick them in the list of - // matchables. - std::vector<Record*> AllInstAliases = - Records.getAllDerivedDefinitions("InstAlias"); - for (unsigned i = 0, e = AllInstAliases.size(); i != e; ++i) { - CodeGenInstAlias *Alias = new CodeGenInstAlias(AllInstAliases[i], Target); - - // If the tblgen -match-prefix option is specified (for tblgen hackers), - // filter the set of instruction aliases we consider, based on the target - // instruction. - if (!StringRef(Alias->ResultInst->TheDef->getName()).startswith( - MatchPrefix)) - continue; + // Parse all of the InstAlias definitions and stick them in the list of + // matchables. + std::vector<Record*> AllInstAliases = + Records.getAllDerivedDefinitions("InstAlias"); + for (unsigned i = 0, e = AllInstAliases.size(); i != e; ++i) { + CodeGenInstAlias *Alias = new CodeGenInstAlias(AllInstAliases[i], Target); + + // If the tblgen -match-prefix option is specified (for tblgen hackers), + // filter the set of instruction aliases we consider, based on the target + // instruction. + if (!StringRef(Alias->ResultInst->TheDef->getName()).startswith( + MatchPrefix)) + continue; - OwningPtr<MatchableInfo> II(new MatchableInfo(Alias)); + OwningPtr<MatchableInfo> II(new MatchableInfo(Alias)); - II->Initialize(*this, SingletonRegisters); + II->Initialize(*this, SingletonRegisters, AsmVariantNo, RegisterPrefix); - // Validate the alias definitions. - II->Validate(CommentDelimiter, false); + // Validate the alias definitions. + II->Validate(CommentDelimiter, false); - Matchables.push_back(II.take()); + Matchables.push_back(II.take()); + } } // Build info for the register classes. @@ -1262,7 +1283,7 @@ void AsmMatcherInfo::BuildInfo() { StringRef Token = Op.Token; // Check for singleton registers. - if (Record *RegRecord = II->getSingletonRegisterForAsmOperand(i, *this)) { + if (Record *RegRecord = II->AsmOperands[i].SingletonReg) { Op.Class = RegisterClasses[RegRecord]; assert(Op.Class && Op.Class->Registers.size() == 1 && "Unexpected class for singleton register"); @@ -1468,7 +1489,6 @@ void MatchableInfo::BuildAliasResultOperands() { // Find out what operand from the asmparser that this MCInst operand // comes from. switch (CGA.ResultOperands[AliasOpNo].Kind) { - default: assert(0 && "unexpected InstAlias operand kind"); case CodeGenInstAlias::ResultOperand::K_Record: { StringRef Name = CGA.ResultOperands[AliasOpNo].getName(); int SrcOperand = FindAsmOperand(Name, SubIdx); @@ -2003,40 +2023,48 @@ static void EmitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target, // Emit the static custom operand parsing table; OS << "namespace {\n"; OS << " struct OperandMatchEntry {\n"; - OS << " const char *Mnemonic;\n"; + OS << " static const char *MnemonicTable;\n"; OS << " unsigned OperandMask;\n"; - OS << " MatchClassKind Class;\n"; - OS << " unsigned RequiredFeatures;\n"; + OS << " uint16_t Mnemonic;\n"; + OS << " " << getMinimalTypeForRange(Info.Classes.size()) + << " Class;\n"; + OS << " " << getMinimalTypeForRange(1ULL << Info.SubtargetFeatures.size()) + << " RequiredFeatures;\n\n"; + OS << " StringRef getMnemonic() const {\n"; + OS << " return StringRef(MnemonicTable + Mnemonic + 1,\n"; + OS << " MnemonicTable[Mnemonic]);\n"; + OS << " }\n"; OS << " };\n\n"; OS << " // Predicate for searching for an opcode.\n"; OS << " struct LessOpcodeOperand {\n"; OS << " bool operator()(const OperandMatchEntry &LHS, StringRef RHS) {\n"; - OS << " return StringRef(LHS.Mnemonic) < RHS;\n"; + OS << " return LHS.getMnemonic() < RHS;\n"; OS << " }\n"; OS << " bool operator()(StringRef LHS, const OperandMatchEntry &RHS) {\n"; - OS << " return LHS < StringRef(RHS.Mnemonic);\n"; + OS << " return LHS < RHS.getMnemonic();\n"; OS << " }\n"; OS << " bool operator()(const OperandMatchEntry &LHS,"; OS << " const OperandMatchEntry &RHS) {\n"; - OS << " return StringRef(LHS.Mnemonic) < StringRef(RHS.Mnemonic);\n"; + OS << " return LHS.getMnemonic() < RHS.getMnemonic();\n"; OS << " }\n"; OS << " };\n"; OS << "} // end anonymous namespace.\n\n"; + StringToOffsetTable StringTable; + OS << "static const OperandMatchEntry OperandMatchTable[" << Info.OperandMatchInfo.size() << "] = {\n"; - OS << " /* Mnemonic, Operand List Mask, Operand Class, Features */\n"; + OS << " /* Operand List Mask, Mnemonic, Operand Class, Features */\n"; for (std::vector<OperandMatchEntry>::const_iterator it = Info.OperandMatchInfo.begin(), ie = Info.OperandMatchInfo.end(); it != ie; ++it) { const OperandMatchEntry &OMI = *it; const MatchableInfo &II = *OMI.MI; - OS << " { \"" << II.Mnemonic << "\"" - << ", " << OMI.OperandMask; + OS << " { " << OMI.OperandMask; OS << " /* "; bool printComma = false; @@ -2049,6 +2077,11 @@ static void EmitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target, } OS << " */"; + // Store a pascal-style length byte in the mnemonic. + std::string LenMnemonic = char(II.Mnemonic.size()) + II.Mnemonic.str(); + OS << ", " << StringTable.GetOrAddStringOffset(LenMnemonic, false) + << " /* " << II.Mnemonic << " */"; + OS << ", " << OMI.CI->Name << ", "; @@ -2064,6 +2097,10 @@ static void EmitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target, } OS << "};\n\n"; + OS << "const char *OperandMatchEntry::MnemonicTable =\n"; + StringTable.EmitString(OS); + OS << ";\n\n"; + // Emit the operand class switch to call the correct custom parser for // the found operand class. OS << Target.getName() << ClassName << "::OperandMatchResultTy " @@ -2117,7 +2154,7 @@ static void EmitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target, << " *ie = MnemonicRange.second; it != ie; ++it) {\n"; OS << " // equal_range guarantees that instruction mnemonic matches.\n"; - OS << " assert(Mnemonic == it->Mnemonic);\n\n"; + OS << " assert(Mnemonic == it->getMnemonic());\n\n"; // Emit check that the required features are available. OS << " // check if the available features match\n"; @@ -2209,7 +2246,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " bool MnemonicIsValid(StringRef Mnemonic);\n"; OS << " unsigned MatchInstructionImpl(\n"; OS << " const SmallVectorImpl<MCParsedAsmOperand*> &Operands,\n"; - OS << " MCInst &Inst, unsigned &ErrorInfo);\n"; + OS << " MCInst &Inst, unsigned &ErrorInfo, unsigned VariantID = 0);\n"; if (Info.OperandMatchInfo.size()) { OS << "\n enum OperandMatchResultTy {\n"; @@ -2283,31 +2320,39 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { // following the mnemonic. OS << "namespace {\n"; OS << " struct MatchEntry {\n"; - OS << " unsigned Opcode;\n"; - OS << " const char *Mnemonic;\n"; + OS << " static const char *MnemonicTable;\n"; + OS << " uint16_t Opcode;\n"; + OS << " uint16_t Mnemonic;\n"; OS << " " << getMinimalTypeForRange(Info.Matchables.size()) << " ConvertFn;\n"; OS << " " << getMinimalTypeForRange(Info.Classes.size()) << " Classes[" << MaxNumOperands << "];\n"; OS << " " << getMinimalTypeForRange(1ULL << Info.SubtargetFeatures.size()) << " RequiredFeatures;\n"; + OS << " uint8_t AsmVariantID;\n\n"; + OS << " StringRef getMnemonic() const {\n"; + OS << " return StringRef(MnemonicTable + Mnemonic + 1,\n"; + OS << " MnemonicTable[Mnemonic]);\n"; + OS << " }\n"; OS << " };\n\n"; OS << " // Predicate for searching for an opcode.\n"; OS << " struct LessOpcode {\n"; OS << " bool operator()(const MatchEntry &LHS, StringRef RHS) {\n"; - OS << " return StringRef(LHS.Mnemonic) < RHS;\n"; + OS << " return LHS.getMnemonic() < RHS;\n"; OS << " }\n"; OS << " bool operator()(StringRef LHS, const MatchEntry &RHS) {\n"; - OS << " return LHS < StringRef(RHS.Mnemonic);\n"; + OS << " return LHS < RHS.getMnemonic();\n"; OS << " }\n"; OS << " bool operator()(const MatchEntry &LHS, const MatchEntry &RHS) {\n"; - OS << " return StringRef(LHS.Mnemonic) < StringRef(RHS.Mnemonic);\n"; + OS << " return LHS.getMnemonic() < RHS.getMnemonic();\n"; OS << " }\n"; OS << " };\n"; OS << "} // end anonymous namespace.\n\n"; + StringToOffsetTable StringTable; + OS << "static const MatchEntry MatchTable[" << Info.Matchables.size() << "] = {\n"; @@ -2316,8 +2361,12 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { it != ie; ++it) { MatchableInfo &II = **it; + // Store a pascal-style length byte in the mnemonic. + std::string LenMnemonic = char(II.Mnemonic.size()) + II.Mnemonic.str(); OS << " { " << Target.getName() << "::" - << II.getResultInst()->TheDef->getName() << ", \"" << II.Mnemonic << "\"" + << II.getResultInst()->TheDef->getName() << ", " + << StringTable.GetOrAddStringOffset(LenMnemonic, false) + << " /* " << II.Mnemonic << " */" << ", " << II.ConversionFnKind << ", { "; for (unsigned i = 0, e = II.AsmOperands.size(); i != e; ++i) { MatchableInfo::AsmOperand &Op = II.AsmOperands[i]; @@ -2335,12 +2384,16 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { } } else OS << "0"; - + OS << ", " << II.AsmVariantID; OS << "},\n"; } OS << "};\n\n"; + OS << "const char *MatchEntry::MnemonicTable =\n"; + StringTable.EmitString(OS); + OS << ";\n\n"; + // A method to determine if a mnemonic is in the list. OS << "bool " << Target.getName() << ClassName << "::\n" << "MnemonicIsValid(StringRef Mnemonic) {\n"; @@ -2356,7 +2409,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { << Target.getName() << ClassName << "::\n" << "MatchInstructionImpl(const SmallVectorImpl<MCParsedAsmOperand*>" << " &Operands,\n"; - OS << " MCInst &Inst, unsigned &ErrorInfo) {\n"; + OS << " MCInst &Inst, unsigned &ErrorInfo,\n"; + OS << " unsigned VariantID) {\n"; // Emit code to get the available features. OS << " // Get the current feature set.\n"; @@ -2368,7 +2422,9 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { if (HasMnemonicAliases) { OS << " // Process all MnemonicAliases to remap the mnemonic.\n"; - OS << " applyMnemonicAliases(Mnemonic, AvailableFeatures);\n\n"; + OS << " // FIXME : Add an entry in AsmParserVariant to check this.\n"; + OS << " if (!VariantID)\n"; + OS << " applyMnemonicAliases(Mnemonic, AvailableFeatures);\n\n"; } // Emit code to compute the class list for this operand vector. @@ -2401,9 +2457,10 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " it != ie; ++it) {\n"; OS << " // equal_range guarantees that instruction mnemonic matches.\n"; - OS << " assert(Mnemonic == it->Mnemonic);\n"; + OS << " assert(Mnemonic == it->getMnemonic());\n"; // Emit check that the subclasses match. + OS << " if (VariantID != it->AsmVariantID) continue;\n"; OS << " bool OperandsValid = true;\n"; OS << " for (unsigned i = 0; i != " << MaxNumOperands << "; ++i) {\n"; OS << " if (i + 1 >= Operands.size()) {\n"; |