function.c (try_fit_stack_local, [...]): New static functions.
authorBernd Schmidt <bernds@codesourcery.com>
Mon, 17 May 2010 11:16:00 +0000 (11:16 +0000)
committerBernd Schmidt <bernds@gcc.gnu.org>
Mon, 17 May 2010 11:16:00 +0000 (11:16 +0000)
* function.c (try_fit_stack_local, add_frame_space): New static
functions.
(assign_stack_local_1): Use them.  Look for opportunities to use
space previously wasted on alignment.
* function.h (struct frame_space): New.
(struct rtl_data): Add FRAME_SPACE_LIST member.
* reload1.c (something_was_spilled): New static variable.
(alter_reg): Set it.
(reload): Test it in addition to testing if the frame size changed.

From-SVN: r159480

gcc/ChangeLog
gcc/function.c
gcc/function.h
gcc/reload1.c

index 7482a367f7cfc971d3ba056fc1f6d8a19f422d5c..e53fc44d79c66325648f81882edf821b997f3a5e 100644 (file)
@@ -1,3 +1,15 @@
+2010-05-17  Bernd Schmidt  <bernds@codesourcery.com>
+
+       * function.c (try_fit_stack_local, add_frame_space): New static
+       functions.
+       (assign_stack_local_1): Use them.  Look for opportunities to use
+       space previously wasted on alignment.
+       * function.h (struct frame_space): New.
+       (struct rtl_data): Add FRAME_SPACE_LIST member.
+       * reload1.c (something_was_spilled): New static variable.
+       (alter_reg): Set it.
+       (reload): Test it in addition to testing if the frame size changed.
+
 2010-05-17  Christian Borntraeger  <borntraeger@de.ibm.com>
 
         * config/s390/s390.c: Define sane prefetch settings and activate
index 949480ca9d0826232432f2dbe05201b592032759..5d0e7e5c9543de5e06a947a5205dfe5dd03c908b 100644 (file)
@@ -278,6 +278,75 @@ get_stack_local_alignment (tree type, enum machine_mode mode)
   return STACK_SLOT_ALIGNMENT (type, mode, alignment);
 }
 
