aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBernd Schmidt <bernds@codesourcery.com>2010-05-17 11:16:00 +0000
committerBernd Schmidt <bernds@gcc.gnu.org>2010-05-17 11:16:00 +0000
commit56731d645e826bc7524c85bef3d32d75772f72cb (patch)
tree134ce3aa4098037a175571e45c5fbc2d2a49bbd1
parent1041dabaa27fa33389263dcb1aacd7aae5a73396 (diff)
downloadgcc-56731d645e826bc7524c85bef3d32d75772f72cb.zip
gcc-56731d645e826bc7524c85bef3d32d75772f72cb.tar.gz
gcc-56731d645e826bc7524c85bef3d32d75772f72cb.tar.bz2
function.c (try_fit_stack_local, [...]): New static functions.
* 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
-rw-r--r--gcc/ChangeLog12
-rw-r--r--gcc/function.c151
-rw-r--r--gcc/function.h14
-rw-r--r--gcc/reload1.c9
4 files changed, 150 insertions, 36 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 7482a36..e53fc44 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/function.c b/gcc/function.c
index 949480c..5d0e7e5 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -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;
diff --git a/gcc/function.h b/gcc/function.h
index e5e0338..d008e85 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -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;
diff --git a/gcc/reload1.c b/gcc/reload1.c
index ce0b602..4321b08 100644
--- a/gcc/reload1.c
+++ b/gcc/reload1.c
@@ -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. */