summaryrefslogtreecommitdiffstats
path: root/llvm/utils/TableGen/AsmMatcherEmitter.cpp
diff options
context:
space:
mode:
authorSjoerd Meijer <sjoerd.meijer@arm.com>2017-07-05 12:39:13 +0000
committerSjoerd Meijer <sjoerd.meijer@arm.com>2017-07-05 12:39:13 +0000
commit6d14fdf62da34df9e65669a00745d597cfb882df (patch)
treebcbdd7d3714056b7d5edda5f629b5c2a441e6514 /llvm/utils/TableGen/AsmMatcherEmitter.cpp
parent835ac9bc62fdea9e9a35861b1a5c95a63f340c19 (diff)
downloadbcm5719-llvm-6d14fdf62da34df9e65669a00745d597cfb882df.tar.gz
bcm5719-llvm-6d14fdf62da34df9e65669a00745d597cfb882df.zip
[AsmParser] Mnemonic Spell Corrector
This implements suggesting other mnemonics when an invalid one is specified, for example: $ echo "adXd r1,r2,#3" | llvm-mc -triple arm <stdin>:1:1: error: invalid instruction, did you mean: add, qadd? adXd r1,r2,#3 ^ The implementation is target agnostic, but as a first step I have added it only to the ARM backend; so the ARM backend is a good example if someone wants to enable this too for another target. Differential Revision: https://reviews.llvm.org/D33128 llvm-svn: 307148
Diffstat (limited to 'llvm/utils/TableGen/AsmMatcherEmitter.cpp')
-rw-r--r--llvm/utils/TableGen/AsmMatcherEmitter.cpp43
1 files changed, 43 insertions, 0 deletions
diff --git a/llvm/utils/TableGen/AsmMatcherEmitter.cpp b/llvm/utils/TableGen/AsmMatcherEmitter.cpp
index 0980e08f67f..b73a4f17527 100644
--- a/llvm/utils/TableGen/AsmMatcherEmitter.cpp
+++ b/llvm/utils/TableGen/AsmMatcherEmitter.cpp
@@ -2711,6 +2711,47 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
OS << "}\n\n";
}
+static void emitMnemonicSpellChecker(raw_ostream &OS, CodeGenTarget &Target,
+ unsigned VariantCount) {
+ OS << "std::string " << Target.getName() << "MnemonicSpellCheck(StringRef S, uint64_t FBS) {\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 << " // Ignore unsupported instructions.\n";
+ OS << " if ((FBS & I->RequiredFeatures) != I->RequiredFeatures)\n";
+ OS << " continue;\n";
+ OS << "\n";
+ OS << " StringRef T = I->getMnemonic();\n";
+ OS << " // Avoid recomputing the edit distance for the same string.\n";
+ OS << " if (T.equals(Prev))\n";
+ OS << " continue;\n";
+ OS << "\n";
+ OS << " Prev = T;\n";
+ OS << " unsigned Dist = S.edit_distance(T, false, MaxEditDist);\n";
+ OS << " if (Dist <= MaxEditDist)\n";
+ OS << " Candidates.push_back(T);\n";
+ OS << " }\n";
+ OS << "\n";
+ OS << " if (Candidates.empty())\n";
+ OS << " return \"\";\n";
+ OS << "\n";
+ OS << " std::string Res = \", did you mean: \";\n";
+ OS << " unsigned i = 0;\n";
+ OS << " for( ; i < Candidates.size() - 1; i++)\n";
+ OS << " Res += Candidates[i].str() + \", \";\n";
+ OS << " return Res + Candidates[i].str() + \"?\";\n";
+ }
+ OS << "}\n";
+ OS << "\n";
+}
+
+
void AsmMatcherEmitter::run(raw_ostream &OS) {
CodeGenTarget Target(Records);
Record *AsmParser = Target.getAsmParser();
@@ -2974,6 +3015,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << "};\n\n";
}
+ emitMnemonicSpellChecker(OS, Target, VariantCount);
+
// Finally, build the match function.
OS << "unsigned " << Target.getName() << ClassName << "::\n"
<< "MatchInstructionImpl(const OperandVector &Operands,\n";
OpenPOWER on IntegriCloud