arm.c (arm_compute_static_chain_stack_bytes): New function.
authorAndrew Jenner <andrew@codesourcery.com>
Wed, 30 Jul 2008 16:28:01 +0000 (16:28 +0000)
committerAndrew Jenner <andrewjenner@gcc.gnu.org>
Wed, 30 Jul 2008 16:28:01 +0000 (16:28 +0000)
* config/arm/arm.c (arm_compute_static_chain_stack_bytes): New
function.
(arm_compute_initial_elimination_offset): Use it.
(arm_compute_save_reg_mask): Include static chain save slot when
calculating alignment.
(arm_get_frame_offsets): Ditto.
(thumb1_compute_save_reg_mask): Ensure we have a low register saved
that we can use to decrement the stack when the stack decrement
could be too big for an immediate value in a single insn.
(thumb1_expand_prologue): Avoid using r12 for stack decrement.

From-SVN: r138327

gcc/ChangeLog
gcc/config/arm/arm.c

index 474cc2cc90cd96672e02e9eb0c33b0b7473aa814..2951220b6eb25cdf50fbd30d4e394b4ac1f6a58b 100644 (file)
@@ -1,3 +1,16 @@
+2008-07-30  Andrew Jenner  <andrew@codesourcery.com>
+
+       * config/arm/arm.c (arm_compute_static_chain_stack_bytes): New
+        function.
+       (arm_compute_initial_elimination_offset): Use it.
+       (arm_compute_save_reg_mask): Include static chain save slot when
+       calculating alignment.
+       (arm_get_frame_offsets): Ditto.
+       (thumb1_compute_save_reg_mask): Ensure we have a low register saved
+       that we can use to decrement the stack when the stack decrement
+       could be too big for an immediate value in a single insn.
+       (thumb1_expand_prologue): Avoid using r12 for stack decrement.
+
 2008-07-30  Richard Guenther  <rguenther@suse.de>
 
        PR tree-optimization/36967
index 7410517d6c8fc6e06b75c7edd05a2d7c6b449e5c..a89229ec12ac99455170d01bd690ab9bbb3864ad 100644 (file)
@@ -62,6 +62,7 @@ const struct attribute_spec arm_attribute_table[];
 void (*arm_lang_output_object_attributes_hook)(void);
 
 /* Forward function declarations.  */
+static int arm_compute_static_chain_stack_bytes (void);
 static arm_stack_offsets *arm_get_frame_offsets (void);
 static void arm_add_gc_roots (void);
 static int arm_gen_constant (enum rtx_code, enum machine_mode, rtx,
@@ -10792,6 +10793,24 @@ arm_compute_save_reg0_reg12_mask (void)
 }
 
 
+/* Compute the number of bytes used to store the static chain register on the 
+   stack, above the stack frame. We need to know this accurately to get the
+   alignment of the rest of the stack frame correct. */
+
+static int arm_compute_static_chain_stack_bytes (void)
+{
+  unsigned long func_type = arm_current_func_type ();
+  int static_chain_stack_bytes = 0;
+
+  if (TARGET_APCS_FRAME && frame_pointer_needed && TARGET_ARM &&
+      IS_NESTED (func_type) &&
+      df_regs_ever_live_p (3) && crtl->args.pretend_args_size == 0)
+    static_chain_stack_bytes = 4;
+
+  return static_chain_stack_bytes;
+}
+
+
 /* Compute a bit mask of which registers need to be
    saved on the stack for the current function.
    This is used by arm_get_frame_offsets, which may add extra registers.  */
@@ -10844,7 +10863,9 @@ arm_compute_save_reg_mask (void)
 
   if (TARGET_REALLY_IWMMXT
       && ((bit_count (save_reg_mask)
-          + ARM_NUM_INTS (crtl->args.pretend_args_size)) % 2) != 0)
+          + ARM_NUM_INTS (crtl->args.pretend_args_size +
+                          arm_compute_static_chain_stack_bytes())
+          ) % 2) != 0)
     {
       /* The total number of registers that are going to be pushed
         onto the stack is odd.  We need to ensure that the stack
@@ -10929,6 +10950,26 @@ thumb1_compute_save_reg_mask (void)
        mask |= 1 << reg;
     }
 
+  /* The 504 below is 8 bytes less than 512 because there are two possible
+     alignment words.  We can't tell here if they will be present or not so we
+     have to play it safe and assume that they are. */
+  if ((CALLER_INTERWORKING_SLOT_SIZE +
+       ROUND_UP_WORD (get_frame_size ()) +
+       crtl->outgoing_args_size) >= 504)
+    {
+      /* This is the same as the code in thumb1_expand_prologue() which
+        determines which register to use for stack decrement. */
+      for (reg = LAST_ARG_REGNUM + 1; reg <= LAST_LO_REGNUM; reg++)
+       if (mask & (1 << reg))
+         break;
+
+      if (reg > LAST_LO_REGNUM)
+       {
+         /* Make sure we have a register available for stack decrement. */
+         mask |= 1 << LAST_LO_REGNUM;
+       }
+    }
+
   return mask;
 }
 
@@ -12064,7 +12105,8 @@ arm_get_frame_offsets (void)
   offsets->saved_args = crtl->args.pretend_args_size;
 
   /* In Thumb mode this is incorrect, but never used.  */
