in llvm/utils/TableGen/AsmMatcherEmitter.cpp [3191:3981]
void AsmMatcherEmitter::run(raw_ostream &OS) {
CodeGenTarget Target(Records);
Record *AsmParser = Target.getAsmParser();
StringRef ClassName = AsmParser->getValueAsString("AsmParserClassName");
// Compute the information on the instructions to match.
AsmMatcherInfo Info(AsmParser, Target, Records);
Info.buildInfo();
// Sort the instruction table using the partial order on classes. We use
// stable_sort to ensure that ambiguous instructions are still
// deterministically ordered.
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.
for (auto I = Info.Matchables.begin(), E = Info.Matchables.end(); I != E;
++I) {
for (auto J = I; J != E; ++J) {
assert(!(**J < **I));
}
}
#endif
DEBUG_WITH_TYPE("instruction_info", {
for (const auto &MI : Info.Matchables)
MI->dump();
});
// Check for ambiguous matchables.
DEBUG_WITH_TYPE("ambiguous_instrs", {
unsigned NumAmbiguous = 0;
for (auto I = Info.Matchables.begin(), E = Info.Matchables.end(); I != E;
++I) {
for (auto J = std::next(I); J != E; ++J) {
const MatchableInfo &A = **I;
const MatchableInfo &B = **J;
if (A.couldMatchAmbiguouslyWith(B)) {
errs() << "warning: ambiguous matchables:\n";
A.dump();
errs() << "\nis incomparable with:\n";
B.dump();
errs() << "\n\n";
++NumAmbiguous;
}
}
}
if (NumAmbiguous)
errs() << "warning: " << NumAmbiguous
<< " ambiguous matchables!\n";
});
// Compute the information on the custom operand parsing.
Info.buildOperandMatchInfo();
bool HasMnemonicFirst = AsmParser->getValueAsBit("HasMnemonicFirst");
bool HasOptionalOperands = Info.hasOptionalOperands();
bool ReportMultipleNearMisses =
AsmParser->getValueAsBit("ReportMultipleNearMisses");
// Write the output.
// Information for the class declaration.
OS << "\n#ifdef GET_ASSEMBLER_HEADER\n";
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 << " FeatureBitset ComputeAvailableFeatures(const FeatureBitset &FB) const;\n";
if (HasOptionalOperands) {
OS << " void convertToMCInst(unsigned Kind, MCInst &Inst, "
<< "unsigned Opcode,\n"
<< " const OperandVector &Operands,\n"
<< " const SmallBitVector &OptionalOperandsMask);\n";
} else {
OS << " void convertToMCInst(unsigned Kind, MCInst &Inst, "
<< "unsigned Opcode,\n"
<< " const OperandVector &Operands);\n";
}
OS << " void convertToMapAndConstraints(unsigned Kind,\n ";
OS << " const OperandVector &Operands) override;\n";
OS << " unsigned MatchInstructionImpl(const OperandVector &Operands,\n"
<< " MCInst &Inst,\n";
if (ReportMultipleNearMisses)
OS << " SmallVectorImpl<NearMissInfo> *NearMisses,\n";
else
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";
OS << " OperandVector &Operands,\n";
OS << " StringRef Mnemonic,\n";
OS << " bool ParseForAllFeatures = false);\n";
OS << " OperandMatchResultTy tryCustomParseOperand(\n";
OS << " OperandVector &Operands,\n";
OS << " unsigned MCK);\n\n";
}
OS << "#endif // GET_ASSEMBLER_HEADER_INFO\n\n";
// Emit the operand match diagnostic enum names.
OS << "\n#ifdef GET_OPERAND_DIAGNOSTIC_TYPES\n";
OS << "#undef GET_OPERAND_DIAGNOSTIC_TYPES\n\n";
emitOperandDiagnosticTypes(Info, OS);
OS << "#endif // GET_OPERAND_DIAGNOSTIC_TYPES\n\n";
OS << "\n#ifdef GET_REGISTER_MATCHER\n";
OS << "#undef GET_REGISTER_MATCHER\n\n";
// Emit the subtarget feature enumeration.
SubtargetFeatureInfo::emitSubtargetFeatureBitEnumeration(
Info.SubtargetFeatures, OS);
// Emit the function to match a register name to number.
// This should be omitted for Mips target
if (AsmParser->getValueAsBit("ShouldEmitMatchRegisterName"))
emitMatchRegisterName(Target, AsmParser, OS);
if (AsmParser->getValueAsBit("ShouldEmitMatchRegisterAltName"))
emitMatchRegisterAltName(Target, AsmParser, OS);
OS << "#endif // GET_REGISTER_MATCHER\n\n";
OS << "\n#ifdef GET_SUBTARGET_FEATURE_NAME\n";
OS << "#undef GET_SUBTARGET_FEATURE_NAME\n\n";
// Generate the helper function to get the names for subtarget features.
emitGetSubtargetFeatureName(Info, OS);
OS << "#endif // GET_SUBTARGET_FEATURE_NAME\n\n";
OS << "\n#ifdef GET_MATCHER_IMPLEMENTATION\n";
OS << "#undef GET_MATCHER_IMPLEMENTATION\n\n";
// Generate the function that remaps for mnemonic aliases.
bool HasMnemonicAliases = emitMnemonicAliases(OS, Info, Target);
// 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.
unsigned NumConverters = emitConvertFuncs(Target, ClassName, Info.Matchables,
HasMnemonicFirst,
HasOptionalOperands, OS);
// Emit the enumeration for classes which participate in matching.
emitMatchClassEnumeration(Target, Info.Classes, OS);
// Emit a function to get the user-visible string to describe an operand
// match failure in diagnostics.
emitOperandMatchErrorDiagStrings(Info, OS);
// Emit a function to map register classes to operand match failure codes.
emitRegisterMatchErrorFunc(Info, OS);
// Emit the routine to match token strings to their match class.
emitMatchTokenString(Target, Info.Classes, OS);
// Emit the subclass predicate routine.
emitIsSubclass(Target, Info.Classes, OS);
// Emit the routine to validate an operand against a match class.
emitValidateOperandClass(Info, OS);
emitMatchClassKindNames(Info.Classes, OS);
// Emit the available features compute function.
SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures(
Info.Target.getName(), ClassName, "ComputeAvailableFeatures",
Info.SubtargetFeatures, OS);
if (!ReportMultipleNearMisses)
emitAsmTiedOperandConstraints(Target, Info, OS);
StringToOffsetTable StringTable;
size_t MaxNumOperands = 0;
unsigned MaxMnemonicIndex = 0;
bool HasDeprecation = false;
for (const auto &MI : Info.Matchables) {
MaxNumOperands = std::max(MaxNumOperands, MI->AsmOperands.size());
HasDeprecation |= MI->HasDeprecation;
// Store a pascal-style length byte in the mnemonic.
std::string LenMnemonic = char(MI->Mnemonic.size()) + MI->Mnemonic.lower();
MaxMnemonicIndex = std::max(MaxMnemonicIndex,
StringTable.GetOrAddStringOffset(LenMnemonic, false));
}
OS << "static const char *const MnemonicTable =\n";
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 (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"
<< "static constexpr 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.
//
// FIXME: We can reduce the size of this table very easily. First, we change
// it so that store the kinds in separate bit-fields for each index, which
// only needs to be the max width used for classes at that index (we also need
// to reject based on this during classification). If we then make sure to
// order the match kinds appropriately (putting mnemonics last), then we
// should only end up using a few bits for each class, especially the ones
// following the mnemonic.
OS << "namespace {\n";
OS << " struct MatchEntry {\n";
OS << " " << getMinimalTypeForRange(MaxMnemonicIndex)
<< " Mnemonic;\n";
OS << " uint16_t Opcode;\n";
OS << " " << getMinimalTypeForRange(NumConverters)
<< " ConvertFn;\n";
OS << " " << getMinimalTypeForRange(FeatureBitsets.size())
<< " RequiredFeaturesIdx;\n";
OS << " " << getMinimalTypeForRange(
std::distance(Info.Classes.begin(), Info.Classes.end()))
<< " Classes[" << MaxNumOperands << "];\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 LHS.getMnemonic() < RHS;\n";
OS << " }\n";
OS << " bool operator()(StringRef LHS, const MatchEntry &RHS) {\n";
OS << " return LHS < RHS.getMnemonic();\n";
OS << " }\n";
OS << " bool operator()(const MatchEntry &LHS, const MatchEntry &RHS) {\n";
OS << " return LHS.getMnemonic() < RHS.getMnemonic();\n";
OS << " }\n";
OS << " };\n";
OS << "} // end anonymous namespace\n\n";
unsigned VariantCount = Target.getAsmParserVariantCount();
for (unsigned VC = 0; VC != VariantCount; ++VC) {
Record *AsmVariant = Target.getAsmParserVariant(VC);
int AsmVariantNo = AsmVariant->getValueAsInt("Variant");
OS << "static const MatchEntry MatchTable" << VC << "[] = {\n";
for (const auto &MI : Info.Matchables) {
if (MI->AsmVariantID != AsmVariantNo)
continue;
// Store a pascal-style length byte in the mnemonic.
std::string LenMnemonic =
char(MI->Mnemonic.size()) + MI->Mnemonic.lower();
OS << " { " << StringTable.GetOrAddStringOffset(LenMnemonic, false)
<< " /* " << MI->Mnemonic << " */, "
<< Target.getInstNamespace() << "::"
<< MI->getResultInst()->TheDef->getName() << ", "
<< MI->ConversionFnKind << ", ";
// Write the required features mask.
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 << ", { ";
ListSeparator LS;
for (const MatchableInfo::AsmOperand &Op : MI->AsmOperands)
OS << LS << Op.Class->Name;
OS << " }, },\n";
}
OS << "};\n\n";
}
OS << "#include \"llvm/Support/Debug.h\"\n";
OS << "#include \"llvm/Support/Format.h\"\n\n";
// Finally, build the match function.
OS << "unsigned " << Target.getName() << ClassName << "::\n"
<< "MatchInstructionImpl(const OperandVector &Operands,\n";
OS << " MCInst &Inst,\n";
if (ReportMultipleNearMisses)
OS << " SmallVectorImpl<NearMissInfo> *NearMisses,\n";
else
OS << " uint64_t &ErrorInfo,\n"
<< " FeatureBitset &MissingFeatures,\n";
OS << " bool matchingInlineAsm, unsigned VariantID) {\n";
if (!ReportMultipleNearMisses) {
OS << " // Eliminate obvious mismatches.\n";
OS << " if (Operands.size() > "
<< (MaxNumOperands + HasMnemonicFirst) << ") {\n";
OS << " ErrorInfo = "
<< (MaxNumOperands + HasMnemonicFirst) << ";\n";
OS << " return Match_InvalidOperand;\n";
OS << " }\n\n";
}
// Emit code to get the available features.
OS << " // Get the current feature set.\n";
OS << " const FeatureBitset &AvailableFeatures = getAvailableFeatures();\n\n";
OS << " // Get the instruction mnemonic, which is the first token.\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";
OS << " applyMnemonicAliases(Mnemonic, AvailableFeatures, VariantID);\n\n";
}
// Emit code to compute the class list for this operand vector.
if (!ReportMultipleNearMisses) {
OS << " // Some state to try to produce better error messages.\n";
OS << " bool HadMatchOtherThanFeatures = false;\n";
OS << " bool HadMatchOtherThanPredicate = false;\n";
OS << " unsigned RetCode = Match_InvalidOperand;\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";
}
if (HasOptionalOperands) {
OS << " SmallBitVector OptionalOperandsMask(" << MaxNumOperands << ");\n";
}
// Emit code to search the table.
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";
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 << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"AsmMatcher: found \" <<\n"
<< " std::distance(MnemonicRange.first, MnemonicRange.second) <<\n"
<< " \" encodings with mnemonic '\" << Mnemonic << \"'\\n\");\n\n";
OS << " // Return a more specific error code if no mnemonics match.\n";
OS << " if (MnemonicRange.first == MnemonicRange.second)\n";
OS << " return Match_MnemonicFail;\n\n";
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 & RequiredFeatures) == RequiredFeatures;\n";
OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"Trying to match opcode \"\n";
OS << " << MII.getName(it->Opcode) << \"\\n\");\n";
if (ReportMultipleNearMisses) {
OS << " // Some state to record ways in which this instruction did not match.\n";
OS << " NearMissInfo OperandNearMiss = NearMissInfo::getSuccess();\n";
OS << " NearMissInfo FeaturesNearMiss = NearMissInfo::getSuccess();\n";
OS << " NearMissInfo EarlyPredicateNearMiss = NearMissInfo::getSuccess();\n";
OS << " NearMissInfo LatePredicateNearMiss = NearMissInfo::getSuccess();\n";
OS << " bool MultipleInvalidOperands = false;\n";
}
if (HasMnemonicFirst) {
OS << " // equal_range guarantees that instruction mnemonic matches.\n";
OS << " assert(Mnemonic == it->getMnemonic());\n";
}
// Emit check that the subclasses match.
if (!ReportMultipleNearMisses)
OS << " bool OperandsValid = true;\n";
if (HasOptionalOperands) {
OS << " OptionalOperandsMask.reset(0, " << MaxNumOperands << ");\n";
}
OS << " for (unsigned FormalIdx = " << (HasMnemonicFirst ? "0" : "SIndex")
<< ", ActualIdx = " << (HasMnemonicFirst ? "1" : "SIndex")
<< "; FormalIdx != " << MaxNumOperands << "; ++FormalIdx) {\n";
OS << " auto Formal = "
<< "static_cast<MatchClassKind>(it->Classes[FormalIdx]);\n";
OS << " DEBUG_WITH_TYPE(\"asm-matcher\",\n";
OS << " dbgs() << \" Matching formal operand class \" << getMatchClassName(Formal)\n";
OS << " << \" against actual operand at index \" << ActualIdx);\n";
OS << " if (ActualIdx < Operands.size())\n";
OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \" (\";\n";
OS << " Operands[ActualIdx]->print(dbgs()); dbgs() << \"): \");\n";
OS << " else\n";
OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \": \");\n";
OS << " if (ActualIdx >= Operands.size()) {\n";
OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"actual operand index out of range \");\n";
if (ReportMultipleNearMisses) {
OS << " bool ThisOperandValid = (Formal == " <<"InvalidMatchClass) || "
"isSubclass(Formal, OptionalMatchClass);\n";
OS << " if (!ThisOperandValid) {\n";
OS << " if (!OperandNearMiss) {\n";
OS << " // Record info about match failure for later use.\n";
OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"recording too-few-operands near miss\\n\");\n";
OS << " OperandNearMiss =\n";
OS << " NearMissInfo::getTooFewOperands(Formal, it->Opcode);\n";
OS << " } else if (OperandNearMiss.getKind() != NearMissInfo::NearMissTooFewOperands) {\n";
OS << " // If more than one operand is invalid, give up on this match entry.\n";
OS << " DEBUG_WITH_TYPE(\n";
OS << " \"asm-matcher\",\n";
OS << " dbgs() << \"second invalid operand, giving up on this opcode\\n\");\n";
OS << " MultipleInvalidOperands = true;\n";
OS << " break;\n";
OS << " }\n";
OS << " } else {\n";
OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"but formal operand not required\\n\");\n";
OS << " break;\n";
OS << " }\n";
OS << " continue;\n";
} else {
OS << " OperandsValid = (Formal == InvalidMatchClass) || isSubclass(Formal, OptionalMatchClass);\n";
OS << " if (!OperandsValid) ErrorInfo = ActualIdx;\n";
if (HasOptionalOperands) {
OS << " OptionalOperandsMask.set(FormalIdx, " << MaxNumOperands
<< ");\n";
}
OS << " break;\n";
}
OS << " }\n";
OS << " MCParsedAsmOperand &Actual = *Operands[ActualIdx];\n";
OS << " unsigned Diag = validateOperandClass(Actual, Formal);\n";
OS << " if (Diag == Match_Success) {\n";
OS << " DEBUG_WITH_TYPE(\"asm-matcher\",\n";
OS << " dbgs() << \"match success using generic matcher\\n\");\n";
OS << " ++ActualIdx;\n";
OS << " continue;\n";
OS << " }\n";
OS << " // If the generic handler indicates an invalid operand\n";
OS << " // failure, check for a special case.\n";
OS << " if (Diag != Match_Success) {\n";
OS << " unsigned TargetDiag = validateTargetOperandClass(Actual, Formal);\n";
OS << " if (TargetDiag == Match_Success) {\n";
OS << " DEBUG_WITH_TYPE(\"asm-matcher\",\n";
OS << " dbgs() << \"match success using target matcher\\n\");\n";
OS << " ++ActualIdx;\n";
OS << " continue;\n";
OS << " }\n";
OS << " // If the target matcher returned a specific error code use\n";
OS << " // that, else use the one from the generic matcher.\n";
OS << " if (TargetDiag != Match_InvalidOperand && "
"HasRequiredFeatures)\n";
OS << " Diag = TargetDiag;\n";
OS << " }\n";
OS << " // If current formal operand wasn't matched and it is optional\n"
<< " // then try to match next formal operand\n";
OS << " if (Diag == Match_InvalidOperand "
<< "&& isSubclass(Formal, OptionalMatchClass)) {\n";
if (HasOptionalOperands) {
OS << " OptionalOperandsMask.set(FormalIdx);\n";
}
OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"ignoring optional operand\\n\");\n";
OS << " continue;\n";
OS << " }\n";
if (ReportMultipleNearMisses) {
OS << " if (!OperandNearMiss) {\n";
OS << " // If this is the first invalid operand we have seen, record some\n";
OS << " // information about it.\n";
OS << " DEBUG_WITH_TYPE(\n";
OS << " \"asm-matcher\",\n";
OS << " dbgs()\n";
OS << " << \"operand match failed, recording near-miss with diag code \"\n";
OS << " << Diag << \"\\n\");\n";
OS << " OperandNearMiss =\n";
OS << " NearMissInfo::getMissedOperand(Diag, Formal, it->Opcode, ActualIdx);\n";
OS << " ++ActualIdx;\n";
OS << " } else {\n";
OS << " // If more than one operand is invalid, give up on this match entry.\n";
OS << " DEBUG_WITH_TYPE(\n";
OS << " \"asm-matcher\",\n";
OS << " dbgs() << \"second operand mismatch, skipping this opcode\\n\");\n";
OS << " MultipleInvalidOperands = true;\n";
OS << " break;\n";
OS << " }\n";
OS << " }\n\n";
} else {
OS << " // If this operand is broken for all of the instances of this\n";
OS << " // mnemonic, keep track of it so we can report loc info.\n";
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 <= ActualIdx)) {\n";
OS << " if (HasRequiredFeatures && (ErrorInfo != ActualIdx || Diag "
"!= Match_InvalidOperand))\n";
OS << " RetCode = Diag;\n";
OS << " ErrorInfo = ActualIdx;\n";
OS << " }\n";
OS << " // Otherwise, just reject this instance of the mnemonic.\n";
OS << " OperandsValid = false;\n";
OS << " break;\n";
OS << " }\n\n";
}
if (ReportMultipleNearMisses)
OS << " if (MultipleInvalidOperands) {\n";
else
OS << " if (!OperandsValid) {\n";
OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"Opcode result: multiple \"\n";
OS << " \"operand mismatches, ignoring \"\n";
OS << " \"this opcode\\n\");\n";
OS << " continue;\n";
OS << " }\n";
// Emit check that the required features are available.
OS << " if (!HasRequiredFeatures) {\n";
if (!ReportMultipleNearMisses)
OS << " HadMatchOtherThanFeatures = true;\n";
OS << " FeatureBitset NewMissingFeatures = RequiredFeatures & "
"~AvailableFeatures;\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 (NewMissingFeatures.count() <=\n"
" MissingFeatures.count())\n";
OS << " MissingFeatures = NewMissingFeatures;\n";
OS << " continue;\n";
}
OS << " }\n";
OS << "\n";
OS << " Inst.clear();\n\n";
OS << " Inst.setOpcode(it->Opcode);\n";
// Verify the instruction with the target-specific match predicate function.
OS << " // We have a potential match but have not rendered the operands.\n"
<< " // Check the target predicate to handle any context sensitive\n"
" // constraints.\n"
<< " // For example, Ties that are referenced multiple times must be\n"
" // checked here to ensure the input is the same for each match\n"
" // constraints. If we leave it any later the ties will have been\n"
" // canonicalized\n"
<< " unsigned MatchResult;\n"
<< " if ((MatchResult = checkEarlyTargetMatchPredicate(Inst, "
"Operands)) != Match_Success) {\n"
<< " Inst.clear();\n";
OS << " DEBUG_WITH_TYPE(\n";
OS << " \"asm-matcher\",\n";
OS << " dbgs() << \"Early target match predicate failed with diag code \"\n";
OS << " << MatchResult << \"\\n\");\n";
if (ReportMultipleNearMisses) {
OS << " EarlyPredicateNearMiss = NearMissInfo::getMissedPredicate(MatchResult);\n";
} else {
OS << " RetCode = MatchResult;\n"
<< " HadMatchOtherThanPredicate = true;\n"
<< " continue;\n";
}
OS << " }\n\n";
if (ReportMultipleNearMisses) {
OS << " // If we did not successfully match the operands, then we can't convert to\n";
OS << " // an MCInst, so bail out on this instruction variant now.\n";
OS << " if (OperandNearMiss) {\n";
OS << " // If the operand mismatch was the only problem, reprrt it as a near-miss.\n";
OS << " if (NearMisses && !FeaturesNearMiss && !EarlyPredicateNearMiss) {\n";
OS << " DEBUG_WITH_TYPE(\n";
OS << " \"asm-matcher\",\n";
OS << " dbgs()\n";
OS << " << \"Opcode result: one mismatched operand, adding near-miss\\n\");\n";
OS << " NearMisses->push_back(OperandNearMiss);\n";
OS << " } else {\n";
OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"Opcode result: multiple \"\n";
OS << " \"types of mismatch, so not \"\n";
OS << " \"reporting near-miss\\n\");\n";
OS << " }\n";
OS << " continue;\n";
OS << " }\n\n";
}
OS << " if (matchingInlineAsm) {\n";
OS << " convertToMapAndConstraints(it->ConvertFn, Operands);\n";
if (!ReportMultipleNearMisses) {
OS << " if (!checkAsmTiedOperandConstraints(*this, it->ConvertFn, "
"Operands, ErrorInfo))\n";
OS << " return Match_InvalidTiedOperand;\n";
OS << "\n";
}
OS << " return Match_Success;\n";
OS << " }\n\n";
OS << " // We have selected a definite instruction, convert the parsed\n"
<< " // operands into the appropriate MCInst.\n";
if (HasOptionalOperands) {
OS << " convertToMCInst(it->ConvertFn, Inst, it->Opcode, Operands,\n"
<< " OptionalOperandsMask);\n";
} else {
OS << " convertToMCInst(it->ConvertFn, Inst, it->Opcode, Operands);\n";
}
OS << "\n";
// Verify the instruction with the target-specific match predicate function.
OS << " // We have a potential match. Check the target predicate to\n"
<< " // handle any context sensitive constraints.\n"
<< " if ((MatchResult = checkTargetMatchPredicate(Inst)) !="
<< " Match_Success) {\n"
<< " DEBUG_WITH_TYPE(\"asm-matcher\",\n"
<< " dbgs() << \"Target match predicate failed with diag code \"\n"
<< " << MatchResult << \"\\n\");\n"
<< " Inst.clear();\n";
if (ReportMultipleNearMisses) {
OS << " LatePredicateNearMiss = NearMissInfo::getMissedPredicate(MatchResult);\n";
} else {
OS << " RetCode = MatchResult;\n"
<< " HadMatchOtherThanPredicate = true;\n"
<< " continue;\n";
}
OS << " }\n\n";
if (ReportMultipleNearMisses) {
OS << " int NumNearMisses = ((int)(bool)OperandNearMiss +\n";
OS << " (int)(bool)FeaturesNearMiss +\n";
OS << " (int)(bool)EarlyPredicateNearMiss +\n";
OS << " (int)(bool)LatePredicateNearMiss);\n";
OS << " if (NumNearMisses == 1) {\n";
OS << " // We had exactly one type of near-miss, so add that to the list.\n";
OS << " assert(!OperandNearMiss && \"OperandNearMiss was handled earlier\");\n";
OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"Opcode result: found one type of \"\n";
OS << " \"mismatch, so reporting a \"\n";
OS << " \"near-miss\\n\");\n";
OS << " if (NearMisses && FeaturesNearMiss)\n";
OS << " NearMisses->push_back(FeaturesNearMiss);\n";
OS << " else if (NearMisses && EarlyPredicateNearMiss)\n";
OS << " NearMisses->push_back(EarlyPredicateNearMiss);\n";
OS << " else if (NearMisses && LatePredicateNearMiss)\n";
OS << " NearMisses->push_back(LatePredicateNearMiss);\n";
OS << "\n";
OS << " continue;\n";
OS << " } else if (NumNearMisses > 1) {\n";
OS << " // This instruction missed in more than one way, so ignore it.\n";
OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"Opcode result: multiple \"\n";
OS << " \"types of mismatch, so not \"\n";
OS << " \"reporting near-miss\\n\");\n";
OS << " continue;\n";
OS << " }\n";
}
// Call the post-processing function, if used.
StringRef InsnCleanupFn = AsmParser->getValueAsString("AsmParserInstCleanup");
if (!InsnCleanupFn.empty())
OS << " " << InsnCleanupFn << "(Inst);\n";
if (HasDeprecation) {
OS << " std::string Info;\n";
OS << " if (!getParser().getTargetParser().getTargetOptions().MCNoDeprecatedWarn &&\n";
OS << " MII.getDeprecatedInfo(Inst, getSTI(), Info)) {\n";
OS << " SMLoc Loc = ((" << Target.getName()
<< "Operand &)*Operands[0]).getStartLoc();\n";
OS << " getParser().Warning(Loc, Info, None);\n";
OS << " }\n";
}
if (!ReportMultipleNearMisses) {
OS << " if (!checkAsmTiedOperandConstraints(*this, it->ConvertFn, "
"Operands, ErrorInfo))\n";
OS << " return Match_InvalidTiedOperand;\n";
OS << "\n";
}
OS << " DEBUG_WITH_TYPE(\n";
OS << " \"asm-matcher\",\n";
OS << " dbgs() << \"Opcode result: complete match, selecting this opcode\\n\");\n";
OS << " return Match_Success;\n";
OS << " }\n\n";
if (ReportMultipleNearMisses) {
OS << " // No instruction variants matched exactly.\n";
OS << " return Match_NearMisses;\n";
} else {
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 << " ErrorInfo = 0;\n";
OS << " return Match_MissingFeature;\n";
}
OS << "}\n\n";
if (!Info.OperandMatchInfo.empty())
emitCustomOperandParsing(OS, Target, Info, ClassName, StringTable,
MaxMnemonicIndex, FeatureBitsets.size(),
HasMnemonicFirst);
OS << "#endif // GET_MATCHER_IMPLEMENTATION\n\n";
OS << "\n#ifdef GET_MNEMONIC_SPELL_CHECKER\n";
OS << "#undef GET_MNEMONIC_SPELL_CHECKER\n\n";
emitMnemonicSpellChecker(OS, Target, VariantCount);
OS << "#endif // GET_MNEMONIC_SPELL_CHECKER\n\n";
OS << "\n#ifdef GET_MNEMONIC_CHECKER\n";
OS << "#undef GET_MNEMONIC_CHECKER\n\n";
emitMnemonicChecker(OS, Target, VariantCount,
HasMnemonicFirst, HasMnemonicAliases);
OS << "#endif // GET_MNEMONIC_CHECKER\n\n";
}