void AsmMatcherEmitter::run()

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";
}