X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=utils%2FTableGen%2FAsmMatcherEmitter.cpp;h=3d74c904f375783a378531ecdf10bfa21a9ea3d0;hb=6018944afd2931a15829223d4e3862495cb4ec7c;hp=fb8d7048143ba0f113c1aded4845a93dbcdf5a4b;hpb=4dbfdfba6c92b6224bf58364371569f5780844d3;p=oota-llvm.git diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp index fb8d7048143..3d74c904f37 100644 --- a/utils/TableGen/AsmMatcherEmitter.cpp +++ b/utils/TableGen/AsmMatcherEmitter.cpp @@ -77,7 +77,7 @@ // // Some targets need a custom way to parse operands, some specific instructions // can contain arguments that can represent processor flags and other kinds of -// identifiers that need to be mapped to specific valeus in the final encoded +// identifiers that need to be mapped to specific values in the final encoded // instructions. The target specific custom operand parsing works in the // following way: // @@ -199,7 +199,7 @@ public: return Kind >= UserClass0; } - /// isRelatedTo - Check whether this class is "related" to \arg RHS. Classes + /// isRelatedTo - Check whether this class is "related" to \p RHS. Classes /// are related if they are in the same class hierarchy. bool isRelatedTo(const ClassInfo &RHS) const { // Tokens are only related to tokens. @@ -238,7 +238,7 @@ public: return Root == RHSRoot; } - /// isSubsetOf - Test whether this class is a subset of \arg RHS; + /// isSubsetOf - Test whether this class is a subset of \p RHS. bool isSubsetOf(const ClassInfo &RHS) const { // This is a subset of RHS if it is the same class... if (this == &RHS) @@ -279,6 +279,15 @@ public: } }; +namespace { +/// Sort ClassInfo pointers independently of pointer value. +struct LessClassInfoPtr { + bool operator()(const ClassInfo *LHS, const ClassInfo *RHS) const { + return *LHS < *RHS; + } +}; +} + /// MatchableInfo - Helper class for storing the necessary information for an /// instruction or alias which is capable of being matched. struct MatchableInfo { @@ -416,7 +425,7 @@ struct MatchableInfo { SmallVector RequiredFeatures; /// ConversionFnKind - The enum value which is passed to the generated - /// ConvertToMCInst to convert parsed operands into an MCInst for this + /// convertToMCInst to convert parsed operands into an MCInst for this /// function. std::string ConversionFnKind; @@ -488,11 +497,20 @@ struct MatchableInfo { return false; } + // Give matches that require more features higher precedence. This is useful + // because we cannot define AssemblerPredicates with the negation of + // processor features. For example, ARM v6 "nop" may be either a HINT or + // MOV. With v6, we want to match HINT. The assembler has no way to + // predicate MOV under "NoV6", but HINT will always match first because it + // requires V6 while MOV does not. + if (RequiredFeatures.size() != RHS.RequiredFeatures.size()) + return RequiredFeatures.size() > RHS.RequiredFeatures.size(); + return false; } /// couldMatchAmbiguouslyWith - Check whether this matchable could - /// ambiguously match the same set of operands as \arg RHS (without being a + /// ambiguously match the same set of operands as \p RHS (without being a /// strictly superior match). bool couldMatchAmbiguouslyWith(const MatchableInfo &RHS) { // The primary comparator is the instruction mnemonic. @@ -590,7 +608,8 @@ public: std::vector OperandMatchInfo; /// Map of Register records to their class information. - std::map RegisterClasses; + typedef std::map RegisterClassesTy; + RegisterClassesTy RegisterClasses; /// Map of Predicate records to their subtarget information. std::map SubtargetFeatures; @@ -666,7 +685,7 @@ void MatchableInfo::dump() { } static std::pair -parseTwoOperandConstraint(StringRef S, SMLoc Loc) { +parseTwoOperandConstraint(StringRef S, ArrayRef Loc) { // Split via the '='. std::pair Ops = S.split('='); if (Ops.second == "") @@ -1011,7 +1030,9 @@ AsmMatcherInfo::getOperandClass(Record *Rec, int SubOpIdx) { throw TGError(Rec->getLoc(), "register class has no class info!"); } - assert(Rec->isSubClassOf("Operand") && "Unexpected operand!"); + if (!Rec->isSubClassOf("Operand")) + throw TGError(Rec->getLoc(), "Operand `" + Rec->getName() + + "' does not derive from class Operand!\n"); Record *MatchClass = Rec->getValueAsDef("ParserMatchClass"); if (ClassInfo *CI = AsmOperandClasses[MatchClass]) return CI; @@ -1228,7 +1249,8 @@ void AsmMatcherInfo::buildOperandMatchInfo() { /// Map containing a mask with all operands indices that can be found for /// that class inside a instruction. - std::map OpClassMask; + typedef std::map OpClassMaskTy; + OpClassMaskTy OpClassMask; for (std::vector::const_iterator it = Matchables.begin(), ie = Matchables.end(); @@ -1247,7 +1269,7 @@ void AsmMatcherInfo::buildOperandMatchInfo() { } // Generate operand match info for each mnemonic/operand class pair. - for (std::map::iterator iit = OpClassMask.begin(), + for (OpClassMaskTy::iterator iit = OpClassMask.begin(), iie = OpClassMask.end(); iit != iie; ++iit) { unsigned OpMask = iit->second; ClassInfo *CI = iit->first; @@ -1638,34 +1660,90 @@ void MatchableInfo::buildAliasResultOperands() { } } +static unsigned getConverterOperandID(const std::string &Name, + SetVector &Table, + bool &IsNew) { + IsNew = Table.insert(Name); + + unsigned ID = IsNew ? Table.size() - 1 : + std::find(Table.begin(), Table.end(), Name) - Table.begin(); + + assert(ID < Table.size()); + + return ID; +} + + static void emitConvertToMCInst(CodeGenTarget &Target, StringRef ClassName, std::vector &Infos, raw_ostream &OS) { + SetVector OperandConversionKinds; + SetVector InstructionConversionKinds; + std::vector > ConversionTable; + size_t MaxRowLength = 2; // minimum is custom converter plus terminator. + + // TargetOperandClass - This is the target's operand class, like X86Operand. + std::string TargetOperandClass = Target.getName() + "Operand"; + // Write the convert function to a separate stream, so we can drop it after - // the enum. + // the enum. We'll build up the conversion handlers for the individual + // operand types opportunistically as we encounter them. std::string ConvertFnBody; raw_string_ostream CvtOS(ConvertFnBody); - - // Function we have already generated. - std::set GeneratedFns; - // Start the unified conversion function. - CvtOS << "bool " << Target.getName() << ClassName << "::\n"; - CvtOS << "ConvertToMCInst(unsigned Kind, MCInst &Inst, " + CvtOS << "void " << Target.getName() << ClassName << "::\n" + << "convertToMCInst(unsigned Kind, MCInst &Inst, " << "unsigned Opcode,\n" - << " const SmallVectorImpl &Operands) {\n"; - CvtOS << " Inst.setOpcode(Opcode);\n"; - CvtOS << " switch (Kind) {\n"; - CvtOS << " default:\n"; - - // Start the enum, which we will generate inline. - - OS << "// Unified function for converting operands to MCInst instances.\n\n"; - OS << "enum ConversionKind {\n"; - - // TargetOperandClass - This is the target's operand class, like X86Operand. - std::string TargetOperandClass = Target.getName() + "Operand"; + << " const SmallVectorImpl &Operands) {\n" + << " assert(Kind < CVT_NUM_SIGNATURES && \"Invalid signature!\");\n" + << " const uint8_t *Converter = ConversionTable[Kind];\n" + << " Inst.setOpcode(Opcode);\n" + << " for (const uint8_t *p = Converter; *p; p+= 2) {\n" + << " switch (*p) {\n" + << " default: llvm_unreachable(\"invalid conversion entry!\");\n" + << " case CVT_Reg:\n" + << " static_cast<" << TargetOperandClass + << "*>(Operands[*(p + 1)])->addRegOperands(Inst, 1);\n" + << " break;\n" + << " case CVT_Tied:\n" + << " Inst.addOperand(Inst.getOperand(*(p + 1)));\n" + << " break;\n"; + + std::string OperandFnBody; + raw_string_ostream OpOS(OperandFnBody); + // Start the operand number lookup function. + OpOS << "unsigned " << Target.getName() << ClassName << "::\n" + << "getMCInstOperandNumImpl(unsigned Kind, MCInst &Inst,\n" + << " const SmallVectorImpl " + << "&Operands,\n unsigned OperandNum, unsigned " + << "&NumMCOperands) {\n" + << " assert(Kind < CVT_NUM_SIGNATURES && \"Invalid signature!\");\n" + << " NumMCOperands = 0;\n" + << " unsigned MCOperandNum = 0;\n" + << " const uint8_t *Converter = ConversionTable[Kind];\n" + << " for (const uint8_t *p = Converter; *p; p+= 2) {\n" + << " if (*(p + 1) > OperandNum) continue;\n" + << " switch (*p) {\n" + << " default: llvm_unreachable(\"invalid conversion entry!\");\n" + << " case CVT_Reg:\n" + << " if (*(p + 1) == OperandNum) {\n" + << " NumMCOperands = 1;\n" + << " break;\n" + << " }\n" + << " ++MCOperandNum;\n" + << " break;\n" + << " case CVT_Tied:\n" + << " // FIXME: Tied operand calculation not supported.\n" + << " assert (0 && \"getMCInstOperandNumImpl() doesn't support tied operands, yet!\");\n" + << " break;\n"; + + // Pre-populate the operand conversion kinds with the standard always + // available entries. + OperandConversionKinds.insert("CVT_Done"); + OperandConversionKinds.insert("CVT_Reg"); + OperandConversionKinds.insert("CVT_Tied"); + enum { CVT_Done, CVT_Reg, CVT_Tied }; for (std::vector::const_iterator it = Infos.begin(), ie = Infos.end(); it != ie; ++it) { @@ -1679,24 +1757,35 @@ static void emitConvertToMCInst(CodeGenTarget &Target, StringRef ClassName, II.ConversionFnKind = Signature; // Check if we have already generated this signature. - if (!GeneratedFns.insert(Signature).second) + if (!InstructionConversionKinds.insert(Signature)) continue; - // If not, emit it now. Add to the enum list. - OS << " " << Signature << ",\n"; + // Remember this converter for the kind enum. + unsigned KindID = OperandConversionKinds.size(); + OperandConversionKinds.insert("CVT_" + AsmMatchConverter); - CvtOS << " case " << Signature << ":\n"; - CvtOS << " return " << AsmMatchConverter - << "(Inst, Opcode, Operands);\n"; + // Add the converter row for this instruction. + ConversionTable.push_back(std::vector()); + ConversionTable.back().push_back(KindID); + ConversionTable.back().push_back(CVT_Done); + + // Add the handler to the conversion driver function. + CvtOS << " case CVT_" << AsmMatchConverter << ":\n" + << " " << AsmMatchConverter << "(Inst, Operands);\n" + << " break;\n"; + + // FIXME: Handle the operand number lookup for custom match functions. continue; } // Build the conversion function signature. std::string Signature = "Convert"; - std::string CaseBody; - raw_string_ostream CaseOS(CaseBody); + + std::vector ConversionRow; // Compute the convert enum and the case body. + MaxRowLength = std::max(MaxRowLength, II.ResOperands.size()*2 + 1 ); + for (unsigned i = 0, e = II.ResOperands.size(); i != e; ++i) { const MatchableInfo::ResOperand &OpInfo = II.ResOperands[i]; @@ -1709,74 +1798,186 @@ static void emitConvertToMCInst(CodeGenTarget &Target, StringRef ClassName, // Registers are always converted the same, don't duplicate the // conversion function based on them. Signature += "__"; - if (Op.Class->isRegisterClass()) - Signature += "Reg"; - else - Signature += Op.Class->ClassName; + std::string Class; + Class = Op.Class->isRegisterClass() ? "Reg" : Op.Class->ClassName; + Signature += Class; Signature += utostr(OpInfo.MINumOperands); Signature += "_" + itostr(OpInfo.AsmOperandNum); - CaseOS << " ((" << TargetOperandClass << "*)Operands[" - << (OpInfo.AsmOperandNum+1) << "])->" << Op.Class->RenderMethod - << "(Inst, " << OpInfo.MINumOperands << ");\n"; + // Add the conversion kind, if necessary, and get the associated ID + // the index of its entry in the vector). + std::string Name = "CVT_" + (Op.Class->isRegisterClass() ? "Reg" : + Op.Class->RenderMethod); + + bool IsNewConverter = false; + unsigned ID = getConverterOperandID(Name, OperandConversionKinds, + IsNewConverter); + + // Add the operand entry to the instruction kind conversion row. + ConversionRow.push_back(ID); + ConversionRow.push_back(OpInfo.AsmOperandNum + 1); + + if (!IsNewConverter) + break; + + // This is a new operand kind. Add a handler for it to the + // converter driver. + CvtOS << " case " << Name << ":\n" + << " static_cast<" << TargetOperandClass + << "*>(Operands[*(p + 1)])->" + << Op.Class->RenderMethod << "(Inst, " << OpInfo.MINumOperands + << ");\n" + << " break;\n"; + + // Add a handler for the operand number lookup. + OpOS << " case " << Name << ":\n" + << " if (*(p + 1) == OperandNum) {\n" + << " NumMCOperands = " << OpInfo.MINumOperands << ";\n" + << " break;\n" + << " }\n" + << " MCOperandNum += " << OpInfo.MINumOperands << ";\n" + << " break;\n"; break; } - case MatchableInfo::ResOperand::TiedOperand: { // If this operand is tied to a previous one, just copy the MCInst // operand from the earlier one.We can only tie single MCOperand values. //assert(OpInfo.MINumOperands == 1 && "Not a singular MCOperand"); unsigned TiedOp = OpInfo.TiedOperandNum; assert(i > TiedOp && "Tied operand precedes its target!"); - CaseOS << " Inst.addOperand(Inst.getOperand(" << TiedOp << "));\n"; Signature += "__Tie" + utostr(TiedOp); + ConversionRow.push_back(CVT_Tied); + ConversionRow.push_back(TiedOp); + // FIXME: Handle the operand number lookup for tied operands. break; } case MatchableInfo::ResOperand::ImmOperand: { int64_t Val = OpInfo.ImmVal; - CaseOS << " Inst.addOperand(MCOperand::CreateImm(" << Val << "));\n"; - Signature += "__imm" + itostr(Val); + std::string Ty = "imm_" + itostr(Val); + Signature += "__" + Ty; + + std::string Name = "CVT_" + Ty; + bool IsNewConverter = false; + unsigned ID = getConverterOperandID(Name, OperandConversionKinds, + IsNewConverter); + // Add the operand entry to the instruction kind conversion row. + ConversionRow.push_back(ID); + ConversionRow.push_back(0); + + if (!IsNewConverter) + break; + + CvtOS << " case " << Name << ":\n" + << " Inst.addOperand(MCOperand::CreateImm(" << Val << "));\n" + << " break;\n"; + + OpOS << " case " << Name << ":\n" + << " if (*(p + 1) == OperandNum) {\n" + << " NumMCOperands = 1;\n" + << " break;\n" + << " }\n" + << " ++MCOperandNum;\n" + << " break;\n"; break; } case MatchableInfo::ResOperand::RegOperand: { + std::string Reg, Name; if (OpInfo.Register == 0) { - CaseOS << " Inst.addOperand(MCOperand::CreateReg(0));\n"; - Signature += "__reg0"; + Name = "reg0"; + Reg = "0"; } else { - std::string N = getQualifiedName(OpInfo.Register); - CaseOS << " Inst.addOperand(MCOperand::CreateReg(" << N << "));\n"; - Signature += "__reg" + OpInfo.Register->getName(); + Reg = getQualifiedName(OpInfo.Register); + Name = "reg" + OpInfo.Register->getName(); } + Signature += "__" + Name; + Name = "CVT_" + Name; + bool IsNewConverter = false; + unsigned ID = getConverterOperandID(Name, OperandConversionKinds, + IsNewConverter); + // Add the operand entry to the instruction kind conversion row. + ConversionRow.push_back(ID); + ConversionRow.push_back(0); + + if (!IsNewConverter) + break; + CvtOS << " case " << Name << ":\n" + << " Inst.addOperand(MCOperand::CreateReg(" << Reg << "));\n" + << " break;\n"; + + OpOS << " case " << Name << ":\n" + << " if (*(p + 1) == OperandNum) {\n" + << " NumMCOperands = 1;\n" + << " break;\n" + << " }\n" + << " ++MCOperandNum;\n" + << " break;\n"; } } } + // If there were no operands, add to the signature to that effect + if (Signature == "Convert") + Signature += "_NoOperands"; + II.ConversionFnKind = Signature; - // Check if we have already generated this signature. - if (!GeneratedFns.insert(Signature).second) + // Save the signature. If we already have it, don't add a new row + // to the table. + if (!InstructionConversionKinds.insert(Signature)) continue; - // If not, emit it now. Add to the enum list. - OS << " " << Signature << ",\n"; - - CvtOS << " case " << Signature << ":\n"; - CvtOS << CaseOS.str(); - CvtOS << " return true;\n"; + // Add the row to the table. + ConversionTable.push_back(ConversionRow); } - // Finish the convert function. + // Finish up the converter driver function. + CvtOS << " }\n }\n}\n\n"; + + // Finish up the operand number lookup function. + OpOS << " }\n }\n return MCOperandNum;\n}\n\n"; + + OS << "namespace {\n"; + + // Output the operand conversion kind enum. + OS << "enum OperatorConversionKind {\n"; + for (unsigned i = 0, e = OperandConversionKinds.size(); i != e; ++i) + OS << " " << OperandConversionKinds[i] << ",\n"; + OS << " CVT_NUM_CONVERTERS\n"; + OS << "};\n\n"; + + // Output the instruction conversion kind enum. + OS << "enum InstructionConversionKind {\n"; + for (SetVector::const_iterator + i = InstructionConversionKinds.begin(), + e = InstructionConversionKinds.end(); i != e; ++i) + OS << " " << *i << ",\n"; + OS << " CVT_NUM_SIGNATURES\n"; + OS << "};\n\n"; + - CvtOS << " }\n"; - CvtOS << " return false;\n"; - CvtOS << "}\n\n"; + OS << "} // end anonymous namespace\n\n"; - // Finish the enum, and drop the convert function after it. + // Output the conversion table. + OS << "static const uint8_t ConversionTable[CVT_NUM_SIGNATURES][" + << MaxRowLength << "] = {\n"; + + for (unsigned Row = 0, ERow = ConversionTable.size(); Row != ERow; ++Row) { + assert(ConversionTable[Row].size() % 2 == 0 && "bad conversion row!"); + OS << " // " << InstructionConversionKinds[Row] << "\n"; + OS << " { "; + for (unsigned i = 0, e = ConversionTable[Row].size(); i != e; i += 2) + OS << OperandConversionKinds[ConversionTable[Row][i]] << ", " + << (unsigned)(ConversionTable[Row][i + 1]) << ", "; + OS << "CVT_Done },\n"; + } - OS << " NumConversionVariants\n"; OS << "};\n\n"; + // Spit out the conversion driver function. OS << CvtOS.str(); + + // Spit out the operand number lookup function. + OS << OpOS.str(); } /// emitMatchClassEnumeration - Emit the enumeration for match class kinds. @@ -1829,22 +2030,6 @@ static void emitValidateOperandClass(AsmMatcherInfo &Info, << " MCTargetAsmParser::Match_Success :\n" << " MCTargetAsmParser::Match_InvalidOperand;\n\n"; - // Check for register operands, including sub-classes. - OS << " if (Operand.isReg()) {\n"; - OS << " MatchClassKind OpKind;\n"; - OS << " switch (Operand.getReg()) {\n"; - OS << " default: OpKind = InvalidMatchClass; break;\n"; - for (std::map::iterator - it = Info.RegisterClasses.begin(), ie = Info.RegisterClasses.end(); - it != ie; ++it) - OS << " case " << Info.Target.getName() << "::" - << it->first->getName() << ": OpKind = " << it->second->Name - << "; break;\n"; - OS << " }\n"; - OS << " return isSubclass(OpKind, Kind) ? " - << "MCTargetAsmParser::Match_Success :\n " - << " MCTargetAsmParser::Match_InvalidOperand;\n }\n\n"; - // Check the user classes. We don't care what order since we're only // actually matching against one of them. for (std::vector::iterator it = Info.Classes.begin(), @@ -1864,6 +2049,22 @@ static void emitValidateOperandClass(AsmMatcherInfo &Info, OS << " }\n\n"; } + // Check for register operands, including sub-classes. + OS << " if (Operand.isReg()) {\n"; + OS << " MatchClassKind OpKind;\n"; + OS << " switch (Operand.getReg()) {\n"; + OS << " default: OpKind = InvalidMatchClass; break;\n"; + for (AsmMatcherInfo::RegisterClassesTy::iterator + it = Info.RegisterClasses.begin(), ie = Info.RegisterClasses.end(); + it != ie; ++it) + OS << " case " << Info.Target.getName() << "::" + << it->first->getName() << ": OpKind = " << it->second->Name + << "; break;\n"; + OS << " }\n"; + OS << " return isSubclass(OpKind, Kind) ? " + << "MCTargetAsmParser::Match_Success :\n " + << " MCTargetAsmParser::Match_InvalidOperand;\n }\n\n"; + // Generic fallthrough match failure case for operands that don't have // specialized diagnostic types. OS << " return MCTargetAsmParser::Match_InvalidOperand;\n"; @@ -1874,7 +2075,7 @@ static void emitValidateOperandClass(AsmMatcherInfo &Info, static void emitIsSubclass(CodeGenTarget &Target, std::vector &Infos, raw_ostream &OS) { - OS << "/// isSubclass - Compute whether \\arg A is a subclass of \\arg B.\n"; + OS << "/// isSubclass - Compute whether \\p A is a subclass of \\p B.\n"; OS << "static bool isSubclass(MatchClassKind A, MatchClassKind B) {\n"; OS << " if (A == B)\n"; OS << " return true;\n\n"; @@ -2189,17 +2390,27 @@ static const char *getMinimalTypeForRange(uint64_t Range) { } static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target, - const AsmMatcherInfo &Info, StringRef ClassName) { + const AsmMatcherInfo &Info, StringRef ClassName, + StringToOffsetTable &StringTable, + unsigned MaxMnemonicIndex) { + unsigned MaxMask = 0; + for (std::vector::const_iterator it = + Info.OperandMatchInfo.begin(), ie = Info.OperandMatchInfo.end(); + it != ie; ++it) { + MaxMask |= it->OperandMask; + } + // Emit the static custom operand parsing table; OS << "namespace {\n"; OS << " struct OperandMatchEntry {\n"; - OS << " static const char *const MnemonicTable;\n"; - OS << " uint32_t OperandMask;\n"; - OS << " uint32_t Mnemonic;\n"; OS << " " << getMinimalTypeForRange(1ULL << Info.SubtargetFeatures.size()) << " RequiredFeatures;\n"; + OS << " " << getMinimalTypeForRange(MaxMnemonicIndex) + << " Mnemonic;\n"; OS << " " << getMinimalTypeForRange(Info.Classes.size()) - << " Class;\n\n"; + << " Class;\n"; + OS << " " << getMinimalTypeForRange(MaxMask) + << " OperandMask;\n\n"; OS << " StringRef getMnemonic() const {\n"; OS << " return StringRef(MnemonicTable + Mnemonic + 1,\n"; OS << " MnemonicTable[Mnemonic]);\n"; @@ -2222,8 +2433,6 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target, OS << "} // end anonymous namespace.\n\n"; - StringToOffsetTable StringTable; - OS << "static const OperandMatchEntry OperandMatchTable[" << Info.OperandMatchInfo.size() << "] = {\n"; @@ -2234,8 +2443,25 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target, const OperandMatchEntry &OMI = *it; const MatchableInfo &II = *OMI.MI; - OS << " { " << OMI.OperandMask; + 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) + << " /* " << II.Mnemonic << " */, "; + + OS << OMI.CI->Name; + + OS << ", " << OMI.OperandMask; OS << " /* "; bool printComma = false; for (int i = 0, e = 31; i !=e; ++i) @@ -2247,30 +2473,10 @@ 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 << " */, "; - - // 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"; - - OS << ", " << OMI.CI->Name; - OS << " },\n"; } OS << "};\n\n"; - OS << "const char *const 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 " @@ -2407,14 +2613,19 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " // This should be included into the middle of the declaration of\n"; OS << " // your subclasses implementation of MCTargetAsmParser.\n"; OS << " unsigned ComputeAvailableFeatures(uint64_t FeatureBits) const;\n"; - OS << " bool ConvertToMCInst(unsigned Kind, MCInst &Inst, " + OS << " void convertToMCInst(unsigned Kind, MCInst &Inst, " << "unsigned Opcode,\n" - << " const SmallVectorImpl " + << " const SmallVectorImpl " << "&Operands);\n"; + OS << " unsigned getMCInstOperandNumImpl(unsigned Kind, MCInst &Inst,\n" + << " const " + << "SmallVectorImpl &Operands,\n " + << " unsigned OperandNum, unsigned &NumMCOperands);\n"; OS << " bool MnemonicIsValid(StringRef Mnemonic);\n"; - OS << " unsigned MatchInstructionImpl(\n"; - OS << " const SmallVectorImpl &Operands,\n"; - OS << " MCInst &Inst, unsigned &ErrorInfo, unsigned VariantID = 0);\n"; + OS << " unsigned MatchInstructionImpl(\n" + << " const SmallVectorImpl &Operands,\n" + << " unsigned &Kind, MCInst &Inst, " + << "unsigned &ErrorInfo,\n unsigned VariantID = 0);\n"; if (Info.OperandMatchInfo.size()) { OS << "\n enum OperandMatchResultTy {\n"; @@ -2447,7 +2658,9 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { emitSubtargetFeatureFlagEnumeration(Info, OS); // Emit the function to match a register name to number. - emitMatchRegisterName(Target, AsmParser, OS); + // This should be omitted for Mips target + if (AsmParser->getValueAsBit("ShouldEmitMatchRegisterName")) + emitMatchRegisterName(Target, AsmParser, OS); OS << "#endif // GET_REGISTER_MATCHER\n\n"; @@ -2484,11 +2697,25 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { emitComputeAvailableFeatures(Info, OS); + StringToOffsetTable StringTable; + size_t MaxNumOperands = 0; + unsigned MaxMnemonicIndex = 0; for (std::vector::const_iterator it = Info.Matchables.begin(), ie = Info.Matchables.end(); - it != ie; ++it) - MaxNumOperands = std::max(MaxNumOperands, (*it)->AsmOperands.size()); + it != ie; ++it) { + MatchableInfo &II = **it; + MaxNumOperands = std::max(MaxNumOperands, II.AsmOperands.size()); + + // Store a pascal-style length byte in the mnemonic. + std::string LenMnemonic = char(II.Mnemonic.size()) + II.Mnemonic.str(); + MaxMnemonicIndex = std::max(MaxMnemonicIndex, + StringTable.GetOrAddStringOffset(LenMnemonic, false)); + } + + OS << "static const char *const MnemonicTable =\n"; + StringTable.EmitString(OS); + OS << ";\n\n"; // Emit the static match table; unused classes get initalized to 0 which is // guaranteed to be InvalidMatchClass. @@ -2502,8 +2729,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { // following the mnemonic. OS << "namespace {\n"; OS << " struct MatchEntry {\n"; - OS << " static const char *const MnemonicTable;\n"; - OS << " uint32_t Mnemonic;\n"; + OS << " " << getMinimalTypeForRange(MaxMnemonicIndex) + << " Mnemonic;\n"; OS << " uint16_t Opcode;\n"; OS << " " << getMinimalTypeForRange(Info.Matchables.size()) << " ConvertFn;\n"; @@ -2533,8 +2760,6 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << "} // end anonymous namespace.\n\n"; - StringToOffsetTable StringTable; - OS << "static const MatchEntry MatchTable[" << Info.Matchables.size() << "] = {\n"; @@ -2573,10 +2798,6 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << "};\n\n"; - OS << "const char *const 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"; @@ -2592,8 +2813,14 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { << Target.getName() << ClassName << "::\n" << "MatchInstructionImpl(const SmallVectorImpl" << " &Operands,\n"; - OS << " MCInst &Inst, unsigned &ErrorInfo, "; - OS << "unsigned VariantID) {\n"; + OS << " unsigned &Kind, MCInst &Inst, unsigned "; + OS << "&ErrorInfo,\n unsigned VariantID) {\n"; + + OS << " // Eliminate obvious mismatches.\n"; + OS << " if (Operands.size() > " << (MaxNumOperands+1) << ") {\n"; + OS << " ErrorInfo = " << (MaxNumOperands+1) << ";\n"; + OS << " return Match_InvalidOperand;\n"; + OS << " }\n\n"; // Emit code to get the available features. OS << " // Get the current feature set.\n"; @@ -2611,12 +2838,6 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { } // Emit code to compute the class list for this operand vector. - OS << " // Eliminate obvious mismatches.\n"; - OS << " if (Operands.size() > " << (MaxNumOperands+1) << ") {\n"; - OS << " ErrorInfo = " << (MaxNumOperands+1) << ";\n"; - OS << " return Match_InvalidOperand;\n"; - OS << " }\n\n"; - OS << " // Some state to try to produce better error messages.\n"; OS << " bool HadMatchOtherThanFeatures = false;\n"; OS << " bool HadMatchOtherThanPredicate = false;\n"; @@ -2649,6 +2870,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " for (unsigned i = 0; i != " << MaxNumOperands << "; ++i) {\n"; OS << " if (i + 1 >= Operands.size()) {\n"; OS << " OperandsValid = (it->Classes[i] == " <<"InvalidMatchClass);\n"; + OS << " if (!OperandsValid) ErrorInfo = i + 1;\n"; OS << " break;\n"; OS << " }\n"; OS << " unsigned Diag = validateOperandClass(Operands[i+1],\n"; @@ -2663,7 +2885,9 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " if (!HadMatchOtherThanPredicate &&\n"; OS << " (it == MnemonicRange.first || ErrorInfo <= i+1)) {\n"; OS << " ErrorInfo = i+1;\n"; - OS << " RetCode = Diag;\n"; + OS << " // InvalidOperand is the default. Prefer specificity.\n"; + OS << " if (Diag != Match_InvalidOperand)\n"; + OS << " RetCode = Diag;\n"; OS << " }\n"; OS << " // Otherwise, just reject this instance of the mnemonic.\n"; OS << " OperandsValid = false;\n"; @@ -2678,17 +2902,15 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " HadMatchOtherThanFeatures = true;\n"; OS << " unsigned NewMissingFeatures = it->RequiredFeatures & " "~AvailableFeatures;\n"; - OS << " if (CountPopulation_32(NewMissingFeatures) <= " - "CountPopulation_32(MissingFeatures))\n"; + OS << " if (CountPopulation_32(NewMissingFeatures) <=\n" + " CountPopulation_32(MissingFeatures))\n"; OS << " MissingFeatures = NewMissingFeatures;\n"; OS << " continue;\n"; OS << " }\n"; OS << "\n"; OS << " // We have selected a definite instruction, convert the parsed\n" << " // operands into the appropriate MCInst.\n"; - OS << " if (!ConvertToMCInst(it->ConvertFn, Inst,\n" - << " it->Opcode, Operands))\n"; - OS << " return Match_ConversionFail;\n"; + OS << " convertToMCInst(it->ConvertFn, Inst, it->Opcode, Operands);\n"; OS << "\n"; // Verify the instruction with the target-specific match predicate function. @@ -2709,19 +2931,21 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { if (!InsnCleanupFn.empty()) OS << " " << InsnCleanupFn << "(Inst);\n"; + OS << " Kind = it->ConvertFn;\n"; OS << " return Match_Success;\n"; OS << " }\n\n"; OS << " // Okay, we had no match. Try to return a useful error code.\n"; - OS << " if (HadMatchOtherThanPredicate || !HadMatchOtherThanFeatures)"; - OS << " return RetCode;\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 << " return Match_MissingFeature;\n"; OS << "}\n\n"; if (Info.OperandMatchInfo.size()) - emitCustomOperandParsing(OS, Target, Info, ClassName); + emitCustomOperandParsing(OS, Target, Info, ClassName, StringTable, + MaxMnemonicIndex); OS << "#endif // GET_MATCHER_IMPLEMENTATION\n\n"; }