Fix a bug with the ARM thumb2 CBNZ and CBNZ instructions that
authorKevin Enderby <enderby@apple.com>
Fri, 10 Jan 2014 00:43:32 +0000 (00:43 +0000)
committerKevin Enderby <enderby@apple.com>
Fri, 10 Jan 2014 00:43:32 +0000 (00:43 +0000)
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
test/MC/ARM/thumb2-cbn-to-next-inst.s [new file with mode: 0644]

index fecab9f5d49b72afbfe60f9857f975288e2e1c39..20dce218ea3c60d2b0faa2ca5ab866bdea3aa17d 100644 (file)
@@ -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 (file)
index 0000000..a7ad11b
--- /dev/null
@@ -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