+/* Determine whether it is possible to fit a stack slot of size SIZE and
+   alignment ALIGNMENT into an area in the stack frame that starts at
+   frame offset START and has a length of LENGTH.  If so, store the frame
+   offset to be used for the stack slot in *POFFSET and return true;
+   return false otherwise.  This function will extend the frame size when
+   given a start/length pair that lies at the end of the frame.  */
+
+static bool
+try_fit_stack_local (HOST_WIDE_INT start, HOST_WIDE_INT length,
+                    HOST_WIDE_INT size, unsigned int alignment,
+                    HOST_WIDE_INT *poffset)
+{
+  HOST_WIDE_INT this_frame_offset;
+  int frame_off, frame_alignment, frame_phase;
+
+  /* Calculate how many bytes the start of local variables is off from
+     stack alignment.  */
+  frame_alignment = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT;
+  frame_off = STARTING_FRAME_OFFSET % frame_alignment;
+  frame_phase = frame_off ? frame_alignment - frame_off : 0;
+
+  /* Round the frame offset to the specified alignment.  */
+
+  /*  We must be careful here, since FRAME_OFFSET might be negative and
+      division with a negative dividend isn't as well defined as we might
+      like.  So we instead assume that ALIGNMENT is a power of two and
+      use logical operations which are unambiguous.  */
+  if (FRAME_GROWS_DOWNWARD)
+    this_frame_offset
+      = (FLOOR_ROUND (start + length - size - frame_phase,
+                     (unsigned HOST_WIDE_INT) alignment)
+        + frame_phase);
+  else
+    this_frame_offset
+      = (CEIL_ROUND (start - frame_phase,
+                    (unsigned HOST_WIDE_INT) alignment)
+        + frame_phase);
+
+  /* See if it fits.  If this space is at the edge of the frame,
+     consider extending the frame to make it fit.  Our caller relies on
+     this when allocating a new slot.  */
+  if (frame_offset == start && this_frame_offset < frame_offset)
+    frame_offset = this_frame_offset;
+  else if (this_frame_offset < start)
+    return false;
+  else if (start + length == frame_offset
+          && this_frame_offset + size > start + length)
+    frame_offset = this_frame_offset + size;
+  else if (this_frame_offset + size > start + length)
+    return false;
+
+  *poffset = this_frame_offset;
+  return true;
+}
+
+/* Create a new frame_space structure describing free space in the stack
+   frame beginning at START and ending at END, and chain it into the
+   function's frame_space_list.  */
+
+static void
+add_frame_space (HOST_WIDE_INT start, HOST_WIDE_INT end)
+{
+  struct frame_space *space = GGC_NEW (struct frame_space);
+  space->next = crtl->frame_space_list;
+  crtl->frame_space_list = space;
+  space->start = start;
+  space->length = end - start;
+}
+
 /* Allocate a stack slot of SIZE bytes and return a MEM rtx for it
    with machine mode MODE.
 
@@ -298,8 +367,8 @@ assign_stack_local_1 (enum machine_mode mode, HOST_WIDE_INT size,
 {
   rtx x, addr;
   int bigend_correction = 0;
+  HOST_WIDE_INT slot_offset, old_frame_offset;
   unsigned int alignment, alignment_in_bits;
-  int frame_off, frame_alignment, frame_phase;
 
   if (align == 0)
     {
@@ -318,9 +387,6 @@ assign_stack_local_1 (enum machine_mode mode, HOST_WIDE_INT size,
 
   alignment_in_bits = alignment * BITS_PER_UNIT;
 
-  if (FRAME_GROWS_DOWNWARD)
-    frame_offset -= size;
-
   /* Ignore alignment if it exceeds MAX_SUPPORTED_STACK_ALIGNMENT.  */
   if (alignment_in_bits > MAX_SUPPORTED_STACK_ALIGNMENT)
     {
@@ -363,35 +429,55 @@ assign_stack_local_1 (enum machine_mode mode, HOST_WIDE_INT size,
   if (crtl->max_used_stack_slot_alignment < alignment_in_bits)
     crtl->max_used_stack_slot_alignment = alignment_in_bits;
 
-  /* Calculate how many bytes the start of local variables is off from
-     stack alignment.  */
-  frame_alignment = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT;
-  frame_off = STARTING_FRAME_OFFSET % frame_alignment;
-  frame_phase = frame_off ? frame_alignment - frame_off : 0;
+  if (mode != BLKmode || size != 0)
+    {
+      struct frame_space **psp;
 
-  /* Round the frame offset to the specified alignment.  The default is
-     to always honor requests to align the stack but a port may choose to
-     do its own stack alignment by defining STACK_ALIGNMENT_NEEDED.  */
-  if (STACK_ALIGNMENT_NEEDED
-      || mode != BLKmode
-      || size != 0)
+      for (psp = &crtl->frame_space_list; *psp; psp = &(*psp)->next)
+       {
+         struct frame_space *space = *psp;
+         if (!try_fit_stack_local (space->start, space->length, size,
+                                   alignment, &slot_offset))
+           continue;
+         *psp = space->next;
+         if (slot_offset > space->start)
+           add_frame_space (space->start, slot_offset);
+         if (slot_offset + size < space->start + space->length)
+           add_frame_space (slot_offset + size,
+                            space->start + space->length);
+         goto found_space;
+       }
+    }
+  else if (!STACK_ALIGNMENT_NEEDED)
     {
-      /*  We must be careful here, since FRAME_OFFSET might be negative and
-         division with a negative dividend isn't as well defined as we might
-         like.  So we instead assume that ALIGNMENT is a power of two and
-         use logical operations which are unambiguous.  */
-      if (FRAME_GROWS_DOWNWARD)
-       frame_offset
-         = (FLOOR_ROUND (frame_offset - frame_phase,
-                         (unsigned HOST_WIDE_INT) alignment)
-            + frame_phase);
-      else
-       frame_offset
-         = (CEIL_ROUND (frame_offset - frame_phase,
-                        (unsigned HOST_WIDE_INT) alignment)
-            + frame_phase);
+      slot_offset = frame_offset;
+      goto found_space;
+    }
+
+  old_frame_offset = frame_offset;
+
+  if (FRAME_GROWS_DOWNWARD)
+    {
+      frame_offset -= size;
+      try_fit_stack_local (frame_offset, size, size, alignment, &slot_offset);
+
+      if (slot_offset > frame_offset)
+       add_frame_space (frame_offset, slot_offset);
+      if (slot_offset + size < old_frame_offset)
+       add_frame_space (slot_offset + size, old_frame_offset);
+    }
+  else
+    {
+      frame_offset += size;
+      try_fit_stack_local (old_frame_offset, size, size, alignment, &slot_offset);
+
+      if (slot_offset > old_frame_offset)
+       add_frame_space (old_frame_offset, slot_offset);
+      if (slot_offset + size < frame_offset)
+       add_frame_space (slot_offset + size, frame_offset);
     }
 
+ found_space:
   /* On a big-endian machine, if we are allocating more space than we will use,
      use the least significant bytes of those that are allocated.  */
   if (BYTES_BIG_ENDIAN && mode != BLKmode && GET_MODE_SIZE (mode) < size)
@@ -402,17 +488,14 @@ assign_stack_local_1 (enum machine_mode mode, HOST_WIDE_INT size,
   if (virtuals_instantiated)
     addr = plus_constant (frame_pointer_rtx,
                          trunc_int_for_mode
-                         (frame_offset + bigend_correction
+                         (slot_offset + bigend_correction
                           + STARTING_FRAME_OFFSET, Pmode));
   else
     addr = plus_constant (virtual_stack_vars_rtx,
                          trunc_int_for_mode
-                         (frame_offset + bigend_correction,
+                         (slot_offset + bigend_correction,
                           Pmode));
 
-  if (!FRAME_GROWS_DOWNWARD)
-    frame_offset += size;
-
   x = gen_rtx_MEM (mode, addr);
   set_mem_align (x, alignment_in_bits);
   MEM_NOTRAP_P (x) = 1;
index e5e033847185a4e9491fd02865e0f23eae9fb3a7..d008e8586efdf13dcbefe128e26612df1b53dff7 100644 (file)
@@ -231,6 +231,17 @@ struct GTY(()) function_subsections {
   const char *unlikely_text_section_name;
 };
 
+/* Describe an empty area of space in the stack frame.  These can be chained
+   into a list; this is used to keep track of space wasted for alignment
+   reasons.  */
+struct GTY(()) frame_space
+{
+  struct frame_space *next;
+
+  HOST_WIDE_INT start;
+  HOST_WIDE_INT length;
+};
+
 /* Datastructures maintained for currently processed function in RTL form.  */
 struct GTY(()) rtl_data {
   struct expr_status expr;
@@ -278,6 +289,9 @@ struct GTY(()) rtl_data {
      Made for the sake of unshare_all_rtl.  */
   rtx x_stack_slot_list;
 
+  /* List of empty areas in the stack frame.  */
+  struct frame_space *frame_space_list;
+
   /* Place after which to insert the tail_recursion_label if we need one.  */
   rtx x_stack_check_probe_note;
 
index ce0b602a7cf4a6c87498683c1ab6d4dddf2301cc..4321b08546b7f2dd2b44a2767a916072be43ac7f 100644 (file)
@@ -702,6 +702,8 @@ has_nonexceptional_receiver (void)
 static int something_needs_elimination;
 /* Set during calculate_needs if an insn needs an operand changed.  */
 static int something_needs_operands_changed;
+/* Set by alter_regs if we spilled a register to the stack.  */
+static bool something_was_spilled;
 
 /* Nonzero means we couldn't get enough spill regs.  */
 static int failure;
@@ -981,6 +983,7 @@ reload (rtx first, int global)
       HOST_WIDE_INT starting_frame_size;
 
       starting_frame_size = get_frame_size ();
+      something_was_spilled = false;
 
       set_initial_elim_offsets ();
       set_initial_label_offsets ();
@@ -1046,7 +1049,7 @@ reload (rtx first, int global)
        setup_save_areas ();
 
       /* If we allocated another stack slot, redo elimination bookkeeping.  */
-      if (starting_frame_size != get_frame_size ())
+      if (something_was_spilled || starting_frame_size != get_frame_size ())
        continue;
       if (starting_frame_size && crtl->stack_alignment_needed)
        {
@@ -1084,7 +1087,7 @@ reload (rtx first, int global)
 
       /* If we allocated any new memory locations, make another pass
         since it might have changed elimination offsets.  */
-      if (starting_frame_size != get_frame_size ())
+      if (something_was_spilled || starting_frame_size != get_frame_size ())
        something_changed = 1;
 
       /* Even if the frame size remained the same, we might still have
@@ -2223,6 +2226,8 @@ alter_reg (int i, int from_reg, bool dont_share_p)
       unsigned int min_align = reg_max_ref_width[i] * BITS_PER_UNIT;
       int adjust = 0;
 
+      something_was_spilled = true;
+
       if (ira_conflicts_p)
        {
          /* Mark the spill for IRA.  */