/* Allocate registers within a basic block, for GNU compiler.
Copyright (C) 1987, 1988, 1991, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 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 "hard-reg-set.h"
#include "rtl.h"
#include "tm_p.h"
#include "flags.h"
-#include "hard-reg-set.h"
#include "basic-block.h"
#include "regs.h"
#include "function.h"
or -1 if none was found. */
short phys_reg;
-
- /* Nonzero if this quantity has been used in a SUBREG in some
- way that is illegal. */
-
- char changes_mode;
-
};
static struct qty *qty;
qty[qtyno].alternate_class = reg_alternate_class (regno);
qty[qtyno].n_refs = REG_N_REFS (regno);
qty[qtyno].freq = REG_FREQ (regno);
- qty[qtyno].changes_mode = REG_CHANGES_MODE (regno);
}
\f
/* Main entry point of this file. */
int
local_alloc ()
{
- int b, i;
+ int i;
int max_qty;
+ basic_block b;
/* We need to keep track of whether or not we recorded a LABEL_REF so
that we know if the jump optimizer needs to be rerun. */
/* Allocate each block's local registers, block by block. */
- for (b = 0; b < n_basic_blocks; b++)
+ FOR_EACH_BB (b)
{
/* NEXT_QTY indicates which elements of the `qty_...'
vectors might need to be initialized because they were used
next_qty = 0;
- block_alloc (b);
+ block_alloc (b->index);
}
free (qty);
return 0;
}
-/* Returns non-zero if X (used to initialize register REGNO) is movable.
+/* Returns nonzero if X (used to initialize register REGNO) is movable.
X is only movable if the registers it uses have equivalent initializations
which appear to be within the same loop (or in an inner loop) and movable
or if they are not candidates for local_alloc and don't vary. */
update_equiv_regs ()
{
rtx insn;
- int block;
+ basic_block bb;
int loop_depth;
regset_head cleared_regs;
int clear_regnos = 0;
/* Scan the insns and find which registers have equivalences. Do this
in a separate scan of the insns because (due to -fcse-follow-jumps)
a register can be set below its use. */
- for (block = 0; block < n_basic_blocks; block++)
+ FOR_EACH_BB (bb)
{
- basic_block bb = BASIC_BLOCK (block);
loop_depth = bb->loop_depth;
for (insn = bb->head; insn != NEXT_INSN (bb->end); insn = NEXT_INSN (insn))
within the same loop (or in an inner loop), then move the register
initialization just before the use, so that they are in the same
basic block. */
- for (block = n_basic_blocks - 1; block >= 0; block--)
+ FOR_EACH_BB_REVERSE (bb)
{
- basic_block bb = BASIC_BLOCK (block);
-
loop_depth = bb->loop_depth;
for (insn = bb->end; insn != PREV_INSN (bb->head); insn = PREV_INSN (insn))
{
REG_N_REFS (regno) = 0;
REG_FREQ (regno) = 0;
delete_insn (equiv_insn);
-
+
reg_equiv[regno].init_insns
= XEXP (reg_equiv[regno].init_insns, 1);
}
XEXP (reg_equiv[regno].init_insns, 0) = new_insn;
- REG_BASIC_BLOCK (regno) = block >= 0 ? block : 0;
+ REG_BASIC_BLOCK (regno) = bb->index;
REG_N_CALLS_CROSSED (regno) = 0;
REG_LIVE_LENGTH (regno) = 2;
- if (block >= 0 && insn == BLOCK_HEAD (block))
- BLOCK_HEAD (block) = PREV_INSN (insn);
+ if (insn == bb->head)
+ bb->head = PREV_INSN (insn);
/* Remember to clear REGNO from all basic block's live
info. */
/* Clear all dead REGNOs from all basic block's live info. */
if (clear_regnos)
{
- int j, l;
+ int j;
if (clear_regnos > 8)
- {
- for (l = 0; l < n_basic_blocks; l++)
+ {
+ FOR_EACH_BB (bb)
{
- AND_COMPL_REG_SET (BASIC_BLOCK (l)->global_live_at_start,
- &cleared_regs);
- AND_COMPL_REG_SET (BASIC_BLOCK (l)->global_live_at_end,
- &cleared_regs);
+ AND_COMPL_REG_SET (bb->global_live_at_start, &cleared_regs);
+ AND_COMPL_REG_SET (bb->global_live_at_end, &cleared_regs);
}
}
else
- EXECUTE_IF_SET_IN_REG_SET (&cleared_regs, 0, j,
- {
- for (l = 0; l < n_basic_blocks; l++)
+ EXECUTE_IF_SET_IN_REG_SET (&cleared_regs, 0, j,
+ {
+ FOR_EACH_BB (bb)
{
- CLEAR_REGNO_REG_SET (BASIC_BLOCK (l)->global_live_at_start, j);
- CLEAR_REGNO_REG_SET (BASIC_BLOCK (l)->global_live_at_end, j);
+ CLEAR_REGNO_REG_SET (bb->global_live_at_start, j);
+ CLEAR_REGNO_REG_SET (bb->global_live_at_end, j);
}
});
}
}
/* Mark REG as having no known equivalence.
- Some instructions might have been proceessed before and furnished
+ Some instructions might have been processed before and furnished
with REG_EQUIV notes for this register; these notes will have to be
removed.
STORE is the piece of RTL that does the non-constant / conflicting
must match operand zero. In that case, skip any
operand that doesn't list operand 0 since we know that
the operand always conflicts with operand 0. We
- ignore commutatity in this case to keep things simple. */
+ ignore commutativity in this case to keep things simple. */
if (n_matching_alts == recog_data.n_alternatives
&& 0 == requires_inout (recog_data.constraints[i]))
continue;
/* If the operand is an address, find a register in it.
There may be more than one register, but we only try one
of them. */
- if (recog_data.constraints[i][0] == 'p')
+ if (recog_data.constraints[i][0] == 'p'
+ || EXTRA_ADDRESS_CONSTRAINT (recog_data.constraints[i][0],
+ recog_data.constraints[i]))
while (GET_CODE (r1) == PLUS || GET_CODE (r1) == MULT)
r1 = XEXP (r1, 0);
If we really combined them, we could lose if the pseudo lives
across an insn that clobbers the hard reg (eg, movstr).
- ALREADY_DEAD is non-zero if USEDREG is known to be dead even though
+ ALREADY_DEAD is nonzero if USEDREG is known to be dead even though
there is no REG_DEAD note on INSN. This occurs during the processing
of REG_NO_CONFLICT blocks.
- MAY_SAVE_COPYCOPY is non-zero if this insn is simply copying USEDREG to
+ MAY_SAVE_COPYCOPY is nonzero if this insn is simply copying USEDREG to
SETREG or if the input and output must share a register.
In that case, we record a hard reg suggestion in QTY_PHYS_COPY_SUGG.
rclass = reg_alternate_class (reg);
if (reg_class_subset_p (rclass, qty[qtyno].alternate_class))
qty[qtyno].alternate_class = rclass;
-
- if (REG_CHANGES_MODE (reg))
- qty[qtyno].changes_mode = 1;
}
\f
/* Handle something which alters the value of an rtx REG.
}
}
-/* Record the death of REG in the current insn. If OUTPUT_P is non-zero,
+/* Record the death of REG in the current insn. If OUTPUT_P is nonzero,
REG is an output that is dying (i.e., it is never used), otherwise it
is an input (the normal case).
If OUTPUT_P is 1, then we extend the life past the end of this insn. */
If QTYNO crosses calls, insist on a register preserved by calls,
unless ACCEPT_CALL_CLOBBERED is nonzero.
- If JUST_TRY_SUGGESTED is non-zero, only try to see if the suggested
+ If JUST_TRY_SUGGESTED is nonzero, only try to see if the suggested
register is available. If not, return -1. */
static int
int born_index, dead_index;
{
int i, ins;
-#ifdef HARD_REG_SET
- /* Declare it register if it's a scalar. */
- register
-#endif
- HARD_REG_SET used, first_used;
+ HARD_REG_SET first_used, used;
#ifdef ELIMINABLE_REGS
static const struct {const int from, to; } eliminables[] = ELIMINABLE_REGS;
#endif
SET_HARD_REG_BIT (used, FRAME_POINTER_REGNUM);
#endif
-#ifdef CLASS_CANNOT_CHANGE_MODE
- if (qty[qtyno].changes_mode)
- IOR_HARD_REG_SET (used,
- reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE]);
+#ifdef CANNOT_CHANGE_MODE_CLASS
+ cannot_change_mode_set_regs (&used, mode, qty[qtyno].first_reg);
#endif
/* Normally, the registers that can be used for the first register in
}
\f
/* Mark that REGNO with machine-mode MODE is live starting from the current
- insn (if LIFE is non-zero) or dead starting at the current insn (if LIFE
+ insn (if LIFE is nonzero) or dead starting at the current insn (if LIFE
is zero). */
static void
}
/* Mark register number REGNO (with machine-mode MODE) as live (if LIFE
- is non-zero) or dead (if LIFE is zero) from insn number BIRTH (inclusive)
+ is nonzero) or dead (if LIFE is zero) from insn number BIRTH (inclusive)
to insn number DEATH (exclusive). */
static void
int found_zero = 0;
int reg_allowed = 0;
int num_matching_alts = 0;
+ int len;
- while ((c = *p++))
- switch (c)
- {
- case '=': case '+': case '?':
- case '#': case '&': case '!':
- case '*': case '%':
- case 'm': case '<': case '>': case 'V': case 'o':
- case 'E': case 'F': case 'G': case 'H':
- case 's': case 'i': case 'n':
- case 'I': case 'J': case 'K': case 'L':
- case 'M': case 'N': case 'O': case 'P':
- case 'X':
- /* These don't say anything we care about. */
- break;
+ for ( ; (c = *p); p += len)
+ {
+ len = CONSTRAINT_LEN (c, p);
+ switch (c)
+ {
+ case '=': case '+': case '?':
+ case '#': case '&': case '!':
+ case '*': case '%':
+ case 'm': case '<': case '>': case 'V': case 'o':
+ case 'E': case 'F': case 'G': case 'H':
+ case 's': case 'i': case 'n':
+ case 'I': case 'J': case 'K': case 'L':
+ case 'M': case 'N': case 'O': case 'P':
+ case 'X':
+ /* These don't say anything we care about. */
+ break;
- case ',':
- if (found_zero && ! reg_allowed)
- num_matching_alts++;
+ case ',':
+ if (found_zero && ! reg_allowed)
+ num_matching_alts++;
- found_zero = reg_allowed = 0;
- break;
+ found_zero = reg_allowed = 0;
+ break;
- case '0':
- found_zero = 1;
- break;
+ case '0':
+ found_zero = 1;
+ break;
- case '1': case '2': case '3': case '4': case '5':
- case '6': case '7': case '8': case '9':
- /* Skip the balance of the matching constraint. */
- while (ISDIGIT (*p))
- p++;
- break;
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ /* Skip the balance of the matching constraint. */
+ do
+ p++;
+ while (ISDIGIT (*p));
+ len = 0;
+ break;
- default:
- if (REG_CLASS_FROM_LETTER (c) == NO_REGS)
+ default:
+ if (REG_CLASS_FROM_CONSTRAINT (c, p) == NO_REGS
+ && !EXTRA_ADDRESS_CONSTRAINT (c, p))
+ break;
+ /* FALLTHRU */
+ case 'p':
+ case 'g': case 'r':
+ reg_allowed = 1;
break;
- /* FALLTHRU */
- case 'p':
- case 'g': case 'r':
- reg_allowed = 1;
- break;
- }
+ }
+ }
if (found_zero && ! reg_allowed)
num_matching_alts++;