This adds range checking for "ldr Rn, [pc, #imm]" Thumb
authorMihai Popa <mihail.popa@gmail.com>
Mon, 22 Jul 2013 15:49:36 +0000 (15:49 +0000)
committerMihai Popa <mihail.popa@gmail.com>
Mon, 22 Jul 2013 15:49:36 +0000 (15:49 +0000)
instructions. With this patch:

1. ldr.n is recognized as mnemonic for the short encoding
2. ldr.w is recognized as menmonic for the long encoding
3. ldr will map to either short or long encodings depending on the size of the offset

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@186831 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/ARM/ARMInstrThumb.td
lib/Target/ARM/ARMInstrThumb2.td
lib/Target/ARM/AsmParser/ARMAsmParser.cpp
lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp
test/CodeGen/ARM/fast-isel-pic.ll
test/CodeGen/ARM/indirectbr.ll
test/CodeGen/ARM/load-global.ll
test/CodeGen/ARM/machine-licm.ll
test/CodeGen/Thumb/large-stack.ll
test/MC/ARM/basic-thumb2-instructions.s

index a0edaba04e89dcc8fd0c52099c787610d97976b1..e7218c66586fcba60db47d35bf9dc52955810aa7 100644 (file)
@@ -100,6 +100,13 @@ class OperandUnsignedOffset_b8s2 : AsmOperandClass {
 
 def UnsignedOffset_b8s2 : OperandUnsignedOffset_b8s2;
 
 
 def UnsignedOffset_b8s2 : OperandUnsignedOffset_b8s2;
 
+// thumb style PC relative operand. signed, 8 bits magnitude,
+// two bits shift. can be represented as either [pc, #imm], #imm,
+// or relocatable expression...
+def ThumbMemPC : AsmOperandClass {
+  let Name = "ThumbMemPC";
+}
+
 let OperandType = "OPERAND_PCREL" in {
 def t_brtarget : Operand<OtherVT> {
   let EncoderMethod = "getThumbBRTargetOpValue";
 let OperandType = "OPERAND_PCREL" in {
 def t_brtarget : Operand<OtherVT> {
   let EncoderMethod = "getThumbBRTargetOpValue";
@@ -132,6 +139,15 @@ def t_blxtarget : Operand<i32> {
   let EncoderMethod = "getThumbBLXTargetOpValue";
   let DecoderMethod = "DecodeThumbBLXOffset";
 }
   let EncoderMethod = "getThumbBLXTargetOpValue";
   let DecoderMethod = "DecodeThumbBLXOffset";
 }
+
+// t_addrmode_pc := <label> => pc + imm8 * 4
+//
+def t_addrmode_pc : Operand<i32> {
+  let EncoderMethod = "getAddrModePCOpValue";
+  let DecoderMethod = "DecodeThumbAddrModePC";
+  let PrintMethod = "printThumbLdrLabelOperand";
+  let ParserMatchClass = ThumbMemPC;
+}
 }
 
 // t_addrmode_rr := reg + reg
 }
 
 // t_addrmode_rr := reg + reg
@@ -228,14 +244,6 @@ def t_addrmode_sp : Operand<i32>,
   let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm);
 }
 
   let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm);
 }
 
-// t_addrmode_pc := <label> => pc + imm8 * 4
-//
-def t_addrmode_pc : Operand<i32> {
-  let EncoderMethod = "getAddrModePCOpValue";
-  let DecoderMethod = "DecodeThumbAddrModePC";
-  let PrintMethod = "printThumbLdrLabelOperand";
-}
-
 //===----------------------------------------------------------------------===//
 //  Miscellaneous Instructions.
 //
 //===----------------------------------------------------------------------===//
 //  Miscellaneous Instructions.
 //
@@ -640,11 +648,9 @@ def tLDRspi : T1pIs<(outs tGPR:$Rt), (ins t_addrmode_sp:$addr), IIC_iLoad_i,
   let Inst{7-0} = addr;
 }
 
   let Inst{7-0} = addr;
 }
 
-// Load tconstpool
-// FIXME: Use ldr.n to work around a darwin assembler bug.
-let canFoldAsLoad = 1, isReMaterializable = 1, isCodeGenOnly = 1 in
+let canFoldAsLoad = 1, isReMaterializable = 1 in
 def tLDRpci : T1pIs<(outs tGPR:$Rt), (ins t_addrmode_pc:$addr), IIC_iLoad_i,
 def tLDRpci : T1pIs<(outs tGPR:$Rt), (ins t_addrmode_pc:$addr), IIC_iLoad_i,
