/* Allocate registers for pseudo-registers that span basic blocks.
Copyright (C) 1987, 1988, 1991, 1994, 1996, 1997, 1998,
- 1999, 2000 Free Software Foundation, Inc.
+ 1999, 2000, 2002 Free Software Foundation, Inc.
This file is part of GCC.
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "machmode.h"
#include "hard-reg-set.h"
1. Assign allocation-numbers (allocnos) to the pseudo-registers
still needing allocations and to the pseudo-registers currently
allocated by local-alloc which may be spilled by reload.
- Set up tables reg_allocno and allocno_reg to map
+ Set up tables reg_allocno and allocno_reg to map
reg numbers to allocnos and vice versa.
max_allocno gets the number of allocnos in use.
/* Set of hard registers that some later allocno has a preference for. */
HARD_REG_SET regs_someone_prefers;
+
+#ifdef STACK_REGS
+ /* Set to true if allocno can't be allocated in the stack register. */
+ bool no_stack_reg;
+#endif
};
static struct allocno *allocno;
/* Two macros to test or store 1 in an element of `conflicts'. */
#define CONFLICTP(I, J) \
- (conflicts[(I) * allocno_row_words + (unsigned)(J) / INT_BITS] \
- & ((INT_TYPE) 1 << ((unsigned)(J) % INT_BITS)))
-
-#define SET_CONFLICT(I, J) \
- (conflicts[(I) * allocno_row_words + (unsigned)(J) / INT_BITS] \
- |= ((INT_TYPE) 1 << ((unsigned)(J) % INT_BITS)))
+ (conflicts[(I) * allocno_row_words + (unsigned) (J) / INT_BITS] \
+ & ((INT_TYPE) 1 << ((unsigned) (J) % INT_BITS)))
/* For any allocno set in ALLOCNO_SET, set ALLOCNO to that allocno,
and execute CODE. */
static int local_reg_live_length[FIRST_PSEUDO_REGISTER];
-/* Test a bit in TABLE, a vector of HARD_REG_SETs,
- for vector element I, and hard register number J. */
-
-#define REGBITP(TABLE, I, J) TEST_HARD_REG_BIT (allocno[I].TABLE, J)
-
-/* Set to 1 a bit in a vector of HARD_REG_SETs. Works like REGBITP. */
+/* Set to 1 a bit in a vector TABLE of HARD_REG_SETs, for vector
+ element I, and hard register number J. */
#define SET_REGBIT(TABLE, I, J) SET_HARD_REG_BIT (allocno[I].TABLE, J)
/* Test, set or clear bit number I in allocnos_live,
a bit vector indexed by allocno. */
-#define ALLOCNO_LIVE_P(I) \
- (allocnos_live[(unsigned)(I) / INT_BITS] \
- & ((INT_TYPE) 1 << ((unsigned)(I) % INT_BITS)))
-
#define SET_ALLOCNO_LIVE(I) \
- (allocnos_live[(unsigned)(I) / INT_BITS] \
- |= ((INT_TYPE) 1 << ((unsigned)(I) % INT_BITS)))
+ (allocnos_live[(unsigned) (I) / INT_BITS] \
+ |= ((INT_TYPE) 1 << ((unsigned) (I) % INT_BITS)))
#define CLEAR_ALLOCNO_LIVE(I) \
- (allocnos_live[(unsigned)(I) / INT_BITS] \
- &= ~((INT_TYPE) 1 << ((unsigned)(I) % INT_BITS)))
+ (allocnos_live[(unsigned) (I) / INT_BITS] \
+ &= ~((INT_TYPE) 1 << ((unsigned) (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.)
that need a register window. So prefer the ones that can be used in
a leaf function. */
{
- char *cheap_regs;
- char *leaf_regs = LEAF_REGISTERS;
+ const char *cheap_regs;
+ const char *const leaf_regs = LEAF_REGISTERS;
if (only_leaf_regs_used () && leaf_function_p ())
cheap_regs = leaf_regs;
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (regs_ever_live[i])
local_reg_n_refs[i] = 0, local_reg_freq[i] = 0;
-
+
allocno_row_words = (max_allocno + INT_BITS - 1) / INT_BITS;
/* We used to use alloca here, but the size of what it would try to
}
qsort (allocno_order, max_allocno, sizeof (int), allocno_compare);
-
+
prune_preferences ();
if (file)
static void
global_conflicts ()
{
- int b, i;
+ int i;
+ basic_block b;
rtx insn;
int *block_start_allocnos;
block_start_allocnos = (int *) xmalloc (max_allocno * sizeof (int));
- for (b = 0; b < n_basic_blocks; b++)
+ FOR_EACH_BB (b)
{
memset ((char *) allocnos_live, 0, allocno_row_words * sizeof (INT_TYPE));
are explicitly marked in basic_block_live_at_start. */
{
- regset old = BASIC_BLOCK (b)->global_live_at_start;
+ regset old = b->global_live_at_start;
int ax = 0;
REG_SET_TO_HARD_REG_SET (hard_regs_live, old);
2. Y is live at some instruction on the path that
evaluates X.
- 3. Either X or Y is not evaluted on the path to P
+ 3. Either X or Y is not evaluated on the path to P
(ie it is used uninitialized) and thus the
conflict can be ignored.
that is reached by an abnormal edge. */
edge e;
- for (e = BASIC_BLOCK (b)->pred; e ; e = e->pred_next)
+ for (e = b->pred; e ; e = e->pred_next)
if (e->flags & EDGE_ABNORMAL)
break;
if (e != NULL)
- for (ax = FIRST_STACK_REG; ax <= LAST_STACK_REG; ax++)
- record_one_conflict (ax);
+ {
+ EXECUTE_IF_SET_IN_ALLOCNO_SET (allocnos_live, ax,
+ {
+ allocno[ax].no_stack_reg = 1;
+ });
+ for (ax = FIRST_STACK_REG; ax <= LAST_STACK_REG; ax++)
+ record_one_conflict (ax);
+ }
}
#endif
}
- insn = BLOCK_HEAD (b);
+ insn = b->head;
/* Scan the code of this basic block, noting which allocnos
and hard regs are born or die. When one is born,
}
}
- if (insn == BLOCK_END (b))
+ if (insn == b->end)
break;
insn = NEXT_INSN (insn);
}
\f
/* Prune the preferences for global registers to exclude registers that cannot
be used.
-
+
Compute `regs_someone_prefers', which is a bitmask of the hard registers
that are preferred by conflicting registers of lower priority. If possible,
we will avoid using these registers. */
-
+
static void
prune_preferences ()
{
int i;
int num;
int *allocno_to_order = (int *) xmalloc (max_allocno * sizeof (int));
-
+
/* 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
of a long enough stretch of hard regs none of which conflicts with ALLOCNO.
The registers marked in PREFREGS are tried first.
- LOSERS, if non-zero, is a HARD_REG_SET indicating registers that cannot
+ LOSERS, if nonzero, is a HARD_REG_SET indicating registers that cannot
be used for this allocation.
If ALT_REGS_P is zero, consider only the preferred class of ALLOCNO's reg.
int retrying;
{
int i, best_reg, pass;
-#ifdef HARD_REG_SET
- register /* Declare it register if it's a scalar. */
-#endif
- HARD_REG_SET used, used1, used2;
+ HARD_REG_SET used, used1, used2;
enum reg_class class = (alt_regs_p
? reg_alternate_class (allocno[num].reg)
IOR_HARD_REG_SET (used1, allocno[num].hard_reg_conflicts);
-#ifdef CLASS_CANNOT_CHANGE_MODE
- if (REG_CHANGES_MODE (allocno[num].reg))
- IOR_HARD_REG_SET (used1,
- reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE]);
+#ifdef CANNOT_CHANGE_MODE_CLASS
+ cannot_change_mode_set_regs (&used1, mode, allocno[num].reg);
#endif
/* Try each hard reg to see if it fits. Do this in two passes.
COPY_HARD_REG_SET (used, used1);
IOR_COMPL_HARD_REG_SET (used, regs_used_so_far);
IOR_HARD_REG_SET (used, allocno[num].regs_someone_prefers);
-
+
best_reg = -1;
for (i = FIRST_PSEUDO_REGISTER, pass = 0;
pass <= 1 && i >= FIRST_PSEUDO_REGISTER;
Remove from the preferred registers and conflicting registers. Note that
additional conflicts may have been added after `prune_preferences' was
- called.
+ called.
First do this for those register with copy preferences, then all
preferred registers. */
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (TEST_HARD_REG_BIT (allocno[num].hard_reg_copy_preferences, i)
&& HARD_REGNO_MODE_OK (i, mode)
+ && (allocno[num].calls_crossed == 0
+ || accept_call_clobbered
+ || ! HARD_REGNO_CALL_PART_CLOBBERED (i, mode))
&& (REGNO_REG_CLASS (i) == REGNO_REG_CLASS (best_reg)
|| reg_class_subset_p (REGNO_REG_CLASS (i),
REGNO_REG_CLASS (best_reg))
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (TEST_HARD_REG_BIT (allocno[num].hard_reg_preferences, i)
&& HARD_REGNO_MODE_OK (i, mode)
+ && (allocno[num].calls_crossed == 0
+ || accept_call_clobbered
+ || ! HARD_REGNO_CALL_PART_CLOBBERED (i, mode))
&& (REGNO_REG_CLASS (i) == REGNO_REG_CLASS (best_reg)
|| reg_class_subset_p (REGNO_REG_CLASS (i),
REGNO_REG_CLASS (best_reg))
}
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. */
CLEAR_HARD_REG_SET (new_losers);
else
COPY_HARD_REG_SET (new_losers, losers);
-
+
IOR_HARD_REG_SET(new_losers, losing_caller_save_reg_set);
find_reg (num, new_losers, alt_regs_p, 1, retrying);
if (reg_renumber[allocno[num].reg] >= 0)
/* Don't use a reg no good for this pseudo. */
&& ! TEST_HARD_REG_BIT (used2, regno)
&& HARD_REGNO_MODE_OK (regno, mode)
-#ifdef CLASS_CANNOT_CHANGE_MODE
- && ! (REG_CHANGES_MODE (allocno[num].reg)
- && (TEST_HARD_REG_BIT
- (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE],
- regno)))
+ /* The code below assumes that we need only a single
+ register, but the check of allocno[num].size above
+ was not enough. Sometimes we need more than one
+ register for a single-word value. */
+ && HARD_REGNO_NREGS (regno, mode) == 1
+ && (allocno[num].calls_crossed == 0
+ || accept_call_clobbered
+ || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode))
+#ifdef CANNOT_CHANGE_MODE_CLASS
+ && ! invalid_mode_change_p (regno, REGNO_REG_CLASS (regno),
+ mode)
+#endif
+#ifdef STACK_REGS
+ && (!allocno[num].no_stack_reg
+ || regno < FIRST_STACK_REG || regno > LAST_STACK_REG)
#endif
)
{
/* We explicitly evaluate the divide results into temporary
variables so as to avoid excess precision problems that occur
on an i386-unknown-sysv4.2 (unixware) host. */
-
+
double tmp1 = ((double) local_reg_freq[regno]
/ local_reg_live_length[regno]);
double tmp2 = ((double) allocno[num].freq
int *allocno_vec;
int len;
{
- int num;
- int ialloc_prod;
-
while (--len >= 0)
- {
- num = allocno_vec[len];
- ialloc_prod = num * allocno_row_words;
- IOR_HARD_REG_SET (allocno[num].hard_reg_conflicts, hard_regs_live);
- }
+ IOR_HARD_REG_SET (allocno[allocno_vec[len]].hard_reg_conflicts,
+ hard_regs_live);
}
/* If CONFLICTP (i, j) is true, make sure CONFLICTP (j, i) is also true. */
that SRC is a register. If SRC or the first operand of SRC is a 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 aggressive as local-alloc in trying to tie a
pseudo-register to a hard register. */
mark_elimination (from, to)
int from, to;
{
- int i;
+ basic_block bb;
- for (i = 0; i < n_basic_blocks; i++)
+ FOR_EACH_BB (bb)
{
- regset r = BASIC_BLOCK (i)->global_live_at_start;
+ regset r = bb->global_live_at_start;
if (REGNO_REG_SET_P (r, from))
{
CLEAR_REGNO_REG_SET (r, from);
if (GET_CODE (reg) != REG)
return;
-
+
regno = REGNO (reg);
if (regno < FIRST_PSEUDO_REGISTER)
{
{
struct insn_chain **p = &reload_insn_chain;
struct insn_chain *prev = 0;
- int b = 0;
+ basic_block b = ENTRY_BLOCK_PTR->next_bb;
regset_head live_relevant_regs_head;
live_relevant_regs = INITIALIZE_REG_SET (live_relevant_regs_head);
{
struct insn_chain *c;
- if (first == BLOCK_HEAD (b))
+ if (first == b->head)
{
int i;
CLEAR_REG_SET (live_relevant_regs);
EXECUTE_IF_SET_IN_BITMAP
- (BASIC_BLOCK (b)->global_live_at_start, 0, i,
+ (b->global_live_at_start, 0, i,
{
if (i < FIRST_PSEUDO_REGISTER
? ! TEST_HARD_REG_BIT (eliminable_regset, i)
: reg_renumber[i] >= 0)
SET_REGNO_REG_SET (live_relevant_regs, i);
});
- }
+ }
if (GET_CODE (first) != NOTE && GET_CODE (first) != BARRIER)
{
*p = c;
p = &c->next;
c->insn = first;
- c->block = b;
+ c->block = b->index;
if (INSN_P (first))
{
}
}
- if (first == BLOCK_END (b))
- b++;
+ if (first == b->end)
+ b = b->next_bb;
/* Stop after we pass the end of the last basic block. Verify that
no real insns are after the end of the last basic block.
We may want to reorganize the loop somewhat since this test should
always be the right exit test. Allow an ADDR_VEC or ADDR_DIF_VEC if
the previous real insn is a JUMP_INSN. */
- if (b == n_basic_blocks)
+ if (b == EXIT_BLOCK_PTR)
{
for (first = NEXT_INSN (first) ; first; first = NEXT_INSN (first))
if (INSN_P (first)
for (i = 0; i < max_allocno; i++)
{
if (reg_renumber[allocno[allocno_order[i]].reg] >= 0)
- continue;
+ continue;
nregs++;
}
fprintf (file, ";; %d regs to allocate:", nregs);
FILE *file;
{
int i, j;
-
+
fprintf (file, ";; Register dispositions:\n");
for (i = FIRST_PSEUDO_REGISTER, j = 0; i < max_regno; i++)
if (reg_renumber[i] >= 0)
{
fprintf (file, "%d in %d ", i, reg_renumber[i]);
- if (++j % 6 == 0)
+ if (++j % 6 == 0)
fprintf (file, "\n");
}