/* 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.
#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;
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))
- note = set_unique_reg_note (insn, REG_EQUAL, src);
+ note = set_unique_reg_note (insn, REG_EQUAL, copy_rtx (src));
/* Don't bother considering a REG_EQUAL note containing an EXPR_LIST
since it represents a function call */
/* 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), 0))
- PUT_MODE (note, (enum machine_mode) REG_EQUIV);
+ if (REG_N_SETS (regno) == 1
+ && note && ! rtx_varies_p (XEXP (note, 0), 0))
+ {
+ rtx note_value = XEXP (note, 0);
+ remove_note (insn, note);
+ set_unique_reg_note (insn, REG_EQUIV, note_value);
+ }
/* If this insn introduces a "constant" register, decrease the priority
of that register. Record this insn if the register is only used once
if (note == 0 && REG_BASIC_BLOCK (regno) >= 0
&& MEM_P (SET_SRC (set))
&& validate_equiv_mem (insn, dest, SET_SRC (set)))
- REG_NOTES (insn) = note = gen_rtx_EXPR_LIST (REG_EQUIV, SET_SRC (set),
- REG_NOTES (insn));
+ note = set_unique_reg_note (insn, REG_EQUIV, copy_rtx (SET_SRC (set)));
if (note)
{
/* 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]);
{
rtx init_insn = XEXP (reg_equiv[regno].init_insns, 0);
if (validate_equiv_mem (init_insn, src, dest)
- && ! memref_used_between_p (dest, init_insn, insn))
+ && ! memref_used_between_p (dest, init_insn, insn)
+ /* Attaching a REG_EQUIV note will fail if INIT_INSN has
+ multiple sets. */
+ && set_unique_reg_note (init_insn, REG_EQUIV, copy_rtx (dest)))
{
- REG_NOTES (init_insn)
- = gen_rtx_EXPR_LIST (REG_EQUIV, dest,
- REG_NOTES (init_insn));
/* This insn makes the equivalence, not the one initializing
the register. */
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))
/* +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. */
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 */
+};
+