/* Allocate registers within a basic block, for GNU compiler.
Copyright (C) 1987, 1988, 1991, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
+ Inc.
This file is part of GCC.
You should have received a copy of the GNU General Public License
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. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, 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 "integrate.h"
#include "reload.h"
#include "ggc.h"
+#include "timevar.h"
+#include "tree-pass.h"
\f
/* Next quantity number available for allocation. */
int n_calls_crossed;
+ /* Number of times a reg tied to given qty lives across a CALL_INSN
+ that might throw. */
+
+ int n_throwing_calls_crossed;
+
/* The register number of one pseudo register whose reg_qty value is Q.
This register should be the head of the chain
maintained in reg_next_in_qty. */
qty[qtyno].mode = mode;
qty[qtyno].birth = birth;
qty[qtyno].n_calls_crossed = REG_N_CALLS_CROSSED (regno);
+ qty[qtyno].n_throwing_calls_crossed = REG_N_THROWING_CALLS_CROSSED (regno);
qty[qtyno].min_class = reg_preferred_class (regno);
qty[qtyno].alternate_class = reg_alternate_class (regno);
qty[qtyno].n_refs = REG_N_REFS (regno);
\f
/* Main entry point of this file. */
-int
+static int
local_alloc (void)
{
int i;
See the declarations of these variables, above,
for what they mean. */
- qty = xmalloc (max_qty * sizeof (struct qty));
- qty_phys_copy_sugg = xmalloc (max_qty * sizeof (HARD_REG_SET));
- qty_phys_num_copy_sugg = xmalloc (max_qty * sizeof (short));
- qty_phys_sugg = xmalloc (max_qty * sizeof (HARD_REG_SET));
- qty_phys_num_sugg = xmalloc (max_qty * sizeof (short));
+ qty = XNEWVEC (struct qty, max_qty);
+ qty_phys_copy_sugg = XNEWVEC (HARD_REG_SET, max_qty);
+ qty_phys_num_copy_sugg = XNEWVEC (short, max_qty);
+ qty_phys_sugg = XNEWVEC (HARD_REG_SET, max_qty);
+ qty_phys_num_sugg = XNEWVEC (short, max_qty);
- reg_qty = xmalloc (max_regno * sizeof (int));
- reg_offset = xmalloc (max_regno * sizeof (char));
- reg_next_in_qty = xmalloc (max_regno * sizeof (int));
+ reg_qty = XNEWVEC (int, max_regno);
+ reg_offset = XNEWVEC (char, max_regno);
+ reg_next_in_qty = XNEWVEC (int, max_regno);
/* Determine which pseudo-registers can be allocated by local-alloc.
In general, these are the registers used only in a single block and
for (insn = NEXT_INSN (start); insn != NEXT_INSN (end);
insn = NEXT_INSN (insn))
- if (INSN_P (insn) && memref_referenced_p (memref, PATTERN (insn)))
- return 1;
+ {
+ if (!INSN_P (insn))
+ continue;
+
+ if (memref_referenced_p (memref, PATTERN (insn)))
+ return 1;
+
+ /* Nonconst functions may access memory. */
+ if (CALL_P (insn)
+ && (! CONST_OR_PURE_CALL_P (insn)
+ || pure_call_p (insn)))
+ return 1;
+ }
return 0;
}
regset_head cleared_regs;
int clear_regnos = 0;
- reg_equiv = xcalloc (max_regno, sizeof *reg_equiv);
+ reg_equiv = XCNEWVEC (struct equivalence, max_regno);
INIT_REG_SET (&cleared_regs);
reg_equiv_init = ggc_alloc_cleared (max_regno * sizeof (rtx));
reg_equiv_init_size = max_regno;
/* If we haven't done so, record for reload that this is an
equivalencing insn. */
- if (!reg_equiv[regno].is_arg_equivalence
- && (!MEM_P (x) || rtx_equal_p (src, x)))
+ if (!reg_equiv[regno].is_arg_equivalence)
reg_equiv_init[regno]
= gen_rtx_INSN_LIST (VOIDmode, insn, reg_equiv_init[regno]);
REG_BASIC_BLOCK (regno) = bb->index;
REG_N_CALLS_CROSSED (regno) = 0;
+ REG_N_THROWING_CALLS_CROSSED (regno) = 0;
REG_LIVE_LENGTH (regno) = 2;
if (insn == BB_HEAD (bb))
info. */
SET_REGNO_REG_SET (&cleared_regs, regno);
clear_regnos++;
- reg_equiv_init[regno] = NULL_RTX;
+ reg_equiv_init[regno]
+ = gen_rtx_INSN_LIST (VOIDmode, new_insn, NULL_RTX);
}
}
}
{
FOR_EACH_BB (bb)
{
- AND_COMPL_REG_SET (bb->global_live_at_start, &cleared_regs);
- AND_COMPL_REG_SET (bb->global_live_at_end, &cleared_regs);
+ AND_COMPL_REG_SET (bb->il.rtl->global_live_at_start,
+ &cleared_regs);
+ AND_COMPL_REG_SET (bb->il.rtl->global_live_at_end,
+ &cleared_regs);
}
}
else
{
FOR_EACH_BB (bb)
{
- CLEAR_REGNO_REG_SET (bb->global_live_at_start, j);
- CLEAR_REGNO_REG_SET (bb->global_live_at_end, j);
+ CLEAR_REGNO_REG_SET (bb->il.rtl->global_live_at_start, j);
+ CLEAR_REGNO_REG_SET (bb->il.rtl->global_live_at_end, j);
}
}
}
/* +2 to leave room for a post_mark_life at the last insn and for
the birth of a CLOBBER in the first insn. */
- regs_live_at = xcalloc ((2 * insn_count + 2), sizeof (HARD_REG_SET));
+ regs_live_at = XCNEWVEC (HARD_REG_SET, 2 * insn_count + 2);
/* Initialize table of hardware registers currently live. */
- REG_SET_TO_HARD_REG_SET (regs_live, BASIC_BLOCK (b)->global_live_at_start);
+ REG_SET_TO_HARD_REG_SET (regs_live,
+ BASIC_BLOCK (b)->il.rtl->global_live_at_start);
/* This loop scans the instructions of the basic block
and assigns quantities to registers.
number of suggested registers they need so we allocate those with
the most restrictive needs first. */
- qty_order = xmalloc (next_qty * sizeof (int));
+ qty_order = XNEWVEC (int, next_qty);
for (i = 0; i < next_qty; i++)
qty_order[i] = i;
/* Update info about quantity SQTY. */
qty[sqty].n_calls_crossed += REG_N_CALLS_CROSSED (sreg);
+ qty[sqty].n_throwing_calls_crossed
+ += REG_N_THROWING_CALLS_CROSSED (sreg);
qty[sqty].n_refs += REG_N_REFS (sreg);
qty[sqty].freq += REG_FREQ (sreg);
if (usize < ssize)
/* 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. */
+ registers in that case. Avoid putting pseudos crossing calls that
+ might throw into call used registers. */
if (! accept_call_clobbered
&& flag_caller_saves
&& ! just_try_suggested
&& qty[qtyno].n_calls_crossed != 0
+ && qty[qtyno].n_throwing_calls_crossed == 0
&& CALLER_SAVE_PROFITABLE (qty[qtyno].n_refs,
qty[qtyno].n_calls_crossed))
{
if (reg_renumber[i] != -1)
fprintf (file, ";; Register %d in %d.\n", i, reg_renumber[i]);
}
+
+/* Run old register allocator. Return TRUE if we must exit
+ rest_of_compilation upon return. */
+static unsigned int
+rest_of_handle_local_alloc (void)
+{
+ int rebuild_notes;
+
+ /* Determine if the current function is a leaf before running reload
+ since this can impact optimizations done by the prologue and
+ epilogue thus changing register elimination offsets. */
+ current_function_is_leaf = leaf_function_p ();
+
+ /* Allocate the reg_renumber array. */
+ allocate_reg_info (max_regno, FALSE, TRUE);
+
+ /* And the reg_equiv_memory_loc array. */
+ VEC_safe_grow (rtx, gc, reg_equiv_memory_loc_vec, max_regno);
+ memset (VEC_address (rtx, reg_equiv_memory_loc_vec), 0,
+ sizeof (rtx) * max_regno);
+ reg_equiv_memory_loc = VEC_address (rtx, reg_equiv_memory_loc_vec);
+
+ allocate_initial_values (reg_equiv_memory_loc);
+
+ regclass (get_insns (), max_reg_num ());
+ rebuild_notes = local_alloc ();
+
+ /* Local allocation may have turned an indirect jump into a direct
+ jump. If so, we must rebuild the JUMP_LABEL fields of jumping
+ instructions. */
+ if (rebuild_notes)
+ {
+ timevar_push (TV_JUMP);
+
+ rebuild_jump_labels (get_insns ());
+ purge_all_dead_edges ();
+ delete_unreachable_blocks ();
+
+ timevar_pop (TV_JUMP);
+ }
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ timevar_push (TV_DUMP);
+ dump_flow_info (dump_file, dump_flags);
+ dump_local_alloc (dump_file);
+ timevar_pop (TV_DUMP);
+ }
+ return 0;
+}
+
+struct tree_opt_pass pass_local_alloc =
+{
+ "lreg", /* name */
+ NULL, /* gate */
+ rest_of_handle_local_alloc, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_LOCAL_ALLOC, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_dump_func |
+ TODO_ggc_collect, /* todo_flags_finish */
+ 'l' /* letter */
+};
+