This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: hard register reload patch
- To: Bernd Schmidt <bernds at pasanda dot cygnus dot co dot uk>
- Subject: Re: hard register reload patch
- From: Joern Rennecke <amylaar at cygnus dot co dot uk>
- Date: Thu, 27 Jan 2000 02:51:54 +0000 (GMT)
- CC: gcc-patches at gcc dot gnu dot org, amylaar at pasanda dot cygnus dot co dot uk
> Did you ever send an updated version of this after the first part went in?
> If so, I missed it.
Here is an updated version:
Fri Nov 26 02:44:08 1999 J"orn Rennecke <amylaar@cygnus.co.uk>
* flow.c (propagate_block): When deleting a dead insn, preserve
clobbers for registers that are live.
Thu Jan 27 01:42:37 2000 J"orn Rennecke <amylaar@cygnus.co.uk>
* reload.c (basic-block.h): #include.
(reload.h):#include after had-reg-set.h & basic-block.h .
(n_earlyclobbers, reload_earlyclobbers): Now static.
(combine_reloads): Deleted.
(push_hard_reload, note_earlyclobbers): New functions.
(earlyclobber_overlap_p, mentioned_in_operand): Likewise.
(find_reloads): First parameter is now of type struct insn_chain*.
Changed all callers.
Set used_spill_regs to the set of regsisters that die or are set
in this insn. Push hard register reloads for these registers.
* reload.h (n_earlyclobbers, reload_earlyclobbers): Don't declare.
(find_reloads): Update declaration.
(earlyclobber_overlap_p): Declare.
* reload1.c (reg_reloaded_dead, pseudos_counted): Delete. Reove all
sets / uses.
(spill_pseudo, hard_reload_conflict): New functions.
(mark_regs_outside_operands): Likewise.
(reload): Call mark_regs_outside_operands.
(maybe_fix_stack_asms): Don't clear bits in &chain->dead_or_set.
(order_regs_for_reload): Remove tests of &chain->dead_or_set.
(find_reg): Look at all reloads for conflicts.
Call hard_reload_conflict. Don't test &chain->dead_or_set.
(find_reload_regs): Call spill_pseudo.
Don't overwrite used_spill_regs, ior to it.
(finish_spills): Don't put regs from &chain->dead_or_set into
pseudo_forbidden_regs.
instead of chain->live_before and chain->live_after.
Don't adjust used_spill_regs.
(reload_reg_unavailable): Delete.
(reload_reg_free_p): Check reg_used_in_insn, not reload_reg_unavailable.
(reload_reg_fre_for_value_p): Don't test reload_reg_unavailable.
In RELOAD_OTHER case, use earlyclobber_overlap_p for earlyclobber test.
Test for conflicts with hard reloads.
(allocate_reload_reg): Check reg_used_in_insn, not reload_reg_used.
(choose_reload_regs_init): Don't put regs from &chain->dead_or_set
into reg_used_in_insn. Mark register usage of hard reloads.
(choose_reload_regs): Use earlyclobber_overlap_p.
Use search_equiv as value, and NULL_RTX as out to pass to
reload_reg_free_for_value_p.
Make action taken for earlyclobber operands dependent on reload type.
Don't abort for RELOAD_FOR_OUTPUT_ADDRESS hard reloads.
(emit_output_reload_insns, emit_reload_insns):
Remove reg_reloaded_dead / reg_relaoded_died code.
Index: flow.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/flow.c,v
retrieving revision 1.209
diff -p -r1.209 flow.c
*** flow.c 2000/01/26 00:54:44 1.209
--- flow.c 2000/01/27 01:38:04
*************** propagate_block (bb, old, significant, f
*** 3347,3352 ****
--- 3347,3381 ----
}
}
+ /* If INSN contained a clobber of a reg that is live,
+ we must emit a separate clobber for it; otherwise,
+ the register would become live above INSN.
+ This can happen when a function returns no value,
+ and the return register is used as a scratch in INSN -
+ e.g. gcc.c-torture/compile/920829-1.c on SH4. */
+ if (GET_CODE (PATTERN (insn)) == PARALLEL)
+ {
+ rtx pat = PATTERN (insn);
+ int i = XVECLEN (pat, 0);
+
+ while (--i >= 0)
+ {
+ rtx part = XVECEXP (pat, 0, i);
+ if (GET_CODE (part) == CLOBBER
+ && GET_CODE (XEXP (part, 0)) == REG
+ && REGNO_REG_SET_P (old, REGNO (XEXP (part, 0))))
+ {
+ /* INSN could be the only insn in block BNUM,
+ and we could have more than one clobber that
+ needs emitting, so we can't dodge updating
+ either start or end of the basic block. */
+ part = emit_insn_after (part, insn);
+ if (bb->end == PREV_INSN (part))
+ bb->end = part;
+ }
+ }
+ }
+
PUT_CODE (insn, NOTE);
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (insn) = 0;
Index: reload.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/reload.c,v
retrieving revision 1.99
diff -p -r1.99 reload.c
*** reload.c 2000/01/17 15:47:28 1.99
--- reload.c 2000/01/27 02:12:42
*************** a register with any other reload. */
*** 94,102 ****
#include "insn-config.h"
#include "insn-codes.h"
#include "recog.h"
- #include "reload.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "flags.h"
#include "real.h"
#include "output.h"
--- 94,103 ----
#include "insn-config.h"
#include "insn-codes.h"
#include "recog.h"
#include "regs.h"
#include "hard-reg-set.h"
+ #include "basic-block.h"
+ #include "reload.h"
#include "flags.h"
#include "real.h"
#include "output.h"
*************** struct reload rld[MAX_RELOADS];
*** 123,130 ****
/* All the "earlyclobber" operands of the current insn
are recorded here. */
! int n_earlyclobbers;
! rtx reload_earlyclobbers[MAX_RECOG_OPERANDS];
int reload_n_operands;
--- 124,131 ----
/* All the "earlyclobber" operands of the current insn
are recorded here. */
! static int n_earlyclobbers;
! static rtx reload_earlyclobbers[MAX_RECOG_OPERANDS];
int reload_n_operands;
*************** static enum reg_class find_valid_class P
*** 245,252 ****
static int push_reload PARAMS ((rtx, rtx, rtx *, rtx *, enum reg_class,
enum machine_mode, enum machine_mode,
int, int, int, enum reload_type));
static void push_replacement PARAMS ((rtx *, int, enum machine_mode));
- static void combine_reloads PARAMS ((void));
static int find_reusable_reload PARAMS ((rtx *, rtx, enum reg_class,
enum reload_type, int, int));
static rtx find_dummy_reload PARAMS ((rtx, rtx, rtx *, rtx *,
--- 246,253 ----
static int push_reload PARAMS ((rtx, rtx, rtx *, rtx *, enum reg_class,
enum machine_mode, enum machine_mode,
int, int, int, enum reload_type));
+ static void push_hard_reload PARAMS ((int, int, int, enum reload_type));
static void push_replacement PARAMS ((rtx *, int, enum machine_mode));
static int find_reusable_reload PARAMS ((rtx *, rtx, enum reg_class,
enum reload_type, int, int));
static rtx find_dummy_reload PARAMS ((rtx, rtx, rtx *, rtx *,
*************** static int find_inc_amount PARAMS ((rtx,
*** 273,278 ****
--- 274,281 ----
static int loc_mentioned_in_p PARAMS ((rtx *, rtx));
extern void debug_reload_to_stream PARAMS ((FILE *));
extern void debug_reload PARAMS ((void));
+ static void note_earlyclobbers PARAMS ((rtx, rtx, void *));
+ static int mentioned_in_operand PARAMS ((rtx *, void *));
#ifdef HAVE_SECONDARY_RELOADS
*************** push_reload (in, out, inloc, outloc, cla
*** 1481,1486 ****
--- 1484,1547 ----
return i;
}
+ /* Indicate that the hard register with register number REGNO is in use
+ for operand OPNUM, using a TYPE reload. If IN_P is set, use
+ rld[].in / in_reg, otherwise rld[].out / out_reg. */
+ static void
+ push_hard_reload (in_p, regno, opnum, type)
+ int in_p;
+ int regno;
+ int opnum;
+ enum reload_type type;
+ {
+ rtx x;
+ rtx in, out;
+ int i;
+ enum reg_class class = REGNO_REG_CLASS (regno);
+ enum machine_mode mode = reg_raw_mode[regno];
+
+ x = gen_rtx_REG (mode, regno);
+ x = gen_rtx_REG (GET_MODE (x), true_regnum (x));
+ if (in_p)
+ {
+ in = x;
+ out = NULL_RTX;
+ }
+ else
+ {
+ out = x;
+ in = NULL_RTX;
+ }
+
+ /* We want a specific reload register to be reserved for type / opnum,
+ thus re-using another reload is just asking for trouble.
+ So unconditionally add a new reload. */
+
+ i = n_reloads;
+ rld[i].in = in;
+ rld[i].out = out;
+ rld[i].class = class;
+ rld[i].inmode = in_p ? mode : VOIDmode;
+ rld[i].outmode = in_p ? VOIDmode : mode;
+ rld[i].reg_rtx = x;
+ rld[i].optional = 0;
+ rld[i].nongroup = 0;
+ rld[i].inc = 0;
+ rld[i].nocombine = 0;
+ rld[i].in_reg = in;
+ rld[i].out_reg = out;
+ rld[i].opnum = opnum;
+ rld[i].when_needed = type;
+ rld[i].secondary_in_reload = -1;
+ rld[i].secondary_out_reload = -1;
+ rld[i].secondary_in_icode = CODE_FOR_nothing;
+ rld[i].secondary_out_icode = CODE_FOR_nothing;
+ rld[i].secondary_p = 0;
+ rld[i].reg_rtx = x;
+
+ n_reloads++;
+ }
+
/* Record an additional place we must replace a value
for which we have already recorded a reload.
RELOADNUM is the value returned by push_reload
*************** loc_mentioned_in_p (loc, in)
*** 1582,1764 ****
return 0;
}
- /* If there is only one output reload, and it is not for an earlyclobber
- operand, try to combine it with a (logically unrelated) input reload
- to reduce the number of reload registers needed.
-
- This is safe if the input reload does not appear in
- the value being output-reloaded, because this implies
- it is not needed any more once the original insn completes.
-
- If that doesn't work, see we can use any of the registers that
- die in this insn as a reload register. We can if it is of the right
- class and does not appear in the value being output-reloaded. */
-
- static void
- combine_reloads ()
- {
- int i;
- int output_reload = -1;
- int secondary_out = -1;
- rtx note;
-
- /* Find the output reload; return unless there is exactly one
- and that one is mandatory. */
-
- for (i = 0; i < n_reloads; i++)
- if (rld[i].out != 0)
- {
- if (output_reload >= 0)
- return;
- output_reload = i;
- }
-
- if (output_reload < 0 || rld[output_reload].optional)
- return;
-
- /* An input-output reload isn't combinable. */
-
- if (rld[output_reload].in != 0)
- return;
-
- /* If this reload is for an earlyclobber operand, we can't do anything. */
- if (earlyclobber_operand_p (rld[output_reload].out))
- return;
-
- /* Check each input reload; can we combine it? */
-
- for (i = 0; i < n_reloads; i++)
- if (rld[i].in && ! rld[i].optional && ! rld[i].nocombine
- /* Life span of this reload must not extend past main insn. */
- && rld[i].when_needed != RELOAD_FOR_OUTPUT_ADDRESS
- && rld[i].when_needed != RELOAD_FOR_OUTADDR_ADDRESS
- && rld[i].when_needed != RELOAD_OTHER
- && (CLASS_MAX_NREGS (rld[i].class, rld[i].inmode)
- == CLASS_MAX_NREGS (rld[output_reload].class,
- rld[output_reload].outmode))
- && rld[i].inc == 0
- && rld[i].reg_rtx == 0
- #ifdef SECONDARY_MEMORY_NEEDED
- /* Don't combine two reloads with different secondary
- memory locations. */
- && (secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[i].opnum] == 0
- || secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[output_reload].opnum] == 0
- || rtx_equal_p (secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[i].opnum],
- secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[output_reload].opnum]))
- #endif
- && (SMALL_REGISTER_CLASSES
- ? (rld[i].class == rld[output_reload].class)
- : (reg_class_subset_p (rld[i].class,
- rld[output_reload].class)
- || reg_class_subset_p (rld[output_reload].class,
- rld[i].class)))
- && (MATCHES (rld[i].in, rld[output_reload].out)
- /* Args reversed because the first arg seems to be
- the one that we imagine being modified
- while the second is the one that might be affected. */
- || (! reg_overlap_mentioned_for_reload_p (rld[output_reload].out,
- rld[i].in)
- /* However, if the input is a register that appears inside
- the output, then we also can't share.
- Imagine (set (mem (reg 69)) (plus (reg 69) ...)).
- If the same reload reg is used for both reg 69 and the
- result to be stored in memory, then that result
- will clobber the address of the memory ref. */
- && ! (GET_CODE (rld[i].in) == REG
- && reg_overlap_mentioned_for_reload_p (rld[i].in,
- rld[output_reload].out))))
- && (reg_class_size[(int) rld[i].class]
- || SMALL_REGISTER_CLASSES)
- /* We will allow making things slightly worse by combining an
- input and an output, but no worse than that. */
- && (rld[i].when_needed == RELOAD_FOR_INPUT
- || rld[i].when_needed == RELOAD_FOR_OUTPUT))
- {
- int j;
-
- /* We have found a reload to combine with! */
- rld[i].out = rld[output_reload].out;
- rld[i].out_reg = rld[output_reload].out_reg;
- rld[i].outmode = rld[output_reload].outmode;
- /* Mark the old output reload as inoperative. */
- rld[output_reload].out = 0;
- /* The combined reload is needed for the entire insn. */
- rld[i].when_needed = RELOAD_OTHER;
- /* If the output reload had a secondary reload, copy it. */
- if (rld[output_reload].secondary_out_reload != -1)
- {
- rld[i].secondary_out_reload
- = rld[output_reload].secondary_out_reload;
- rld[i].secondary_out_icode
- = rld[output_reload].secondary_out_icode;
- }
-
- #ifdef SECONDARY_MEMORY_NEEDED
- /* Copy any secondary MEM. */
- if (secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[output_reload].opnum] != 0)
- secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[i].opnum]
- = secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[output_reload].opnum];
- #endif
- /* If required, minimize the register class. */
- if (reg_class_subset_p (rld[output_reload].class,
- rld[i].class))
- rld[i].class = rld[output_reload].class;
-
- /* Transfer all replacements from the old reload to the combined. */
- for (j = 0; j < n_replacements; j++)
- if (replacements[j].what == output_reload)
- replacements[j].what = i;
-
- return;
- }
-
- /* If this insn has only one operand that is modified or written (assumed
- to be the first), it must be the one corresponding to this reload. It
- is safe to use anything that dies in this insn for that output provided
- that it does not occur in the output (we already know it isn't an
- earlyclobber. If this is an asm insn, give up. */
-
- if (INSN_CODE (this_insn) == -1)
- return;
-
- for (i = 1; i < insn_data[INSN_CODE (this_insn)].n_operands; i++)
- if (insn_data[INSN_CODE (this_insn)].operand[i].constraint[0] == '='
- || insn_data[INSN_CODE (this_insn)].operand[i].constraint[0] == '+')
- return;
-
- /* See if some hard register that dies in this insn and is not used in
- the output is the right class. Only works if the register we pick
- up can fully hold our output reload. */
- for (note = REG_NOTES (this_insn); note; note = XEXP (note, 1))
- if (REG_NOTE_KIND (note) == REG_DEAD
- && GET_CODE (XEXP (note, 0)) == REG
- && ! reg_overlap_mentioned_for_reload_p (XEXP (note, 0),
- rld[output_reload].out)
- && REGNO (XEXP (note, 0)) < FIRST_PSEUDO_REGISTER
- && HARD_REGNO_MODE_OK (REGNO (XEXP (note, 0)), rld[output_reload].outmode)
- && TEST_HARD_REG_BIT (reg_class_contents[(int) rld[output_reload].class],
- REGNO (XEXP (note, 0)))
- && (HARD_REGNO_NREGS (REGNO (XEXP (note, 0)), rld[output_reload].outmode)
- <= HARD_REGNO_NREGS (REGNO (XEXP (note, 0)), GET_MODE (XEXP (note, 0))))
- /* Ensure that a secondary or tertiary reload for this output
- won't want this register. */
- && ((secondary_out = rld[output_reload].secondary_out_reload) == -1
- || (! (TEST_HARD_REG_BIT
- (reg_class_contents[(int) rld[secondary_out].class],
- REGNO (XEXP (note, 0))))
- && ((secondary_out = rld[secondary_out].secondary_out_reload) == -1
- || ! (TEST_HARD_REG_BIT
- (reg_class_contents[(int) rld[secondary_out].class],
- REGNO (XEXP (note, 0)))))))
- && ! fixed_regs[REGNO (XEXP (note, 0))])
- {
- rld[output_reload].reg_rtx
- = gen_rtx_REG (rld[output_reload].outmode,
- REGNO (XEXP (note, 0)));
- return;
- }
- }
-
/* Try to find a reload register for an in-out reload (expressions IN and OUT).
See if one of IN and OUT is a register that may be used;
this is desirable since a spill-register won't be needed.
--- 1643,1648 ----
*************** earlyclobber_operand_p (x)
*** 1934,1939 ****
--- 1818,1839 ----
return 0;
}
+ /* Return 1 if X overlaps an operand that is being earlyclobbered. */
+
+ int
+ earlyclobber_overlap_p (x)
+ rtx x;
+ {
+ int i;
+
+ for (i = 0; i < n_earlyclobbers; i++)
+ {
+ if (reg_overlap_mentioned_for_reload_p (x, reload_earlyclobbers[i]))
+ return 1;
+ }
+ return 0;
+ }
+
/* Return 1 if expression X alters a hard reg in the range
from BEG_REGNO (inclusive) to END_REGNO (exclusive),
either explicitly or in the guise of a pseudo-reg allocated to REGNO.
*************** safe_from_earlyclobber (op, clobber)
*** 2325,2332 ****
early_data = decompose (clobber);
return immune_p (op, clobber, early_data);
}
! /* Main entry point of this file: search the body of INSN
for values that need reloading and record them with push_reload.
REPLACE nonzero means record also where the values occur
so that subst_reloads can be used.
--- 2225,2275 ----
early_data = decompose (clobber);
return immune_p (op, clobber, early_data);
}
+
+ /* Called via for_each_rtx; We look for a hard register *(int*)REGNOP in a
+ piece of rtl *XP from an instruction that has just been recognized.
+ When a match is found, store its address in *(rtx **)regnop. */
+ static int
+ mentioned_in_operand (xp, regnop)
+ rtx *xp;
+ void *regnop;
+ {
+ rtx x = *xp;
+
+ if (GET_CODE (x) == REG
+ || (GET_CODE (x) == SUBREG && GET_CODE (SUBREG_REG (x)) == REG))
+ {
+ int regno = * (int *) regnop;
+ if (refers_to_regno_p (regno, regno + 1, x, NULL_PTR))
+ {
+ *(rtx**)regnop = xp;
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+ /* Called from find_reloads via note_stores. N_OPERAND_EARLYCLOBBERS
+ points to an integer that says how many earlyclobbers have been found
+ in the operands of the current insn. If we find a clobber that was
+ not noted in the first N_OPERAND_EARLYCLOBBERS in RELOAD_EARLYCLOBBERS,
+ add it to the ones noted in RELOAD_EARLYCLOBBERS. */
+ static void
+ note_earlyclobbers (x, setter, n_operand_earlyclobbers)
+ rtx x, setter;
+ void *n_operand_earlyclobbers;
+ {
+ int i;
+
+ if (GET_CODE (setter) != CLOBBER)
+ return;
+ for (i = *(int *) n_operand_earlyclobbers; i >= 0; i--)
+ if (reload_earlyclobbers[i] == x)
+ return;
+ reload_earlyclobbers[n_earlyclobbers++] = XEXP (setter, 0);
+ }
! /* Main entry point of this file: search the body of CHAIN->INSN
for values that need reloading and record them with push_reload.
REPLACE nonzero means record also where the values occur
so that subst_reloads can be used.
*************** safe_from_earlyclobber (op, clobber)
*** 2349,2360 ****
commutative operands, reg_equiv_address substitution, or whatever. */
int
! find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
! rtx insn;
int replace, ind_levels;
int live_known;
short *reload_reg_p;
{
register int insn_code_number;
register int i, j;
int noperands;
--- 2292,2304 ----
commutative operands, reg_equiv_address substitution, or whatever. */
int
! find_reloads (chain, replace, ind_levels, live_known, reload_reg_p)
! struct insn_chain *chain;
int replace, ind_levels;
int live_known;
short *reload_reg_p;
{
+ rtx insn = chain->insn;
register int insn_code_number;
register int i, j;
int noperands;
*************** find_reloads (insn, replace, ind_levels,
*** 2400,2405 ****
--- 2344,2351 ----
int goal_earlyclobber = 0, this_earlyclobber;
enum machine_mode operand_mode[MAX_RECOG_OPERANDS];
int retval = 0;
+ int n_operand_earlyclobbers;
+ HARD_REG_SET live_throughout;
this_insn = insn;
n_reloads = 0;
*************** find_reloads (insn, replace, ind_levels,
*** 2409,2414 ****
--- 2355,2372 ----
hard_regs_live_known = live_known;
static_reload_reg_p = reload_reg_p;
+ /* Registers that die or are set in
+ this insn are 'free' spill regs. */
+ REG_SET_TO_HARD_REG_SET (chain->used_spill_regs, &chain->dead_or_set);
+ compute_use_by_pseudos (&chain->used_spill_regs, &chain->dead_or_set);
+
+ /* However, since global can now allocate multiple pseudos to one
+ hard reg at a time (when all but one pseudo is uninitialized),
+ we must exclude any hard regs that are live due to another pseudo. */
+ REG_SET_TO_HARD_REG_SET (live_throughout, &chain->live_throughout);
+ compute_use_by_pseudos (&live_throughout, &chain->live_throughout);
+ AND_COMPL_HARD_REG_SET(chain->used_spill_regs, live_throughout);
+
/* JUMP_INSNs and CALL_INSNs are not allowed to have any output reloads;
neither are insns that SET cc0. Insns that use CC0 are not allowed
to have any input reloads. */
*************** find_reloads (insn, replace, ind_levels,
*** 2567,2573 ****
|| GET_CODE (recog_data.operand[i]) == PLUS))
{
INSN_CODE (insn) = -1;
! retval = find_reloads (insn, replace, ind_levels, live_known,
reload_reg_p);
return retval;
}
--- 2525,2531 ----
|| GET_CODE (recog_data.operand[i]) == PLUS))
{
INSN_CODE (insn) = -1;
! retval = find_reloads (chain, replace, ind_levels, live_known,
reload_reg_p);
return retval;
}
*************** find_reloads (insn, replace, ind_levels,
*** 3553,3558 ****
--- 3511,3518 ----
for (i = 0; i < noperands; i++)
if (goal_alternative_earlyclobber[i])
reload_earlyclobbers[n_earlyclobbers++] = recog_data.operand[i];
+ n_operand_earlyclobbers = n_earlyclobbers;
+ note_stores (PATTERN (insn), note_earlyclobbers, &n_operand_earlyclobbers);
/* Now record reloads for all the operands that need them. */
for (i = 0; i < noperands; i++)
*************** find_reloads (insn, replace, ind_levels,
*** 3838,3848 ****
rld[i].in = rld[i].reg_rtx;
}
#endif
! /* Perhaps an output reload can be combined with another
! to reduce needs by one. */
! if (!goal_earlyclobber)
! combine_reloads ();
/* If we have a pair of reloads for parts of an address, they are reloading
the same object, the operands themselves were not reloaded, and they
--- 3798,3930 ----
rld[i].in = rld[i].reg_rtx;
}
#endif
+
+ /* If a hard register dies or is born in the insn, record dummy reloads
+ for it. Some insn have hard register inputs or outputs and these
+ should be noted as RELOAD_FOR_INPUT / RELOAD_FOR_OUTPUT, respectively,
+ to avoid artificial spill register shortage.
+ We don't have to register these uses if there are no reloads otherwise.
+ If the use is outside the operands, we generate a RELOAD_OTHER - to make
+ an insn use more fine-tuned reloads, you have to use a match_operand. */
+
+ if (n_reloads)
+ {
+ int next_reg;
+ int n_ordinary_reloads = n_reloads;
+ if (GET_CODE (insn) == CALL_INSN)
+ {
+ rtx link;
+
+ for (link = CALL_INSN_FUNCTION_USAGE (insn); link;
+ link = XEXP (link, 1))
+ {
+ rtx op = XEXP (link, 0);
+ rtx reg;
+ int in_p, regno, endregno;
+
+ if (GET_CODE (op) != USE && GET_CODE (op) != CLOBBER)
+ continue;
+ reg = XEXP (op, 0);
+ if (GET_CODE (reg) != REG)
+ continue;
+
+ in_p = GET_CODE (op) == USE;
+ regno = REGNO (reg);
+ endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (reg));
+
+ for (i = regno; i < endregno; i = next_reg)
+ {
+ next_reg = i + 1;
+ if (! TEST_HARD_REG_BIT (chain->used_spill_regs, i))
+ continue;
+ next_reg = i + HARD_REGNO_NREGS (i, reg_raw_mode[i]);
+ goal_alternative_matches[noperands] = -1;
+ reload_n_operands = noperands + 1;
+ push_hard_reload (in_p, i, noperands,
+ (in_p
+ ? RELOAD_FOR_INPUT : RELOAD_FOR_OUTPUT));
+ }
+ }
+ }
+
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i = next_reg)
+ {
+ union { int i; rtx *p; } u;
+
+ next_reg = i + 1;
+
+ if (! TEST_HARD_REG_BIT (chain->used_spill_regs, i))
+ continue;
+
+ next_reg = i + HARD_REGNO_NREGS (i, reg_raw_mode[i]);
! u.i = i;
!
! for (j = 0; j < noperands; j++)
! {
! rtx op = recog_data.operand[j];
! enum reload_type type;
! int in_p, out_p;
!
! u.i = i;
! if (! for_each_rtx (recog_data.operand_loc[j],
! mentioned_in_operand, &u))
! continue;
!
! out_p = recog_data.operand_loc[j] == u.p;
!
! while (GET_CODE (op) == SUBREG
! || GET_CODE (op) == SIGN_EXTRACT
! || GET_CODE (op) == ZERO_EXTRACT
! || GET_CODE (op) == STRICT_LOW_PART)
! {
! out_p |= &XEXP (op, 0) == u.p;
! op = XEXP (op, 0);
! }
!
! out_p &= modified[j] != RELOAD_READ;
! in_p = ! out_p || modified[j] != RELOAD_WRITE;
!
! if (GET_CODE (op) == REG && constraints[j][0] != 'p')
! {
! int k;
!
! type = operand_type[j];
! /* Check if this hard reg is already reloaded by an ordinary
! reload. We can't use the replacements array here because
! that doesn't work when REPLACE is zero. */
! for (k = n_ordinary_reloads - 1; k >= 0; k--)
! {
! if (rld[k].opnum == j && ! rld[k].secondary_p
! && ((in_p
! && (rld[k].in == *u.p
! || loc_mentioned_in_p (u.p, rld[k].in)))
! || (out_p
! && (rld[k].out == *u.p
! || loc_mentioned_in_p (u.p,
! rld[k].out)))))
! {
! /* This is like a secondary reload. */
! type = address_type[j];
! if (type == RELOAD_OTHER)
! type = (in_p
! ? RELOAD_FOR_INPUT_ADDRESS
! : RELOAD_FOR_OUTPUT_ADDRESS);
! break;
! }
! }
! }
! else
! type = address_type[j];
! push_hard_reload (in_p, i, j, type);
! if (in_p && out_p)
! push_hard_reload (0, i, j,
! (type == RELOAD_FOR_INPUT_ADDRESS
! ? RELOAD_FOR_OUTPUT_ADDRESS
! : type));
! }
! }
! }
/* If we have a pair of reloads for parts of an address, they are reloading
the same object, the operands themselves were not reloaded, and they
Index: reload.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/reload.h,v
retrieving revision 1.26
diff -p -r1.26 reload.h
*** reload.h 2000/01/17 17:16:19 1.26
--- reload.h 2000/01/27 01:38:07
*************** Boston, MA 02111-1307, USA. */
*** 29,34 ****
--- 29,36 ----
SECONDARY_RELOAD_CLASS (CLASS, MODE, X)
#endif
+ struct insn_chain;
+
/* If either macro is defined, show that we need secondary reloads. */
#if defined(SECONDARY_INPUT_RELOAD_CLASS) || defined(SECONDARY_OUTPUT_RELOAD_CLASS)
#define HAVE_SECONDARY_RELOADS
*************** extern rtx *reg_equiv_memory_loc;
*** 168,178 ****
extern rtx *reg_equiv_address;
extern rtx *reg_equiv_mem;
- /* All the "earlyclobber" operands of the current insn
- are recorded here. */
- extern int n_earlyclobbers;
- extern rtx reload_earlyclobbers[MAX_RECOG_OPERANDS];
-
/* Save the number of operands. */
extern int reload_n_operands;
--- 170,175 ----
*************** extern int safe_from_earlyclobber PARAMS
*** 291,297 ****
/* Search the body of INSN for values that need reloading and record them
with push_reload. REPLACE nonzero means record also where the values occur
so that subst_reloads can be used. */
! extern int find_reloads PARAMS ((rtx, int, int, int, short *));
/* Compute the sum of X and Y, making canonicalizations assumed in an
address, namely: sum constant integers, surround the sum of two
--- 288,294 ----
/* Search the body of INSN for values that need reloading and record them
with push_reload. REPLACE nonzero means record also where the values occur
so that subst_reloads can be used. */
! extern int find_reloads PARAMS ((struct insn_chain *, int, int, int, short *));
/* Compute the sum of X and Y, making canonicalizations assumed in an
address, namely: sum constant integers, surround the sum of two
*************** extern int regno_clobbered_p PARAMS ((in
*** 337,342 ****
--- 334,342 ----
/* Return 1 if X is an operand of an insn that is being earlyclobbered. */
int earlyclobber_operand_p PARAMS ((rtx));
+
+ /* Return 1 if X overlaps an operand that is being earlyclobbered. */
+ int earlyclobber_overlap_p PARAMS ((rtx));
/* Functions in reload1.c: */
Index: reload1.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/reload1.c,v
retrieving revision 1.197
diff -p -r1.197 reload1.c
*** reload1.c 2000/01/17 15:47:28 1.197
--- reload1.c 2000/01/27 01:38:09
*************** static rtx reg_reloaded_insn[FIRST_PSEUD
*** 140,148 ****
/* Indicate if reg_reloaded_insn / reg_reloaded_contents is valid */
static HARD_REG_SET reg_reloaded_valid;
- /* Indicate if the register was dead at the end of the reload.
- This is only valid if reg_reloaded_contents is set and valid. */
- static HARD_REG_SET reg_reloaded_dead;
/* Number of spill-regs so far; number of valid elements of spill_regs. */
static int n_spills;
--- 140,145 ----
*************** static short spill_reg_order[FIRST_PSEUD
*** 173,180 ****
/* This reg set indicates registers that can't be used as spill registers for
the currently processed insn. These are the hard registers which are live
! during the insn, but not allocated to pseudos, as well as fixed
! registers. */
static HARD_REG_SET bad_spill_regs;
/* These are the hard registers that can't be used as spill register for any
--- 170,177 ----
/* This reg set indicates registers that can't be used as spill registers for
the currently processed insn. These are the hard registers which are live
! during the insn, but not allocated to pseudos, dying, or set, as well as
! fixed registers. */
static HARD_REG_SET bad_spill_regs;
/* These are the hard registers that can't be used as spill register for any
*************** static int spill_stack_slot_width[FIRST_
*** 240,249 ****
/* Record which pseudos needed to be spilled. */
static regset_head spilled_pseudos;
- /* Used for communication between order_regs_for_reload and count_pseudo.
- Used to avoid counting one pseudo twice. */
- static regset_head pseudos_counted;
-
/* First uid used by insns created by reload in this function.
Used in find_equiv_reg. */
int reload_first_uid;
--- 237,242 ----
*************** static void find_reload_regs PARAMS ((s
*** 375,380 ****
--- 368,374 ----
static void select_reload_regs PARAMS ((FILE *));
static void delete_caller_save_insns PARAMS ((void));
+ static int spill_pseudo PARAMS ((regset, enum reg_class));
static void spill_failure PARAMS ((rtx, enum reg_class));
static void count_spilled_pseudo PARAMS ((int, int, int));
static void delete_dead_insn PARAMS ((rtx));
*************** static int reload_reg_free_p PARAMS ((i
*** 408,413 ****
--- 402,408 ----
static int reload_reg_free_for_value_p PARAMS ((int, int, enum reload_type,
rtx, rtx, int, int));
static int reload_reg_reaches_end_p PARAMS ((int, int, enum reload_type));
+ static int hard_reload_conflict PARAMS ((int, int));
static int allocate_reload_reg PARAMS ((struct insn_chain *, int, int));
static void failed_reload PARAMS ((rtx, int));
static int set_reload_reg PARAMS ((int, int));
*************** static rtx gen_mode_int PARAMS ((enum
*** 452,457 ****
--- 447,453 ----
static void failed_reload PARAMS ((rtx, int));
static int set_reload_reg PARAMS ((int, int));
extern void dump_needs PARAMS ((struct insn_chain *, FILE *));
+ static int mark_regs_outside_operands PARAMS ((rtx *, void *));
/* Initialize the reload pass once per compilation. */
*************** init_reload ()
*** 506,512 ****
reload_startobj = (char *) obstack_alloc (&reload_obstack, 0);
INIT_REG_SET (&spilled_pseudos);
- INIT_REG_SET (&pseudos_counted);
}
/* List of insn chains that are currently unused. */
--- 502,507 ----
*************** compute_use_by_pseudos (to, from)
*** 567,572 ****
--- 562,609 ----
}
});
}
+
+ /* Called via for_each_rtx; We look for a registers in a
+ piece of rtl *XP from an instruction that has just been recognized.
+ *XP is not inside an operand (but it may be one). Do not look at
+ operands of the recognized insn.
+ LIVE_THROUGHOUT is actually a regset.
+ Include all register numbers found in LIVE_THROUGHOUT. */
+
+ static int
+ mark_regs_outside_operands (xp, live_throughout)
+ rtx *xp;
+ void *live_throughout;
+ {
+ int i;
+ rtx x, reg;
+
+ for (i = recog_data.n_operands - 1; i >= 0; i--)
+ {
+ if (xp == recog_data.operand_loc[i])
+ return -1;
+ }
+ x = *xp;
+ reg = x;
+ if (GET_CODE (x) == SUBREG)
+ reg = SUBREG_REG (x);
+ if (GET_CODE (reg) == REG)
+ {
+ int regno = REGNO (reg);
+
+ if (regno < FIRST_PSEUDO_REGISTER)
+ {
+ int nregs = HARD_REGNO_NREGS (regno, GET_MODE (x));
+
+ do
+ SET_REGNO_REG_SET ((regset) live_throughout, regno++);
+ while (--nregs);
+ }
+ else if (reg_renumber[regno] >= 0)
+ SET_REGNO_REG_SET ((regset) live_throughout, regno);
+ }
+ return 0;
+ }
/* Global variables used by reload and its subroutines. */
*************** reload (first, global, dumpfile)
*** 605,610 ****
--- 642,649 ----
register int i;
register rtx insn;
register struct elim_table *ep;
+ struct insn_chain *chain;
+
/* The two pointers used to track the true location of the memory used
for label offsets. */
*************** reload (first, global, dumpfile)
*** 772,777 ****
--- 811,829 ----
scan_paradoxical_subregs (PATTERN (insn));
}
+ /* Note which register operands are life throughout each insn. */
+ for (chain = reload_insn_chain; chain; chain = chain->next)
+ {
+ if (GET_RTX_CLASS (GET_CODE (chain->insn)) == 'i')
+ {
+ int i;
+
+ extract_insn (chain->insn);
+ for_each_rtx (&PATTERN (chain->insn), mark_regs_outside_operands,
+ &chain->live_throughout);
+ }
+ }
+
init_elim_table ();
num_labels = max_label_num () - get_first_label_num ();
*************** maybe_fix_stack_asms ()
*** 1304,1310 ****
if (TEST_HARD_REG_BIT (allowed, i))
{
CLEAR_REGNO_REG_SET (&chain->live_throughout, i);
- CLEAR_REGNO_REG_SET (&chain->dead_or_set, i);
}
}
--- 1356,1361 ----
*************** calculate_needs_all_insns (global)
*** 1377,1383 ****
did_elimination = eliminate_regs_in_insn (insn, 0);
/* Analyze the instruction. */
! operands_changed = find_reloads (insn, 0, spill_indirect_levels,
global, spill_reg_order);
/* If a no-op set needs more than one reload, this is likely
--- 1428,1434 ----
did_elimination = eliminate_regs_in_insn (insn, 0);
/* Analyze the instruction. */
! operands_changed = find_reloads (chain, 0, spill_indirect_levels,
global, spill_reg_order);
/* If a no-op set needs more than one reload, this is likely
*************** calculate_needs_all_insns (global)
*** 1433,1438 ****
--- 1484,1542 ----
*pprev_reload = 0;
}
+ /* Try to find pseudo in DEAD_OR_SET that contains has a hard register in
+ CLASS allocated it. If successful, add it to spilled_pseudos, and
+ return 1. */
+ static int
+ spill_pseudo (dead_or_set, class)
+ regset dead_or_set;
+ enum reg_class class;
+ {
+ int pseudo;
+ int best_reg = -1;
+ unsigned long best_cost = ~0L;
+
+ /* We kick out the least-used pseudo that contains a hard
+ register of the desired class. We don't strive to kick
+ out all pseudos that live on that hard register, since
+ just kicking out one pseudo might already satisfy our
+ requirements. */
+ /* ??? We could refine this further by only kicking out pseudos
+ that are actually live during lifetime of the requested
+ reload; i.e. for a RELOAD_FOR_INPUT we'd want to kick out a
+ pseudo that dies, but for a RELOAD_FOR_OUTPUT we'd want to
+ kick out a pseudo that is set. But for that we'd have to
+ record separately which pseudos are set and which die.
+ For now, we assume it's not worth the hassle. */
+ EXECUTE_IF_SET_IN_REG_SET
+ (dead_or_set, FIRST_PSEUDO_REGISTER, pseudo,
+ {
+ int r = reg_renumber[pseudo];
+ int n = HARD_REGNO_NREGS (r, PSEUDO_REGNO_MODE (pseudo));
+ unsigned long cost = REG_N_REFS (pseudo) * n;
+
+ if (cost < best_cost)
+ {
+ do
+ n--;
+ while (n >= 0
+ && ! TEST_HARD_REG_BIT (reg_class_contents[class],
+ n+r));
+ if (n >= 0)
+ {
+ best_cost = cost;
+ best_reg = pseudo;
+ }
+ }
+ });
+ if (best_reg >= 0)
+ {
+ SET_REGNO_REG_SET (&spilled_pseudos, best_reg);
+ return 1;
+ }
+ return 0;
+ }
+
/* Comparison function for qsort to decide which of two reloads
should be handled first. *P1 and *P2 are the reload numbers. */
*************** count_pseudo (reg)
*** 1487,1498 ****
int r = reg_renumber[reg];
int nregs;
! if (REGNO_REG_SET_P (&pseudos_counted, reg)
! || REGNO_REG_SET_P (&spilled_pseudos, reg))
return;
- SET_REGNO_REG_SET (&pseudos_counted, reg);
-
if (r < 0)
abort ();
--- 1591,1599 ----
int r = reg_renumber[reg];
int nregs;
! if (REGNO_REG_SET_P (&spilled_pseudos, reg))
return;
if (r < 0)
abort ();
*************** order_regs_for_reload (chain)
*** 1524,1548 ****
/* Test the various reasons why we can't use a register for
spilling in this insn. */
if (fixed_regs[i]
! || REGNO_REG_SET_P (&chain->live_throughout, i)
! || REGNO_REG_SET_P (&chain->dead_or_set, i))
SET_HARD_REG_BIT (bad_spill_regs, i);
}
/* Now find out which pseudos are allocated to it, and update
hard_reg_n_uses. */
- CLEAR_REG_SET (&pseudos_counted);
EXECUTE_IF_SET_IN_REG_SET
(&chain->live_throughout, FIRST_PSEUDO_REGISTER, j,
{
count_pseudo (j);
});
- EXECUTE_IF_SET_IN_REG_SET
- (&chain->dead_or_set, FIRST_PSEUDO_REGISTER, j,
- {
- count_pseudo (j);
- });
- CLEAR_REG_SET (&pseudos_counted);
}
/* Vector of reload-numbers showing the order in which the reloads should
--- 1625,1641 ----
/* Test the various reasons why we can't use a register for
spilling in this insn. */
if (fixed_regs[i]
! || REGNO_REG_SET_P (&chain->live_throughout, i))
SET_HARD_REG_BIT (bad_spill_regs, i);
}
/* Now find out which pseudos are allocated to it, and update
hard_reg_n_uses. */
EXECUTE_IF_SET_IN_REG_SET
(&chain->live_throughout, FIRST_PSEUDO_REGISTER, j,
{
count_pseudo (j);
});
}
/* Vector of reload-numbers showing the order in which the reloads should
*************** find_reg (chain, order, dumpfile)
*** 1595,1606 ****
IOR_COMPL_HARD_REG_SET (not_usable, reg_class_contents[rl->class]);
CLEAR_HARD_REG_SET (used_by_other_reload);
! for (i = 0; i < order; i++)
{
! int other = reload_order[i];
! if (rld[other].regno >= 0 && reloads_conflict (other, rnum))
! for (j = 0; j < rld[other].nregs; j++)
! SET_HARD_REG_BIT (used_by_other_reload, rld[other].regno + j);
}
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
--- 1688,1700 ----
IOR_COMPL_HARD_REG_SET (not_usable, reg_class_contents[rl->class]);
CLEAR_HARD_REG_SET (used_by_other_reload);
! for (i = n_reloads - 1; i >= 0; i--)
{
! if (rld[i].regno >= 0
! && (reloads_conflict (i, rnum)
! || hard_reload_conflict (i, rnum)))
! for (j = 0; j < rld[i].nregs; j++)
! SET_HARD_REG_BIT (used_by_other_reload, rld[i].regno + j);
}
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
*************** find_reg (chain, order, dumpfile)
*** 1657,1667 ****
{
count_spilled_pseudo (best_reg, rl->nregs, j);
});
- EXECUTE_IF_SET_IN_REG_SET
- (&chain->dead_or_set, FIRST_PSEUDO_REGISTER, j,
- {
- count_spilled_pseudo (best_reg, rl->nregs, j);
- });
for (i = 0; i < rl->nregs; i++)
{
--- 1751,1756 ----
*************** find_reload_regs (chain, dumpfile)
*** 1728,1740 ****
&& rld[r].regno == -1)
if (! find_reg (chain, i, dumpfile))
{
spill_failure (chain->insn, rld[r].class);
failure = 1;
return;
}
}
! COPY_HARD_REG_SET (chain->used_spill_regs, used_spill_regs_local);
IOR_HARD_REG_SET (used_spill_regs, used_spill_regs_local);
memcpy (chain->rld, rld, n_reloads * sizeof (struct reload));
--- 1817,1839 ----
&& rld[r].regno == -1)
if (! find_reg (chain, i, dumpfile))
{
+ /* Sometimes a pseudo that dies or is set in the insn is allocated
+ to (a group of hard regsiters containing) a hard register in a
+ class that we urgently need - typically a one-register class.
+ If we can find a pseudo we can kick out, do so, and
+ stop further register allocation; we don't know how many
+ hard registers and for what timespan(s) we have freed up.
+ The next reload iteration will find out the new reload
+ requirements. */
+ if (spill_pseudo (&chain->dead_or_set, rld[r].class))
+ break;
spill_failure (chain->insn, rld[r].class);
failure = 1;
return;
}
}
! IOR_HARD_REG_SET (chain->used_spill_regs, used_spill_regs_local);
IOR_HARD_REG_SET (used_spill_regs, used_spill_regs_local);
memcpy (chain->rld, rld, n_reloads * sizeof (struct reload));
*************** finish_spills (global, dumpfile)
*** 3509,3526 ****
ior_hard_reg_set (pseudo_forbidden_regs + i,
&chain->used_spill_regs);
});
- EXECUTE_IF_SET_IN_REG_SET
- (&chain->dead_or_set, FIRST_PSEUDO_REGISTER, i,
- {
- ior_hard_reg_set (pseudo_forbidden_regs + i,
- &chain->used_spill_regs);
- });
}
/* Retry allocating the spilled pseudos. For each reg, merge the
various reg sets that indicate which hard regs can't be used,
and call retry_global_alloc.
! We change spill_pseudos here to only contain pseudos that did not
get a new hard register. */
for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
if (reg_old_renumber[i] != reg_renumber[i])
--- 3608,3619 ----
ior_hard_reg_set (pseudo_forbidden_regs + i,
&chain->used_spill_regs);
});
}
/* Retry allocating the spilled pseudos. For each reg, merge the
various reg sets that indicate which hard regs can't be used,
and call retry_global_alloc.
! We change spilled_pseudos here to only contain pseudos that did not
get a new hard register. */
for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
if (reg_old_renumber[i] != reg_renumber[i])
*************** finish_spills (global, dumpfile)
*** 3537,3572 ****
/* Fix up the register information in the insn chain.
This involves deleting those of the spilled pseudos which did not get
! a new hard register home from the live_{before,after} sets. */
for (chain = reload_insn_chain; chain; chain = chain->next)
{
- HARD_REG_SET used_by_pseudos;
- HARD_REG_SET used_by_pseudos2;
-
AND_COMPL_REG_SET (&chain->live_throughout, &spilled_pseudos);
AND_COMPL_REG_SET (&chain->dead_or_set, &spilled_pseudos);
-
- /* Mark any unallocated hard regs as available for spills. That
- makes inheritance work somewhat better. */
- if (chain->need_reload)
- {
- REG_SET_TO_HARD_REG_SET (used_by_pseudos, &chain->live_throughout);
- REG_SET_TO_HARD_REG_SET (used_by_pseudos2, &chain->dead_or_set);
- IOR_HARD_REG_SET (used_by_pseudos, used_by_pseudos2);
-
- /* Save the old value for the sanity test below. */
- COPY_HARD_REG_SET (used_by_pseudos2, chain->used_spill_regs);
-
- compute_use_by_pseudos (&used_by_pseudos, &chain->live_throughout);
- compute_use_by_pseudos (&used_by_pseudos, &chain->dead_or_set);
- COMPL_HARD_REG_SET (chain->used_spill_regs, used_by_pseudos);
- AND_HARD_REG_SET (chain->used_spill_regs, used_spill_regs);
-
- /* Make sure we only enlarge the set. */
- GO_IF_HARD_REG_SUBSET (used_by_pseudos2, chain->used_spill_regs, ok);
- abort ();
- ok:;
- }
}
/* Let alter_reg modify the reg rtx's for the modified pseudos. */
--- 3630,3641 ----
/* Fix up the register information in the insn chain.
This involves deleting those of the spilled pseudos which did not get
! a new hard register home from the live_throughout / pseudo_dead_or_set
! sets. */
for (chain = reload_insn_chain; chain; chain = chain->next)
{
AND_COMPL_REG_SET (&chain->live_throughout, &spilled_pseudos);
AND_COMPL_REG_SET (&chain->dead_or_set, &spilled_pseudos);
}
/* Let alter_reg modify the reg rtx's for the modified pseudos. */
*************** reload_as_needed (live_known)
*** 3733,3739 ****
bzero (reg_has_output_reload, max_regno);
CLEAR_HARD_REG_SET (reg_is_output_reload);
! find_reloads (insn, 1, spill_indirect_levels, live_known,
spill_reg_order);
}
--- 3802,3808 ----
bzero (reg_has_output_reload, max_regno);
CLEAR_HARD_REG_SET (reg_is_output_reload);
! find_reloads (chain, 1, spill_indirect_levels, live_known,
spill_reg_order);
}
*************** forget_old_reloads_1 (x, ignored, data)
*** 3990,3997 ****
/* The following HARD_REG_SETs indicate when each hard register is
used for a reload of various parts of the current insn. */
- /* If reg is unavailable for all reloads. */
- static HARD_REG_SET reload_reg_unavailable;
/* If reg is in use as a reload reg for a RELOAD_OTHER reload. */
static HARD_REG_SET reload_reg_used;
/* If reg is in use for a RELOAD_FOR_INPUT_ADDRESS reload for operand I. */
--- 4059,4064 ----
*************** static HARD_REG_SET reload_reg_used_at_a
*** 4022,4029 ****
in the group. */
static HARD_REG_SET reload_reg_used_for_inherit;
! /* Records which hard regs are used in any way, either as explicit use or
! by being allocated to a pseudo during any point of the current insn. */
static HARD_REG_SET reg_used_in_insn;
/* Mark reg REGNO as in use for a reload of the sort spec'd by OPNUM and
--- 4089,4097 ----
in the group. */
static HARD_REG_SET reload_reg_used_for_inherit;
! /* Records which hard regs are used in any way not evident in the insn,
! by being a live hard register or allocated to a pseudo throughout
! the current insn. */
static HARD_REG_SET reg_used_in_insn;
/* Mark reg REGNO as in use for a reload of the sort spec'd by OPNUM and
*************** reload_reg_free_p (regno, opnum, type)
*** 4214,4222 ****
{
int i;
/* In use for a RELOAD_OTHER means it's not available for anything. */
! if (TEST_HARD_REG_BIT (reload_reg_used, regno)
! || TEST_HARD_REG_BIT (reload_reg_unavailable, regno))
return 0;
switch (type)
--- 4282,4293 ----
{
int i;
+ /* Is this a live hard reg or allocated to a pseudo? */
+ if (TEST_HARD_REG_BIT (reg_used_in_insn, regno))
+ return 0;
+
/* In use for a RELOAD_OTHER means it's not available for anything. */
! if (TEST_HARD_REG_BIT (reload_reg_used, regno))
return 0;
switch (type)
*************** reloads_conflict (r1, r2)
*** 4566,4571 ****
--- 4637,4695 ----
abort ();
}
}
+
+ /* Return nonzero if reload OLD is a hard reload and therefore conflicts
+ with reload NEW. return zero if there is no conflict.
+ If reloads_conflict will find a conflict, we don't care about the
+ return value of hard_reload_conflict. */
+ static int
+ hard_reload_conflict (old, new)
+ int old, new;
+ {
+ if (rld[old].reg_rtx == rld[old].in)
+ {
+ enum reload_type old_type = rld[old].when_needed;
+
+ switch (rld[new].when_needed)
+ {
+ case RELOAD_FOR_OTHER_ADDRESS:
+ return 1;
+ case RELOAD_FOR_INPADDR_ADDRESS:
+ case RELOAD_FOR_INPUT_ADDRESS:
+ if (old_type == RELOAD_FOR_INPUT_ADDRESS
+ && rld[old].opnum >= rld[new].opnum)
+ return 1;
+ /* Fall through. */
+ case RELOAD_FOR_OPADDR_ADDR:
+ case RELOAD_FOR_OPERAND_ADDRESS:
+ return (old_type == RELOAD_FOR_INPUT
+ || old_type == RELOAD_FOR_OPERAND_ADDRESS);
+
+ case RELOAD_FOR_INPUT: case RELOAD_FOR_INSN: case RELOAD_OTHER:
+ case RELOAD_FOR_OUTPUT_ADDRESS: case RELOAD_FOR_OUTPUT:
+ case RELOAD_FOR_OUTADDR_ADDRESS:
+ ;
+ }
+ }
+ if (rld[old].reg_rtx == rld[old].out)
+ {
+ switch (rld[new].when_needed)
+ {
+ case RELOAD_FOR_OUTPUT_ADDRESS:
+ case RELOAD_FOR_OUTADDR_ADDRESS:
+ return (rld[old].when_needed == RELOAD_FOR_OUTPUT
+ || (rld[old].when_needed == RELOAD_FOR_OUTPUT_ADDRESS
+ && rld[old].opnum <= rld[new].opnum));
+
+ case RELOAD_FOR_OUTPUT: case RELOAD_FOR_INSN: case RELOAD_OTHER:
+ case RELOAD_FOR_OTHER_ADDRESS: case RELOAD_FOR_INPADDR_ADDRESS:
+ case RELOAD_FOR_INPUT_ADDRESS: case RELOAD_FOR_OPADDR_ADDR:
+ case RELOAD_FOR_OPERAND_ADDRESS: case RELOAD_FOR_INPUT:
+ ;
+ }
+ }
+ return 0;
+ }
/* Indexed by reload number, 1 if incoming value
inherited from previous insns. */
*************** reload_reg_free_for_value_p (regno, opnu
*** 4620,4628 ****
int i;
int copy = 0;
- if (TEST_HARD_REG_BIT (reload_reg_unavailable, regno))
- return 0;
-
if (out == const0_rtx)
{
copy = 1;
--- 4744,4749 ----
*************** reload_reg_free_for_value_p (regno, opnu
*** 4782,4789 ****
if (! rld[i].in || rtx_equal_p (rld[i].in, value))
{
time2 = MAX_RECOG_OPERANDS * 4 + 4;
! /* Earlyclobbered outputs must conflict with inputs. */
! if (earlyclobber_operand_p (rld[i].out))
time2 = MAX_RECOG_OPERANDS * 4 + 3;
break;
--- 4903,4912 ----
if (! rld[i].in || rtx_equal_p (rld[i].in, value))
{
time2 = MAX_RECOG_OPERANDS * 4 + 4;
! /* Earlyclobbered outputs must conflict with inputs.
! If this is a hard reload, earlyclobber_operand_p
! doesn't work, so use earlyclobber_overlap_p. */
! if (rld[i].out && earlyclobber_overlap_p (rld[i].out))
time2 = MAX_RECOG_OPERANDS * 4 + 3;
break;
*************** reload_reg_free_for_value_p (regno, opnu
*** 4799,4805 ****
default:
return 0;
}
! if ((time1 >= time2
&& (! rld[i].in || rld[i].out
|| ! rtx_equal_p (rld[i].in, value)))
|| (out && rld[reloadnum].out_reg
--- 4922,4930 ----
default:
return 0;
}
! if (((time1 >= time2
! /* Test for hard reloads */
! || (rld[i].in && rld[i].in == rld[i].reg_rtx))
&& (! rld[i].in || rld[i].out
|| ! rtx_equal_p (rld[i].in, value)))
|| (out && rld[reloadnum].out_reg
*************** allocate_reload_reg (chain, r, last_relo
*** 4954,4962 ****
if ((reload_reg_free_p (regnum, rld[r].opnum,
rld[r].when_needed)
|| (rld[r].in
! /* We check reload_reg_used to make sure we
! don't clobber the return register. */
! && ! TEST_HARD_REG_BIT (reload_reg_used, regnum)
&& reload_reg_free_for_value_p (regnum,
rld[r].opnum,
rld[r].when_needed,
--- 5079,5089 ----
if ((reload_reg_free_p (regnum, rld[r].opnum,
rld[r].when_needed)
|| (rld[r].in
! /* We check reg_used_in_insn to make sure we don't clobber
! pseudos or hard regs live after the insn.
! Registers that are set in the insn will be accounted
! for with reloads. */
! && ! TEST_HARD_REG_BIT (reg_used_in_insn, regnum)
&& reload_reg_free_for_value_p (regnum,
rld[r].opnum,
rld[r].when_needed,
*************** choose_reload_regs_init (chain, save_rel
*** 5043,5058 ****
CLEAR_HARD_REG_SET (reload_reg_used_in_insn);
CLEAR_HARD_REG_SET (reload_reg_used_in_other_addr);
! CLEAR_HARD_REG_SET (reg_used_in_insn);
! {
! HARD_REG_SET tmp;
! REG_SET_TO_HARD_REG_SET (tmp, &chain->live_throughout);
! IOR_HARD_REG_SET (reg_used_in_insn, tmp);
! REG_SET_TO_HARD_REG_SET (tmp, &chain->dead_or_set);
! IOR_HARD_REG_SET (reg_used_in_insn, tmp);
! compute_use_by_pseudos (®_used_in_insn, &chain->live_throughout);
! compute_use_by_pseudos (®_used_in_insn, &chain->dead_or_set);
! }
for (i = 0; i < reload_n_operands; i++)
{
CLEAR_HARD_REG_SET (reload_reg_used_in_output[i]);
--- 5170,5178 ----
CLEAR_HARD_REG_SET (reload_reg_used_in_insn);
CLEAR_HARD_REG_SET (reload_reg_used_in_other_addr);
! REG_SET_TO_HARD_REG_SET (reg_used_in_insn, &chain->live_throughout);
! compute_use_by_pseudos (®_used_in_insn, &chain->live_throughout);
!
for (i = 0; i < reload_n_operands; i++)
{
CLEAR_HARD_REG_SET (reload_reg_used_in_output[i]);
*************** choose_reload_regs_init (chain, save_rel
*** 5063,5078 ****
CLEAR_HARD_REG_SET (reload_reg_used_in_outaddr_addr[i]);
}
- COMPL_HARD_REG_SET (reload_reg_unavailable, chain->used_spill_regs);
-
CLEAR_HARD_REG_SET (reload_reg_used_for_inherit);
for (i = 0; i < n_reloads; i++)
/* If we have already decided to use a certain register,
don't use it in another way. */
if (rld[i].reg_rtx)
! mark_reload_reg_in_use (REGNO (rld[i].reg_rtx), rld[i].opnum,
! rld[i].when_needed, rld[i].mode);
}
/* Assign hard reg targets for the pseudo-registers we must reload
--- 5183,5240 ----
CLEAR_HARD_REG_SET (reload_reg_used_in_outaddr_addr[i]);
}
CLEAR_HARD_REG_SET (reload_reg_used_for_inherit);
for (i = 0; i < n_reloads; i++)
/* If we have already decided to use a certain register,
don't use it in another way. */
if (rld[i].reg_rtx)
! {
! mark_reload_reg_in_use (REGNO (rld[i].reg_rtx), rld[i].opnum,
! rld[i].when_needed, rld[i].mode);
! /* Hard reloads start out life before the first regular reload and/or
! remain life till after the last regular reload. */
! if (rld[i].reg_rtx == rld[i].in)
! {
! enum reload_type type;
!
! mark_reload_reg_in_use (REGNO (rld[i].reg_rtx), rld[i].opnum,
! RELOAD_FOR_OTHER_ADDRESS, rld[i].mode);
! type = rld[i].when_needed;
! if (type == RELOAD_FOR_OPERAND_ADDRESS)
! mark_reload_reg_in_use (REGNO (rld[i].reg_rtx), rld[i].opnum,
! RELOAD_FOR_INPUT, rld[i].mode);
! if (type == RELOAD_FOR_INPUT_ADDRESS
! || type == RELOAD_FOR_INPUT
! || type == RELOAD_FOR_OPERAND_ADDRESS)
! {
! int j;
!
! for (j = rld[i].opnum; j >= 0; j--)
! {
! mark_reload_reg_in_use (REGNO (rld[i].reg_rtx), j,
! RELOAD_FOR_INPUT_ADDRESS,
! rld[i].mode);
! mark_reload_reg_in_use (REGNO (rld[i].reg_rtx), j,
! RELOAD_FOR_INPADDR_ADDRESS,
! rld[i].mode);
! }
! }
! }
! if (rld[i].reg_rtx == rld[i].out)
! {
! int j = rld[i].opnum;
!
! while (--j >= 0)
! {
! mark_reload_reg_in_use (REGNO (rld[i].reg_rtx), j,
! RELOAD_FOR_OUTPUT_ADDRESS, rld[i].mode);
! mark_reload_reg_in_use (REGNO (rld[i].reg_rtx), j,
! RELOAD_FOR_OUTADDR_ADDRESS,
! rld[i].mode);
! }
! }
! }
}
/* Assign hard reg targets for the pseudo-registers we must reload
*************** choose_reload_regs (chain)
*** 5299,5306 ****
if (k == nr)
{
- int i1;
-
last_reg = (GET_MODE (last_reg) == mode
? last_reg : gen_rtx_REG (mode, i));
--- 5461,5466 ----
*************** choose_reload_regs (chain)
*** 5310,5330 ****
current insn, just mark it as a place to
reload from since we can't use it as the
reload register itself. */
-
- for (i1 = 0; i1 < n_earlyclobbers; i1++)
- if (reg_overlap_mentioned_for_reload_p
- (reg_last_reload_reg[regno],
- reload_earlyclobbers[i1]))
- break;
! if (i1 != n_earlyclobbers
|| ! (reload_reg_free_for_value_p
(i, rld[r].opnum, rld[r].when_needed,
rld[r].in, rld[r].out, r, 1))
/* Don't use it if we'd clobber a pseudo reg. */
|| (TEST_HARD_REG_BIT (reg_used_in_insn, i)
! && rld[r].out
! && ! TEST_HARD_REG_BIT (reg_reloaded_dead, i))
/* Don't clobber the frame pointer. */
|| (i == HARD_FRAME_POINTER_REGNUM && rld[r].out)
/* Don't really use the inherited spill reg
--- 5470,5483 ----
current insn, just mark it as a place to
reload from since we can't use it as the
reload register itself. */
! if (earlyclobber_overlap_p (last_reg)
|| ! (reload_reg_free_for_value_p
(i, rld[r].opnum, rld[r].when_needed,
rld[r].in, rld[r].out, r, 1))
/* Don't use it if we'd clobber a pseudo reg. */
|| (TEST_HARD_REG_BIT (reg_used_in_insn, i)
! && rld[r].out)
/* Don't clobber the frame pointer. */
|| (i == HARD_FRAME_POINTER_REGNUM && rld[r].out)
/* Don't really use the inherited spill reg
*************** choose_reload_regs (chain)
*** 5390,5395 ****
--- 5543,5551 ----
&& rtx_equal_p (rld[r].out, SET_DEST (set))
&& CONSTANT_P (SET_SRC (set)))
search_equiv = SET_SRC (set);
+ /* N.B. since this is a simple move insn, we don't actually
+ change the register we use, hence we don't have to
+ tell reload_reg_free_for_value_p about rld[r].out. */
}
if (search_equiv)
*************** choose_reload_regs (chain)
*** 5422,5429 ****
&& ((TEST_HARD_REG_BIT (reload_reg_used_at_all, regno)
&& ! reload_reg_free_for_value_p (regno, rld[r].opnum,
rld[r].when_needed,
! rld[r].in,
! rld[r].out, r, 1))
|| ! TEST_HARD_REG_BIT (reg_class_contents[(int) rld[r].class],
regno)))
equiv = 0;
--- 5578,5585 ----
&& ((TEST_HARD_REG_BIT (reload_reg_used_at_all, regno)
&& ! reload_reg_free_for_value_p (regno, rld[r].opnum,
rld[r].when_needed,
! search_equiv,
! NULL_RTX, r, 1))
|| ! TEST_HARD_REG_BIT (reg_class_contents[(int) rld[r].class],
regno)))
equiv = 0;
*************** choose_reload_regs (chain)
*** 5432,5458 ****
equiv = 0;
/* We found a register that contains the value we need.
! If this register is the same as an `earlyclobber' operand
! of the current insn, just mark it as a place to reload from
! since we can't use it as the reload register itself. */
!
! if (equiv != 0)
! for (i = 0; i < n_earlyclobbers; i++)
! if (reg_overlap_mentioned_for_reload_p (equiv,
! reload_earlyclobbers[i]))
! {
! reload_override_in[r] = equiv;
! equiv = 0;
! break;
! }
!
! /* If the equiv register we have found is explicitly clobbered
! in the current insn, it depends on the reload type if we
! can use it, use it for reload_override_in, or not at all.
In particular, we then can't use EQUIV for a
RELOAD_FOR_OUTPUT_ADDRESS reload. */
! if (equiv != 0 && regno_clobbered_p (regno, insn))
{
switch (rld[r].when_needed)
{
--- 5588,5604 ----
equiv = 0;
/* We found a register that contains the value we need.
! If this register is the same as an `earlyclobber' operand,
! or it is explicitly clobbered in the current insn, it depends
! on the reload type if we can use it as the reload register
! itself, use it only for reload_override_in (i.e as a place
! to reload from), or not at all.
In particular, we then can't use EQUIV for a
RELOAD_FOR_OUTPUT_ADDRESS reload. */
! if (equiv != 0
! && (earlyclobber_overlap_p (equiv)
! || regno_clobbered_p (regno, insn)))
{
switch (rld[r].when_needed)
{
*************** choose_reload_regs (chain)
*** 5706,5712 ****
if (rld[r].when_needed != RELOAD_OTHER
&& rld[r].when_needed != RELOAD_FOR_OUTPUT
! && rld[r].when_needed != RELOAD_FOR_INSN)
abort ();
}
}
--- 5852,5860 ----
if (rld[r].when_needed != RELOAD_OTHER
&& rld[r].when_needed != RELOAD_FOR_OUTPUT
! && rld[r].when_needed != RELOAD_FOR_INSN
! && (rld[r].when_needed != RELOAD_FOR_OUTPUT_ADDRESS
! || rld[r].out_reg != rld[r].reg_rtx))
abort ();
}
}
*************** static rtx other_output_reload_insns[MAX
*** 5856,5862 ****
/* Values to be put in spill_reg_store are put here first. */
static rtx new_spill_reg_store[FIRST_PSEUDO_REGISTER];
- static HARD_REG_SET reg_reloaded_died;
/* Generate insns to perform reload RL, which is for the insn in CHAIN and
has the number J. OLD contains the value to be used as input. */
--- 6004,6009 ----
*************** emit_output_reload_insns (chain, rl, j)
*** 6500,6507 ****
reload_spill_index[j] = src;
SET_HARD_REG_BIT (reg_is_output_reload, src);
- if (find_regno_note (insn, REG_DEAD, src))
- SET_HARD_REG_BIT (reg_reloaded_died, src);
}
if (REGNO (rl->reg_rtx) < FIRST_PSEUDO_REGISTER)
{
--- 6647,6652 ----
*************** emit_reload_insns (chain)
*** 6700,6707 ****
rtx following_insn = NEXT_INSN (insn);
rtx before_insn = PREV_INSN (insn);
- CLEAR_HARD_REG_SET (reg_reloaded_died);
-
for (j = 0; j < reload_n_operands; j++)
input_reload_insns[j] = input_address_reload_insns[j]
= inpaddr_address_reload_insns[j]
--- 6845,6850 ----
*************** emit_reload_insns (chain)
*** 6894,6900 ****
/* Now do the inverse operation. */
for (k = 0; k < nr; k++)
{
- CLEAR_HARD_REG_BIT (reg_reloaded_dead, i + k);
reg_reloaded_contents[i + k]
= (nregno >= FIRST_PSEUDO_REGISTER || nr != nnr
? nregno
--- 7037,7042 ----
*************** emit_reload_insns (chain)
*** 6951,6957 ****
for (k = 0; k < nr; k++)
{
- CLEAR_HARD_REG_BIT (reg_reloaded_dead, i + k);
reg_reloaded_contents[i + k]
= (nregno >= FIRST_PSEUDO_REGISTER || nr != nnr
? nregno
--- 7093,7098 ----
*************** emit_reload_insns (chain)
*** 7042,7054 ****
spill_reg_stored_to[src_regno + nr] = out;
reg_reloaded_contents[src_regno + nr] = nregno;
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);
SET_HARD_REG_BIT (reg_is_output_reload, src_regno + nr);
- if (note)
- SET_HARD_REG_BIT (reg_reloaded_died, src_regno);
- else
- CLEAR_HARD_REG_BIT (reg_reloaded_died, src_regno);
}
reg_last_reload_reg[nregno] = src_reg;
}
--- 7183,7190 ----
*************** emit_reload_insns (chain)
*** 7062,7068 ****
}
}
}
- IOR_HARD_REG_SET (reg_reloaded_dead, reg_reloaded_died);
}
/* Emit code to perform a reload from IN (which may be a reload register) to
--- 7198,7203 ----