2007-03-30 Paul Brook <paul@codesourcery.com>
authorPaul Brook <paul@codesourcery.com>
Fri, 30 Mar 2007 14:51:25 +0000 (14:51 +0000)
committerPaul Brook <paul@codesourcery.com>
Fri, 30 Mar 2007 14:51:25 +0000 (14:51 +0000)
gas/
* config/tc-arm.c (encode_thumb2_ldmstm): New function.
(do_t_ldmstm): Generate 16-bit push/pop.  Use encode_thumb2_ldmstm.
(do_t_push_pop):  Use encode_thumb2_ldmstm.

gas/testsuite/
* gas/arm/thumb2_ldmstm.d: New test.
* gas/arm/thumb2_ldmstm.s: New test.

gas/ChangeLog
gas/config/tc-arm.c
gas/testsuite/ChangeLog
gas/testsuite/gas/arm/thumb2_ldmstm.d [new file with mode: 0644]
gas/testsuite/gas/arm/thumb2_ldmstm.s [new file with mode: 0644]

index d629396a75a34cdfafdf41feed8361910aa7177f..7f46533452d05aee5c4754388134ab3e13c21ef9 100644 (file)
@@ -1,3 +1,9 @@
+2007-03-30  Paul Brook  <paul@codesourcery.com>
+
+       * config/tc-arm.c (encode_thumb2_ldmstm): New function.
+       (do_t_ldmstm): Generate 16-bit push/pop.  Use encode_thumb2_ldmstm.
+       (do_t_push_pop):  Use encode_thumb2_ldmstm.
+
 2007-03-29  DJ Delorie  <dj@redhat.com>
 
        * config/tc-m32c.c (rl_for, relaxable): Protect argument.
index e1cd5fcaa509bc3f08877c74a7f8476814c83adb..6b915ba19cdbe7a3807b116df4326659bea17564 100644 (file)
@@ -9086,6 +9086,68 @@ do_t_it (void)
   inst.instruction |= cond << 4;
 }
 