-                  "ldr", ".n\t$Rt, $addr",
+                  "ldr", "\t$Rt, $addr",
                   [(set tGPR:$Rt, (load (ARMWrapper tconstpool:$addr)))]>,
               T1Encoding<{0,1,0,0,1,?}> {
   // A6.2 & A8.6.59
                   [(set tGPR:$Rt, (load (ARMWrapper tconstpool:$addr)))]>,
               T1Encoding<{0,1,0,0,1,?}> {
   // A6.2 & A8.6.59
@@ -654,17 +660,8 @@ def tLDRpci : T1pIs<(outs tGPR:$Rt), (ins t_addrmode_pc:$addr), IIC_iLoad_i,
   let Inst{7-0}  = addr;
 }
 
   let Inst{7-0}  = addr;
 }
 
-// FIXME: Remove this entry when the above ldr.n workaround is fixed.
-// For assembly/disassembly use only.
-def tLDRpciASM : T1pIs<(outs tGPR:$Rt), (ins t_addrmode_pc:$addr), IIC_iLoad_i,
-                       "ldr", "\t$Rt, $addr", []>,
-                 T1Encoding<{0,1,0,0,1,?}> {
-  // A6.2 & A8.6.59
-  bits<3> Rt;
-  bits<8> addr;
-  let Inst{10-8} = Rt;
-  let Inst{7-0}  = addr;
-}
+def : tInstAlias<"ldr${p}.n $Rt, $addr", 
+                 (tLDRpci tGPR:$Rt, t_addrmode_pc:$addr, pred:$p), 0>;
 
 // A8.6.194 & A8.6.192
 defm tSTR  : thumb_st_rr_ri_enc<0b000, 0b0110, t_addrmode_rrs4,
 
 // A8.6.194 & A8.6.192
 defm tSTR  : thumb_st_rr_ri_enc<0b000, 0b0110, t_addrmode_rrs4,
index 5a425c69228eacfc74e628750dbef71fe9d99b26..8e5e8c1735a4ac7e55e86179c46faf981237d2ae 100644 (file)
@@ -4399,7 +4399,7 @@ def t2LDRSHpcrel  : t2AsmPseudo<"ldrsh${p} $Rt, $addr",
                          (ins GPRnopc:$Rt, t2ldr_pcrel_imm12:$addr, pred:$p)>;
     // Version w/ the .w suffix.
 def : t2InstAlias<"ldr${p}.w $Rt, $addr",
                          (ins GPRnopc:$Rt, t2ldr_pcrel_imm12:$addr, pred:$p)>;
     // Version w/ the .w suffix.
 def : t2InstAlias<"ldr${p}.w $Rt, $addr",
-                  (t2LDRpcrel GPRnopc:$Rt, t2ldr_pcrel_imm12:$addr, pred:$p)>;
+                  (t2LDRpcrel GPRnopc:$Rt, t2ldr_pcrel_imm12:$addr, pred:$p), 0>;
 def : t2InstAlias<"ldrb${p}.w $Rt, $addr",
                   (t2LDRBpcrel GPRnopc:$Rt, t2ldr_pcrel_imm12:$addr, pred:$p)>;
 def : t2InstAlias<"ldrh${p}.w $Rt, $addr",
 def : t2InstAlias<"ldrb${p}.w $Rt, $addr",
                   (t2LDRBpcrel GPRnopc:$Rt, t2ldr_pcrel_imm12:$addr, pred:$p)>;
 def : t2InstAlias<"ldrh${p}.w $Rt, $addr",
index fc1faffd0bb4cfc999decc777b5ee555fe177386..6d885a0d91827ed6925a8544aae4f352776f231c 100644 (file)
@@ -609,6 +609,26 @@ public:
     }
     return false;
   }
     }
     return false;
   }
