X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Freg-stack.c;h=fc742bdce6080d876d02ac36fdf638372cfc0d88;hb=138fbfd03489528c7f71b4c9e755fb1da3e0e277;hp=6aaa8bed0d4e4a57003d53353a74a9076a2fc0b5;hpb=ea06f79740c70d1e8992c5f8313d06caec7a0c97;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/reg-stack.c b/gcc/reg-stack.c index 6aaa8bed0d4..fc742bdce60 100644 --- a/gcc/reg-stack.c +++ b/gcc/reg-stack.c @@ -16,8 +16,8 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free - Software Foundation, 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. */ + Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. */ /* This pass converts stack-like registers from the "flat register file" model that gcc uses, to a stack convention that the 387 uses. @@ -170,6 +170,12 @@ #include "varray.h" #include "reload.h" #include "ggc.h" +#include "timevar.h" +#include "tree-pass.h" +#include "target.h" +#include "vecprim.h" + +#ifdef STACK_REGS /* We use this array to cache info about insns, because otherwise we spend too much time in stack_regs_mentioned_p. @@ -177,12 +183,12 @@ Indexed by insn UIDs. A value of zero is uninitialized, one indicates the insn uses stack registers, two indicates the insn does not use stack registers. */ -static GTY(()) varray_type stack_regs_mentioned_data; - -#ifdef STACK_REGS +static VEC(char,heap) *stack_regs_mentioned_data; #define REG_STACK_SIZE (LAST_STACK_REG - FIRST_STACK_REG + 1) +int regstack_completed = 0; + /* This is the basic stack record. TOP is an index into REG[] such that REG[TOP] is the top of stack. If TOP is -1 the stack is empty. @@ -208,7 +214,7 @@ typedef struct block_info_def struct stack_def stack_out; /* Output stack configuration. */ HARD_REG_SET out_reg_set; /* Stack regs live on output. */ int done; /* True if block already converted. */ - int predecessors; /* Number of predecessors that needs + int predecessors; /* Number of predecessors that need to be visited. */ } *block_info; @@ -224,6 +230,11 @@ enum emit_where /* The block we're currently working on. */ static basic_block current_block; +/* In the current_block, whether we're processing the first register + stack or call instruction, i.e. the regstack is currently the + same as BLOCK_INFO(current_block)->stack_in. */ +static bool starting_stack_p; + /* This is the register file for all register after conversion. */ static rtx FP_mode_reg[LAST_STACK_REG+1-FIRST_STACK_REG][(int) MAX_MACHINE_MODE]; @@ -237,7 +248,6 @@ static rtx not_a_num; /* Forward declarations */ static int stack_regs_mentioned_p (rtx pat); -static void straighten_stack (rtx, stack); static void pop_stack (stack, int); static rtx *get_true_reg (rtx *); @@ -248,7 +258,6 @@ static void replace_reg (rtx *, int); static void remove_regno_note (rtx, enum reg_note, unsigned int); static int get_hard_regnum (stack, rtx); static rtx emit_pop_insn (rtx, stack, rtx, enum emit_where); -static void emit_swap_insn (rtx, stack, rtx); static void swap_to_top(rtx, stack, rtx, rtx); static bool move_for_stack_reg (rtx, stack, rtx); static bool move_nan_for_stack_reg (rtx, stack, rtx); @@ -303,21 +312,27 @@ stack_regs_mentioned (rtx insn) return 0; uid = INSN_UID (insn); - max = VARRAY_SIZE (stack_regs_mentioned_data); + max = VEC_length (char, stack_regs_mentioned_data); if (uid >= max) { + char *p; + unsigned int old_max = max; + /* Allocate some extra size to avoid too many reallocs, but do not grow too quickly. */ - max = uid + uid / 20; - VARRAY_GROW (stack_regs_mentioned_data, max); + max = uid + uid / 20 + 1; + VEC_safe_grow (char, heap, stack_regs_mentioned_data, max); + p = VEC_address (char, stack_regs_mentioned_data); + memset (&p[old_max], 0, + sizeof (char) * (max - old_max)); } - test = VARRAY_CHAR (stack_regs_mentioned_data, uid); + test = VEC_index (char, stack_regs_mentioned_data, uid); if (test == 0) { /* This insn has yet to be examined. Do so now. */ test = stack_regs_mentioned_p (PATTERN (insn)) ? 1 : 2; - VARRAY_CHAR (stack_regs_mentioned_data, uid) = test; + VEC_replace (char, stack_regs_mentioned_data, uid, test); } return test == 1; @@ -344,8 +359,7 @@ next_flags_user (rtx insn) return NULL_RTX; } -/* Reorganize the stack into ascending numbers, - after this insn. */ +/* Reorganize the stack into ascending numbers, before this insn. */ static void straighten_stack (rtx insn, stack regstack) @@ -365,7 +379,7 @@ straighten_stack (rtx insn, stack regstack) for (top = temp_stack.top = regstack->top; top >= 0; top--) temp_stack.reg[top] = FIRST_STACK_REG + temp_stack.top - top; - change_stack (insn, regstack, &temp_stack, EMIT_AFTER); + change_stack (insn, regstack, &temp_stack, EMIT_BEFORE); } /* Pop a register from the stack. */ @@ -663,14 +677,8 @@ stack_result (tree decl) result = DECL_RTL_IF_SET (DECL_RESULT (decl)); if (result != 0) - { -#ifdef FUNCTION_OUTGOING_VALUE - result - = FUNCTION_OUTGOING_VALUE (TREE_TYPE (DECL_RESULT (decl)), decl); -#else - result = FUNCTION_VALUE (TREE_TYPE (DECL_RESULT (decl)), decl); -#endif - } + result = targetm.calls.function_value (TREE_TYPE (DECL_RESULT (decl)), + decl, true); return result != 0 && STACK_REG_P (result) ? result : 0; } @@ -691,7 +699,7 @@ replace_reg (rtx *reg, int regno) gcc_assert (regno <= LAST_STACK_REG); gcc_assert (STACK_REG_P (*reg)); - gcc_assert (GET_MODE_CLASS (GET_MODE (*reg)) == MODE_FLOAT + gcc_assert (SCALAR_FLOAT_MODE_P (GET_MODE (*reg)) || GET_MODE_CLASS (GET_MODE (*reg)) == MODE_COMPLEX_FLOAT); *reg = FP_MODE_REG (regno, GET_MODE (*reg)); @@ -864,6 +872,16 @@ emit_swap_insn (rtx insn, stack regstack, rtx reg) return; } + /* Avoid emitting the swap if this is the first register stack insn + of the current_block. Instead update the current_block's stack_in + and let compensate edges take care of this for us. */ + if (current_block && starting_stack_p) + { + BLOCK_INFO (current_block)->stack_in = *regstack; + starting_stack_p = false; + return; + } + swap_rtx = gen_swapxf (FP_MODE_REG (hard_regno, XFmode), FP_MODE_REG (FIRST_STACK_REG, XFmode)); @@ -1353,16 +1371,20 @@ subst_stack_regs_pat (rtx insn, stack regstack, rtx pat) if (!note) { rtx t = *dest; - if (get_hard_regnum (regstack, t) == -1) - control_flow_insn_deleted - |= move_nan_for_stack_reg (insn, regstack, t); if (COMPLEX_MODE_P (GET_MODE (t))) { - t = FP_MODE_REG (REGNO (t) + 1, DFmode); - if (get_hard_regnum (regstack, t) == -1) - control_flow_insn_deleted - |= move_nan_for_stack_reg (insn, regstack, t); + rtx u = FP_MODE_REG (REGNO (t) + 1, SFmode); + if (get_hard_regnum (regstack, u) == -1) + { + rtx pat2 = gen_rtx_CLOBBER (VOIDmode, u); + rtx insn2 = emit_insn_before (pat2, insn); + control_flow_insn_deleted + |= move_nan_for_stack_reg (insn2, regstack, u); + } } + if (get_hard_regnum (regstack, t) == -1) + control_flow_insn_deleted + |= move_nan_for_stack_reg (insn, regstack, t); } } } @@ -2205,7 +2227,7 @@ subst_stack_regs (rtx insn, stack regstack) if (top >= 0) { - straighten_stack (PREV_INSN (insn), regstack); + straighten_stack (insn, regstack); /* Now mark the arguments as dead after the call. */ @@ -2260,6 +2282,16 @@ subst_stack_regs (rtx insn, stack regstack) if (NOTE_P (insn) || INSN_DELETED_P (insn)) return control_flow_insn_deleted; + /* If this a noreturn call, we can't insert pop insns after it. + Instead, reset the stack state to empty. */ + if (CALL_P (insn) + && find_reg_note (insn, REG_NORETURN, NULL)) + { + regstack->top = -1; + CLEAR_HARD_REG_SET (regstack->reg_set); + return control_flow_insn_deleted; + } + /* If there is a REG_UNUSED note on a stack register on this insn, the indicated reg must be popped. The REG_UNUSED note is removed, since the form of the newly emitted pop insn references the reg, @@ -2296,6 +2328,19 @@ change_stack (rtx insn, stack old, stack new, enum emit_where where) int reg; int update_end = 0; + /* Stack adjustments for the first insn in a block update the + current_block's stack_in instead of inserting insns directly. + compensate_edges will add the necessary code later. */ + if (current_block + && starting_stack_p + && where == EMIT_BEFORE) + { + BLOCK_INFO (current_block)->stack_in = *new; + starting_stack_p = false; + *old = *new; + return; + } + /* We will be inserting new insns "backwards". If we are to insert after INSN, find the next insn, and insert before it. */ @@ -2578,28 +2623,22 @@ convert_regs_exit (void) } } -/* If the stack of the target block hasn't been processed yet, - copy the stack info from the source block. */ +/* Copy the stack info from the end of edge E's source block to the + start of E's destination block. */ static void propagate_stack (edge e) { - basic_block dest = e->dest; - stack dest_stack = &BLOCK_INFO (dest)->stack_in; - - if (dest_stack->top == -2) - { - basic_block src = e->src; - stack src_stack = &BLOCK_INFO (src)->stack_out; - int reg; + stack src_stack = &BLOCK_INFO (e->src)->stack_out; + stack dest_stack = &BLOCK_INFO (e->dest)->stack_in; + int reg; - /* Preserve the order of the original stack, but check whether - any pops are needed. */ - dest_stack->top = -1; - for (reg = 0; reg <= src_stack->top; ++reg) - if (TEST_HARD_REG_BIT (dest_stack->reg_set, src_stack->reg[reg])) - dest_stack->reg[++dest_stack->top] = src_stack->reg[reg]; - } + /* Preserve the order of the original stack, but check whether + any pops are needed. */ + dest_stack->top = -1; + for (reg = 0; reg <= src_stack->top; ++reg) + if (TEST_HARD_REG_BIT (dest_stack->reg_set, src_stack->reg[reg])) + dest_stack->reg[++dest_stack->top] = src_stack->reg[reg]; } @@ -2608,104 +2647,91 @@ propagate_stack (edge e) should have been defined by now. */ static bool -compensate_edge (edge e, FILE *file) +compensate_edge (edge e) { - basic_block block = e->src, target = e->dest; - block_info bi = BLOCK_INFO (block); - struct stack_def regstack, tmpstack; + basic_block source = e->src, target = e->dest; stack target_stack = &BLOCK_INFO (target)->stack_in; + stack source_stack = &BLOCK_INFO (source)->stack_out; + struct stack_def regstack; int reg; - current_block = block; - regstack = bi->stack_out; - if (file) - fprintf (file, "Edge %d->%d: ", block->index, target->index); + if (dump_file) + fprintf (dump_file, "Edge %d->%d: ", source->index, target->index); gcc_assert (target_stack->top != -2); /* Check whether stacks are identical. */ - if (target_stack->top == regstack.top) + if (target_stack->top == source_stack->top) { for (reg = target_stack->top; reg >= 0; --reg) - if (target_stack->reg[reg] != regstack.reg[reg]) + if (target_stack->reg[reg] != source_stack->reg[reg]) break; if (reg == -1) { - if (file) - fprintf (file, "no changes needed\n"); + if (dump_file) + fprintf (dump_file, "no changes needed\n"); return false; } } - if (file) + if (dump_file) { - fprintf (file, "correcting stack to "); - print_stack (file, target_stack); + fprintf (dump_file, "correcting stack to "); + print_stack (dump_file, target_stack); } - /* Care for non-call EH edges specially. The normal return path have - values in registers. These will be popped en masse by the unwind - library. */ - if ((e->flags & (EDGE_EH | EDGE_ABNORMAL_CALL)) == EDGE_EH) - target_stack->top = -1; - - /* Other calls may appear to have values live in st(0), but the + /* Abnormal calls may appear to have values live in st(0), but the abnormal return path will not have actually loaded the values. */ - else if (e->flags & EDGE_ABNORMAL_CALL) + if (e->flags & EDGE_ABNORMAL_CALL) { /* Assert that the lifetimes are as we expect -- one value live at st(0) on the end of the source block, and no - values live at the beginning of the destination block. */ - HARD_REG_SET tmp; - - CLEAR_HARD_REG_SET (tmp); - GO_IF_HARD_REG_EQUAL (target_stack->reg_set, tmp, eh1); - gcc_unreachable (); - eh1: - - /* We are sure that there is st(0) live, otherwise we won't compensate. + values live at the beginning of the destination block. For complex return values, we may have st(1) live as well. */ - SET_HARD_REG_BIT (tmp, FIRST_STACK_REG); - if (TEST_HARD_REG_BIT (regstack.reg_set, FIRST_STACK_REG + 1)) - SET_HARD_REG_BIT (tmp, FIRST_STACK_REG + 1); - GO_IF_HARD_REG_EQUAL (regstack.reg_set, tmp, eh2); - gcc_unreachable (); - eh2: + gcc_assert (source_stack->top == 0 || source_stack->top == 1); + gcc_assert (target_stack->top == -1); + return false; + } - target_stack->top = -1; + /* Handle non-call EH edges specially. The normal return path have + values in registers. These will be popped en masse by the unwind + library. */ + if (e->flags & EDGE_EH) + { + gcc_assert (target_stack->top == -1); + return false; } + /* We don't support abnormal edges. Global takes care to + avoid any live register across them, so we should never + have to insert instructions on such edges. */ + gcc_assert (! (e->flags & EDGE_ABNORMAL)); + + /* Make a copy of source_stack as change_stack is destructive. */ + regstack = *source_stack; + /* It is better to output directly to the end of the block instead of to the edge, because emit_swap can do minimal insn scheduling. We can do this when there is only one edge out, and it is not abnormal. */ - else if (EDGE_COUNT (block->succs) == 1 && !(e->flags & EDGE_ABNORMAL)) + if (EDGE_COUNT (source->succs) == 1) { - /* change_stack kills values in regstack. */ - tmpstack = regstack; - - change_stack (BB_END (block), &tmpstack, target_stack, - (JUMP_P (BB_END (block)) - ? EMIT_BEFORE : EMIT_AFTER)); + current_block = source; + change_stack (BB_END (source), ®stack, target_stack, + (JUMP_P (BB_END (source)) ? EMIT_BEFORE : EMIT_AFTER)); } else { rtx seq, after; - /* We don't support abnormal edges. Global takes care to - avoid any live register across them, so we should never - have to insert instructions on such edges. */ - gcc_assert (!(e->flags & EDGE_ABNORMAL)); - current_block = NULL; start_sequence (); /* ??? change_stack needs some point to emit insns after. */ after = emit_note (NOTE_INSN_DELETED); - tmpstack = regstack; - change_stack (after, &tmpstack, target_stack, EMIT_BEFORE); + change_stack (after, ®stack, target_stack, EMIT_BEFORE); seq = get_insns (); end_sequence (); @@ -2721,11 +2747,13 @@ compensate_edge (edge e, FILE *file) source block to the stack_in of the destination block. */ static bool -compensate_edges (FILE *file) +compensate_edges (void) { bool inserted = false; basic_block bb; + starting_stack_p = false; + FOR_EACH_BB (bb) if (bb != ENTRY_BLOCK_PTR) { @@ -2733,87 +2761,92 @@ compensate_edges (FILE *file) edge_iterator ei; FOR_EACH_EDGE (e, ei, bb->succs) - inserted |= compensate_edge (e, file); + inserted |= compensate_edge (e); } return inserted; } +/* Select the better of two edges E1 and E2 to use to determine the + stack layout for their shared destination basic block. This is + typically the more frequently executed. The edge E1 may be NULL + (in which case E2 is returned), but E2 is always non-NULL. */ + +static edge +better_edge (edge e1, edge e2) +{ + if (!e1) + return e2; + + if (EDGE_FREQUENCY (e1) > EDGE_FREQUENCY (e2)) + return e1; + if (EDGE_FREQUENCY (e1) < EDGE_FREQUENCY (e2)) + return e2; + + if (e1->count > e2->count) + return e1; + if (e1->count < e2->count) + return e2; + + /* Prefer critical edges to minimize inserting compensation code on + critical edges. */ + + if (EDGE_CRITICAL_P (e1) != EDGE_CRITICAL_P (e2)) + return EDGE_CRITICAL_P (e1) ? e1 : e2; + + /* Avoid non-deterministic behavior. */ + return (e1->src->index < e2->src->index) ? e1 : e2; +} + /* Convert stack register references in one block. */ static void -convert_regs_1 (FILE *file, basic_block block) +convert_regs_1 (basic_block block) { struct stack_def regstack; block_info bi = BLOCK_INFO (block); int reg; rtx insn, next; - edge e, beste = NULL; bool control_flow_insn_deleted = false; - edge_iterator ei; any_malformed_asm = false; - /* Find the edge we will copy stack from. It should be the most frequent - one as it will get cheapest after compensation code is generated, - if multiple such exists, take one with largest count, prefer critical - one (as splitting critical edges is more expensive), or one with lowest - index, to avoid random changes with different orders of the edges. */ - FOR_EACH_EDGE (e, ei, block->preds) - { - if (e->flags & EDGE_DFS_BACK) - ; - else if (! beste) - beste = e; - else if (EDGE_FREQUENCY (beste) < EDGE_FREQUENCY (e)) - beste = e; - else if (EDGE_FREQUENCY (beste) > EDGE_FREQUENCY (e)) - ; - else if (beste->count < e->count) - beste = e; - else if (beste->count > e->count) - ; - else if ((EDGE_CRITICAL_P (e) != 0) - != (EDGE_CRITICAL_P (beste) != 0)) - { - if (EDGE_CRITICAL_P (e)) - beste = e; - } - else if (e->src->index < beste->src->index) - beste = e; - } - - /* Initialize stack at block entry. */ + /* Choose an initial stack layout, if one hasn't already been chosen. */ if (bi->stack_in.top == -2) { + edge e, beste = NULL; + edge_iterator ei; + + /* Select the best incoming edge (typically the most frequent) to + use as a template for this basic block. */ + FOR_EACH_EDGE (e, ei, block->preds) + if (BLOCK_INFO (e->src)->done) + beste = better_edge (beste, e); + if (beste) propagate_stack (beste); else { /* No predecessors. Create an arbitrary input stack. */ - int reg; - bi->stack_in.top = -1; for (reg = LAST_STACK_REG; reg >= FIRST_STACK_REG; --reg) if (TEST_HARD_REG_BIT (bi->stack_in.reg_set, reg)) bi->stack_in.reg[++bi->stack_in.top] = reg; } } - else - /* Entry blocks do have stack already initialized. */ - beste = NULL; - current_block = block; - - if (file) + if (dump_file) { - fprintf (file, "\nBasic block %d\nInput stack: ", block->index); - print_stack (file, &bi->stack_in); + fprintf (dump_file, "\nBasic block %d\nInput stack: ", block->index); + print_stack (dump_file, &bi->stack_in); } /* Process all insns in this block. Keep track of NEXT so that we don't process insns emitted while substituting in INSN. */ + current_block = block; next = BB_HEAD (block); regstack = bi->stack_in; + starting_stack_p = true; + do { insn = next; @@ -2829,25 +2862,26 @@ convert_regs_1 (FILE *file, basic_block block) if (stack_regs_mentioned (insn) || CALL_P (insn)) { - if (file) + if (dump_file) { - fprintf (file, " insn %d input stack: ", + fprintf (dump_file, " insn %d input stack: ", INSN_UID (insn)); - print_stack (file, ®stack); + print_stack (dump_file, ®stack); } control_flow_insn_deleted |= subst_stack_regs (insn, ®stack); + starting_stack_p = false; } } while (next); - if (file) + if (dump_file) { - fprintf (file, "Expected live registers ["); + fprintf (dump_file, "Expected live registers ["); for (reg = FIRST_STACK_REG; reg <= LAST_STACK_REG; ++reg) if (TEST_HARD_REG_BIT (bi->out_reg_set, reg)) - fprintf (file, " %d", reg); - fprintf (file, " ]\nOutput stack: "); - print_stack (file, ®stack); + fprintf (dump_file, " %d", reg); + fprintf (dump_file, " ]\nOutput stack: "); + print_stack (dump_file, ®stack); } insn = BB_END (block); @@ -2865,8 +2899,8 @@ convert_regs_1 (FILE *file, basic_block block) { rtx set; - if (file) - fprintf (file, "Emitting insn initializing reg %d\n", reg); + if (dump_file) + fprintf (dump_file, "Emitting insn initializing reg %d\n", reg); set = gen_rtx_SET (VOIDmode, FP_MODE_REG (reg, SFmode), not_a_num); insn = emit_insn_after (set, insn); @@ -2901,34 +2935,13 @@ convert_regs_1 (FILE *file, basic_block block) gcc_assert (any_malformed_asm); win: bi->stack_out = regstack; - - /* Compensate the back edges, as those wasn't visited yet. */ - FOR_EACH_EDGE (e, ei, block->succs) - { - if (e->flags & EDGE_DFS_BACK - || (e->dest == EXIT_BLOCK_PTR)) - { - gcc_assert (BLOCK_INFO (e->dest)->done - || e->dest == block); - propagate_stack (e); - } - } - - FOR_EACH_EDGE (e, ei, block->preds) - { - if (e != beste && !(e->flags & EDGE_DFS_BACK) - && e->src != ENTRY_BLOCK_PTR) - { - gcc_assert (BLOCK_INFO (e->src)->done); - propagate_stack (e); - } - } + bi->done = true; } /* Convert registers in all blocks reachable from BLOCK. */ static void -convert_regs_2 (FILE *file, basic_block block) +convert_regs_2 (basic_block block) { basic_block *stack, *sp; @@ -2936,7 +2949,7 @@ convert_regs_2 (FILE *file, basic_block block) is only processed after all its predecessors. The number of predecessors of every block has already been computed. */ - stack = xmalloc (sizeof (*stack) * n_basic_blocks); + stack = XNEWVEC (basic_block, n_basic_blocks); sp = stack; *sp++ = block; @@ -2969,8 +2982,7 @@ convert_regs_2 (FILE *file, basic_block block) *sp++ = e->dest; } - convert_regs_1 (file, block); - BLOCK_INFO (block)->done = 1; + convert_regs_1 (block); } while (sp != stack); @@ -2982,7 +2994,7 @@ convert_regs_2 (FILE *file, basic_block block) to the stack-like registers the 387 uses. */ static void -convert_regs (FILE *file) +convert_regs (void) { int inserted; basic_block b; @@ -3002,7 +3014,7 @@ convert_regs (FILE *file) /* Process all blocks reachable from all entry points. */ FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs) - convert_regs_2 (file, e->dest); + convert_regs_2 (e->dest); /* ??? Process all unreachable blocks. Though there's no excuse for keeping these even when not optimizing. */ @@ -3011,10 +3023,10 @@ convert_regs (FILE *file) block_info bi = BLOCK_INFO (b); if (! bi->done) - convert_regs_2 (file, b); + convert_regs_2 (b); } - inserted |= compensate_edges (file); + inserted |= compensate_edges (); clear_aux_for_blocks (); @@ -3022,8 +3034,8 @@ convert_regs (FILE *file) if (inserted) commit_edge_insertions (); - if (file) - fputc ('\n', file); + if (dump_file) + fputc ('\n', dump_file); } /* Convert register usage from "flat" register file usage to a "stack @@ -3034,15 +3046,16 @@ convert_regs (FILE *file) code duplication created when the converter inserts pop insns on the edges. */ -bool -reg_to_stack (FILE *file) +static bool +reg_to_stack (void) { basic_block bb; int i; int max_uid; /* Clean up previous run. */ - stack_regs_mentioned_data = 0; + if (stack_regs_mentioned_data != NULL) + VEC_free (char, heap, stack_regs_mentioned_data); /* See if there is something to do. Flow analysis is quite expensive so we might save some compilation time. */ @@ -3057,11 +3070,11 @@ reg_to_stack (FILE *file) Also need to rebuild life when superblock scheduling is done as it don't update liveness yet. */ if (!optimize - || (flag_sched2_use_superblocks + || ((flag_sched2_use_superblocks || flag_sched2_use_traces) && flag_schedule_insns_after_reload)) { count_or_remove_death_notes (NULL, 1); - life_analysis (file, PROP_DEATH_NOTES); + life_analysis (PROP_DEATH_NOTES); } mark_dfs_back_edges (); @@ -3085,9 +3098,9 @@ reg_to_stack (FILE *file) /* Copy live_at_end and live_at_start into temporaries. */ for (reg = FIRST_STACK_REG; reg <= LAST_STACK_REG; reg++) { - if (REGNO_REG_SET_P (bb->global_live_at_end, reg)) + if (REGNO_REG_SET_P (bb->il.rtl->global_live_at_end, reg)) SET_HARD_REG_BIT (bi->out_reg_set, reg); - if (REGNO_REG_SET_P (bb->global_live_at_start, reg)) + if (REGNO_REG_SET_P (bb->il.rtl->global_live_at_start, reg)) SET_HARD_REG_BIT (bi->stack_in.reg_set, reg); } } @@ -3125,14 +3138,64 @@ reg_to_stack (FILE *file) /* Allocate a cache for stack_regs_mentioned. */ max_uid = get_max_uid (); - VARRAY_CHAR_INIT (stack_regs_mentioned_data, max_uid + 1, - "stack_regs_mentioned cache"); + stack_regs_mentioned_data = VEC_alloc (char, heap, max_uid + 1); + memset (VEC_address (char, stack_regs_mentioned_data), + 0, sizeof (char) * max_uid + 1); - convert_regs (file); + convert_regs (); free_aux_for_blocks (); return true; } #endif /* STACK_REGS */ + +static bool +gate_handle_stack_regs (void) +{ +#ifdef STACK_REGS + return 1; +#else + return 0; +#endif +} + +/* Convert register usage from flat register file usage to a stack + register file. */ +static unsigned int +rest_of_handle_stack_regs (void) +{ +#ifdef STACK_REGS + if (reg_to_stack () && optimize) + { + regstack_completed = 1; + if (cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_POST_REGSTACK + | (flag_crossjumping ? CLEANUP_CROSSJUMP : 0)) + && (flag_reorder_blocks || flag_reorder_blocks_and_partition)) + { + reorder_basic_blocks (0); + cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_POST_REGSTACK); + } + } + else + regstack_completed = 1; +#endif + return 0; +} -#include "gt-reg-stack.h" +struct tree_opt_pass pass_stack_regs = +{ + "stack", /* name */ + gate_handle_stack_regs, /* gate */ + rest_of_handle_stack_regs, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_REG_STACK, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func | + TODO_ggc_collect, /* todo_flags_finish */ + 'k' /* letter */ +};