From d9615670b7d2b6b43d19d6e8706e9d504f91030e Mon Sep 17 00:00:00 2001 From: Kevin Enderby Date: Fri, 10 Jan 2014 00:43:32 +0000 Subject: Fix a bug with the ARM thumb2 CBNZ and CBNZ instructions that branch to the next instruction. This can not be encoded but can be turned into a NOP. rdar://15062072 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@198904 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp | 21 ++++++++++++++++- test/MC/ARM/thumb2-cbn-to-next-inst.s | 33 +++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 test/MC/ARM/thumb2-cbn-to-next-inst.s diff --git a/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp b/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp index fecab9f5d4..20dce218ea 100644 --- a/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp +++ b/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp @@ -155,6 +155,8 @@ static unsigned getRelaxedOpcode(unsigned Op) { case ARM::tLDRpci: return ARM::t2LDRpci; case ARM::tADR: return ARM::t2ADR; case ARM::tB: return ARM::t2B; + case ARM::tCBZ: return ARM::tHINT; + case ARM::tCBNZ: return ARM::tHINT; } } @@ -196,6 +198,12 @@ bool ARMAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup, int64_t Offset = int64_t(Value) - 4; return Offset > 1020 || Offset < 0 || Offset & 3; } + case ARM::fixup_arm_thumb_cb: + // If we have a Thumb CBZ or CBNZ instruction and its target is the next + // instruction it is is actually out of range for the instruction. + // It will be changed to a NOP. + int64_t Offset = (Value & ~1); + return Offset == 2; } llvm_unreachable("Unexpected fixup kind in fixupNeedsRelaxation()!"); } @@ -212,7 +220,18 @@ void ARMAsmBackend::relaxInstruction(const MCInst &Inst, MCInst &Res) const { report_fatal_error("unexpected instruction to relax: " + OS.str()); } - // The instructions we're relaxing have (so far) the same operands. + // If we are changing Thumb CBZ or CBNZ instruction to a NOP, aka tHINT, we + // have to change the operands too. + if ((Inst.getOpcode() == ARM::tCBZ || Inst.getOpcode() == ARM::tCBNZ) && + RelaxedOp == ARM::tHINT) { + Res.setOpcode(RelaxedOp); + Res.addOperand(MCOperand::CreateImm(0)); + Res.addOperand(MCOperand::CreateImm(14)); + Res.addOperand(MCOperand::CreateReg(0)); + return; + } + + // The rest of instructions we're relaxing have the same operands. // We just need to update to the proper opcode. Res = Inst; Res.setOpcode(RelaxedOp); diff --git a/test/MC/ARM/thumb2-cbn-to-next-inst.s b/test/MC/ARM/thumb2-cbn-to-next-inst.s new file mode 100644 index 0000000000..a7ad11b245 --- /dev/null +++ b/test/MC/ARM/thumb2-cbn-to-next-inst.s @@ -0,0 +1,33 @@ +@ RUN: llvm-mc -triple thumbv7-apple-darwin -filetype=obj -o %t.o %s +@ RUN: llvm-objdump -triple thumbv7-apple-darwin -d %t.o | FileCheck %s + +.thumb +start: +.thumb_func start + add r1, r2, r3 + cbnz r2, L1 @ this can't be encoded, must turn into a nop +L1: + add r4, r5, r6 + cbnz r2, L2 + sub r7, r8, r9 +L2: + add r7, r8, r9 + cbz r2, L3 @ this can't be encoded, must turn into a nop +L3: + add r10, r11, r12 + cbz r2, L4 + sub r7, r8, r9 +L4: + add r3, r4, r5 + +@ CHECK: 0: 02 eb 03 01 add.w r1, r2, r3 +@ CHECK: 4: 00 bf nop +@ CHECK: 6: 05 eb 06 04 add.w r4, r5, r6 +@ CHECK: a: 0a b9 cbnz r2, #2 +@ CHECK: c: a8 eb 09 07 sub.w r7, r8, r9 +@ CHECK: 10: 08 eb 09 07 add.w r7, r8, r9 +@ CHECK: 14: 00 bf nop +@ CHECK: 16: 0b eb 0c 0a add.w r10, r11, r12 +@ CHECK: 1a: 0a b1 cbz r2, #2 +@ CHECK: 1c: a8 eb 09 07 sub.w r7, r8, r9 +@ CHECK: 20: 04 eb 05 03 add.w r3, r4, r5 -- cgit v1.2.3