+/* Helper function used for both push/pop and ldm/stm.  */
+static void
+encode_thumb2_ldmstm (int base, unsigned mask, bfd_boolean writeback)
+{
+  bfd_boolean load;
+
+  load = (inst.instruction & (1 << 20)) != 0;
+
+  if (mask & (1 << 13))
+    inst.error =  _("SP not allowed in register list");
+  if (load)
+    {
+      if (mask & (1 << 14)
+         && mask & (1 << 15))
+       inst.error = _("LR and PC should not both be in register list");
+
+      if ((mask & (1 << base)) != 0
+         && writeback)
+       as_warn (_("base register should not be in register list "
+                  "when written back"));
+    }
+  else
+    {
+      if (mask & (1 << 15))
+       inst.error = _("PC not allowed in register list");
+
+      if (mask & (1 << base))
+       as_warn (_("value stored for r%d is UNPREDICTABLE"), base);
+    }
+
+  if ((mask & (mask - 1)) == 0)
+    {
+      /* Single register transfers implemented as str/ldr.  */
+      if (writeback)
+       {
+         if (inst.instruction & (1 << 23))
+           inst.instruction = 0x00000b04; /* ia! -> [base], #4 */
+         else
+           inst.instruction = 0x00000d04; /* db! -> [base, #-4]! */
+       }
+      else
+       {
+         if (inst.instruction & (1 << 23))
+           inst.instruction = 0x00800000; /* ia -> [base] */
+         else
+           inst.instruction = 0x00000c04; /* db -> [base, #-4] */
+       }
+
+      inst.instruction |= 0xf8400000;
+      if (load)
+       inst.instruction |= 0x00100000;
+
+      mask = ffs(mask) - 1;
+      mask <<= 12;
+    }
+  else if (writeback)
+    inst.instruction |= WRITE_BACK;
+
+  inst.instruction |= mask;
+  inst.instruction |= base << 16;
+}
+
 static void
 do_t_ldmstm (void)
 {
@@ -9097,54 +9159,51 @@ do_t_ldmstm (void)
 
   if (unified_syntax)
     {
+      bfd_boolean narrow;
+      unsigned mask;
+
+      narrow = FALSE;
       /* See if we can use a 16-bit instruction.  */
       if (inst.instruction < 0xffff /* not ldmdb/stmdb */
          && inst.size_req != 4
-         && inst.operands[0].reg <= 7
-         && !(inst.operands[1].imm & ~0xff)
-         && (inst.instruction == T_MNEM_stmia
-             ? inst.operands[0].writeback
-             : (inst.operands[0].writeback
-                == !(inst.operands[1].imm & (1 << inst.operands[0].reg)))))
+         && !(inst.operands[1].imm & ~0xff))
        {
-         if (inst.instruction == T_MNEM_stmia
-             && (inst.operands[1].imm & (1 << inst.operands[0].reg))
-             && (inst.operands[1].imm & ((1 << inst.operands[0].reg) - 1)))
-           as_warn (_("value stored for r%d is UNPREDICTABLE"),
-                    inst.operands[0].reg);
+         mask = 1 << inst.operands[0].reg;
 
-         inst.instruction = THUMB_OP16 (inst.instruction);
-         inst.instruction |= inst.operands[0].reg << 8;
-         inst.instruction |= inst.operands[1].imm;
-       }
-      else
-       {
-         if (inst.operands[1].imm & (1 << 13))
-           as_warn (_("SP should not be in register list"));
-         if (inst.instruction == T_MNEM_stmia)
+         if (inst.operands[0].reg <= 7
+             && (inst.instruction == T_MNEM_stmia
+                 ? inst.operands[0].writeback
+                 : (inst.operands[0].writeback
+                    == !(inst.operands[1].imm & mask))))
            {
-             if (inst.operands[1].imm & (1 << 15))
-               as_warn (_("PC should not be in register list"));
-             if (inst.operands[1].imm & (1 << inst.operands[0].reg))
+             if (inst.instruction == T_MNEM_stmia
+                 && (inst.operands[1].imm & mask)
+                 && (inst.operands[1].imm & (mask - 1)))
                as_warn (_("value stored for r%d is UNPREDICTABLE"),
                         inst.operands[0].reg);
+
+             inst.instruction = THUMB_OP16 (inst.instruction);
+             inst.instruction |= inst.operands[0].reg << 8;
+             inst.instruction |= inst.operands[1].imm;
+             narrow = TRUE;
            }
-         else
+         else if (inst.operands[0] .reg == REG_SP
+                  && inst.operands[0].writeback)
            {
-             if (inst.operands[1].imm & (1 << 14)
-                 && inst.operands[1].imm & (1 << 15))
-               as_warn (_("LR and PC should not both be in register list"));
-             if ((inst.operands[1].imm & (1 << inst.operands[0].reg))
-                 && inst.operands[0].writeback)
-               as_warn (_("base register should not be in register list "
-                          "when written back"));
+             inst.instruction = THUMB_OP16 (inst.instruction == T_MNEM_stmia
+                                            ? T_MNEM_push : T_MNEM_pop);
+             inst.instruction |= inst.operands[1].imm;
+             narrow = TRUE;
            }
+       }
+
+      if (!narrow)
+       {
          if (inst.instruction < 0xffff)
            inst.instruction = THUMB_OP32 (inst.instruction);
-         inst.instruction |= inst.operands[0].reg << 16;
-         inst.instruction |= inst.operands[1].imm;
-         if (inst.operands[0].writeback)
-           inst.instruction |= WRITE_BACK;
+
+         encode_thumb2_ldmstm(inst.operands[0].reg, inst.operands[1].imm,
+                              inst.operands[0].writeback);
        }
     }
   else
@@ -9833,7 +9892,7 @@ do_t_push_pop (void)
 
   mask = inst.operands[0].imm;
   if ((mask & ~0xff) == 0)
