return EndLoc;
}
+ SMRange getLocRange() const {
+ return SMRange(StartLoc, EndLoc);
+ }
+
Modifiers getModifiers() const {
assert(isRegKind() || isImmTy(ImmTyNone));
return isRegKind() ? Reg.Mods : Imm.Mods;
return true;
}
+static std::string AMDGPUMnemonicSpellCheck(StringRef S, uint64_t FBS,
+ unsigned VariantID = 0);
+
bool AMDGPUAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
OperandVector &Operands,
MCStreamer &Out,
case Match_MissingFeature:
return Error(IDLoc, "instruction not supported on this GPU");
- case Match_MnemonicFail:
- return Error(IDLoc, "unrecognized instruction mnemonic");
+ case Match_MnemonicFail: {
+ uint64_t FBS = ComputeAvailableFeatures(getSTI().getFeatureBits());
+ std::string Suggestion = AMDGPUMnemonicSpellCheck(
+ ((AMDGPUOperand &)*Operands[0]).getToken(), FBS);
+ return Error(IDLoc, "invalid instruction" + Suggestion,
+ ((AMDGPUOperand &)*Operands[0]).getLocRange());
+ }
case Match_InvalidOperand: {
SMLoc ErrorLoc = IDLoc;
#define GET_REGISTER_MATCHER
#define GET_MATCHER_IMPLEMENTATION
+#define GET_MNEMONIC_SPELL_CHECKER
#include "AMDGPUGenAsmMatcher.inc"
// This fuction should be defined after auto-generated include so that we have
--- /dev/null
+# RUN: not llvm-mc -triple amdgcn < %s 2>&1 | FileCheck %s
+
+# This tests the mnemonic spell checker.
+
+# First check what happens when an instruction is omitted:
+
+v2, v4, v6
+
+# CHECK: unknown token in expression
+# CHECK-NEXT: v2, v4, v6
+# CHECK-NEXT: ^
+
+# CHECK: error: not a valid operand.
+# CHECK-NEXT: v2, v4, v6
+# CHECK-NEXT: ^
+
+# We don't want to see a suggestion here; the edit distance is too large to
+# give sensible suggestions:
+
+aaaaaaaaaaaaaaa v1, v2, v3
+
+# CHECK: error: invalid instruction
+# CHECK-NEXT: aaaaaaaaaaaaaaa v1, v2, v3
+# CHECK-NEXT: ^
+
+# Check that we get one suggestion: 'dsc_write_src2_b64' is 1 edit away, i.e. an deletion.
+
+dsc_write_src2_b64 v1, v2, v3
+
+# CHECK: error: invalid instruction, did you mean: ds_write_src2_b64?
+# CHECK-NEXT: dsc_write_src2_b64 v1, v2, v3
+# CHECK-NEXT: ^
+
+# Check edit distance 1 and 2, just insertions:
+
+s_mov_b v1, v2
+
+# CHECK: error: invalid instruction, did you mean: s_mov_b32, s_mov_b64?
+# CHECK-NEXT: s_mov_b v1, v2
+# CHECK-NEXT: ^
+
+# Check an instruction that is 2 edits away, and also has a lot of candidates:
+
+s_load_dwordx v1, v2, v3
+
+# CHECK: error: invalid instruction, did you mean: s_load_dword, s_load_dwordx16, s_load_dwordx2, s_load_dwordx4, s_load_dwordx8?
+# CHECK-NEXT: s_load_dwordx v1, v2, v3
+# CHECK-NEXT: ^
-// RUN: not llvm-mc -arch=amdgcn -mcpu=gfx900 -show-encoding %s 2>&1 | FileCheck -check-prefix=GCN %s
-// RUN: not llvm-mc -arch=amdgcn -mcpu=tonga -show-encoding %s 2>&1 | FileCheck -check-prefix=GCN %s
-// RUN: not llvm-mc -arch=amdgcn -mcpu=hawaii -show-encoding %s 2>&1 | FileCheck -check-prefix=GCN %s
+// RUN: not llvm-mc -arch=amdgcn -mcpu=gfx900 -show-encoding %s 2>&1 | FileCheck -check-prefixes=GCN,GFX9 %s
+// RUN: not llvm-mc -arch=amdgcn -mcpu=tonga -show-encoding %s 2>&1 | FileCheck -check-prefixes=GCN,VI %s
+// RUN: not llvm-mc -arch=amdgcn -mcpu=hawaii -show-encoding %s 2>&1 | FileCheck -check-prefixes=GCN,CI %s
v_swap_b32 v1, 1
// GCN: :16: error: invalid operand for instruction
// FIXME: Better error for it requiring VOP1 encoding
v_swap_b32_e64 v1, v2
-// GCN: :1: error: unrecognized instruction mnemonic
+// GFX9: :1: error: invalid instruction, did you mean: v_swap_b32?
+// CI: :1: error: invalid instruction
+// VI: :1: error: invalid instruction
v_swap_b32 v1, v2, v1
// GCN: :20: error: invalid operand for instruction
// GCN: :20: error: invalid operand for instruction
v_swap_codegen_pseudo_b32 v1, v2
-// GCN: :1: error: unrecognized instruction mnemonic
+// GCN: :1: error: invalid instruction