arm.c (arm_expand_prologue): In a nested APCS frame with arguments to push onto the...
authorEric Botcazou <ebotcazou@gcc.gnu.org>
Fri, 20 Dec 2013 16:46:37 +0000 (16:46 +0000)
committerEric Botcazou <ebotcazou@gcc.gnu.org>
Fri, 20 Dec 2013 16:46:37 +0000 (16:46 +0000)
* config/arm/arm.c (arm_expand_prologue): In a nested APCS frame with
arguments to push onto the stack and no varargs, save ip into the last
stack slot if r3 isn't available on entry.

From-SVN: r206154

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

index 2f4f57e1296429633b84ad3ef4c51478901bd7f2..c7a8c254fb854dd4727bbe3901a2cd6e104b02f2 100644 (file)
@@ -1,3 +1,9 @@
+2013-12-20  Eric Botcazou  <ebotcazou@adacore.com>
+
+       * config/arm/arm.c (arm_expand_prologue): In a nested APCS frame with
+       arguments to push onto the stack and no varargs, save ip into the last
+       stack slot if r3 isn't available on entry.
+
 2013-12-20  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
 
        * config/arm/neon.ml (crypto_intrinsics): Add vceq_64 and vtst_p64.
index 8c6eaaa66959a4d8564925fd30833d9aa861efb8..706846e909f5aa70547c382947724e89900c635d 100644 (file)
@@ -18679,8 +18679,7 @@ arm_r3_live_at_start_p (void)
   /* Just look at cfg info, which is still close enough to correct at this
      point.  This gives false positives for broken functions that might use
      uninitialized data that happens to be allocated in r3, but who cares?  */
-  return REGNO_REG_SET_P (df_get_live_out (ENTRY_BLOCK_PTR_FOR_FN (cfun)),
-                         3);
+  return REGNO_REG_SET_P (df_get_live_out (ENTRY_BLOCK_PTR_FOR_FN (cfun)), 3);
 }
 
 /* Compute the number of bytes used to store the static chain register on the
@@ -20706,11 +20705,13 @@ arm_expand_prologue (void)
             whilst the frame is being created.  We try the following
             places in order:
 
-              1. The last argument register r3.
-              2. A slot on the stack above the frame.  (This only
-                 works if the function is not a varargs function).
+              1. The last argument register r3 if it is available.
+              2. A slot on the stack above the frame if there are no
+                 arguments to push onto the stack.
               3. Register r3 again, after pushing the argument registers
-                 onto the stack.
+                 onto the stack, if this is a varargs function.
+              4. The last slot on the stack created for the arguments to
+                 push, if this isn't a varargs function.
 
             Note - we only need to tell the dwarf2 backend about the SP
             adjustment in the second variant; the static chain register
@@ -20721,13 +20722,13 @@ arm_expand_prologue (void)
            insn = emit_set_insn (gen_rtx_REG (SImode, 3), ip_rtx);
          else if (args_to_push == 0)
            {
-             rtx dwarf;
+             rtx addr, dwarf;
 
              gcc_assert(arm_compute_static_chain_stack_bytes() == 4);
              saved_regs += 4;
 
-             insn = gen_rtx_PRE_DEC (SImode, stack_pointer_rtx);
-             insn = emit_set_insn (gen_frame_mem (SImode, insn), ip_rtx);
+             addr = gen_rtx_PRE_DEC (Pmode, stack_pointer_rtx);
+             insn = emit_set_insn (gen_frame_mem (SImode, addr), ip_rtx);
              fp_offset = 4;
 
              /* Just tell the dwarf backend that we adjusted SP.  */
@@ -20741,21 +20742,38 @@ arm_expand_prologue (void)
            {
              /* Store the args on the stack.  */
              if (cfun->machine->uses_anonymous_args)
-               insn = emit_multi_reg_push
-                 ((0xf0 >> (args_to_push / 4)) & 0xf);
+               {
+                 insn
+                   = emit_multi_reg_push ((0xf0 >> (args_to_push / 4)) & 0xf);
+                 emit_set_insn (gen_rtx_REG (SImode, 3), ip_rtx);
+                 saved_pretend_args = 1;
+               }
              else
-               insn = emit_insn
-                 (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
-                              GEN_INT (- args_to_push)));
+               {
+                 rtx addr, dwarf;
 
-             RTX_FRAME_RELATED_P (insn) = 1;
+                 if (args_to_push == 4)
+                   addr = gen_rtx_PRE_DEC (Pmode, stack_pointer_rtx);
+                 else
+                   addr
+                     = gen_rtx_PRE_MODIFY (Pmode, stack_pointer_rtx,
+                                           plus_constant (Pmode,
+                                                          stack_pointer_rtx,
+                                                          -args_to_push));
+
+                 insn = emit_set_insn (gen_frame_mem (SImode, addr), ip_rtx);
 
-             saved_pretend_args = 1;
+                 /* Just tell the dwarf backend that we adjusted SP.  */
+                 dwarf
+                   = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
+                                  plus_constant (Pmode, stack_pointer_rtx,
+                                                 -args_to_push));
+                 add_reg_note (insn, REG_FRAME_RELATED_EXPR, dwarf);
+               }
+
+             RTX_FRAME_RELATED_P (insn) = 1;
              fp_offset = args_to_push;
              args_to_push = 0;
-
-             /* Now reuse r3 to preserve IP.  */
-             emit_set_insn (gen_rtx_REG (SImode, 3), ip_rtx);
            }
        }
 
@@ -20861,7 +20879,7 @@ arm_expand_prologue (void)
              /* Recover the static chain register.  */
              if (!arm_r3_live_at_start_p () || saved_pretend_args)
                insn = gen_rtx_REG (SImode, 3);
-             else /* if (crtl->args.pretend_args_size == 0) */
+             else
                {
                  insn = plus_constant (Pmode, hard_frame_pointer_rtx, 4);
                  insn = gen_frame_mem (SImode, insn);
index 73f0cb904a289ac9b999bff96e72eea5fc5e9abf..ac0b7e0acc4f3132eec1d71f5425c11b108774f6 100644 (file)
@@ -1,3 +1,7 @@
+2013-12-20  Richard Earnshaw  <rearnsha@arm.com>
+
+       * gcc.target/arm/nested-apcs.c: New test.
+
 2013-12-20  Jakub Jelinek  <jakub@redhat.com>
 
        PR c++/59255
diff --git a/gcc/testsuite/gcc.target/arm/nested-apcs.c b/gcc/testsuite/gcc.target/arm/nested-apcs.c
new file mode 100644 (file)
index 0000000..9dac304
--- /dev/null
@@ -0,0 +1,34 @@
+/* { dg-do run } */
+/* { dg-options "-fno-omit-frame-pointer -mapcs-frame -O" } */
+
+extern void abort (void);
+
+struct x
+{
+  int y;
+  int z;
+};
+
+int __attribute__((noinline)) f (int c, int d, int e, int h, int i)
+{
+  int a;
+  struct x b;
+
+  int __attribute__((noinline)) g (int p, int q, int r, struct x s)
+  {
+    return a + p + q + r + s.y + s.z;
+  }
+
+  a = 5;
+  b.y = h;
+  b.z = i;
+
+  return g(c, d, e, b);
+}
+
+int main(void)
+{
+  if (f (1, 2, 3, 4, 5) != 20)
+    abort();
+  return 0;
+}