/* Allocate registers for pseudo-registers that span basic blocks.
Copyright (C) 1987, 1988, 1991, 1994, 1996, 1997, 1998,
- 1999, 2000, 2002 Free Software Foundation, Inc.
+ 1999, 2000, 2002, 2003 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"
/* 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;
static HARD_REG_SET eliminable_regset;
-static int allocno_compare PARAMS ((const PTR, const PTR));
-static void global_conflicts PARAMS ((void));
-static void mirror_conflicts PARAMS ((void));
-static void expand_preferences PARAMS ((void));
-static void prune_preferences PARAMS ((void));
-static void find_reg PARAMS ((int, HARD_REG_SET, int, int, int));
-static void record_one_conflict PARAMS ((int));
-static void record_conflicts PARAMS ((int *, int));
-static void mark_reg_store PARAMS ((rtx, rtx, void *));
-static void mark_reg_clobber PARAMS ((rtx, rtx, void *));
-static void mark_reg_conflicts PARAMS ((rtx));
-static void mark_reg_death PARAMS ((rtx));
-static void mark_reg_live_nc PARAMS ((int, enum machine_mode));
-static void set_preference PARAMS ((rtx, rtx));
-static void dump_conflicts PARAMS ((FILE *));
-static void reg_becomes_live PARAMS ((rtx, rtx, void *));
-static void reg_dies PARAMS ((int, enum machine_mode,
- struct insn_chain *));
+static int allocno_compare (const void *, const void *);
+static void global_conflicts (void);
+static void mirror_conflicts (void);
+static void expand_preferences (void);
+static void prune_preferences (void);
+static void find_reg (int, HARD_REG_SET, int, int, int);
+static void record_one_conflict (int);
+static void record_conflicts (int *, int);
+static void mark_reg_store (rtx, rtx, void *);
+static void mark_reg_clobber (rtx, rtx, void *);
+static void mark_reg_conflicts (rtx);
+static void mark_reg_death (rtx);
+static void mark_reg_live_nc (int, enum machine_mode);
+static void set_preference (rtx, rtx);
+static void dump_conflicts (FILE *);
+static void reg_becomes_live (rtx, rtx, void *);
+static void reg_dies (int, enum machine_mode, struct insn_chain *);
\f
/* Perform allocation of pseudo-registers not allocated by local_alloc.
FILE is a file to output debugging information on,
and we must not do any more for this function. */
int
-global_alloc (file)
- FILE *file;
+global_alloc (FILE *file)
{
int retval;
#ifdef ELIMINABLE_REGS
Returns -1 (1) if *v1 should be allocated before (after) *v2. */
static int
-allocno_compare (v1p, v2p)
- const PTR v1p;
- const PTR v2p;
+allocno_compare (const void *v1p, const void *v2p)
{
int v1 = *(const int *)v1p, v2 = *(const int *)v2p;
/* Note that the quotient will never be bigger than
conflict matrices and preference tables. */
static void
-global_conflicts ()
+global_conflicts (void)
{
int i;
basic_block b;
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.
scan the instruction that makes either X or Y become live. */
record_conflicts (block_start_allocnos, ax);
-#ifdef STACK_REGS
+ /* Pseudos can't go in stack regs at the start of a basic block that
+ is reached by an abnormal edge. Likewise for call clobbered regs,
+ because because caller-save, fixup_abnormal_edges, and possibly
+ the table driven EH machinery are not quite ready to handle such
+ regs live across such edges. */
{
- /* Pseudos can't go in stack regs at the start of a basic block
- that is reached by an abnormal edge. */
-
edge e;
+
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);
- }
+ {
+#ifdef STACK_REGS
+ 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
+
+ /* No need to record conflicts for call clobbered regs if we have
+ nonlocal labels around, as we don't ever try to allocate such
+ regs in this case. */
+ if (! current_function_has_nonlocal_label)
+ for (ax = 0; ax < FIRST_PSEUDO_REGISTER; ax++)
+ if (call_used_regs [ax])
+ record_one_conflict (ax);
+ }
+ }
}
insn = b->head;
merge any preferences between those allocnos. */
static void
-expand_preferences ()
+expand_preferences (void)
{
rtx insn;
rtx link;
we will avoid using these registers. */
static void
-prune_preferences ()
+prune_preferences (void)
{
int i;
int num;
If not, do nothing. */
static void
-find_reg (num, losers, alt_regs_p, accept_call_clobbered, retrying)
- int num;
- HARD_REG_SET losers;
- int alt_regs_p;
- int accept_call_clobbered;
- int retrying;
+find_reg (int num, HARD_REG_SET losers, int alt_regs_p, int accept_call_clobbered, 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.
(j < lim
&& ! TEST_HARD_REG_BIT (used, j)
&& (REGNO_REG_CLASS (j)
- == REGNO_REG_CLASS (best_reg + (j - i))
+ == REGNO_REG_CLASS (best_reg + (j - i))
|| reg_class_subset_p (REGNO_REG_CLASS (j),
REGNO_REG_CLASS (best_reg + (j - i)))
|| reg_class_subset_p (REGNO_REG_CLASS (best_reg + (j - i)),
(j < lim
&& ! TEST_HARD_REG_BIT (used, j)
&& (REGNO_REG_CLASS (j)
- == REGNO_REG_CLASS (best_reg + (j - i))
+ == REGNO_REG_CLASS (best_reg + (j - i))
|| reg_class_subset_p (REGNO_REG_CLASS (j),
REGNO_REG_CLASS (best_reg + (j - i)))
|| reg_class_subset_p (REGNO_REG_CLASS (best_reg + (j - i)),
/* Don't use a reg no good for this pseudo. */
&& ! TEST_HARD_REG_BIT (used2, regno)
&& HARD_REGNO_MODE_OK (regno, mode)
+ /* 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 CLASS_CANNOT_CHANGE_MODE
- && ! (REG_CHANGES_MODE (allocno[num].reg)
- && (TEST_HARD_REG_BIT
- (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE],
- regno)))
+#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
)
{
If FORBIDDEN_REGS is zero, no regs are forbidden. */
void
-retry_global_alloc (regno, forbidden_regs)
- int regno;
- HARD_REG_SET forbidden_regs;
+retry_global_alloc (int regno, HARD_REG_SET forbidden_regs)
{
int alloc_no = reg_allocno[regno];
if (alloc_no >= 0)
reg_renumber before calling here. */
static void
-record_one_conflict (regno)
- int regno;
+record_one_conflict (int regno)
{
int j;
are currently live. Their bits are also flagged in allocnos_live. */
static void
-record_conflicts (allocno_vec, len)
- int *allocno_vec;
- int len;
+record_conflicts (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. */
static void
-mirror_conflicts ()
+mirror_conflicts (void)
{
int i, j;
int rw = allocno_row_words;
a REG_INC note was found for it). */
static void
-mark_reg_store (reg, setter, data)
- rtx reg, setter;
- void *data ATTRIBUTE_UNUSED;
+mark_reg_store (rtx reg, rtx setter, void *data ATTRIBUTE_UNUSED)
{
int regno;
/* Like mark_reg_set except notice just CLOBBERs; ignore SETs. */
static void
-mark_reg_clobber (reg, setter, data)
- rtx reg, setter;
- void *data ATTRIBUTE_UNUSED;
+mark_reg_clobber (rtx reg, rtx setter, void *data ATTRIBUTE_UNUSED)
{
if (GET_CODE (setter) == CLOBBER)
mark_reg_store (reg, setter, data);
Do not mark REG itself as live. */
static void
-mark_reg_conflicts (reg)
- rtx reg;
+mark_reg_conflicts (rtx reg)
{
int regno;
Store a 0 in regs_live or allocnos_live for this register. */
static void
-mark_reg_death (reg)
- rtx reg;
+mark_reg_death (rtx reg)
{
int regno = REGNO (reg);
it is assumed that the caller will do that. */
static void
-mark_reg_live_nc (regno, mode)
- int regno;
- enum machine_mode mode;
+mark_reg_live_nc (int regno, enum machine_mode mode)
{
int last = regno + HARD_REGNO_NREGS (regno, mode);
while (regno < last)
pseudo-register to a hard register. */
static void
-set_preference (dest, src)
- rtx dest, src;
+set_preference (rtx dest, rtx src)
{
unsigned int src_regno, dest_regno;
/* Amount to add to the hard regno for SRC, or subtract from that for DEST,
a use of TO. */
void
-mark_elimination (from, to)
- int from, to;
+mark_elimination (int from, int to)
{
basic_block bb;
/* Record in live_relevant_regs and REGS_SET that register REG became live.
This is called via note_stores. */
static void
-reg_becomes_live (reg, setter, regs_set)
- rtx reg;
- rtx setter ATTRIBUTE_UNUSED;
- void *regs_set;
+reg_becomes_live (rtx reg, rtx setter ATTRIBUTE_UNUSED, void *regs_set)
{
int regno;
/* Record in live_relevant_regs that register REGNO died. */
static void
-reg_dies (regno, mode, chain)
- int regno;
- enum machine_mode mode;
- struct insn_chain *chain;
+reg_dies (int regno, enum machine_mode mode, struct insn_chain *chain)
{
if (regno < FIRST_PSEUDO_REGISTER)
{
/* Walk the insns of the current function and build reload_insn_chain,
and record register life information. */
void
-build_insn_chain (first)
- rtx first;
+build_insn_chain (rtx first)
{
struct insn_chain **p = &reload_insn_chain;
struct insn_chain *prev = 0;
showing the information on which the allocation decisions are based. */
static void
-dump_conflicts (file)
- FILE *file;
+dump_conflicts (FILE *file)
{
int i;
int has_preferences;
}
void
-dump_global_regs (file)
- FILE *file;
+dump_global_regs (FILE *file)
{
int i, j;