+2005-09-01 Jakub Jelinek <jakub@redhat.com>
+
+ PR rtl-optimization/23478
+ * regs.h (reg_info): Add throw_calls_crossed.
+ (REG_N_THROWING_CALLS_CROSSED): Define.
+ * flow.c (allocate_reg_life_data): Initialize
+ REG_N_THROWING_CALLS_CROSSED.
+ (propagate_one_insn, attempt_auto_inc): Update
+ REG_N_THROWING_CALLS_CROSSED.
+ * local-alloc.c (struct qty): Add n_throwing_calls_crossed field.
+ (alloc_qty): Initialize it.
+ (update_equiv_regs): Clear REG_N_THROWING_CALLS_CROSSED.
+ (combine_regs): Combine also n_throwing_calls_crossed fields.
+ (find_free_reg): Don't attempt to caller-save pseudos crossing
+ calls that might throw.
+ * global.c (struct allocno): Add throwing_calls_crossed field.
+ (global_alloc): Initialize throwing_calls_crossed.
+ (find_reg): Don't attempt to caller-save pseudos crossing calls that
+ might throw.
+
2005-09-01 Richard Earnshaw <richard.earnshaw@arm.com>
PR rtl-optimization/17810 target/15342
life_analysis fills in certain vectors containing information about
register usage: REG_N_REFS, REG_N_DEATHS, REG_N_SETS, REG_LIVE_LENGTH,
- REG_N_CALLS_CROSSED and REG_BASIC_BLOCK.
+ REG_N_CALLS_CROSSED, REG_N_THROWING_CALLS_CROSSED and REG_BASIC_BLOCK.
life_analysis sets current_function_sp_is_unchanging if the function
doesn't modify the stack pointer. */
REG_N_REFS (i) = 0;
REG_N_DEATHS (i) = 0;
REG_N_CALLS_CROSSED (i) = 0;
+ REG_N_THROWING_CALLS_CROSSED (i) = 0;
REG_LIVE_LENGTH (i) = 0;
REG_FREQ (i) = 0;
REG_BASIC_BLOCK (i) = REG_BLOCK_UNKNOWN;
record this for them. */
if (GET_CODE (insn) == CALL_INSN && (flags & PROP_REG_INFO))
- EXECUTE_IF_SET_IN_REG_SET (pbi->reg_live, 0, i,
- { REG_N_CALLS_CROSSED (i)++; });
+ {
+ EXECUTE_IF_SET_IN_REG_SET (pbi->reg_live, 0, i,
+ { REG_N_CALLS_CROSSED (i)++; });
+ if (can_throw_internal (insn))
+ EXECUTE_IF_SET_IN_REG_SET (pbi->reg_live, 0, i,
+ { REG_N_THROWING_CALLS_CROSSED (i)++; });
+ }
/* Record sets. Do this even for dead instructions, since they
would have killed the values if they hadn't been deleted. */
that REGNO now crosses them. */
for (temp = insn; temp != incr; temp = NEXT_INSN (temp))
if (GET_CODE (temp) == CALL_INSN)
- REG_N_CALLS_CROSSED (regno)++;
+ {
+ REG_N_CALLS_CROSSED (regno)++;
+ if (can_throw_internal (temp))
+ REG_N_THROWING_CALLS_CROSSED (regno)++;
+ }
/* Invalidate alias info for Q since we just changed its value. */
clear_reg_alias_info (q);
/* Number of calls crossed by each allocno. */
int calls_crossed;
+ /* Number of calls that might throw crossed by each allocno. */
+ int throwing_calls_crossed;
+
/* Number of refs to each allocno. */
int n_refs;
allocno[num].reg = i;
allocno[num].size = PSEUDO_REGNO_SIZE (i);
allocno[num].calls_crossed += REG_N_CALLS_CROSSED (i);
+ allocno[num].throwing_calls_crossed
+ += REG_N_THROWING_CALLS_CROSSED (i);
allocno[num].n_refs += REG_N_REFS (i);
allocno[num].freq += REG_FREQ (i);
if (allocno[num].live_length < REG_LIVE_LENGTH (i))
{
/* Did not find a register. If it would be profitable to
allocate a call-clobbered register and save and restore it
- around calls, do that. */
+ around calls, do that. Don't do this if it crosses any calls
+ that might throw. */
if (! accept_call_clobbered
&& allocno[num].calls_crossed != 0
+ && allocno[num].throwing_calls_crossed == 0
&& CALLER_SAVE_PROFITABLE (allocno[num].n_refs,
allocno[num].calls_crossed))
{
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);
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))
/* 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))
{
int deaths; /* # of times (REG n) dies */
int live_length; /* # of instructions (REG n) is live */
int calls_crossed; /* # of calls (REG n) is live across */
+ int throw_calls_crossed; /* # of calls that may throw (REG n) is live across */
int basic_block; /* # of basic blocks (REG n) is used in */
char changes_mode; /* whether (SUBREG (REG n)) exists and
is illegal. */
#define REG_N_CALLS_CROSSED(N) (VARRAY_REG (reg_n_info, N)->calls_crossed)
+/* Indexed by N, gives number of CALL_INSNS that may throw, across which
+ (REG n) is live. */
+
+#define REG_N_THROWING_CALLS_CROSSED(N) \
+ (VARRAY_REG (reg_n_info, N)->throw_calls_crossed)
+
/* Total number of instructions at which (REG n) is live.
The larger this is, the less priority (REG n) gets for
allocation in a hard register (in global-alloc).
+2005-09-01 Jakub Jelinek <jakub@redhat.com>
+
+ PR rtl-optimization/23478
+ * g++.dg/opt/pr23478.C: New test.
+
2005-09-01 Volker Reichelt <reichelt@igpm.rwth-aachen.de>
Backport: