/* Allocate registers within a basic block, for GNU compiler.
Copyright (C) 1987, 1988, 1991, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
This file is part of GCC.
#include "output.h"
#include "toplev.h"
#include "except.h"
+#include "integrate.h"
\f
/* Next quantity number available for allocation. */
static int next_qty;
-/* Information we maitain about each quantity. */
+/* Information we maintain about each quantity. */
struct qty
{
/* The number of refs to quantity Q. */
struct equivalence
{
/* Set when an attempt should be made to replace a register
- with the associated src entry. */
+ with the associated src_p entry. */
char replace;
rtx replacement;
- rtx src;
+ rtx *src_p;
/* Loop depth is used to recognize equivalences which appear
to be present within the same loop (or in an inner loop). */
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. */
/* Promote REG_EQUAL notes to REG_EQUIV notes and adjust status of affected
registers. */
- update_equiv_regs ();
+ if (optimize)
+ update_equiv_regs ();
/* This sets the maximum number of quantities we can have. Quantity
numbers start at zero and we can have one for each pseudo. */
/* 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);
case CONST:
case CONST_INT:
case CONST_DOUBLE:
+ case CONST_VECTOR:
case SYMBOL_REF:
case LABEL_REF:
return 0;
case LABEL_REF:
case SYMBOL_REF:
case CONST_DOUBLE:
+ case CONST_VECTOR:
case PC:
case CC0:
case HIGH:
- case LO_SUM:
return 0;
case REG:
case LABEL_REF:
case SYMBOL_REF:
case CONST_DOUBLE:
+ case CONST_VECTOR:
case PC:
case CC0:
case HIGH:
}
\f
/* Return nonzero if the rtx X is invariant over the current function. */
+/* ??? Actually, the places this is used in reload expect exactly what
+ is tested here, and not everything that is function invariant. In
+ particular, the frame pointer and arg pointer are special cased;
+ pic_offset_table_rtx is not, and this will cause aborts when we
+ go to spill these things to memory. */
+
int
function_invariant_p (x)
rtx x;
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))
REG_EQUAL note on the insn. Since this note would be redundant,
there's no point creating it earlier than here. */
if (! note && ! rtx_varies_p (src, 0))
- REG_NOTES (insn)
- = note = gen_rtx_EXPR_LIST (REG_EQUAL, src, REG_NOTES (insn));
+ note = set_unique_reg_note (insn, REG_EQUAL, src);
/* Don't bother considering a REG_EQUAL note containing an EXPR_LIST
since it represents a function call */
recorded_label_ref = 1;
reg_equiv[regno].replacement = XEXP (note, 0);
- reg_equiv[regno].src = src;
+ reg_equiv[regno].src_p = &SET_SRC (set);
reg_equiv[regno].loop_depth = loop_depth;
/* Don't mess with things live during setjmp. */
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))
{
if (asm_noperands (PATTERN (equiv_insn)) < 0
&& validate_replace_rtx (regno_reg_rtx[regno],
- reg_equiv[regno].src, insn))
+ *(reg_equiv[regno].src_p), insn))
{
rtx equiv_link;
rtx last_link;
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);
}
});
}
{
int i, q;
rtx insn;
- rtx note;
+ rtx note, hard_reg;
int insn_number = 0;
int insn_count = 0;
int max_uid = get_max_uid ();
for (i = 1; i < recog_data.n_operands; i++)
{
const char *p = recog_data.constraints[i];
- int this_match = (requires_inout (p));
+ int this_match = requires_inout (p);
n_matching_alts += this_match;
if (this_match == recog_data.n_alternatives)
while (GET_CODE (r1) == PLUS || GET_CODE (r1) == MULT)
r1 = XEXP (r1, 0);
+ /* Avoid making a call-saved register unnecessarily
+ clobbered. */
+ hard_reg = get_hard_reg_initial_reg (cfun, r1);
+ if (hard_reg != NULL_RTX)
+ {
+ if (GET_CODE (hard_reg) == REG
+ && IN_RANGE (REGNO (hard_reg),
+ 0, FIRST_PSEUDO_REGISTER - 1)
+ && ! call_used_regs[REGNO (hard_reg)])
+ continue;
+ }
+
if (GET_CODE (r0) == REG || GET_CODE (r0) == SUBREG)
{
/* We have two priorities for hard register preferences.
discourage the register allocator from creating false
dependencies.
- The adjustment value is choosen to indicate that this qty
+ The adjustment value is chosen to indicate that this qty
conflicts with all the qtys in the instructions immediately
before and after the lifetime of this qty.
while (GET_CODE (usedreg) == SUBREG)
{
- if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (usedreg))) > UNITS_PER_WORD)
- may_save_copy = 0;
- if (REGNO (SUBREG_REG (usedreg)) < FIRST_PSEUDO_REGISTER)
- offset += subreg_regno_offset (REGNO (SUBREG_REG (usedreg)),
- GET_MODE (SUBREG_REG (usedreg)),
- SUBREG_BYTE (usedreg),
- GET_MODE (usedreg));
- else
- offset += (SUBREG_BYTE (usedreg)
- / REGMODE_NATURAL_SIZE (GET_MODE (usedreg)));
- usedreg = SUBREG_REG (usedreg);
+ rtx subreg = SUBREG_REG (usedreg);
+
+ if (GET_CODE (subreg) == REG)
+ {
+ if (GET_MODE_SIZE (GET_MODE (subreg)) > UNITS_PER_WORD)
+ may_save_copy = 0;
+
+ if (REGNO (subreg) < FIRST_PSEUDO_REGISTER)
+ offset += subreg_regno_offset (REGNO (subreg),
+ GET_MODE (subreg),
+ SUBREG_BYTE (usedreg),
+ GET_MODE (usedreg));
+ else
+ offset += (SUBREG_BYTE (usedreg)
+ / REGMODE_NATURAL_SIZE (GET_MODE (usedreg)));
+ }
+
+ usedreg = subreg;
}
+
if (GET_CODE (usedreg) != REG)
return 0;
+
ureg = REGNO (usedreg);
if (ureg < FIRST_PSEUDO_REGISTER)
usize = HARD_REGNO_NREGS (ureg, GET_MODE (usedreg));
while (GET_CODE (setreg) == SUBREG)
{
- if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (setreg))) > UNITS_PER_WORD)
- may_save_copy = 0;
- if (REGNO (SUBREG_REG (setreg)) < FIRST_PSEUDO_REGISTER)
- offset -= subreg_regno_offset (REGNO (SUBREG_REG (setreg)),
- GET_MODE (SUBREG_REG (setreg)),
- SUBREG_BYTE (setreg),
- GET_MODE (setreg));
- else
- offset -= (SUBREG_BYTE (setreg)
- / REGMODE_NATURAL_SIZE (GET_MODE (setreg)));
- setreg = SUBREG_REG (setreg);
+ rtx subreg = SUBREG_REG (setreg);
+
+ if (GET_CODE (subreg) == REG)
+ {
+ if (GET_MODE_SIZE (GET_MODE (subreg)) > UNITS_PER_WORD)
+ may_save_copy = 0;
+
+ if (REGNO (subreg) < FIRST_PSEUDO_REGISTER)
+ offset -= subreg_regno_offset (REGNO (subreg),
+ GET_MODE (subreg),
+ SUBREG_BYTE (setreg),
+ GET_MODE (setreg));
+ else
+ offset -= (SUBREG_BYTE (setreg)
+ / REGMODE_NATURAL_SIZE (GET_MODE (setreg)));
+ }
+
+ setreg = subreg;
}
+
if (GET_CODE (setreg) != REG)
return 0;
+
sreg = REGNO (setreg);
if (sreg < FIRST_PSEUDO_REGISTER)
ssize = HARD_REGNO_NREGS (sreg, GET_MODE (setreg));
case '=': case '+': case '?':
case '#': case '&': case '!':
case '*': case '%':
- case '1': case '2': case '3': case '4': case '5':
- case '6': case '7': case '8': case '9':
case 'm': case '<': case '>': case 'V': case 'o':
case 'E': case 'F': case 'G': case 'H':
case 's': case 'i': case 'n':
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;
+
default:
if (REG_CLASS_FROM_LETTER (c) == NO_REGS)
break;