static int *allocno_size;
/* Indexed by (pseudo) reg number, gives the number of another
- lower-numbered pseudo reg which can share a hard reg with this peudo
+ lower-numbered pseudo reg which can share a hard reg with this pseudo
*even if the two pseudos would otherwise appear to conflict*. */
static int *reg_may_share;
+/* Define the number of bits in each element of `conflicts' and what
+ type that element has. We use the largest integer format on the
+ host machine. */
+
+#define INT_BITS HOST_BITS_PER_WIDE_INT
+#define INT_TYPE HOST_WIDE_INT
+
/* max_allocno by max_allocno array of bits,
recording whether two allocno's conflict (can't go in the same
hardware register).
`conflicts' is not symmetric; a conflict between allocno's i and j
is recorded either in element i,j or in element j,i. */
-static int *conflicts;
+static INT_TYPE *conflicts;
/* Number of ints require to hold max_allocno bits.
This is the length of a row in `conflicts'. */
#define CONFLICTP(I, J) \
(conflicts[(I) * allocno_row_words + (J) / INT_BITS] \
- & (1 << ((J) % INT_BITS)))
+ & ((INT_TYPE) 1 << ((J) % INT_BITS)))
#define SET_CONFLICT(I, J) \
(conflicts[(I) * allocno_row_words + (J) / INT_BITS] \
- |= (1 << ((J) % INT_BITS)))
+ |= ((INT_TYPE) 1 << ((J) % INT_BITS)))
/* Set of hard regs currently live (during scan of all insns). */
/* Bit mask for allocnos live at current point in the scan. */
-static int *allocnos_live;
-
-#define INT_BITS HOST_BITS_PER_INT
+static INT_TYPE *allocnos_live;
/* Test, set or clear bit number I in allocnos_live,
a bit vector indexed by allocno. */
#define ALLOCNO_LIVE_P(I) \
- (allocnos_live[(I) / INT_BITS] & (1 << ((I) % INT_BITS)))
+ (allocnos_live[(I) / INT_BITS] & ((INT_TYPE) 1 << ((I) % INT_BITS)))
#define SET_ALLOCNO_LIVE(I) \
- (allocnos_live[(I) / INT_BITS] |= (1 << ((I) % INT_BITS)))
+ (allocnos_live[(I) / INT_BITS] |= ((INT_TYPE) 1 << ((I) % INT_BITS)))
#define CLEAR_ALLOCNO_LIVE(I) \
- (allocnos_live[(I) / INT_BITS] &= ~(1 << ((I) % INT_BITS)))
+ (allocnos_live[(I) / INT_BITS] &= ~((INT_TYPE) 1 << ((I) % INT_BITS)))
/* This is turned off because it doesn't work right for DImode.
(And it is only used for DImode, so the other cases are worthless.)
static int allocno_compare ();
static void mark_reg_store ();
static void mark_reg_clobber ();
+static void mark_reg_conflicts ();
static void mark_reg_live_nc ();
static void mark_reg_death ();
static void dump_conflicts ();
\f
/* Perform allocation of pseudo-registers not allocated by local_alloc.
FILE is a file to output debugging information on,
- or zero if such output is not desired. */
+ or zero if such output is not desired.
-void
+ Return value is nonzero if reload failed
+ and we must not do any more for this function. */
+
+int
global_alloc (file)
FILE *file;
{
allocno_row_words = (max_allocno + INT_BITS - 1) / INT_BITS;
- conflicts = (int *) alloca (max_allocno * allocno_row_words * sizeof (int));
- bzero (conflicts, max_allocno * allocno_row_words * sizeof (int));
+ conflicts = (INT_TYPE *) alloca (max_allocno * allocno_row_words
+ * sizeof (INT_TYPE));
+ bzero (conflicts, max_allocno * allocno_row_words
+ * sizeof (INT_TYPE));
- allocnos_live = (int *) alloca (allocno_row_words * sizeof (int));
+ allocnos_live = (INT_TYPE *) alloca (allocno_row_words * sizeof (INT_TYPE));
/* If there is work to be done (at least one reg to allocate),
perform global conflict analysis and allocate the regs. */
if (reg_renumber[allocno_reg[allocno_order[i]]] >= 0)
continue;
}
- if (!reg_preferred_or_nothing (allocno_reg[allocno_order[i]]))
+ if (reg_alternate_class (allocno_reg[allocno_order[i]]) != NO_REGS)
find_reg (allocno_order[i], HARD_CONST (0), 1, 0, 0);
}
}
for the sake of debugging information. */
if (n_basic_blocks > 0)
#endif
- reload (basic_block_head[0], 1, file);
+ return reload (get_insns (), 1, file);
}
/* Sort predicate for ordering the allocnos.
for (b = 0; b < n_basic_blocks; b++)
{
- bzero (allocnos_live, allocno_row_words * sizeof (int));
+ bzero (allocnos_live, allocno_row_words * sizeof (INT_TYPE));
/* Initialize table of registers currently live
to the state at the beginning of this basic block.
are explicitly marked in basic_block_live_at_start. */
{
- register int offset, bit;
+ register int offset;
+ REGSET_ELT_TYPE bit;
register regset old = basic_block_live_at_start[b];
int ax = 0;
#endif
for (offset = 0, i = 0; offset < regset_size; offset++)
if (old[offset] == 0)
- i += HOST_BITS_PER_INT;
+ i += REGSET_ELT_BITS;
else
for (bit = 1; bit; bit <<= 1, i++)
{
#ifdef AUTO_INC_DEC
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
if (REG_NOTE_KIND (link) == REG_INC)
- mark_reg_store (XEXP (link, 0), 0);
+ mark_reg_store (XEXP (link, 0), NULL_RTX);
#endif
+ /* If INSN has multiple outputs, then any reg that dies here
+ and is used inside of an output
+ must conflict with the other outputs. */
+
+ if (GET_CODE (PATTERN (insn)) == PARALLEL && !single_set (insn))
+ for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
+ if (REG_NOTE_KIND (link) == REG_DEAD)
+ {
+ int used_in_output = 0;
+ int i;
+ rtx reg = XEXP (link, 0);
+
+ for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
+ {
+ rtx set = XVECEXP (PATTERN (insn), 0, i);
+ if (GET_CODE (set) == SET
+ && GET_CODE (SET_DEST (set)) != REG
+ && !rtx_equal_p (reg, SET_DEST (set))
+ && reg_overlap_mentioned_p (reg, SET_DEST (set)))
+ used_in_output = 1;
+ }
+ if (used_in_output)
+ mark_reg_conflicts (reg);
+ }
+
/* Mark any registers set in INSN and then never used. */
while (n_regs_set > 0)
/* Scan least most important to most important.
For each allocno, remove from preferences registers that cannot be used,
either because of conflicts or register type. Then compute all registers
- prefered by each lower-priority register that conflicts. */
+ preferred by each lower-priority register that conflicts. */
for (i = max_allocno - 1; i >= 0; i--)
{
LOSERS, if non-zero, is a HARD_REG_SET indicating registers that cannot
be used for this allocation.
- If ALL_REGS_P is zero, consider only the preferred class of ALLOCNO's reg.
- Otherwise ignore that preferred class.
+ If ALT_REGS_P is zero, consider only the preferred class of ALLOCNO's reg.
+ Otherwise ignore that preferred class and use the alternate class.
If ACCEPT_CALL_CLOBBERED is nonzero, accept a call-clobbered hard reg that
will have to be saved and restored at calls.
If not, do nothing. */
static void
-find_reg (allocno, losers, all_regs_p, accept_call_clobbered, retrying)
+find_reg (allocno, losers, alt_regs_p, accept_call_clobbered, retrying)
int allocno;
HARD_REG_SET losers;
- int all_regs_p;
+ int alt_regs_p;
int accept_call_clobbered;
int retrying;
{
#endif
HARD_REG_SET used, used1, used2;
- enum reg_class class
- = all_regs_p ? ALL_REGS : reg_preferred_class (allocno_reg[allocno]);
+ enum reg_class class = (alt_regs_p
+ ? reg_alternate_class (allocno_reg[allocno])
+ : reg_preferred_class (allocno_reg[allocno]));
enum machine_mode mode = PSEUDO_REGNO_MODE (allocno_reg[allocno]);
if (accept_call_clobbered)
IOR_HARD_REG_SET (used1, hard_reg_conflicts[allocno]);
/* Try each hard reg to see if it fits. Do this in two passes.
- In the first pass, skip registers that are prefered by some other pseudo
+ In the first pass, skip registers that are preferred by some other pseudo
to give it a better chance of getting one of those registers. Only if
we can't get a register when excluding those do we take one of them.
However, we never allocate a register for the first time in pass 0. */
}
no_prefs:
- /* If we haven't succeeded yet, try with caller-saves. */
+ /* If we haven't succeeded yet, try with caller-saves.
+ We need not check to see if the current function has nonlocal
+ labels because we don't put any pseudos that are live over calls in
+ registers in that case. */
+
if (flag_caller_saves && best_reg < 0)
{
/* Did not find a register. If it would be profitable to
&& CALLER_SAVE_PROFITABLE (allocno_n_refs[allocno],
allocno_calls_crossed[allocno]))
{
- find_reg (allocno, losers, all_regs_p, 1, retrying);
+ find_reg (allocno, losers, alt_regs_p, 1, retrying);
if (reg_renumber[allocno_reg[allocno]] >= 0)
{
caller_save_needed = 1;
if (N_REG_CLASSES > 1)
find_reg (allocno, forbidden_regs, 0, 0, 1);
if (reg_renumber[regno] < 0
- && !reg_preferred_or_nothing (regno))
+ && reg_alternate_class (regno) != NO_REGS)
find_reg (allocno, forbidden_regs, 1, 0, 1);
/* If we found a register, modify the RTL for the register to
}
}
}
+
+/* Record that REG has conflicts with all the regs currently live.
+ Do not mark REG itself as live. */
+
+static void
+mark_reg_conflicts (reg)
+ rtx reg;
+{
+ register int regno;
+
+ if (GET_CODE (reg) == SUBREG)
+ reg = SUBREG_REG (reg);
+
+ if (GET_CODE (reg) != REG)
+ return;
+
+ regno = REGNO (reg);
+
+ if (reg_renumber[regno] >= 0)
+ regno = reg_renumber[regno];
+
+ /* Either this is one of the max_allocno pseudo regs not allocated,
+ or it is or has a hardware reg. First handle the pseudo-regs. */
+ if (regno >= FIRST_PSEUDO_REGISTER)
+ {
+ if (reg_allocno[regno] >= 0)
+ record_one_conflict (regno);
+ }
+ /* Handle hardware regs (and pseudos allocated to hard regs). */
+ else if (! fixed_regs[regno])
+ {
+ register int last = regno + HARD_REGNO_NREGS (regno, GET_MODE (reg));
+ while (regno < last)
+ {
+ record_one_conflict (regno);
+ regno++;
+ }
+ }
+}
\f
/* Mark REG as being dead (following the insn being scanned now).
Store a 0 in regs_live or allocnos_live for this register. */
try to set a preference. If one of the two is a hard register and the other
is a pseudo-register, mark the preference.
- Note that we are not as agressive as local-alloc in trying to tie a
+ Note that we are not as aggressive as local-alloc in trying to tie a
pseudo-register to a hard register. */
static void
int i;
for (i = 0; i < n_basic_blocks; i++)
- if ((basic_block_live_at_start[i][from / HOST_BITS_PER_INT]
- & (1 << (from % HOST_BITS_PER_INT))) != 0)
+ if ((basic_block_live_at_start[i][from / REGSET_ELT_BITS]
+ & ((REGSET_ELT_TYPE) 1 << (from % REGSET_ELT_BITS))) != 0)
{
- basic_block_live_at_start[i][from / HOST_BITS_PER_INT]
- &= ~ (1 << (from % HOST_BITS_PER_INT));
- basic_block_live_at_start[i][to / HOST_BITS_PER_INT]
- |= (1 << (to % HOST_BITS_PER_INT));
+ basic_block_live_at_start[i][from / REGSET_ELT_BITS]
+ &= ~ ((REGSET_ELT_TYPE) 1 << (from % REGSET_ELT_BITS));
+ basic_block_live_at_start[i][to / REGSET_ELT_BITS]
+ |= ((REGSET_ELT_TYPE) 1 << (to % REGSET_ELT_BITS));
}
}
\f