/* Allocate registers within a basic block, for GNU compiler.
Copyright (C) 1987, 1988, 1991, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000 Free Software Foundation, Inc.
+ 1999, 2000, 2001 Free Software Foundation, Inc.
-This file is part of GNU CC.
+This file is part of GCC.
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+along with GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
/* Allocation of hard register numbers to pseudo registers is done in
two passes. In this pass we consider only regs that are born and
#include "recog.h"
#include "output.h"
#include "toplev.h"
+#include "except.h"
\f
/* Next quantity number available for allocation. */
int n_refs;
+ /* The frequency of uses of quantity Q. */
+
+ int freq;
+
/* Insn number (counting from head of basic block)
where quantity Q was born. -1 if birth has not been recorded. */
qty[qtyno].min_class = reg_preferred_class (regno);
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
return 1;
if (GET_CODE (insn) == CALL_INSN && ! RTX_UNCHANGING_P (memref)
- && ! CONST_CALL_P (insn))
+ && ! CONST_OR_PURE_CALL_P (insn))
return 0;
note_stores (PATTERN (insn), validate_equiv_mem_from_store, NULL);
return 0;
case REG:
- return reg_equiv[REGNO (x)].replace == 0 && rtx_varies_p (x);
+ return reg_equiv[REGNO (x)].replace == 0 && rtx_varies_p (x, 0);
case ASM_OPERANDS:
if (MEM_VOLATILE_P (x))
case REG:
return (reg_equiv[REGNO (x)].loop_depth >= reg_equiv[regno].loop_depth
&& reg_equiv[REGNO (x)].replace)
- || (REG_BASIC_BLOCK (REGNO (x)) < 0 && ! rtx_varies_p (x));
+ || (REG_BASIC_BLOCK (REGNO (x)) < 0 && ! rtx_varies_p (x, 0));
case UNSPEC_VOLATILE:
return 0;
rtx insn;
int block;
int loop_depth;
+ regset_head cleared_regs;
+ int clear_regnos = 0;
reg_equiv = (struct equivalence *) xcalloc (max_regno, sizeof *reg_equiv);
+ INIT_REG_SET (&cleared_regs);
init_alias_analysis ();
/* cse sometimes generates function invariants, but doesn't put a
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))
+ if (! note && ! rtx_varies_p (src, 0))
REG_NOTES (insn)
= note = gen_rtx_EXPR_LIST (REG_EQUAL, src, REG_NOTES (insn));
if (REG_N_SETS (regno) != 1
&& (! note
- || rtx_varies_p (XEXP (note, 0))
+ || rtx_varies_p (XEXP (note, 0), 0)
|| (reg_equiv[regno].replacement
&& ! rtx_equal_p (XEXP (note, 0),
reg_equiv[regno].replacement))))
/* If this register is known to be equal to a constant, record that
it is always equivalent to the constant. */
- if (note && ! rtx_varies_p (XEXP (note, 0)))
+ if (note && ! rtx_varies_p (XEXP (note, 0), 0))
PUT_MODE (note, (enum machine_mode) REG_EQUIV);
/* If this insn introduces a "constant" register, decrease the priority
reg_equiv[regno].loop_depth = loop_depth;
/* Don't mess with things live during setjmp. */
- if (REG_LIVE_LENGTH (regno) >= 0)
+ if (REG_LIVE_LENGTH (regno) >= 0 && optimize)
{
/* Note that the statement below does not affect the priority
in local-alloc! */
abort ();
equiv_insn = XEXP (reg_equiv[regno].init_insns, 0);
+ /* We may not move instructions that can throw, since
+ that changes basic block boundaries and we are not
+ prepared to adjust the CFG to match. */
+ if (can_throw_internal (equiv_insn))
+ continue;
+
if (asm_noperands (PATTERN (equiv_insn)) < 0
&& validate_replace_rtx (regno_reg_rtx[regno],
reg_equiv[regno].src, insn))
remove_death (regno, insn);
REG_N_REFS (regno) = 0;
+ REG_FREQ (regno) = 0;
PUT_CODE (equiv_insn, NOTE);
NOTE_LINE_NUMBER (equiv_insn) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (equiv_insn) = 0;
- reg_equiv[regno].init_insns =
- XEXP (reg_equiv[regno].init_insns, 1);
+ reg_equiv[regno].init_insns
+ = XEXP (reg_equiv[regno].init_insns, 1);
}
/* Move the initialization of the register to just before
INSN. Update the flow information. */
else if (PREV_INSN (insn) != equiv_insn)
{
- int l;
rtx new_insn;
- new_insn = emit_insn_before (copy_rtx (PATTERN (equiv_insn)),
- insn);
- REG_NOTES (PREV_INSN (insn)) = REG_NOTES (equiv_insn);
+ new_insn = emit_insn_before (PATTERN (equiv_insn), insn);
+ REG_NOTES (new_insn) = REG_NOTES (equiv_insn);
REG_NOTES (equiv_insn) = 0;
+ /* Make sure this insn is recognized before reload begins,
+ otherwise eliminate_regs_in_insn will abort. */
+ INSN_CODE (new_insn) = INSN_CODE (equiv_insn);
+
PUT_CODE (equiv_insn, NOTE);
NOTE_LINE_NUMBER (equiv_insn) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (equiv_insn) = 0;
if (block >= 0 && insn == BLOCK_HEAD (block))
BLOCK_HEAD (block) = PREV_INSN (insn);
- for (l = 0; l < n_basic_blocks; l++)
- {
- CLEAR_REGNO_REG_SET (
- BASIC_BLOCK (l)->global_live_at_start,
- regno);
- CLEAR_REGNO_REG_SET (
- BASIC_BLOCK (l)->global_live_at_end,
- regno);
- }
+ /* Remember to clear REGNO from all basic block's live
+ info. */
+ SET_REGNO_REG_SET (&cleared_regs, regno);
+ clear_regnos++;
}
}
}
}
+ /* Clear all dead REGNOs from all basic block's live info. */
+ if (clear_regnos)
+ {
+ int j, l;
+ if (clear_regnos > 8)
+ {
+ for (l = 0; l < n_basic_blocks; l++)
+ {
+ 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);
+ }
+ }
+ else
+ EXECUTE_IF_SET_IN_REG_SET (&cleared_regs, 0, j,
+ {
+ for (l = 0; l < n_basic_blocks; l++)
+ {
+ CLEAR_REGNO_REG_SET (BASIC_BLOCK (l)->global_live_at_start, j);
+ CLEAR_REGNO_REG_SET (BASIC_BLOCK (l)->global_live_at_end, j);
+ }
+ });
+ }
+
/* Clean up. */
end_alias_analysis ();
+ CLEAR_REG_SET (&cleared_regs);
free (reg_equiv);
}
/* Note that the quotient will never be bigger than
the value of floor_log2 times the maximum number of
- times a register can occur in one insn (surely less than 100).
- Multiplying this by 10000 can't overflow.
+ times a register can occur in one insn (surely less than 100)
+ weighted by frequency (max REG_FREQ_MAX).
+ Multiplying this by 10000/REG_FREQ_MAX can't overflow.
QTY_CMP_PRI is also used by qty_sugg_compare. */
#define QTY_CMP_PRI(q) \
- ((int) (((double) (floor_log2 (qty[q].n_refs) * qty[q].n_refs * qty[q].size) \
- / (qty[q].death - qty[q].birth)) * 10000))
+ ((int) (((double) (floor_log2 (qty[q].n_refs) * qty[q].freq * qty[q].size) \
+ / (qty[q].death - qty[q].birth)) * (10000 / REG_FREQ_MAX)))
static int
qty_compare (q1, q2)
{
if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (usedreg))) > UNITS_PER_WORD)
may_save_copy = 0;
- offset += SUBREG_WORD (usedreg);
+ 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);
}
if (GET_CODE (usedreg) != REG)
return 0;
ureg = REGNO (usedreg);
- usize = REG_SIZE (usedreg);
+ if (ureg < FIRST_PSEUDO_REGISTER)
+ usize = HARD_REGNO_NREGS (ureg, GET_MODE (usedreg));
+ else
+ usize = ((GET_MODE_SIZE (GET_MODE (usedreg))
+ + (REGMODE_NATURAL_SIZE (GET_MODE (usedreg)) - 1))
+ / REGMODE_NATURAL_SIZE (GET_MODE (usedreg)));
while (GET_CODE (setreg) == SUBREG)
{
if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (setreg))) > UNITS_PER_WORD)
may_save_copy = 0;
- offset -= SUBREG_WORD (setreg);
+ 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);
}
if (GET_CODE (setreg) != REG)
return 0;
sreg = REGNO (setreg);
- ssize = REG_SIZE (setreg);
+ if (sreg < FIRST_PSEUDO_REGISTER)
+ ssize = HARD_REGNO_NREGS (sreg, GET_MODE (setreg));
+ else
+ ssize = ((GET_MODE_SIZE (GET_MODE (setreg))
+ + (REGMODE_NATURAL_SIZE (GET_MODE (setreg)) - 1))
+ / REGMODE_NATURAL_SIZE (GET_MODE (setreg)));
/* If UREG is a pseudo-register that hasn't already been assigned a
quantity number, it means that it is not local to this block or dies
/* Update info about quantity SQTY. */
qty[sqty].n_calls_crossed += REG_N_CALLS_CROSSED (sreg);
qty[sqty].n_refs += REG_N_REFS (sreg);
+ qty[sqty].freq += REG_FREQ (sreg);
if (usize < ssize)
{
register int i;
register int regno;
if (GET_CODE (reg) == SUBREG)
- regno = REGNO (SUBREG_REG (reg)) + SUBREG_WORD (reg);
+ {
+ regno = REGNO (SUBREG_REG (reg));
+ if (regno < FIRST_PSEUDO_REGISTER)
+ regno = subreg_hard_regno (reg, 1);
+ }
else
regno = REGNO (reg);