-    inst.instruction = THUMB_OP16 (inst.instruction);
+    inst.instruction = THUMB_OP16 (inst.instruction) | mask;
   else if ((inst.instruction == T_MNEM_push
            && (mask & ~0xff) == 1 << REG_LR)
           || (inst.instruction == T_MNEM_pop
@@ -9841,43 +9900,18 @@ do_t_push_pop (void)
     {
       inst.instruction = THUMB_OP16 (inst.instruction);
       inst.instruction |= THUMB_PP_PC_LR;
-      mask &= 0xff;
+      inst.instruction |= mask & 0xff;
     }
   else if (unified_syntax)
     {
-      if (mask & (1 << 13))
-       inst.error =  _("SP not allowed in register list");
-      if (inst.instruction == T_MNEM_push)
-       {
-         if (mask & (1 << 15))
-           inst.error = _("PC not allowed in register list");
-       }
-      else
-       {
-         if (mask & (1 << 14)
-             && mask & (1 << 15))
-           inst.error = _("LR and PC should not both be in register list");
-       }
-      if ((mask & (mask - 1)) == 0)
-       {
-         /* Single register push/pop implemented as str/ldr.  */
-         if (inst.instruction == T_MNEM_push)
-           inst.instruction = 0xf84d0d04; /* str reg, [sp, #-4]! */
-         else
-           inst.instruction = 0xf85d0b04; /* ldr reg, [sp], #4 */
-         mask = ffs(mask) - 1;
-         mask <<= 12;
-       }
-      else
-       inst.instruction = THUMB_OP32 (inst.instruction);
+      inst.instruction = THUMB_OP32 (inst.instruction);
+      encode_thumb2_ldmstm(13, mask, TRUE);
     }
   else
     {
       inst.error = _("invalid register list to push/pop instruction");
       return;
     }
-
-  inst.instruction |= mask;
 }
 
 static void
index 7397508de4822e15cc7f752d3d0de634dcb2f4d2..bb7be0aaba68c53034e26e220249a4981d6606fb 100644 (file)
@@ -1,3 +1,8 @@
+2007-03-30  Paul Brook  <paul@codesourcery.com>
+
+       * gas/arm/thumb2_ldmstm.d: New test.
+       * gas/arm/thumb2_ldmstm.s: New test.
+
 2007-03-27  Alan Modra  <amodra@bigpond.net.au>
 
        * gas/ppc/reloc.s: New.
diff --git a/gas/testsuite/gas/arm/thumb2_ldmstm.d b/gas/testsuite/gas/arm/thumb2_ldmstm.d
new file mode 100644 (file)
index 0000000..2f50486
--- /dev/null
@@ -0,0 +1,27 @@
+# name: Thumb-2 LDM/STM single reg
+# as: -march=armv6t2
+# objdump: -dr --prefix-addresses --show-raw-insn
+
+.*: +file format .*arm.*
+
+Disassembly of section .text:
+0[0-9a-f]+ <[^>]+> bc01        pop     {r0}
+0[0-9a-f]+ <[^>]+> f85d 8b04   ldr.w   r8, \[sp\], #4
+0[0-9a-f]+ <[^>]+> f8d1 9000   ldr.w   r9, \[r1\]
+0[0-9a-f]+ <[^>]+> f852 cb04   ldr.w   ip, \[r2\], #4
+0[0-9a-f]+ <[^>]+> f85d 2d04   ldr.w   r2, \[sp, #-4\]!
+0[0-9a-f]+ <[^>]+> f85d 8d04   ldr.w   r8, \[sp, #-4\]!
+0[0-9a-f]+ <[^>]+> f856 4c04   ldr.w   r4, \[r6, #-4\]
+0[0-9a-f]+ <[^>]+> f856 8c04   ldr.w   r8, \[r6, #-4\]
+0[0-9a-f]+ <[^>]+> f852 4d04   ldr.w   r4, \[r2, #-4\]!
+0[0-9a-f]+ <[^>]+> f852 cd04   ldr.w   ip, \[r2, #-4\]!
+0[0-9a-f]+ <[^>]+> b408        push    {r3}
+0[0-9a-f]+ <[^>]+> f84d 9b04   str.w   r9, \[sp\], #4
+0[0-9a-f]+ <[^>]+> f8c3 c000   str.w   ip, \[r3\]
+0[0-9a-f]+ <[^>]+> f844 cb04   str.w   ip, \[r4\], #4
+0[0-9a-f]+ <[^>]+> f84d 3d04   str.w   r3, \[sp, #-4\]!
+0[0-9a-f]+ <[^>]+> f84d 9d04   str.w   r9, \[sp, #-4\]!
+0[0-9a-f]+ <[^>]+> f847 5c04   str.w   r5, \[r7, #-4\]
+0[0-9a-f]+ <[^>]+> f846 cc04   str.w   ip, \[r6, #-4\]
+0[0-9a-f]+ <[^>]+> f846 bd04   str.w   fp, \[r6, #-4\]!
+0[0-9a-f]+ <[^>]+> f845 8d04   str.w   r8, \[r5, #-4\]!
diff --git a/gas/testsuite/gas/arm/thumb2_ldmstm.s b/gas/testsuite/gas/arm/thumb2_ldmstm.s
new file mode 100644 (file)
index 0000000..fd4410a
--- /dev/null
@@ -0,0 +1,24 @@
+.syntax unified
+.thumb
+ldmstm:
+       ldmia sp!, {r0}
+       ldmia sp!, {r8}
+       ldmia r1, {r9}
+       ldmia r2!, {ip}
+       ldmdb sp!, {r2}
+       ldmdb sp!, {r8}
+       ldmdb r6, {r4}
+       ldmdb r6, {r8}
+       ldmdb r2!, {r4}
+       ldmdb r2!, {ip}
+       stmia sp!, {r3}
+       stmia sp!, {r9}
+       stmia r3, {ip}
+       stmia r4!, {ip}
+       stmdb sp!, {r3}
+       stmdb sp!, {r9}
+       stmdb r7, {r5}
+       stmdb r6, {ip}
+       stmdb r6!, {fp}
+       stmdb r5!, {r8}
+