-  offsets->frame = offsets->saved_args + (frame_pointer_needed ? 4 : 0);
+  offsets->frame = offsets->saved_args + (frame_pointer_needed ? 4 : 0) +
+                   arm_compute_static_chain_stack_bytes();
 
   if (TARGET_32BIT)
     {
@@ -12111,7 +12153,8 @@ arm_get_frame_offsets (void)
     }
 
   /* Saved registers include the stack frame.  */
-  offsets->saved_regs = offsets->saved_args + saved;
+  offsets->saved_regs = offsets->saved_args + saved +
+                        arm_compute_static_chain_stack_bytes();
   offsets->soft_frame = offsets->saved_regs + CALLER_INTERWORKING_SLOT_SIZE;
   /* A leaf function does not need any stack alignment if it has nothing
      on the stack.  */
@@ -12203,14 +12246,9 @@ arm_compute_initial_elimination_offset (unsigned int from, unsigned int to)
          return offsets->soft_frame - offsets->saved_args;
 
        case ARM_HARD_FRAME_POINTER_REGNUM:
-         /* If there is no stack frame then the hard
-            frame pointer and the arg pointer coincide.  */
-         if (offsets->frame == offsets->saved_regs)
-           return 0;
-         /* FIXME:  Not sure about this.  Maybe we should always return 0 ?  */
-         return (frame_pointer_needed
-                 && cfun->static_chain_decl != NULL
-                 && ! cfun->machine->uses_anonymous_args) ? 4 : 0;
+         /* This is only non-zero in the case where the static chain register
+            is stored above the frame.  */
+         return offsets->frame - offsets->saved_args - 4;
 
        case STACK_POINTER_REGNUM:
          /* If nothing has been pushed on the stack at all
@@ -12498,6 +12536,9 @@ arm_expand_prologue (void)
            insn = emit_set_insn (gen_rtx_REG (SImode, 3), ip_rtx);
          else if (args_to_push == 0)
            {
+             gcc_assert(arm_compute_static_chain_stack_bytes() == 4);
+             saved_regs += 4;
+
              rtx dwarf;
 
              insn = gen_rtx_PRE_DEC (SImode, stack_pointer_rtx);
@@ -17008,62 +17049,25 @@ thumb1_expand_prologue (void)
             been pushed at the start of the prologue and so we can corrupt
             it now.  */
          for (regno = LAST_ARG_REGNUM + 1; regno <= LAST_LO_REGNUM; regno++)
-           if (live_regs_mask & (1 << regno)
-               && !(frame_pointer_needed
-                    && (regno == THUMB_HARD_FRAME_POINTER_REGNUM)))
+           if (live_regs_mask & (1 << regno))
              break;
 
-         if (regno > LAST_LO_REGNUM) /* Very unlikely.  */
-           {
-             rtx spare = gen_rtx_REG (SImode, IP_REGNUM);
-
-             /* Choose an arbitrary, non-argument low register.  */
-             reg = gen_rtx_REG (SImode, LAST_LO_REGNUM);
-
-             /* Save it by copying it into a high, scratch register.  */
-             emit_insn (gen_movsi (spare, reg));
-             /* Add a USE to stop propagate_one_insn() from barfing.  */
-             emit_insn (gen_prologue_use (spare));
+         gcc_assert(regno <= LAST_LO_REGNUM);
 
-             /* Decrement the stack.  */
-             emit_insn (gen_movsi (reg, GEN_INT (- amount)));
-             insn = emit_insn (gen_addsi3 (stack_pointer_rtx,
-                                           stack_pointer_rtx, reg));
-             RTX_FRAME_RELATED_P (insn) = 1;
-             dwarf = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
-                                  plus_constant (stack_pointer_rtx,
-                                                 -amount));
-             RTX_FRAME_RELATED_P (dwarf) = 1;
-             REG_NOTES (insn)
-               = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
-                                    REG_NOTES (insn));
-
-             /* Restore the low register's original value.  */
-             emit_insn (gen_movsi (reg, spare));
-
-             /* Emit a USE of the restored scratch register, so that flow
-                analysis will not consider the restore redundant.  The
-                register won't be used again in this function and isn't
-                restored by the epilogue.  */
-             emit_insn (gen_prologue_use (reg));
-           }
-         else
-           {
-             reg = gen_rtx_REG (SImode, regno);
+         reg = gen_rtx_REG (SImode, regno);
 
-             emit_insn (gen_movsi (reg, GEN_INT (- amount)));
+         emit_insn (gen_movsi (reg, GEN_INT (- amount)));
 
-             insn = emit_insn (gen_addsi3 (stack_pointer_rtx,
-                                           stack_pointer_rtx, reg));
-             RTX_FRAME_RELATED_P (insn) = 1;
-             dwarf = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
-                                  plus_constant (stack_pointer_rtx,
-                                                 -amount));
-             RTX_FRAME_RELATED_P (dwarf) = 1;
-             REG_NOTES (insn)
-               = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
-                                    REG_NOTES (insn));
-           }
+         insn = emit_insn (gen_addsi3 (stack_pointer_rtx,
+                                       stack_pointer_rtx, reg));
+         RTX_FRAME_RELATED_P (insn) = 1;
+         dwarf = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
+                              plus_constant (stack_pointer_rtx,
+                                             -amount));
+         RTX_FRAME_RELATED_P (dwarf) = 1;
+         REG_NOTES (insn)
+           = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
+                                REG_NOTES (insn));
        }
     }