Index: lib/Target/ARM/AsmParser/ARMAsmParser.cpp =================================================================== --- lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -860,6 +860,16 @@ return true; } + bool isPositiveOffset() const { + if (!isImm()) return false; + const MCExpr *ref = getImm(); + + if (ref->getKind() == MCExpr::Constant) + return dyn_cast(ref)->getValue() > 0; + + return true; + } + // checks whether this operand is an unsigned offset which fits is a field // of specified width and scaled by a specific number of bits template @@ -6684,6 +6694,12 @@ return Error(Operands[Op]->getStartLoc(), "branch target out of range"); break; } + case ARM::tCBZ: + case ARM::tCBNZ: { + if (!static_cast(*Operands[2]).isPositiveOffset()) + return Error(Operands[2]->getStartLoc(), "branch target out of range"); + break; + } case ARM::MOVi16: case ARM::t2MOVi16: case ARM::t2MOVTi16: Index: lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp =================================================================== --- lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp +++ lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp @@ -578,6 +578,11 @@ // Offset by 4, and don't encode the low two bits. return ((Value - 4) >> 2) & 0xff; case ARM::fixup_arm_thumb_cb: { + // CB instructions cannot branch backwards with a negative offset + if (Ctx && (int64_t)Value < 0) { + Ctx->reportError(Fixup.getLoc(), "out of range pc-relative fixup value"); + return 0; + } // Offset by 4 and don't encode the lower bit, which is always 0. // FIXME: diagnose if no Thumb2 uint32_t Binary = (Value - 4) >> 1; Index: test/MC/ARM/thumb-cb-negative-offsets.s =================================================================== --- /dev/null +++ test/MC/ARM/thumb-cb-negative-offsets.s @@ -0,0 +1,10 @@ +@ RUN: not llvm-mc -triple thumbv7m-none-eabi -filetype=obj -o /dev/null %s 2>&1 | FileCheck %s +@ RUN: not llvm-mc -triple thumbv8m.base-none-eabi -filetype=obj -o /dev/null %s 2>&1 | FileCheck %s + +label0: + .word 4 + +@ CHECK: out of range pc-relative fixup value + cbz r0, label0 +@ CHECK: out of range pc-relative fixup value + cbnz r0, label0 Index: test/MC/ARM/thumb-diagnostics.s =================================================================== --- test/MC/ARM/thumb-diagnostics.s +++ test/MC/ARM/thumb-diagnostics.s @@ -235,6 +235,18 @@ @ CHECK-ERRORS: error: branch target out of range @------------------------------------------------------------------------------ +@ CBZ/CBNZ - out of range immediates for branches +@------------------------------------------------------------------------------ + + cbz r0, #-4 + cbnz r0, #-8 + +@ CHECK-ERRORS-V7M: error: branch target out of range +@ CHECK-ERRORS-V7M: error: branch target out of range +@ CHECK-ERRORS-V8: error: branch target out of range +@ CHECK-ERRORS-V8: error: branch target out of range + +@------------------------------------------------------------------------------ @ SEV/WFE/WFI/YIELD - are not supported pre v6M or v6T2 @------------------------------------------------------------------------------ sev