diff --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp --- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -10598,6 +10598,12 @@ (isThumb() && !hasV8Ops())) return Match_InvalidOperand; break; + case ARM::t2TBB: + case ARM::t2TBH: + // Rn = sp is only allowed with ARMv8-A + if (!hasV8Ops() && (Inst.getOperand(0).getReg() == ARM::SP)) + return Match_RequiresV8; + break; default: break; } diff --git a/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp b/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp --- a/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp +++ b/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp @@ -4529,12 +4529,14 @@ static DecodeStatus DecodeThumbTableBranch(MCInst &Inst, unsigned Insn, uint64_t Address, const void *Decoder) { + const FeatureBitset &FeatureBits = + ((const MCDisassembler*)Decoder)->getSubtargetInfo().getFeatureBits(); DecodeStatus S = MCDisassembler::Success; unsigned Rn = fieldFromInstruction(Insn, 16, 4); unsigned Rm = fieldFromInstruction(Insn, 0, 4); - if (Rn == ARM::SP) S = MCDisassembler::SoftFail; + if (Rn == 13 && !FeatureBits[ARM::HasV8Ops]) S = MCDisassembler::SoftFail; if (!Check(S, DecodeGPRRegisterClass(Inst, Rn, Address, Decoder))) return MCDisassembler::Fail; if (!Check(S, DecoderGPRRegisterClass(Inst, Rm, Address, Decoder))) diff --git a/llvm/test/MC/ARM/thumb2-diagnostics.s b/llvm/test/MC/ARM/thumb2-diagnostics.s --- a/llvm/test/MC/ARM/thumb2-diagnostics.s +++ b/llvm/test/MC/ARM/thumb2-diagnostics.s @@ -165,3 +165,25 @@ @ CHECK-ERRORS-V7: error: operand must be a register in range [r0, r12] or r14 @ CHECK-ERRORS-V7: operand must be a register in range [r0, r12] or r14 @ CHECK-ERRORS-V7: operand must be a register in range [r0, r12] or r14 + + tbb [r0, sp] + @ v8 allows rm = sp +@ CHECK-ERRORS-V7: error: instruction variant requires ARMv8 or later + tbb [r0, pc] + @ rm = pc is always unpredictable +@ CHECK-ERRORS: error: invalid operand for instruction + tbb [sp, r0] + @ v8 allows rn = sp +@ CHECK-ERRORS-V7: error: instruction variant requires ARMv8 or later + @ rn = pc is allowed so not included here + + tbh [r0, sp, lsl #1] + @ v8 allows rm = sp +@ CHECK-ERRORS-V7: error: instruction variant requires ARMv8 or later + tbh [r0, pc, lsl #1] + @ rm = pc is always unpredictable +@ CHECK-ERRORS: error: invalid operand for instruction + tbh [sp, r0, lsl #1] + @ v8 allows rn = sp +@ CHECK-ERRORS-V7: error: instruction variant requires ARMv8 or later + @ rn=pc is allowed so not included here diff --git a/llvm/test/MC/Disassembler/ARM/thumb2-diagnostic.txt b/llvm/test/MC/Disassembler/ARM/thumb2-diagnostic.txt new file mode 100644 --- /dev/null +++ b/llvm/test/MC/Disassembler/ARM/thumb2-diagnostic.txt @@ -0,0 +1,49 @@ +# RUN: llvm-mc -triple=thumbv7 -disassemble %s 2>&1 | \ +# RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-V7 +# RUN: llvm-mc -triple=thumbv8 -disassemble %s 2>&1 | \ +# RUN: FileCheck %s --check-prefix=CHECK + +# tbb [r0, sp] +0xd0 0xe8 0x0d 0xf0 +# CHECK-V7: warning: potentially undefined instruction encoding +# CHECK-V7-NEXT: 0xd0 0xe8 0x0d 0xf0 + +# tbb [r0, pc] +0xd0 0xe8 0x0f 0xf0 +# CHECK: warning: potentially undefined instruction encoding +# CHECK-NEXT: 0xd0 0xe8 0x0f 0xf0 + +# tbb [sp, r0] +0xdd 0xe8 0x00 0xf0 +# CHECK-V7: warning: potentially undefined instruction encoding +# CHECK-V7-NEXT: 0xdd 0xe8 0x00 0xf0 + +# tbb [pc, r0] +0xdf 0xe8 0x00 0xf0 + +# tbh [r0, sp, lsl #1] +0xd0 0xe8 0x1d 0xf0 +# CHECK-V7: warning: potentially undefined instruction encoding +# CHECK-V7-NEXT: 0xd0 0xe8 0x1d 0xf0 + +# tbh [r0, pc, lsl #1] +0xd0 0xe8 0x1f 0xf0 +# CHECK: warning: potentially undefined instruction encoding +# CHECK-NEXT: 0xd0 0xe8 0x1f 0xf0 + +# tbh [sp, r0, lsl #1] +0xdd 0xe8 0x10 0xf0 +# CHECK-V7: warning: potentially undefined instruction encoding +# CHECK-V7-NEXT: 0xdd 0xe8 0x10 0xf0 + +# tbh [pc, r0, lsl #1] +0xdf 0xe8 0x10 0xf0 + +# CHECK: tbb [r0, sp] +# CHECK: tbb [r0, pc] +# CHECK: tbb [sp, r0] +# CHECK: tbb [pc, r0] +# CHECK: tbh [r0, sp, lsl #1] +# CHECK: tbh [r0, pc, lsl #1] +# CHECK: tbh [sp, r0, lsl #1] +# CHECK: tbh [pc, r0, lsl #1]