Index: lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp =================================================================== --- lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -86,7 +86,7 @@ bool parseOperand(OperandVector &Operands, bool isCondCode, bool invertCondCode); - bool showMatchError(SMLoc Loc, unsigned ErrCode); + bool showMatchError(SMLoc Loc, unsigned ErrCode, OperandVector &Operands); bool parseDirectiveArch(SMLoc L); bool parseDirectiveCPU(SMLoc L); @@ -3257,7 +3257,10 @@ } } -bool AArch64AsmParser::showMatchError(SMLoc Loc, unsigned ErrCode) { +std::string AArch64MnemonicSpellCheck(StringRef S, uint64_t FBS); + +bool AArch64AsmParser::showMatchError(SMLoc Loc, unsigned ErrCode, + OperandVector &Operands) { switch (ErrCode) { case Match_MissingFeature: return Error(Loc, @@ -3380,8 +3383,12 @@ return Error(Loc, "expected readable system register"); case Match_MSR: return Error(Loc, "expected writable system register or pstate"); - case Match_MnemonicFail: - return Error(Loc, "unrecognized instruction mnemonic"); + case Match_MnemonicFail: { + std::string Suggestion = AArch64MnemonicSpellCheck( + ((AArch64Operand &)*Operands[0]).getToken(), + ComputeAvailableFeatures(STI->getFeatureBits())); + return Error(Loc, "unrecognized instruction mnemonic" + Suggestion); + } default: llvm_unreachable("unexpected error code!"); } @@ -3707,7 +3714,7 @@ return Error(IDLoc, Msg); } case Match_MnemonicFail: - return showMatchError(IDLoc, MatchResult); + return showMatchError(IDLoc, MatchResult, Operands); case Match_InvalidOperand: { SMLoc ErrorLoc = IDLoc; @@ -3726,7 +3733,7 @@ ((AArch64Operand &)*Operands[ErrorInfo]).isTokenSuffix()) MatchResult = Match_InvalidSuffix; - return showMatchError(ErrorLoc, MatchResult); + return showMatchError(ErrorLoc, MatchResult, Operands); } case Match_InvalidMemoryIndexed1: case Match_InvalidMemoryIndexed2: @@ -3784,7 +3791,7 @@ SMLoc ErrorLoc = ((AArch64Operand &)*Operands[ErrorInfo]).getStartLoc(); if (ErrorLoc == SMLoc()) ErrorLoc = IDLoc; - return showMatchError(ErrorLoc, MatchResult); + return showMatchError(ErrorLoc, MatchResult, Operands); } } Index: test/MC/AArch64/invalid-instructions-spellcheck.s =================================================================== --- /dev/null +++ test/MC/AArch64/invalid-instructions-spellcheck.s @@ -0,0 +1,37 @@ +// RUN: not llvm-mc -triple=aarch64 -show-encoding < %s 2>&1 | FileCheck %s +// RUN: not llvm-mc -triple=aarch64 -mattr=-neon -show-encoding < %s 2>&1 | FileCheck %s --check-prefix=CHECK-NO-NEON + +// This tests the mnemonic spell checker. + +// First check what happens when an instruction is omitted: + + w1, w2, w3 + +// CHECK: error: unknown token in expression +// CHECK-NEXT: w1, w2, w3 +// CHECK-NEXT: ^ +// CHECK-NEXT: error: invalid operand +// CHECK-NEXT: w1, w2, w3 +// CHECK-NEXT: ^ + +// We don't want to see a suggestion here; the edit distance is too large to +// give sensible suggestions: + + addddddddd w1, w2, w3 + +// CHECK: error: unrecognized instruction mnemonic +// CHECK-NEXT: addddddddd w1, w2, w3 +// CHECK-NEXT: ^ + + addd w1, w2, w3 + +// CHECK: error: unrecognized instruction mnemonic, did you mean: add, addp, adds, addv, fadd, madd? +// CHECK-NEXT: addd w1, w2, w3 +// CHECK-NEXT: ^ + +// Instructions 'addv' and 'addp' are only available when NEON is enabled, so we +// don't want to see them here: + +// CHECK-NO-NEON: error: unrecognized instruction mnemonic, did you mean: add, adds, fadd, madd? +// CHECK-NO-NEON-NEXT: addd w1, w2, w3 +// CHECK-NO-NEON-NEXT: ^