From: Bernd Schmidt Date: Mon, 17 May 2010 11:16:00 +0000 (+0000) Subject: function.c (try_fit_stack_local, [...]): New static functions. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=56731d645e826bc7524c85bef3d32d75772f72cb;p=gcc.git 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 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7482a367f7c..e53fc44d79c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2010-05-17 Bernd Schmidt + + * 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 * config/s390/s390.c: Define sane prefetch settings and activate diff --git a/gcc/function.c b/gcc/function.c index 949480ca9d0..5d0e7e5c954 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 e5e03384718..d008e8586ef 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 ce0b602a7cf..4321b08546b 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. */