+  // checks whether this operand is a memory operand computed as an offset
+  // applied to PC. the offset may have 8 bits of magnitude and is represented
+  // with two bits of shift. textually it may be either [pc, #imm], #imm or 
+  // relocable expression...
+  bool isThumbMemPC() const {
+    int64_t Val = 0;
+    if (isImm()) {
+      if (isa<MCSymbolRefExpr>(Imm.Val)) return true;
+      const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Imm.Val);
+      if (!CE) return false;
+      Val = CE->getValue();
+    }
+    else if (isMem()) {
+      if(!Memory.OffsetImm || Memory.OffsetRegNum) return false;
+      if(Memory.BaseRegNum != ARM::PC) return false;
+      Val = Memory.OffsetImm->getValue();
+    }
+    else return false;
+    return ((Val % 4) == 0) && (Val >= -1020) && (Val <= 1020);
+  }
   bool isFPImm() const {
     if (!isImm()) return false;
     const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
   bool isFPImm() const {
     if (!isImm()) return false;
     const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
@@ -1698,6 +1718,26 @@ public:
     Inst.addOperand(MCOperand::CreateExpr(SR));
   }
 
     Inst.addOperand(MCOperand::CreateExpr(SR));
   }
 
+  void addThumbMemPCOperands(MCInst &Inst, unsigned N) const {
+    assert(N == 1 && "Invalid number of operands!");
+    if (isImm()) {
+      const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
+      if (CE) {
+        Inst.addOperand(MCOperand::CreateImm(CE->getValue()));
+        return;
+      }
+
+      const MCSymbolRefExpr *SR = dyn_cast<MCSymbolRefExpr>(Imm.Val);
+      assert(SR && "Unknown value type!");
+      Inst.addOperand(MCOperand::CreateExpr(SR));
+      return;
+    }
+
+    assert(isMem()  && "Unknown value type!");
+    assert(isa<MCConstantExpr>(Memory.OffsetImm) && "Unknown value type!");
+    Inst.addOperand(MCOperand::CreateImm(Memory.OffsetImm->getValue()));
+  }
+
   void addARMSOImmNotOperands(MCInst &Inst, unsigned N) const {
     assert(N == 1 && "Invalid number of operands!");
     // The operand is actually a so_imm, but we have its bitwise
   void addARMSOImmNotOperands(MCInst &Inst, unsigned N) const {
     assert(N == 1 && "Invalid number of operands!");
     // The operand is actually a so_imm, but we have its bitwise
index 8baa3a6ce6acc1b80211a77f9bc6a697bf71d764..b1e25d8b89e5f45d40e7d78dec3ed90e8d87bc58 100644 (file)
@@ -152,7 +152,7 @@ static unsigned getRelaxedOpcode(unsigned Op) {
   switch (Op) {
   default: return Op;
   case ARM::tBcc:       return ARM::t2Bcc;
   switch (Op) {
   default: return Op;
   case ARM::tBcc:       return ARM::t2Bcc;
-  case ARM::tLDRpciASM: return ARM::t2LDRpci;
+  case ARM::tLDRpci:    return ARM::t2LDRpci;
   case ARM::tADR:       return ARM::t2ADR;
   case ARM::tB:         return ARM::t2B;
   }
   case ARM::tADR:       return ARM::t2ADR;
   case ARM::tB:         return ARM::t2B;
   }
index 0589f9ada8fd47360fda692bb6f94857542f7b20..ad0f15966f728e440d89a5f6f6d92455c6b129fe 100644 (file)
@@ -13,8 +13,8 @@ entry:
 ; THUMB: movt [[reg0]],
 ; THUMB: add  [[reg0]], pc
 ; THUMB-ELF: LoadGV
 ; THUMB: movt [[reg0]],
 ; THUMB: add  [[reg0]], pc
 ; THUMB-ELF: LoadGV
-; THUMB-ELF: ldr.n r[[reg0:[0-9]+]],
-; THUMB-ELF: ldr.n r[[reg1:[0-9]+]],
+; THUMB-ELF: ldr r[[reg0:[0-9]+]],
+; THUMB-ELF: ldr r[[reg1:[0-9]+]],
 ; THUMB-ELF: ldr r[[reg0]], [r[[reg0]], r[[reg1]]]
 ; ARM: LoadGV
 ; ARM: ldr [[reg1:r[0-9]+]],
 ; THUMB-ELF: ldr r[[reg0]], [r[[reg0]], r[[reg1]]]
 ; ARM: LoadGV
 ; ARM: ldr [[reg1:r[0-9]+]],
@@ -41,8 +41,8 @@ entry:
 ; THUMB: add  r[[reg3]], pc
 ; THUMB: ldr  r[[reg3]], [r[[reg3]]]
 ; THUMB-ELF: LoadIndirectSymbol
 ; THUMB: add  r[[reg3]], pc
 ; THUMB: ldr  r[[reg3]], [r[[reg3]]]
 ; THUMB-ELF: LoadIndirectSymbol
-; THUMB-ELF: ldr.n r[[reg3:[0-9]+]],
-; THUMB-ELF: ldr.n r[[reg4:[0-9]+]],
+; THUMB-ELF: ldr r[[reg3:[0-9]+]],
+; THUMB-ELF: ldr r[[reg4:[0-9]+]],
 ; THUMB-ELF: ldr r[[reg3]], [r[[reg3]], r[[reg4]]]
 ; ARM: LoadIndirectSymbol
 ; ARM: ldr [[reg4:r[0-9]+]],
 ; THUMB-ELF: ldr r[[reg3]], [r[[reg3]], r[[reg4]]]
 ; ARM: LoadIndirectSymbol
 ; ARM: ldr [[reg4:r[0-9]+]],
index 6fed8c492f92db417d6a30b9a063342aba38f6d3..99e84a6a6253337d034d9ec94d04f2fbded2ab06 100644 (file)
@@ -51,12 +51,12 @@ L1:                                               ; preds = %L2, %bb2
 ; ARM: ldr [[R1:r[0-9]+]], LCPI
 ; ARM: add [[R1b:r[0-9]+]], pc, [[R1]]
 ; ARM: str [[R1b]]
 ; ARM: ldr [[R1:r[0-9]+]], LCPI
 ; ARM: add [[R1b:r[0-9]+]], pc, [[R1]]
 ; ARM: str [[R1b]]
-; THUMB: ldr.n
+; THUMB: ldr
 ; THUMB: add
 ; THUMB: add
-; THUMB: ldr.n [[R2:r[0-9]+]], LCPI
+; THUMB: ldr [[R2:r[0-9]+]], LCPI
 ; THUMB: add [[R2]], pc
 ; THUMB: str [[R2]]
 ; THUMB: add [[R2]], pc
 ; THUMB: str [[R2]]
-; THUMB2: ldr.n [[R2:r[0-9]+]], LCPI
+; THUMB2: ldr [[R2:r[0-9]+]], LCPI
 ; THUMB2-NEXT: str{{(.w)?}} [[R2]]
   store i8* blockaddress(@foo, %L5), i8** @nextaddr, align 4
   ret i32 %res.3
 ; THUMB2-NEXT: str{{(.w)?}} [[R2]]
   store i8* blockaddress(@foo, %L5), i8** @nextaddr, align 4
   ret i32 %res.3
index 15a415df731dbd81115794314f6a1cee662e927d..00ca2e8b1b7552dafe3f9583378640d9b3cdeb33 100644 (file)
@@ -26,7 +26,7 @@ define i32 @test1() {
 ; PIC: .long L_G$non_lazy_ptr-(LPC0_0+8)
 
 ; PIC_T: _test1
 ; PIC: .long L_G$non_lazy_ptr-(LPC0_0+8)
 
 ; PIC_T: _test1
-; PIC_T: ldr.n r0, LCPI0_0
+; PIC_T: ldr r0, LCPI0_0
 ; PIC_T: add r0, pc
 ; PIC_T: ldr r0, [r0]
 ; PIC_T: ldr r0, [r0]
 ; PIC_T: add r0, pc
 ; PIC_T: ldr r0, [r0]
 ; PIC_T: ldr r0, [r0]
index 87aaacfb55a2b4735367a72d9a2f7a45db623536..fc9b22614d6dcca59ae47ca3e3424c69a929482c 100644 (file)
@@ -40,7 +40,7 @@ bb.nph:                                           ; preds = %entry
 ; ARM: .section
 
 ; THUMB: BB#1
 ; ARM: .section
 
 ; THUMB: BB#1
-; THUMB: ldr.n r2, LCPI0_0
+; THUMB: ldr r2, LCPI0_0
 ; THUMB: add r2, pc
 ; THUMB: ldr r{{[0-9]+}}, [r2]
 ; THUMB: LBB0_2
 ; THUMB: add r2, pc
 ; THUMB: ldr r{{[0-9]+}}, [r2]
 ; THUMB: LBB0_2
index 6fa623123ad78c7a58ebad84f4c74f41f1a2209b..fb6daa4786511214aaacf8af22c43d4a14701918 100644 (file)
@@ -10,7 +10,7 @@ define void @test1() {
 
 define void @test2() {
 ; CHECK-LABEL: test2:
 
 define void @test2() {
 ; CHECK-LABEL: test2:
-; CHECK: ldr.n r0, LCPI
+; CHECK: ldr r0, LCPI
 ; CHECK: add sp, r0
 ; CHECK: subs r4, r7, #4
 ; CHECK: mov sp, r4
 ; CHECK: add sp, r0
 ; CHECK: subs r4, r7, #4
 ; CHECK: mov sp, r4
@@ -20,9 +20,9 @@ define void @test2() {
 
 define i32 @test3() {
 ; CHECK-LABEL: test3:
 
 define i32 @test3() {
 ; CHECK-LABEL: test3:
-; CHECK: ldr.n r1, LCPI
+; CHECK: ldr r1, LCPI
 ; CHECK: add sp, r1
 ; CHECK: add sp, r1
-; CHECK: ldr.n r1, LCPI
+; CHECK: ldr r1, LCPI
 ; CHECK: add r1, sp
 ; CHECK: subs r4, r7, #4
 ; CHECK: mov sp, r4
 ; CHECK: add r1, sp
 ; CHECK: subs r4, r7, #4
 ; CHECK: mov sp, r4
index 2bd9a133384f7f90ef597565c682d8f2115d7bee..43e03c9833a74bd3963a112d5632af6bdc4c2194 100644 (file)
@@ -772,6 +772,23 @@ _func:
 @ CHECK: ldr.w lr, _strcmp-4           @ encoding: [0x5f'A',0xf8'A',A,0xe0'A']
 @ CHECK: @   fixup A - offset: 0, value: _strcmp-4, kind: fixup_t2_ldst_pcrel_12
 
 @ CHECK: ldr.w lr, _strcmp-4           @ encoding: [0x5f'A',0xf8'A',A,0xe0'A']
 @ CHECK: @   fixup A - offset: 0, value: _strcmp-4, kind: fixup_t2_ldst_pcrel_12
 
+        ldr r4, [pc, #1020]
+        ldr r3, [pc, #-1020]
+        ldr r6, [pc, #1024]
+        ldr r0, [pc, #-1024]
+        ldr r2, [pc, #4095]
+        ldr r1, [pc, #-4095]
+        ldr.n r8, [pc, #132]
+        ldr.w r8, [pc, #132]
+
+@ CHECK: ldr   r4, [pc, #1020]       @ encoding: [0xff,0x4c]
+@ CHECK: ldr   r3, [pc, #-1020]      @ encoding: [0x01,0x4b]
+@ CHECK: ldr.w r6, [pc, #1024]       @ encoding: [0xdf,0xf8,0x00,0x64]
+@ CHECK: ldr.w r0, [pc, #-1024]      @ encoding: [0x5f,0xf8,0x00,0x04]
+@ CHECK: ldr.w r2, [pc, #4095]       @ encoding: [0xdf,0xf8,0xff,0x2f]
+@ CHECK: ldr.w r1, [pc, #-4095]      @ encoding: [0x5f,0xf8,0xff,0x1f]
+@ CHECK: ldr   r8, [pc, #132]        @ encoding: [0x21,0x48]
+@ CHECK: ldr.w r8, [pc, #132]        @ encoding: [0xdf,0xf8,0x84,0x80]
 
 @------------------------------------------------------------------------------
 @ LDR(register)
 
 @------------------------------------------------------------------------------
 @ LDR(register)
@@ -3569,5 +3586,5 @@ _func:
 @ CHECK: ldrsh.w r11, [pc, #-22]        @ encoding: [0x3f,0xf9,0x16,0xb0]
 
 @ rdar://12596361
 @ CHECK: ldrsh.w r11, [pc, #-22]        @ encoding: [0x3f,0xf9,0x16,0xb0]
 
 @ rdar://12596361
-        ldr r1, [pc, #12]
-@ CHECK: ldr.n r1, [pc, #12]        @ encoding: [0x03,0x49]
+         ldr r1, [pc, #12]
+@ CHECK: ldr r1, [pc, #12]              @ encoding: [0x03,0x49]