A few more load instructions.
authorEvan Cheng <evan.cheng@apple.com>
Tue, 30 Jun 2009 02:15:48 +0000 (02:15 +0000)
committerEvan Cheng <evan.cheng@apple.com>
Tue, 30 Jun 2009 02:15:48 +0000 (02:15 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@74500 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/ARM/ARMInstrFormats.td
lib/Target/ARM/ARMInstrInfo.h
lib/Target/ARM/ARMInstrThumb.td
lib/Target/ARM/ARMInstrThumb2.td
test/CodeGen/Thumb2/thumb2-ldr_ext.ll [new file with mode: 0644]
test/CodeGen/Thumb2/thumb2-ldrb.ll [new file with mode: 0644]
test/CodeGen/Thumb2/thumb2-ldrh.ll [new file with mode: 0644]

index a98bf1e85676a1f122f49b9274e906a385299fed..f49e38fb2ceedc3508c7d9167782e5327704e437 100644 (file)
@@ -79,7 +79,8 @@ def AddrModeT1_s  : AddrMode<9>;
 def AddrModeT2_i12: AddrMode<10>;
 def AddrModeT2_i8 : AddrMode<11>;
 def AddrModeT2_so : AddrMode<12>;
-def AddrModeT2_pc  : AddrMode<13>;
+def AddrModeT2_pc : AddrMode<13>;
+def AddrModeT2_i8s4 : AddrMode<14>;
 
 // Instruction size.
 class SizeFlagVal<bits<3> val> {
@@ -856,6 +857,8 @@ class T2Iso<dag oops, dag iops, string opc, string asm, list<dag> pattern>
   : Thumb2I<oops, iops, AddrModeT2_so, Size4Bytes, opc, asm, "", pattern>;
 class T2Ipc<dag oops, dag iops, string opc, string asm, list<dag> pattern>
   : Thumb2I<oops, iops, AddrModeT2_pc, Size4Bytes, opc, asm, "", pattern>;
+class T2Ii8s4<dag oops, dag iops, string opc, string asm, list<dag> pattern>
+  : Thumb2I<oops, iops, AddrModeT2_i8s4, Size4Bytes, opc, asm, "", pattern>;
 
 class T2sI<dag oops, dag iops, string opc, string asm, list<dag> pattern>
   : Thumb2sI<oops, iops, AddrModeNone, Size4Bytes, opc, asm, "", pattern>;
index ac1eec0921cd2125cfb049249ecae5056d456180..cdc420820d5753985094820504bca6af9a279785 100644 (file)
@@ -33,20 +33,21 @@ namespace ARMII {
     // This four-bit field describes the addressing mode used.
 
     AddrModeMask  = 0xf,
-    AddrModeNone  = 0,
-    AddrMode1     = 1,
-    AddrMode2     = 2,
-    AddrMode3     = 3,
-    AddrMode4     = 4,
-    AddrMode5     = 5,
-    AddrModeT1_1  = 6,
-    AddrModeT1_2  = 7,
-    AddrModeT1_4  = 8,
-    AddrModeT1_s  = 9,  // i8 * 4 for pc and sp relative data
-    AddrModeT2_i12= 10,
-    AddrModeT2_i8 = 11,
-    AddrModeT2_so = 12,
-    AddrModeT2_pc = 13, // +/- i12 for pc relative data
+    AddrModeNone    = 0,
+    AddrMode1       = 1,
+    AddrMode2       = 2,
+    AddrMode3       = 3,
+    AddrMode4       = 4,
+    AddrMode5       = 5,
+    AddrModeT1_1    = 6,
+    AddrModeT1_2    = 7,
+    AddrModeT1_4    = 8,
+    AddrModeT1_s    = 9,  // i8 * 4 for pc and sp relative data
+    AddrModeT2_i12  = 10,
+    AddrModeT2_i8   = 11,
+    AddrModeT2_so   = 12,
+    AddrModeT2_pc   = 13, // +/- i12 for pc relative data
+    AddrModeT2_i8s4 = 14, // i8 * 4
 
     // Size* - Flags to keep track of the size of an instruction.
     SizeShift     = 4,
index ae54a884dddeb4a99a1603862161461c75959fad..c8e75384849a4e16aa1790e500b0b7c962192dcd 100644 (file)
@@ -622,13 +622,13 @@ def : Tv5Pat<(ARMcall texternalsym:$func), (tBLXi texternalsym:$func)>;
 def : Tv5Pat<(ARMcall tGPR:$dst), (tBLXr tGPR:$dst)>;
 
 // zextload i1 -> zextload i8
-def : TPat<(zextloadi1 t_addrmode_s1:$addr),
-           (tLDRB t_addrmode_s1:$addr)>;
+def : T1Pat<(zextloadi1 t_addrmode_s1:$addr),
+            (tLDRB t_addrmode_s1:$addr)>;
 
 // extload -> zextload
-def : TPat<(extloadi1  t_addrmode_s1:$addr),  (tLDRB t_addrmode_s1:$addr)>;
-def : TPat<(extloadi8  t_addrmode_s1:$addr),  (tLDRB t_addrmode_s1:$addr)>;
-def : TPat<(extloadi16 t_addrmode_s2:$addr),  (tLDRH t_addrmode_s2:$addr)>;
+def : T1Pat<(extloadi1  t_addrmode_s1:$addr),  (tLDRB t_addrmode_s1:$addr)>;
+def : T1Pat<(extloadi8  t_addrmode_s1:$addr),  (tLDRB t_addrmode_s1:$addr)>;
+def : T1Pat<(extloadi16 t_addrmode_s2:$addr),  (tLDRH t_addrmode_s2:$addr)>;
 
 // Large immediate handling.
 
index 7a56fd75970d740cdd525c2d04c6f6459cc64614..f848550a45b53f2c485f949c7f01caa9237ebc9f 100644 (file)
@@ -136,7 +136,7 @@ def t2addrmode_imm12 : Operand<i32>,
   let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm);
 }
 
-// t2addrmode_imm8  := reg - imm8
+// t2addrmode_imm8  := reg - imm8 (also reg + imm8 for some instructions)
 def t2addrmode_imm8 : Operand<i32>,
                       ComplexPattern<i32, 2, "SelectT2AddrModeImm8", []> {
   let PrintMethod = "printT2AddrModeImm8Operand";
@@ -383,6 +383,22 @@ multiclass T2I_cmp_is<string opc, PatFrag opnode> {
 }
 }
 
+/// T2I_ld - Defines a set of (op r, {imm12|imm8|so_reg}) load patterns.
+multiclass T2I_ld<string opc, PatFrag opnode> {
+  def i12 : T2Ii12<(outs GPR:$dst), (ins t2addrmode_imm12:$addr),
+                   opc, " $dst, $addr",
+                   [(set GPR:$dst, (opnode t2addrmode_imm12:$addr))]>;
+  def i8  : T2Ii8 <(outs GPR:$dst), (ins t2addrmode_imm8:$addr),
+                   opc, " $dst, $addr",
+                   [(set GPR:$dst, (opnode t2addrmode_imm8:$addr))]>;
+  def s   : T2Iso <(outs GPR:$dst), (ins t2addrmode_so_reg:$addr),
+                   opc, " $dst, $addr",
+                   [(set GPR:$dst, (opnode t2addrmode_so_reg:$addr))]>;
+  def pci : T2Ipc <(outs GPR:$dst), (ins i32imm:$addr),
+                   opc, " $dst, $addr",
+                   [(set GPR:$dst, (opnode (ARMWrapper tconstpool:$addr)))]>;
+}
+
 //===----------------------------------------------------------------------===//
 // Instructions
 //===----------------------------------------------------------------------===//
@@ -434,24 +450,64 @@ def t2ADDrSPs : T2XI<(outs GPR:$dst), (ins GPR:$sp, t2_so_reg:$rhs),
 //
 
 // Load
-let canFoldAsLoad = 1 in {
-def t2LDRi12 : T2Ii12<(outs GPR:$dst), (ins t2addrmode_imm12:$addr),
-                      "ldr", " $dst, $addr",
-                      [(set GPR:$dst, (load t2addrmode_imm12:$addr))]>;
-
-def t2LDRi8 : T2Ii8<(outs GPR:$dst), (ins t2addrmode_imm8:$addr),
-                    "ldr", " $dst, $addr",
-                    [(set GPR:$dst, (load t2addrmode_imm8:$addr))]>;
-
-def t2LDRs : T2Iso<(outs GPR:$dst), (ins t2addrmode_so_reg:$addr),
-                   "ldr", " $dst, $addr",
-                   [(set GPR:$dst, (load t2addrmode_so_reg:$addr))]>;
-
-// Load tconstpool
-def t2LDRpci : T2Ipc<(outs GPR:$dst), (ins i32imm:$addr),
-                     "ldr", " $dst, $addr",
-                     [(set GPR:$dst, (load (ARMWrapper tconstpool:$addr)))]>;
-} // canFoldAsLoad
+let canFoldAsLoad = 1 in
+defm t2LDR   : T2I_ld<"ldr",  UnOpFrag<(load node:$Src)>>;
+
+// Loads with zero extension
+defm t2LDRH  : T2I_ld<"ldrh", UnOpFrag<(zextloadi16 node:$Src)>>;
+defm t2LDRB  : T2I_ld<"ldrb", UnOpFrag<(zextloadi8  node:$Src)>>;
+
+// Loads with sign extension
+defm t2LDRSH : T2I_ld<"ldrsh", UnOpFrag<(sextloadi16 node:$Src)>>;
+defm t2LDRSB : T2I_ld<"ldrsb", UnOpFrag<(sextloadi8  node:$Src)>>;
+
+let mayLoad = 1 in {
+// Load doubleword
+def t2LDRDi8 : T2Ii8s4<(outs GPR:$dst), (ins t2addrmode_imm8:$addr),
+                       "ldrd", " $dst, $addr", []>;
+def t2LDRDpci : T2Ii8s4<(outs GPR:$dst), (ins i32imm:$addr),
+                       "ldrd", " $dst, $addr", []>;
+}
+
+// zextload i1 -> zextload i8
+def : T2Pat<(zextloadi1 t2addrmode_imm12:$addr),
+            (t2LDRBi12  t2addrmode_imm12:$addr)>;
+def : T2Pat<(zextloadi1 t2addrmode_imm8:$addr),
+            (t2LDRBi8   t2addrmode_imm8:$addr)>;
+def : T2Pat<(zextloadi1 t2addrmode_so_reg:$addr),
+            (t2LDRBs    t2addrmode_so_reg:$addr)>;
+def : T2Pat<(zextloadi1 (ARMWrapper tconstpool:$addr)),
+            (t2LDRBpci  tconstpool:$addr)>;
+
+// extload -> zextload
+// FIXME: Reduce the number of patterns by legalizing extload to zextload
+// earlier?
+def : T2Pat<(extloadi1  t2addrmode_imm12:$addr),
+            (t2LDRBi12  t2addrmode_imm12:$addr)>;
+def : T2Pat<(extloadi1  t2addrmode_imm8:$addr),
+            (t2LDRBi8   t2addrmode_imm8:$addr)>;
+def : T2Pat<(extloadi1  t2addrmode_so_reg:$addr),
+            (t2LDRBs    t2addrmode_so_reg:$addr)>;
+def : T2Pat<(extloadi1  (ARMWrapper tconstpool:$addr)),
+            (t2LDRBpci  tconstpool:$addr)>;
+
+def : T2Pat<(extloadi8  t2addrmode_imm12:$addr),
+            (t2LDRBi12  t2addrmode_imm12:$addr)>;
+def : T2Pat<(extloadi8  t2addrmode_imm8:$addr),
+            (t2LDRBi8   t2addrmode_imm8:$addr)>;
+def : T2Pat<(extloadi8  t2addrmode_so_reg:$addr),
+            (t2LDRBs    t2addrmode_so_reg:$addr)>;
+def : T2Pat<(extloadi8  (ARMWrapper tconstpool:$addr)),
+            (t2LDRBpci  tconstpool:$addr)>;
+
+def : T2Pat<(extloadi16 t2addrmode_imm12:$addr),
+            (t2LDRHi12  t2addrmode_imm12:$addr)>;
+def : T2Pat<(extloadi16 t2addrmode_imm8:$addr),
+            (t2LDRHi8   t2addrmode_imm8:$addr)>;
+def : T2Pat<(extloadi16 t2addrmode_so_reg:$addr),
+            (t2LDRHs    t2addrmode_so_reg:$addr)>;
+def : T2Pat<(extloadi16 (ARMWrapper tconstpool:$addr)),
+            (t2LDRHpci  tconstpool:$addr)>;
 
 //===----------------------------------------------------------------------===//
 //  Move Instructions.
diff --git a/test/CodeGen/Thumb2/thumb2-ldr_ext.ll b/test/CodeGen/Thumb2/thumb2-ldr_ext.ll
new file mode 100644 (file)
index 0000000..d48ecef
--- /dev/null
@@ -0,0 +1,28 @@
+; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep ldrb | count 1
+; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep ldrh | count 1
+; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep ldrsb | count 1
+; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep ldrsh | count 1
+
+define i32 @test1(i8* %v.pntr.s0.u1) {
+    %tmp.u = load i8* %v.pntr.s0.u1
+    %tmp1.s = zext i8 %tmp.u to i32
+    ret i32 %tmp1.s
+}
+
+define i32 @test2(i16* %v.pntr.s0.u1) {
+    %tmp.u = load i16* %v.pntr.s0.u1
+    %tmp1.s = zext i16 %tmp.u to i32
+    ret i32 %tmp1.s
+}
+
+define i32 @test3(i8* %v.pntr.s1.u0) {
+    %tmp.s = load i8* %v.pntr.s1.u0
+    %tmp1.s = sext i8 %tmp.s to i32
+    ret i32 %tmp1.s
+}
+
+define i32 @test4() {
+    %tmp.s = load i16* null
+    %tmp1.s = sext i16 %tmp.s to i32
+    ret i32 %tmp1.s
+}
diff --git a/test/CodeGen/Thumb2/thumb2-ldrb.ll b/test/CodeGen/Thumb2/thumb2-ldrb.ll
new file mode 100644 (file)
index 0000000..5bacb8e
--- /dev/null
@@ -0,0 +1,60 @@
+; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep {ldrb r0} | count 7
+; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep mov | grep 1
+; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | not grep mvn
+; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep ldrb | grep lsl
+; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep lsr | not grep ldrb
+
+define i8 @f1(i8* %v) {
+entry:
+        %tmp = load i8* %v
+        ret i8 %tmp
+}
+
+define i8 @f2(i8* %v) {
+entry:
+        %tmp2 = getelementptr i8* %v, i8 1023
+        %tmp = load i8* %tmp2
+        ret i8 %tmp
+}
+
+define i8 @f3(i32 %base) {
+entry:
+        %tmp1 = add i32 %base, 4096
+        %tmp2 = inttoptr i32 %tmp1 to i8*
+        %tmp3 = load i8* %tmp2
+        ret i8 %tmp3
+}
+
+define i8 @f4(i32 %base) {
+entry:
+        %tmp1 = sub i32 %base, 128
+        %tmp2 = inttoptr i32 %tmp1 to i8*
+        %tmp3 = load i8* %tmp2
+        ret i8 %tmp3
+}
+
+define i8 @f5(i32 %base, i32 %offset) {
+entry:
+        %tmp1 = add i32 %base, %offset
+        %tmp2 = inttoptr i32 %tmp1 to i8*
+        %tmp3 = load i8* %tmp2
+        ret i8 %tmp3
+}
+
+define i8 @f6(i32 %base, i32 %offset) {
+entry:
+        %tmp1 = shl i32 %offset, 2
+        %tmp2 = add i32 %base, %tmp1
+        %tmp3 = inttoptr i32 %tmp2 to i8*
+        %tmp4 = load i8* %tmp3
+        ret i8 %tmp4
+}
+
+define i8 @f7(i32 %base, i32 %offset) {
+entry:
+        %tmp1 = lshr i32 %offset, 2
+        %tmp2 = add i32 %base, %tmp1
+        %tmp3 = inttoptr i32 %tmp2 to i8*
+        %tmp4 = load i8* %tmp3
+        ret i8 %tmp4
+}
diff --git a/test/CodeGen/Thumb2/thumb2-ldrh.ll b/test/CodeGen/Thumb2/thumb2-ldrh.ll
new file mode 100644 (file)
index 0000000..15f803e
--- /dev/null
@@ -0,0 +1,59 @@
+; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep {ldrh r0} | count 7
+; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep mov | grep 1
+; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | not grep mvn
+; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep ldrh | grep lsl
+; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep lsr | not grep ldrh
+
+define i16 @f1(i16* %v) {
+entry:
+        %tmp = load i16* %v
+        ret i16 %tmp
+}
+
+define i16 @f2(i16* %v) {
+entry:
+        %tmp2 = getelementptr i16* %v, i16 1023
+        %tmp = load i16* %tmp2
+        ret i16 %tmp
+}
+
+define i16 @f3(i16* %v) {
+entry:
+        %tmp2 = getelementptr i16* %v, i16 2048
+        %tmp = load i16* %tmp2
+        ret i16 %tmp
+}
+
+define i16 @f4(i32 %base) {
+entry:
+        %tmp1 = sub i32 %base, 128
+        %tmp2 = inttoptr i32 %tmp1 to i16*
+        %tmp3 = load i16* %tmp2
+        ret i16 %tmp3
+}
+
+define i16 @f5(i32 %base, i32 %offset) {
+entry:
+        %tmp1 = add i32 %base, %offset
+        %tmp2 = inttoptr i32 %tmp1 to i16*
+        %tmp3 = load i16* %tmp2
+        ret i16 %tmp3
+}
+
+define i16 @f6(i32 %base, i32 %offset) {
+entry:
+        %tmp1 = shl i32 %offset, 2
+        %tmp2 = add i32 %base, %tmp1
+        %tmp3 = inttoptr i32 %tmp2 to i16*
+        %tmp4 = load i16* %tmp3
+        ret i16 %tmp4
+}
+
+define i16 @f7(i32 %base, i32 %offset) {
+entry:
+        %tmp1 = lshr i32 %offset, 2
+        %tmp2 = add i32 %base, %tmp1
+        %tmp3 = inttoptr i32 %tmp2 to i16*
+        %tmp4 = load i16* %tmp3
+        ret i16 %tmp4
+}