summaryrefslogtreecommitdiff
path: root/utils/TableGen/AsmMatcherEmitter.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-12-18 20:10:56 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-12-18 20:10:56 +0000
commit044eb2f6afba375a914ac9d8024f8f5142bb912e (patch)
tree1475247dc9f9fe5be155ebd4c9069c75aadf8c20 /utils/TableGen/AsmMatcherEmitter.cpp
parenteb70dddbd77e120e5d490bd8fbe7ff3f8fa81c6b (diff)
Notes
Diffstat (limited to 'utils/TableGen/AsmMatcherEmitter.cpp')
-rw-r--r--utils/TableGen/AsmMatcherEmitter.cpp541
1 files changed, 445 insertions, 96 deletions
diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp
index 1f8e1b125889..f2d304bfcf5b 100644
--- a/utils/TableGen/AsmMatcherEmitter.cpp
+++ b/utils/TableGen/AsmMatcherEmitter.cpp
@@ -205,6 +205,9 @@ struct ClassInfo {
/// For custom match classes: the diagnostic kind for when the predicate fails.
std::string DiagnosticType;
+ /// For custom match classes: the diagnostic string for when the predicate fails.
+ std::string DiagnosticString;
+
/// Is this operand optional and not always required.
bool IsOptional;
@@ -701,13 +704,13 @@ public:
/// Map of AsmOperandClass records to their class information.
std::map<Record*, ClassInfo*> AsmOperandClasses;
+ /// Map of RegisterClass records to their class information.
+ std::map<Record*, ClassInfo*> RegisterClassClasses;
+
private:
/// Map of token to class information which has already been constructed.
std::map<std::string, ClassInfo*> TokenClasses;
- /// Map of RegisterClass records to their class information.
- std::map<Record*, ClassInfo*> RegisterClassClasses;
-
private:
/// getTokenClass - Lookup or create the class for the given token.
ClassInfo *getTokenClass(StringRef Token);
@@ -1279,6 +1282,19 @@ buildRegisterClasses(SmallPtrSetImpl<Record*> &SingletonRegisters) {
} else
CI->ValueName = CI->ValueName + "," + RC.getName();
+ Init *DiagnosticType = Def->getValueInit("DiagnosticType");
+ if (StringInit *SI = dyn_cast<StringInit>(DiagnosticType))
+ CI->DiagnosticType = SI->getValue();
+
+ Init *DiagnosticString = Def->getValueInit("DiagnosticString");
+ if (StringInit *SI = dyn_cast<StringInit>(DiagnosticString))
+ CI->DiagnosticString = SI->getValue();
+
+ // If we have a diagnostic string but the diagnostic type is not specified
+ // explicitly, create an anonymous diagnostic type.
+ if (!CI->DiagnosticString.empty() && CI->DiagnosticType.empty())
+ CI->DiagnosticType = RC.getName();
+
RegisterClassClasses.insert(std::make_pair(Def, CI));
}
@@ -1357,11 +1373,17 @@ void AsmMatcherInfo::buildOperandClasses() {
if (StringInit *SI = dyn_cast<StringInit>(PRMName))
CI->ParserMethod = SI->getValue();
- // Get the diagnostic type or leave it as empty.
- // Get the parse method name or leave it as empty.
+ // Get the diagnostic type and string or leave them as empty.
Init *DiagnosticType = Rec->getValueInit("DiagnosticType");
if (StringInit *SI = dyn_cast<StringInit>(DiagnosticType))
CI->DiagnosticType = SI->getValue();
+ Init *DiagnosticString = Rec->getValueInit("DiagnosticString");
+ if (StringInit *SI = dyn_cast<StringInit>(DiagnosticString))
+ CI->DiagnosticString = SI->getValue();
+ // If we have a DiagnosticString, we need a DiagnosticType for use within
+ // the matcher.
+ if (!CI->DiagnosticString.empty() && CI->DiagnosticType.empty())
+ CI->DiagnosticType = CI->ClassName;
Init *IsOptional = Rec->getValueInit("IsOptional");
if (BitInit *BI = dyn_cast<BitInit>(IsOptional))
@@ -1847,13 +1869,25 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName,
CvtOS << " assert(Kind < CVT_NUM_SIGNATURES && \"Invalid signature!\");\n";
CvtOS << " const uint8_t *Converter = ConversionTable[Kind];\n";
if (HasOptionalOperands) {
- CvtOS << " unsigned NumDefaults = 0;\n";
+ size_t MaxNumOperands = 0;
+ for (const auto &MI : Infos) {
+ MaxNumOperands = std::max(MaxNumOperands, MI->AsmOperands.size());
+ }
+ CvtOS << " unsigned DefaultsOffset[" << (MaxNumOperands + 1)
+ << "] = { 0 };\n";
+ CvtOS << " assert(OptionalOperandsMask.size() == " << (MaxNumOperands)
+ << ");\n";
+ CvtOS << " for (unsigned i = 0, NumDefaults = 0; i < " << (MaxNumOperands)
+ << "; ++i) {\n";
+ CvtOS << " DefaultsOffset[i + 1] = NumDefaults;\n";
+ CvtOS << " NumDefaults += (OptionalOperandsMask[i] ? 1 : 0);\n";
+ CvtOS << " }\n";
}
CvtOS << " unsigned OpIdx;\n";
CvtOS << " Inst.setOpcode(Opcode);\n";
CvtOS << " for (const uint8_t *p = Converter; *p; p+= 2) {\n";
if (HasOptionalOperands) {
- CvtOS << " OpIdx = *(p + 1) - NumDefaults;\n";
+ CvtOS << " OpIdx = *(p + 1) - DefaultsOffset[*(p + 1)];\n";
} else {
CvtOS << " OpIdx = *(p + 1);\n";
}
@@ -1988,7 +2022,6 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName,
<< " " << Op.Class->DefaultMethod << "()"
<< "->" << Op.Class->RenderMethod << "(Inst, "
<< OpInfo.MINumOperands << ");\n"
- << " ++NumDefaults;\n"
<< " } else {\n"
<< " static_cast<" << TargetOperandClass
<< "&>(*Operands[OpIdx])." << Op.Class->RenderMethod
@@ -2158,7 +2191,18 @@ static void emitMatchClassEnumeration(CodeGenTarget &Target,
OS << "enum MatchClassKind {\n";
OS << " InvalidMatchClass = 0,\n";
OS << " OptionalMatchClass = 1,\n";
+ ClassInfo::ClassInfoKind LastKind = ClassInfo::Token;
+ StringRef LastName = "OptionalMatchClass";
for (const auto &CI : Infos) {
+ if (LastKind == ClassInfo::Token && CI.Kind != ClassInfo::Token) {
+ OS << " MCK_LAST_TOKEN = " << LastName << ",\n";
+ } else if (LastKind < ClassInfo::UserClass0 &&
+ CI.Kind >= ClassInfo::UserClass0) {
+ OS << " MCK_LAST_REGISTER = " << LastName << ",\n";
+ }
+ LastKind = (ClassInfo::ClassInfoKind)CI.Kind;
+ LastName = CI.Name;
+
OS << " " << CI.Name << ", // ";
if (CI.Kind == ClassInfo::Token) {
OS << "'" << CI.ValueName << "'\n";
@@ -2177,6 +2221,64 @@ static void emitMatchClassEnumeration(CodeGenTarget &Target,
OS << "}\n\n";
}
+/// emitMatchClassDiagStrings - Emit a function to get the diagnostic text to be
+/// used when an assembly operand does not match the expected operand class.
+static void emitOperandMatchErrorDiagStrings(AsmMatcherInfo &Info, raw_ostream &OS) {
+ // If the target does not use DiagnosticString for any operands, don't emit
+ // an unused function.
+ if (std::all_of(
+ Info.Classes.begin(), Info.Classes.end(),
+ [](const ClassInfo &CI) { return CI.DiagnosticString.empty(); }))
+ return;
+
+ OS << "static const char *getMatchKindDiag(" << Info.Target.getName()
+ << "AsmParser::" << Info.Target.getName()
+ << "MatchResultTy MatchResult) {\n";
+ OS << " switch (MatchResult) {\n";
+
+ for (const auto &CI: Info.Classes) {
+ if (!CI.DiagnosticString.empty()) {
+ assert(!CI.DiagnosticType.empty() &&
+ "DiagnosticString set without DiagnosticType");
+ OS << " case " << Info.Target.getName()
+ << "AsmParser::Match_" << CI.DiagnosticType << ":\n";
+ OS << " return \"" << CI.DiagnosticString << "\";\n";
+ }
+ }
+
+ OS << " default:\n";
+ OS << " return nullptr;\n";
+
+ OS << " }\n";
+ OS << "}\n\n";
+}
+
+static void emitRegisterMatchErrorFunc(AsmMatcherInfo &Info, raw_ostream &OS) {
+ OS << "static unsigned getDiagKindFromRegisterClass(MatchClassKind "
+ "RegisterClass) {\n";
+ if (std::none_of(Info.Classes.begin(), Info.Classes.end(),
+ [](const ClassInfo &CI) {
+ return CI.isRegisterClass() && !CI.DiagnosticType.empty();
+ })) {
+ OS << " return MCTargetAsmParser::Match_InvalidOperand;\n";
+ } else {
+ OS << " switch (RegisterClass) {\n";
+ for (const auto &CI: Info.Classes) {
+ if (CI.isRegisterClass() && !CI.DiagnosticType.empty()) {
+ OS << " case " << CI.Name << ":\n";
+ OS << " return " << Info.Target.getName() << "AsmParser::Match_"
+ << CI.DiagnosticType << ";\n";
+ }
+ }
+
+ OS << " default:\n";
+ OS << " return MCTargetAsmParser::Match_InvalidOperand;\n";
+
+ OS << " }\n";
+ }
+ OS << "}\n\n";
+}
+
/// emitValidateOperandClass - Emit the function to validate an operand class.
static void emitValidateOperandClass(AsmMatcherInfo &Info,
raw_ostream &OS) {
@@ -2191,7 +2293,7 @@ static void emitValidateOperandClass(AsmMatcherInfo &Info,
// Check for Token operands first.
// FIXME: Use a more specific diagnostic type.
- OS << " if (Operand.isToken())\n";
+ OS << " if (Operand.isToken() && Kind <= MCK_LAST_TOKEN)\n";
OS << " return isSubclass(matchTokenString(Operand.getToken()), Kind) ?\n"
<< " MCTargetAsmParser::Match_Success :\n"
<< " MCTargetAsmParser::Match_InvalidOperand;\n\n";
@@ -2227,8 +2329,12 @@ static void emitValidateOperandClass(AsmMatcherInfo &Info,
<< "; break;\n";
OS << " }\n";
OS << " return isSubclass(OpKind, Kind) ? "
- << "MCTargetAsmParser::Match_Success :\n "
- << " MCTargetAsmParser::Match_InvalidOperand;\n }\n\n";
+ << "(unsigned)MCTargetAsmParser::Match_Success :\n "
+ << " getDiagKindFromRegisterClass(Kind);\n }\n\n";
+
+ // Expected operand is a register, but actual is not.
+ OS << " if (Kind > MCK_LAST_TOKEN && Kind <= MCK_LAST_REGISTER)\n";
+ OS << " return getDiagKindFromRegisterClass(Kind);\n\n";
// Generic fallthrough match failure case for operands that don't have
// specialized diagnostic types.
@@ -2332,7 +2438,9 @@ static void emitMatchRegisterName(CodeGenTarget &Target, Record *AsmParser,
OS << "static unsigned MatchRegisterName(StringRef Name) {\n";
- StringMatcher("Name", Matches, OS).Emit();
+ bool IgnoreDuplicates =
+ AsmParser->getValueAsBit("AllowDuplicateRegisterNames");
+ StringMatcher("Name", Matches, OS).Emit(0, IgnoreDuplicates);
OS << " return 0;\n";
OS << "}\n\n";
@@ -2363,7 +2471,9 @@ static void emitMatchRegisterAltName(CodeGenTarget &Target, Record *AsmParser,
OS << "static unsigned MatchRegisterAltName(StringRef Name) {\n";
- StringMatcher("Name", Matches, OS).Emit();
+ bool IgnoreDuplicates =
+ AsmParser->getValueAsBit("AllowDuplicateRegisterNames");
+ StringMatcher("Name", Matches, OS).Emit(0, IgnoreDuplicates);
OS << " return 0;\n";
OS << "}\n\n";
@@ -2377,6 +2487,10 @@ static void emitOperandDiagnosticTypes(AsmMatcherInfo &Info, raw_ostream &OS) {
if (!OpClassEntry.second->DiagnosticType.empty())
Types.insert(OpClassEntry.second->DiagnosticType);
}
+ for (const auto &OpClassEntry : Info.RegisterClassClasses) {
+ if (!OpClassEntry.second->DiagnosticType.empty())
+ Types.insert(OpClassEntry.second->DiagnosticType);
+ }
if (Types.empty()) return;
@@ -2650,7 +2764,8 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
// a better error handling.
OS << "OperandMatchResultTy " << Target.getName() << ClassName << "::\n"
<< "MatchOperandParserImpl(OperandVector"
- << " &Operands,\n StringRef Mnemonic) {\n";
+ << " &Operands,\n StringRef Mnemonic,\n"
+ << " bool ParseForAllFeatures) {\n";
// Emit code to get the available features.
OS << " // Get the current feature set.\n";
@@ -2688,10 +2803,9 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
// Emit check that the required features are available.
OS << " // check if the available features match\n";
- OS << " if ((AvailableFeatures & it->RequiredFeatures) "
- << "!= it->RequiredFeatures) {\n";
- OS << " continue;\n";
- OS << " }\n\n";
+ OS << " if (!ParseForAllFeatures && (AvailableFeatures & "
+ "it->RequiredFeatures) != it->RequiredFeatures)\n";
+ OS << " continue;\n\n";
// Emit check to ensure the operand number matches.
OS << " // check if the operand in question has a custom parser.\n";
@@ -2713,16 +2827,27 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
static void emitMnemonicSpellChecker(raw_ostream &OS, CodeGenTarget &Target,
unsigned VariantCount) {
- OS << "std::string " << Target.getName() << "MnemonicSpellCheck(StringRef S, uint64_t FBS) {\n";
+ OS << "static std::string " << Target.getName()
+ << "MnemonicSpellCheck(StringRef S, uint64_t FBS, unsigned VariantID) {\n";
if (!VariantCount)
OS << " return \"\";";
else {
OS << " const unsigned MaxEditDist = 2;\n";
OS << " std::vector<StringRef> Candidates;\n";
- OS << " StringRef Prev = \"\";\n";
- OS << " auto End = std::end(MatchTable0);\n";
- OS << "\n";
- OS << " for (auto I = std::begin(MatchTable0); I < End; I++) {\n";
+ OS << " StringRef Prev = \"\";\n\n";
+
+ 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\n";
+ OS << " for (auto I = Start; I < End; I++) {\n";
OS << " // Ignore unsupported instructions.\n";
OS << " if ((FBS & I->RequiredFeatures) != I->RequiredFeatures)\n";
OS << " continue;\n";
@@ -2752,6 +2877,26 @@ static void emitMnemonicSpellChecker(raw_ostream &OS, CodeGenTarget &Target,
}
+// Emit a function mapping match classes to strings, for debugging.
+static void emitMatchClassKindNames(std::forward_list<ClassInfo> &Infos,
+ raw_ostream &OS) {
+ OS << "#ifndef NDEBUG\n";
+ OS << "const char *getMatchClassName(MatchClassKind Kind) {\n";
+ OS << " switch (Kind) {\n";
+
+ OS << " case InvalidMatchClass: return \"InvalidMatchClass\";\n";
+ OS << " case OptionalMatchClass: return \"OptionalMatchClass\";\n";
+ for (const auto &CI : Infos) {
+ OS << " case " << CI.Name << ": return \"" << CI.Name << "\";\n";
+ }
+ OS << " case NumMatchClassKinds: return \"NumMatchClassKinds\";\n";
+
+ OS << " }\n";
+ OS << " llvm_unreachable(\"unhandled MatchClassKind!\");\n";
+ OS << "}\n\n";
+ OS << "#endif // NDEBUG\n";
+}
+
void AsmMatcherEmitter::run(raw_ostream &OS) {
CodeGenTarget Target(Records);
Record *AsmParser = Target.getAsmParser();
@@ -2813,6 +2958,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
bool HasMnemonicFirst = AsmParser->getValueAsBit("HasMnemonicFirst");
bool HasOptionalOperands = Info.hasOptionalOperands();
+ bool ReportMultipleNearMisses =
+ AsmParser->getValueAsBit("ReportMultipleNearMisses");
// Write the output.
@@ -2835,15 +2982,19 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " void convertToMapAndConstraints(unsigned Kind,\n ";
OS << " const OperandVector &Operands) override;\n";
OS << " unsigned MatchInstructionImpl(const OperandVector &Operands,\n"
- << " MCInst &Inst,\n"
- << " uint64_t &ErrorInfo,"
- << " bool matchingInlineAsm,\n"
+ << " MCInst &Inst,\n";
+ if (ReportMultipleNearMisses)
+ OS << " SmallVectorImpl<NearMissInfo> *NearMisses,\n";
+ else
+ OS << " uint64_t &ErrorInfo,\n";
+ OS << " bool matchingInlineAsm,\n"
<< " unsigned VariantID = 0);\n";
if (!Info.OperandMatchInfo.empty()) {
OS << " OperandMatchResultTy MatchOperandParserImpl(\n";
OS << " OperandVector &Operands,\n";
- OS << " StringRef Mnemonic);\n";
+ OS << " StringRef Mnemonic,\n";
+ OS << " bool ParseForAllFeatures = false);\n";
OS << " OperandMatchResultTy tryCustomParseOperand(\n";
OS << " OperandVector &Operands,\n";
@@ -2898,6 +3049,13 @@ void AsmMatcherEmitter::run(raw_ostream &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);
@@ -2907,6 +3065,8 @@ void AsmMatcherEmitter::run(raw_ostream &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",
@@ -3015,21 +3175,28 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << "};\n\n";
}
- emitMnemonicSpellChecker(OS, Target, VariantCount);
+ 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, uint64_t &ErrorInfo,\n"
- << " bool matchingInlineAsm, unsigned VariantID) {\n";
-
- 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";
+ OS << " MCInst &Inst,\n";
+ if (ReportMultipleNearMisses)
+ OS << " SmallVectorImpl<NearMissInfo> *NearMisses,\n";
+ else
+ OS << " uint64_t &ErrorInfo,\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";
@@ -3052,17 +3219,20 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
}
// Emit code to compute the class list for this operand vector.
- 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 << " uint64_t MissingFeatures = ~0ULL;\n";
+ 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 << " uint64_t MissingFeatures = ~0ULL;\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";
}
- 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";
// Emit code to search the table.
OS << " // Find the appropriate table for this asm variant.\n";
@@ -3089,6 +3259,10 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
"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";
@@ -3096,6 +3270,20 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " for (const MatchEntry *it = MnemonicRange.first, "
<< "*ie = MnemonicRange.second;\n";
OS << " it != ie; ++it) {\n";
+ OS << " bool HasRequiredFeatures =\n";
+ OS << " (AvailableFeatures & it->RequiredFeatures) == "
+ "it->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";
@@ -3103,7 +3291,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
}
// Emit check that the subclasses match.
- OS << " bool OperandsValid = true;\n";
+ if (!ReportMultipleNearMisses)
+ OS << " bool OperandsValid = true;\n";
if (HasOptionalOperands) {
OS << " OptionalOperandsMask.reset(0, " << MaxNumOperands << ");\n";
}
@@ -3112,30 +3301,71 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
<< "; 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 << " OperandsValid = (Formal == " <<"InvalidMatchClass) || "
- "isSubclass(Formal, OptionalMatchClass);\n";
- OS << " if (!OperandsValid) ErrorInfo = ActualIdx;\n";
- if (HasOptionalOperands) {
- OS << " OptionalOperandsMask.set(FormalIdx, " << MaxNumOperands
- << ");\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 << " 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_InvalidOperand) {\n";
- OS << " Diag = validateTargetOperandClass(Actual, Formal);\n";
- OS << " if (Diag == Match_Success) {\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";
@@ -3144,36 +3374,76 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
if (HasOptionalOperands) {
OS << " OptionalOperandsMask.set(FormalIdx);\n";
}
+ OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"ignoring optional operand\\n\");\n";
OS << " continue;\n";
OS << " }\n";
- 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 << " ErrorInfo = ActualIdx;\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";
- OS << " break;\n";
- OS << " }\n\n";
- OS << " if (!OperandsValid) continue;\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 ((AvailableFeatures & it->RequiredFeatures) "
- << "!= it->RequiredFeatures) {\n";
- OS << " HadMatchOtherThanFeatures = true;\n";
+ OS << " if (!HasRequiredFeatures) {\n";
+ if (!ReportMultipleNearMisses)
+ OS << " HadMatchOtherThanFeatures = true;\n";
OS << " uint64_t NewMissingFeatures = it->RequiredFeatures & "
"~AvailableFeatures;\n";
- OS << " if (countPopulation(NewMissingFeatures) <=\n"
- " countPopulation(MissingFeatures))\n";
- OS << " MissingFeatures = NewMissingFeatures;\n";
- OS << " continue;\n";
+ OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"Missing target features: \"\n";
+ OS << " << format_hex(NewMissingFeatures, 18)\n";
+ OS << " << \"\\n\");\n";
+ if (ReportMultipleNearMisses) {
+ OS << " FeaturesNearMiss = NearMissInfo::getMissedFeature(NewMissingFeatures);\n";
+ } else {
+ OS << " if (countPopulation(NewMissingFeatures) <=\n"
+ " countPopulation(MissingFeatures))\n";
+ OS << " MissingFeatures = NewMissingFeatures;\n";
+ OS << " continue;\n";
+ }
OS << " }\n";
OS << "\n";
OS << " Inst.clear();\n\n";
@@ -3189,11 +3459,40 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
<< " unsigned MatchResult;\n"
<< " if ((MatchResult = checkEarlyTargetMatchPredicate(Inst, "
"Operands)) != Match_Success) {\n"
- << " Inst.clear();\n"
- << " RetCode = MatchResult;\n"
- << " HadMatchOtherThanPredicate = true;\n"
- << " continue;\n"
- << " }\n\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";
OS << " return Match_Success;\n";
@@ -3213,11 +3512,46 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
<< " // handle any context sensitive constraints.\n"
<< " if ((MatchResult = checkTargetMatchPredicate(Inst)) !="
<< " Match_Success) {\n"
- << " Inst.clear();\n"
- << " RetCode = MatchResult;\n"
- << " HadMatchOtherThanPredicate = true;\n"
- << " continue;\n"
- << " }\n\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");
@@ -3235,15 +3569,23 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
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";
- OS << " // Okay, we had no match. Try to return a useful error code.\n";
- OS << " if (HadMatchOtherThanPredicate || !HadMatchOtherThanFeatures)\n";
- OS << " return RetCode;\n\n";
- OS << " // Missing feature matches return which features were missing\n";
- OS << " ErrorInfo = MissingFeatures;\n";
- OS << " return Match_MissingFeature;\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 << " // Missing feature matches return which features were missing\n";
+ OS << " ErrorInfo = MissingFeatures;\n";
+ OS << " return Match_MissingFeature;\n";
+ }
OS << "}\n\n";
if (!Info.OperandMatchInfo.empty())
@@ -3251,6 +3593,13 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
MaxMnemonicIndex, 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";
}
namespace llvm {