Index: llvm/trunk/lib/Target/Mips/AsmParser/MipsAsmParser.cpp =================================================================== --- llvm/trunk/lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ llvm/trunk/lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -6371,6 +6371,9 @@ return false; } +static std::string MipsMnemonicSpellCheck(StringRef S, uint64_t FBS, + unsigned VariantID = 0); + bool MipsAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands) { MCAsmParser &Parser = getParser(); @@ -6381,7 +6384,9 @@ // Check if we have valid mnemonic if (!mnemonicIsValid(Name, 0)) { - return Error(NameLoc, "unknown instruction"); + uint64_t FBS = ComputeAvailableFeatures(getSTI().getFeatureBits()); + std::string Suggestion = MipsMnemonicSpellCheck(Name, FBS); + return Error(NameLoc, "unknown instruction" + Suggestion); } // First operand in MCInst is instruction mnemonic. Operands.push_back(MipsOperand::CreateToken(Name, NameLoc, *this)); @@ -8257,6 +8262,7 @@ #define GET_REGISTER_MATCHER #define GET_MATCHER_IMPLEMENTATION +#define GET_MNEMONIC_SPELL_CHECKER #include "MipsGenAsmMatcher.inc" bool MipsAsmParser::mnemonicIsValid(StringRef Mnemonic, unsigned VariantID) { Index: llvm/trunk/test/MC/Mips/invalid-instructions-spellcheck.s =================================================================== --- llvm/trunk/test/MC/Mips/invalid-instructions-spellcheck.s +++ llvm/trunk/test/MC/Mips/invalid-instructions-spellcheck.s @@ -0,0 +1,65 @@ +# RUN: not llvm-mc -arch mips -mcpu=mips32r2 -mattr=+micromips %s 2>&1 \ +# RUN: | FileCheck --check-prefixes=ALL,MMR2 %s +# RUN: not llvm-mc -arch mips -mcpu=mips32r6 -mattr=+micromips %s 2>&1 \ +# RUN: | FileCheck --check-prefixes=ALL,MMR6 %s +# RUN: not llvm-mc -arch mips -mcpu=mips32r6 %s 2>&1 \ +# RUN: | FileCheck --check-prefixes=ALL,MIPS32R6 %s + +# This tests the mnemonic spell checker. + +# First check what happens when an instruction is omitted: + +$2, $1, $25 + +# ALL: error: unexpected token at start of statement +# ALL-NEXT: $2, $1, $25 +# ALL-NEXT: ^ + +# We don't want to see a suggestion here; the edit distance is too large to +# give sensible suggestions: + +aaaaaaaaaaaaaaa $2, $1, $25 + +# ALL: error: unknown instruction +# ALL-NEXT: aaaaaaaaaaaaaaa $2, $1, $25 +# ALL-NEXT: ^ + +# Check that we get one suggestion: 'addiuspi' is 1 edit away, i.e. an deletion. + +addiuspi -16 + +# MMR2: error: unknown instruction, did you mean: addiusp? +# MMR6: error: unknown instruction, did you mean: addiusp? +# MIPS32R6: error: unknown instruction{{$}} +# ALL: addiuspi -16 +# ALL-NEXT: ^ + +# Check edit distance 1 and 2, just insertions: + +addru $9, $6, 17767 + +# MMR2: error: unknown instruction, did you mean: add, addiu, addu, maddu? +# MMR6: error: unknown instruction, did you mean: add, addiu, addu? +# MIPS32R6: error: unknown instruction, did you mean: add, addiu, addu? +# ALL: addru $9, $6, 17767 +# ALL-NEXT: ^ + +# Check an instruction that is 2 edits away, and also has a lot of candidates: + +culE.d $fcc7, $f24, $f18 + +# MMR2: error: unknown instruction, did you mean: c.le.d, c.ule.d? +# MMR6: error: unknown instruction{{$}} +# MIPS32R6: error: unknown instruction{{$}} +# ALL: culE.d $fcc7, $f24, $f18 +# ALL-NEXT: ^ + +# Check that candidates list includes only instructions valid for target CPU. + +swk $3, $4 + +# MMR2: error: unknown instruction, did you mean: sw, swl, swm, swp, swr, usw? +# MMR6: error: unknown instruction, did you mean: sw, swm, swp, usw? +# MIPS32R6: error: unknown instruction, did you mean: sw, usw? +# ALL: swk $3, $4 +# ALL-NEXT: ^