aboutsummaryrefslogtreecommitdiff
path: root/gcc/reload1.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/reload1.c')
-rw-r--r--gcc/reload1.c92
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 < &reg_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)