diff options
Diffstat (limited to 'gcc/reload1.c')
-rw-r--r-- | gcc/reload1.c | 92 |
1 files changed, 61 insertions, 31 deletions
diff --git a/gcc/reload1.c b/gcc/reload1.c index ecab52b68ee..9a0ad894746 100644 --- a/gcc/reload1.c +++ b/gcc/reload1.c @@ -77,10 +77,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA reload needs, spilling, assigning reload registers to use for fixing up each insn, and generating the new insns to copy values into the reload registers. */ - -#ifndef LOCAL_REGNO -#define LOCAL_REGNO(REGNO) 0 -#endif /* During reload_as_needed, element N contains a REG rtx for the hard reg into which reg N has been reloaded (perhaps for a previous insn). */ @@ -142,6 +138,11 @@ static HARD_REG_SET reg_reloaded_valid; This is only valid if reg_reloaded_contents is set and valid. */ static HARD_REG_SET reg_reloaded_dead; +/* Indicate whether the register's current value is one that is not + safe to retain across a call, even for registers that are normally + call-saved. */ +static HARD_REG_SET reg_reloaded_call_part_clobbered; + /* Number of spill-regs so far; number of valid elements of spill_regs. */ static int n_spills; @@ -293,12 +294,12 @@ struct elim_table { int from; /* Register number to be eliminated. */ int to; /* Register number used as replacement. */ - int initial_offset; /* Initial difference between values. */ + HOST_WIDE_INT initial_offset; /* Initial difference between values. */ int can_eliminate; /* Nonzero if this elimination can be done. */ int can_eliminate_previous; /* Value of CAN_ELIMINATE in previous scan over insns made by reload. */ - int offset; /* Current offset between the two regs. */ - int previous_offset; /* Offset at end of previous insn. */ + HOST_WIDE_INT offset; /* Current offset between the two regs. */ + HOST_WIDE_INT previous_offset;/* Offset at end of previous insn. */ int ref_outside_mem; /* "to" has been referenced outside a MEM. */ rtx from_rtx; /* REG rtx for the register to be eliminated. We cannot simply compare the number since @@ -352,7 +353,7 @@ static int num_eliminable_invariants; static int first_label_num; static char *offsets_known_at; -static int (*offsets_at)[NUM_ELIMINABLE_REGS]; +static HOST_WIDE_INT (*offsets_at)[NUM_ELIMINABLE_REGS]; /* Number of labels in the current function. */ @@ -673,6 +674,17 @@ reload (rtx first, int global) if (! call_used_regs[i] && ! fixed_regs[i] && ! LOCAL_REGNO (i)) regs_ever_live[i] = 1; +#ifdef NON_SAVING_SETJMP + /* A function that calls setjmp should save and restore all the + call-saved registers on a system where longjmp clobbers them. */ + if (NON_SAVING_SETJMP && current_function_calls_setjmp) + { + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (! call_used_regs[i]) + regs_ever_live[i] = 1; + } +#endif + /* Find all the pseudo registers that didn't get hard regs but do have known equivalent constants or memory slots. These include parameters (known equivalent to parameter slots) @@ -698,9 +710,7 @@ reload (rtx first, int global) /* Look for REG_EQUIV notes; record what each pseudo is equivalent to. Also find all paradoxical subregs and find largest such for each pseudo. On machines with small register classes, record hard registers that - are used for user variables. These can never be used for spills. - Also look for a "constant" REG_SETJMP. This means that all - caller-saved registers must be marked live. */ + are used for user variables. These can never be used for spills. */ num_eliminable_invariants = 0; for (insn = first; insn; insn = NEXT_INSN (insn)) @@ -714,12 +724,6 @@ reload (rtx first, int global) && GET_MODE (insn) != VOIDmode) PUT_MODE (insn, VOIDmode); - if (GET_CODE (insn) == CALL_INSN - && find_reg_note (insn, REG_SETJMP, NULL)) - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - if (! call_used_regs[i]) - regs_ever_live[i] = 1; - if (set != 0 && GET_CODE (SET_DEST (set)) == REG) { rtx note = find_reg_note (insn, REG_EQUIV, NULL_RTX); @@ -816,7 +820,7 @@ reload (rtx first, int global) allocate would occasionally cause it to exceed the stack limit and cause a core dump. */ offsets_known_at = xmalloc (num_labels); - offsets_at = xmalloc (num_labels * NUM_ELIMINABLE_REGS * sizeof (int)); + offsets_at = xmalloc (num_labels * NUM_ELIMINABLE_REGS * sizeof (HOST_WIDE_INT)); /* Alter each pseudo-reg rtx to contain its hard reg number. Assign stack slots to the pseudos that lack hard regs or equivalents. @@ -1249,6 +1253,14 @@ reload (rtx first, int global) by this, so unshare everything here. */ unshare_all_rtl_again (first); +#ifdef STACK_BOUNDARY + /* init_emit has set the alignment of the hard frame pointer + to STACK_BOUNDARY. It is very likely no longer valid if + the hard frame pointer was used for register allocation. */ + if (!frame_pointer_needed) + REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM) = BITS_PER_UNIT; +#endif + return failure; } @@ -2897,7 +2909,7 @@ eliminate_regs_in_insn (rtx insn, int replace) { rtx base = SET_SRC (old_set); rtx base_insn = insn; - int offset = 0; + HOST_WIDE_INT offset = 0; while (base != ep->to_rtx) { @@ -2980,7 +2992,7 @@ eliminate_regs_in_insn (rtx insn, int replace) && REGNO (XEXP (SET_SRC (old_set), 0)) < FIRST_PSEUDO_REGISTER) { rtx reg = XEXP (SET_SRC (old_set), 0); - int offset = INTVAL (XEXP (SET_SRC (old_set), 1)); + HOST_WIDE_INT offset = INTVAL (XEXP (SET_SRC (old_set), 1)); for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) if (ep->from_rtx == reg && ep->can_eliminate) @@ -3263,7 +3275,7 @@ mark_not_eliminable (rtx dest, rtx x, void *data ATTRIBUTE_UNUSED) static void verify_initial_elim_offsets (void) { - int t; + HOST_WIDE_INT t; #ifdef ELIMINABLE_REGS struct elim_table *ep; @@ -3436,7 +3448,6 @@ init_elim_table (void) /* Does this function require a frame pointer? */ frame_pointer_needed = (! flag_omit_frame_pointer -#ifdef EXIT_IGNORE_STACK /* ?? If EXIT_IGNORE_STACK is set, we will not save and restore sp for alloca. So we can't eliminate the frame pointer in that case. At some point, @@ -3444,7 +3455,6 @@ init_elim_table (void) sp-adjusting insns for this case. */ || (current_function_calls_alloca && EXIT_IGNORE_STACK) -#endif || FRAME_POINTER_REQUIRED); num_eliminable = 0; @@ -3752,6 +3762,7 @@ reload_as_needed (int live_known) reg_last_reload_reg = xcalloc (max_regno, sizeof (rtx)); reg_has_output_reload = xmalloc (max_regno); CLEAR_HARD_REG_SET (reg_reloaded_valid); + CLEAR_HARD_REG_SET (reg_reloaded_call_part_clobbered); set_initial_elim_offsets (); @@ -3999,9 +4010,13 @@ reload_as_needed (int live_known) CLEAR_HARD_REG_SET (reg_reloaded_valid); /* Don't assume a reload reg is still good after a call insn - if it is a call-used reg. */ + if it is a call-used reg, or if it contains a value that will + be partially clobbered by the call. */ else if (GET_CODE (insn) == CALL_INSN) + { AND_COMPL_HARD_REG_SET (reg_reloaded_valid, call_used_reg_set); + AND_COMPL_HARD_REG_SET (reg_reloaded_valid, reg_reloaded_call_part_clobbered); + } } /* Clean up. */ @@ -4056,6 +4071,7 @@ forget_old_reloads_1 (rtx x, rtx ignored ATTRIBUTE_UNUSED, || ! TEST_HARD_REG_BIT (reg_is_output_reload, regno + i)) { CLEAR_HARD_REG_BIT (reg_reloaded_valid, regno + i); + CLEAR_HARD_REG_BIT (reg_reloaded_call_part_clobbered, regno + i); spill_reg_store[regno + i] = 0; } } @@ -7038,7 +7054,10 @@ emit_reload_insns (struct insn_chain *chain) If consecutive registers are used, clear them all. */ for (k = 0; k < nr; k++) + { CLEAR_HARD_REG_BIT (reg_reloaded_valid, i + k); + CLEAR_HARD_REG_BIT (reg_reloaded_call_part_clobbered, i + k); + } /* Maybe the spill reg contains a copy of reload_out. */ if (rld[r].out != 0 @@ -7085,6 +7104,8 @@ emit_reload_insns (struct insn_chain *chain) : nregno + k); reg_reloaded_insn[i + k] = insn; SET_HARD_REG_BIT (reg_reloaded_valid, i + k); + if (HARD_REGNO_CALL_PART_CLOBBERED (i + k, GET_MODE (out))) + SET_HARD_REG_BIT (reg_reloaded_call_part_clobbered, i + k); } } @@ -7102,14 +7123,16 @@ emit_reload_insns (struct insn_chain *chain) { int nregno; int nnr; + rtx in; if (GET_CODE (rld[r].in) == REG && REGNO (rld[r].in) >= FIRST_PSEUDO_REGISTER) - nregno = REGNO (rld[r].in); + in = rld[r].in; else if (GET_CODE (rld[r].in_reg) == REG) - nregno = REGNO (rld[r].in_reg); + in = rld[r].in_reg; else - nregno = REGNO (XEXP (rld[r].in_reg, 0)); + in = XEXP (rld[r].in_reg, 0); + nregno = REGNO (in); nnr = (nregno >= FIRST_PSEUDO_REGISTER ? 1 : HARD_REGNO_NREGS (nregno, @@ -7141,6 +7164,8 @@ emit_reload_insns (struct insn_chain *chain) : nregno + k); reg_reloaded_insn[i + k] = insn; SET_HARD_REG_BIT (reg_reloaded_valid, i + k); + if (HARD_REGNO_CALL_PART_CLOBBERED (i + k, GET_MODE (in))) + SET_HARD_REG_BIT (reg_reloaded_call_part_clobbered, i + k); } } } @@ -7227,6 +7252,10 @@ emit_reload_insns (struct insn_chain *chain) reg_reloaded_insn[src_regno + nr] = store_insn; CLEAR_HARD_REG_BIT (reg_reloaded_dead, src_regno + nr); SET_HARD_REG_BIT (reg_reloaded_valid, src_regno + nr); + if (HARD_REGNO_CALL_PART_CLOBBERED (src_regno + nr, + GET_MODE (src_reg))) + SET_HARD_REG_BIT (reg_reloaded_call_part_clobbered, + src_regno + nr); SET_HARD_REG_BIT (reg_is_output_reload, src_regno + nr); if (note) SET_HARD_REG_BIT (reg_reloaded_died, src_regno); @@ -7956,9 +7985,10 @@ fixup_abnormal_edges (void) == (EDGE_ABNORMAL | EDGE_EH)) break; } - if (e && GET_CODE (bb->end) != CALL_INSN && !can_throw_internal (bb->end)) + if (e && GET_CODE (BB_END (bb)) != CALL_INSN + && !can_throw_internal (BB_END (bb))) { - rtx insn = bb->end, stop = NEXT_INSN (bb->end); + rtx insn = BB_END (bb), stop = NEXT_INSN (BB_END (bb)); rtx next; for (e = bb->succ; e; e = e->succ_next) if (e->flags & EDGE_FALLTHRU) @@ -7967,11 +7997,11 @@ fixup_abnormal_edges (void) be already deleted. */ while ((GET_CODE (insn) == INSN || GET_CODE (insn) == NOTE) && !can_throw_internal (insn) - && insn != bb->head) + && insn != BB_HEAD (bb)) insn = PREV_INSN (insn); if (GET_CODE (insn) != CALL_INSN && !can_throw_internal (insn)) abort (); - bb->end = insn; + BB_END (bb) = insn; inserted = true; insn = NEXT_INSN (insn); while (insn && insn != stop) |