re PR target/40657 (allocate local variables with fewer instructions)
authorBernd Schmidt <bernds@codesourcery.com>
Tue, 27 Apr 2010 09:34:08 +0000 (09:34 +0000)
committerBernd Schmidt <bernds@gcc.gnu.org>
Tue, 27 Apr 2010 09:34:08 +0000 (09:34 +0000)
PR target/40657
* config/arm/arm.c (thumb1_extra_regs_pushed): New function.
(thumb1_expand_prologue, thumb1_output_function_prologue): Call it
here to determine which regs to push and how much stack to reserve.

PR target/40657
* gcc.target/arm/thumb-stackframe.c: New test.

From-SVN: r158771

gcc/ChangeLog
gcc/config/arm/arm.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/arm/thumb-stackframe.c [new file with mode: 0644]

index 4f0e259..95444f1 100644 (file)
@@ -1,3 +1,10 @@
+2010-04-27  Bernd Schmidt  <bernds@codesourcery.com>
+
+       PR target/40657
+       * config/arm/arm.c (thumb1_extra_regs_pushed): New function.
+       (thumb1_expand_prologue, thumb1_output_function_prologue): Call it
+       here to determine which regs to push and how much stack to reserve.
+
 2010-04-27  Jie Zhang  <jie@codesourcery.com>
 
        * doc/gimple.texi (gimple_statement_with_ops): Remove
index 8d21b87..72d5473 100644 (file)
@@ -19402,6 +19402,51 @@ thumb_compute_initial_elimination_offset (unsigned int from, unsigned int to)
     }
 }
 
+/* Given the stack offsets and register mask in OFFSETS, decide
+   how many additional registers to push instead of subtracting
+   a constant from SP.  */
+static int
+thumb1_extra_regs_pushed (arm_stack_offsets *offsets)
+{
+  HOST_WIDE_INT amount = offsets->outgoing_args - offsets->saved_regs;
+  unsigned long live_regs_mask = offsets->saved_regs_mask;
+  /* Extract a mask of the ones we can give to the Thumb's push instruction.  */
+  unsigned long l_mask = live_regs_mask & 0x40ff;
+  /* Then count how many other high registers will need to be pushed.  */
+  unsigned long high_regs_pushed = bit_count (live_regs_mask & 0x0f00);
+  int n_free;
+
+  /* If the stack frame size is 512 exactly, we can save one load
+     instruction, which should make this a win even when optimizing
+     for speed.  */
+  if (!optimize_size && amount != 512)
+    return 0;
+
+  /* Can't do this if there are high registers to push, or if we
+     are not going to do a push at all.  */
+  if (high_regs_pushed != 0 || l_mask == 0)
+    return 0;
+
+  /* Don't do this if thumb1_expand_prologue wants to emit instructions
+     between the push and the stack frame allocation.  */
+  if ((flag_pic && arm_pic_register != INVALID_REGNUM)
+      || (!frame_pointer_needed && CALLER_INTERWORKING_SLOT_SIZE > 0))
+    return 0;
+
+  for (n_free = 0; n_free < 8 && !(live_regs_mask & 1); live_regs_mask >>= 1)
+    n_free++;
+
+  if (n_free == 0)
+    return 0;
+  gcc_assert (amount / 4 * 4 == amount);
+
+  if (amount >= 512 && (amount - n_free * 4) < 512)
+    return (amount - 508) / 4;
+  if (amount <= n_free * 4)
+    return amount / 4;
+  return 0;
+}
+
 /* Generate the rest of a function's prologue.  */
 void
 thumb1_expand_prologue (void)
@@ -19438,6 +19483,7 @@ thumb1_expand_prologue (void)
                    stack_pointer_rtx);
 
   amount = offsets->outgoing_args - offsets->saved_regs;
+  amount -= 4 * thumb1_extra_regs_pushed (offsets);
   if (amount)
     {
       if (amount < 512)
@@ -19742,7 +19788,11 @@ thumb1_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
      register.  */
   else if ((l_mask & 0xff) != 0
           || (high_regs_pushed == 0 && l_mask))
-    thumb_pushpop (f, l_mask, 1, &cfa_offset, l_mask);
+    {
+      unsigned long mask = l_mask;
+      mask |= (1 << thumb1_extra_regs_pushed (offsets)) - 1;
+      thumb_pushpop (f, mask, 1, &cfa_offset, mask);
+    }
 
   if (high_regs_pushed)
     {
index 21640d6..e3b7527 100644 (file)
@@ -1,3 +1,8 @@
+2010-04-27  Bernd Schmidt  <bernds@codesourcery.com>
+
+       PR target/40657
+       * gcc.target/arm/thumb-stackframe.c: New test.
+
 2010-04-27  Shujing Zhao  <pearly.zhao@oracle.com>
        
        * gcc.dg/pr32207.c: Fix typo in expected warning messages.
diff --git a/gcc/testsuite/gcc.target/arm/thumb-stackframe.c b/gcc/testsuite/gcc.target/arm/thumb-stackframe.c
new file mode 100644 (file)
index 0000000..f6c7880
--- /dev/null
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-mthumb -Os" }  */
+/* { dg-require-effective-target arm_thumb1_ok } */
+
+extern void bar(int*);
+int foo()
+{
+  int x;
+  bar(&x);
+  return x;
+}
+
+/* { dg-final { scan-assembler-not "sub\[\\t \]*sp,\[\\t \]*sp," } } */