X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Freload1.c;h=d5cd37ce0bd09765c0f769ebd5745b5e3ad28ae9;hb=a4f7c8f77479aa46ba7962e91b975c0492386a6d;hp=b1e90884712ea2986cf72e74631cbb76928b9925;hpb=f7f3687cd07233d61a39999aeef414ef02b4d936;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/reload1.c b/gcc/reload1.c index b1e90884712..d5cd37ce0bd 100644 --- a/gcc/reload1.c +++ b/gcc/reload1.c @@ -1,6 +1,6 @@ /* Reload pseudo regs into hard regs for insns that require hard regs. Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. This file is part of GCC. @@ -44,9 +44,10 @@ along with GCC; see the file COPYING3. If not see #include "toplev.h" #include "except.h" #include "tree.h" +#include "ira.h" #include "df.h" #include "target.h" -#include "dse.h" +#include "emit-rtl.h" /* This file contains the reload pass of the compiler, which is run after register allocation has been done. It checks that @@ -257,6 +258,9 @@ static unsigned int spill_stack_slot_width[FIRST_PSEUDO_REGISTER]; /* Record which pseudos needed to be spilled. */ static regset_head spilled_pseudos; +/* Record which pseudos changed their allocation in finish_spills. */ +static regset_head changed_allocation_pseudos; + /* Used for communication between order_regs_for_reload and count_pseudo. Used to avoid counting one pseudo twice. */ static regset_head pseudos_counted; @@ -314,8 +318,9 @@ struct elim_table int to; /* Register number used as replacement. */ HOST_WIDE_INT initial_offset; /* Initial difference between values. */ int can_eliminate; /* Nonzero if this elimination can be done. */ - int can_eliminate_previous; /* Value of CAN_ELIMINATE in previous scan over - insns made by reload. */ + int can_eliminate_previous; /* Value returned by TARGET_CAN_ELIMINATE + target hook in previous scan over insns + made by reload. */ HOST_WIDE_INT offset; /* Current offset between the two regs. */ HOST_WIDE_INT previous_offset;/* Offset at end of previous insn. */ int ref_outside_mem; /* "to" has been referenced outside a MEM. */ @@ -389,7 +394,7 @@ static void delete_caller_save_insns (void); static void spill_failure (rtx, enum reg_class); static void count_spilled_pseudo (int, int, int); static void delete_dead_insn (rtx); -static void alter_reg (int, int); +static void alter_reg (int, int, bool); static void set_label_offsets (rtx, rtx, int); static void check_eliminable_occurrences (rtx); static void elimination_effects (rtx, enum machine_mode); @@ -443,6 +448,8 @@ static rtx inc_for_reload (rtx, rtx, rtx, int); static void add_auto_inc_notes (rtx, rtx); #endif static void copy_eh_notes (rtx, rtx); +static void substitute (rtx *, const_rtx, rtx); +static bool gen_reload_chain_without_interm_reg_p (int, int); static int reloads_conflict (int, int); static rtx gen_reload (rtx, rtx, int, enum reload_type); static rtx emit_insn_if_valid_for_reload (rtx); @@ -501,6 +508,7 @@ init_reload (void) reload_startobj = XOBNEWVAR (&reload_obstack, char, 0); INIT_REG_SET (&spilled_pseudos); + INIT_REG_SET (&changed_allocation_pseudos); INIT_REG_SET (&pseudos_counted); } @@ -546,11 +554,11 @@ compute_use_by_pseudos (HARD_REG_SET *to, regset from) if (r < 0) { - /* reload_combine uses the information from - DF_LIVE_IN (BASIC_BLOCK), which might still - contain registers that have not actually been allocated - since they have an equivalence. */ - gcc_assert (reload_completed); + /* reload_combine uses the information from DF_LIVE_IN, + which might still contain registers that have not + actually been allocated since they have an + equivalence. */ + gcc_assert (ira_conflicts_p || reload_completed); } else add_to_hard_reg_set (to, PSEUDO_REGNO_MODE (regno), r); @@ -684,6 +692,9 @@ static int something_needs_operands_changed; /* Nonzero means we couldn't get enough spill regs. */ static int failure; +/* Temporary array of pseudo-register number. */ +static int *temp_pseudo_reg_arr; + /* Main entry point for the reload pass. FIRST is the first insn of the function being compiled. @@ -700,7 +711,7 @@ static int failure; int reload (rtx first, int global) { - int i; + int i, n; rtx insn; struct elim_table *ep; basic_block bb; @@ -790,7 +801,7 @@ reload (rtx first, int global) && GET_MODE (insn) != VOIDmode) PUT_MODE (insn, VOIDmode); - if (INSN_P (insn)) + if (NONDEBUG_INSN_P (insn)) scan_paradoxical_subregs (PATTERN (insn)); if (set != 0 && REG_P (SET_DEST (set))) @@ -883,12 +894,21 @@ reload (rtx first, int global) offsets_known_at = XNEWVEC (char, num_labels); offsets_at = (HOST_WIDE_INT (*)[NUM_ELIMINABLE_REGS]) xmalloc (num_labels * NUM_ELIMINABLE_REGS * sizeof (HOST_WIDE_INT)); - /* Alter each pseudo-reg rtx to contain its hard reg number. - Assign stack slots to the pseudos that lack hard regs or equivalents. + /* Alter each pseudo-reg rtx to contain its hard reg number. Assign + stack slots to the pseudos that lack hard regs or equivalents. Do not touch virtual registers. */ - for (i = LAST_VIRTUAL_REGISTER + 1; i < max_regno; i++) - alter_reg (i, -1); + temp_pseudo_reg_arr = XNEWVEC (int, max_regno - LAST_VIRTUAL_REGISTER - 1); + for (n = 0, i = LAST_VIRTUAL_REGISTER + 1; i < max_regno; i++) + temp_pseudo_reg_arr[n++] = i; + + if (ira_conflicts_p) + /* Ask IRA to order pseudo-registers for better stack slot + sharing. */ + ira_sort_regnos_for_alter_reg (temp_pseudo_reg_arr, n, reg_max_ref_width); + + for (i = 0; i < n; i++) + alter_reg (temp_pseudo_reg_arr[i], -1, false); /* If we have some registers we think can be eliminated, scan all insns to see if there is an insn that sets one of these registers to something @@ -978,7 +998,8 @@ reload (rtx first, int global) for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) if (reg_renumber[i] < 0 && reg_equiv_memory_loc[i]) { - rtx x = eliminate_regs (reg_equiv_memory_loc[i], 0, NULL_RTX); + rtx x = eliminate_regs (reg_equiv_memory_loc[i], VOIDmode, + NULL_RTX); if (strict_memory_address_p (GET_MODE (regno_reg_rtx[i]), XEXP (x, 0))) @@ -1002,7 +1023,7 @@ reload (rtx first, int global) the loop. */ reg_equiv_memory_loc[i] = 0; reg_equiv_init[i] = 0; - alter_reg (i, -1); + alter_reg (i, -1, true); } } @@ -1036,7 +1057,12 @@ reload (rtx first, int global) calculate_needs_all_insns (global); - CLEAR_REG_SET (&spilled_pseudos); + if (! ira_conflicts_p) + /* Don't do it for IRA. We need this info because we don't + change live_throughout and dead_or_set for chains when IRA + is used. */ + CLEAR_REG_SET (&spilled_pseudos); + did_spill = 0; something_changed = 0; @@ -1163,6 +1189,7 @@ reload (rtx first, int global) regs. */ failed: + CLEAR_REG_SET (&changed_allocation_pseudos); CLEAR_REG_SET (&spilled_pseudos); reload_in_progress = 0; @@ -1207,6 +1234,48 @@ reload (rtx first, int global) else if (reg_equiv_mem[i]) XEXP (reg_equiv_mem[i], 0) = addr; } + + /* We don't want complex addressing modes in debug insns + if simpler ones will do, so delegitimize equivalences + in debug insns. */ + if (MAY_HAVE_DEBUG_INSNS && reg_renumber[i] < 0) + { + rtx reg = regno_reg_rtx[i]; + rtx equiv = 0; + df_ref use; + + if (reg_equiv_constant[i]) + equiv = reg_equiv_constant[i]; + else if (reg_equiv_invariant[i]) + equiv = reg_equiv_invariant[i]; + else if (reg && MEM_P (reg)) + { + equiv = targetm.delegitimize_address (reg); + if (equiv == reg) + equiv = 0; + } + else if (reg && REG_P (reg) && (int)REGNO (reg) != i) + equiv = reg; + + if (equiv) + for (use = DF_REG_USE_CHAIN (i); use; + use = DF_REF_NEXT_REG (use)) + if (DEBUG_INSN_P (DF_REF_INSN (use))) + { + rtx *loc = DF_REF_LOC (use); + rtx x = *loc; + + if (x == reg) + *loc = copy_rtx (equiv); + else if (GET_CODE (x) == SUBREG + && SUBREG_REG (x) == reg) + *loc = simplify_gen_subreg (GET_MODE (x), equiv, + GET_MODE (reg), + SUBREG_BYTE (x)); + else + gcc_unreachable (); + } + } } /* We must set reload_completed now since the cleanup_subreg_operands call @@ -1301,9 +1370,9 @@ reload (rtx first, int global) } } - /* If we are doing stack checking, give a warning if this function's - frame size is larger than we expect. */ - if (flag_stack_check && ! STACK_CHECK_BUILTIN) + /* If we are doing generic stack checking, give a warning if this + function's frame size is larger than we expect. */ + if (flag_stack_check == GENERIC_STACK_CHECK) { HOST_WIDE_INT size = get_frame_size () + STACK_CHECK_FIXED_FRAME_SIZE; static int verbose_warned = 0; @@ -1333,6 +1402,8 @@ reload (rtx first, int global) VEC_free (rtx, gc, reg_equiv_memory_loc_vec); reg_equiv_memory_loc = 0; + free (temp_pseudo_reg_arr); + if (offsets_known_at) free (offsets_known_at); if (offsets_at) @@ -1573,10 +1644,24 @@ calculate_needs_all_insns (int global) { rtx set = single_set (insn); if (set - && SET_SRC (set) == SET_DEST (set) - && REG_P (SET_SRC (set)) - && REGNO (SET_SRC (set)) >= FIRST_PSEUDO_REGISTER) + && + ((SET_SRC (set) == SET_DEST (set) + && REG_P (SET_SRC (set)) + && REGNO (SET_SRC (set)) >= FIRST_PSEUDO_REGISTER) + || (REG_P (SET_SRC (set)) && REG_P (SET_DEST (set)) + && reg_renumber[REGNO (SET_SRC (set))] < 0 + && reg_renumber[REGNO (SET_DEST (set))] < 0 + && reg_equiv_memory_loc[REGNO (SET_SRC (set))] != NULL + && reg_equiv_memory_loc[REGNO (SET_DEST (set))] != NULL + && rtx_equal_p (reg_equiv_memory_loc + [REGNO (SET_SRC (set))], + reg_equiv_memory_loc + [REGNO (SET_DEST (set))])))) { + if (ira_conflicts_p) + /* Inform IRA about the insn deletion. */ + ira_mark_memory_move_deletion (REGNO (SET_DEST (set)), + REGNO (SET_SRC (set))); delete_insn (insn); /* Delete it from the reload chain. */ if (chain->prev) @@ -1637,8 +1722,8 @@ reload_reg_class_lower (const void *r1p, const void *r2p) return t; /* Count all solitary classes before non-solitary ones. */ - t = ((reg_class_size[(int) rld[r2].class] == 1) - - (reg_class_size[(int) rld[r1].class] == 1)); + t = ((reg_class_size[(int) rld[r2].rclass] == 1) + - (reg_class_size[(int) rld[r1].rclass] == 1)); if (t != 0) return t; @@ -1648,7 +1733,7 @@ reload_reg_class_lower (const void *r1p, const void *r2p) return t; /* Consider reloads in order of increasing reg-class number. */ - t = (int) rld[r1].class - (int) rld[r2].class; + t = (int) rld[r1].rclass - (int) rld[r2].rclass; if (t != 0) return t; @@ -1665,6 +1750,10 @@ static int spill_cost[FIRST_PSEUDO_REGISTER]; only the first hard reg for a multi-reg pseudo. */ static int spill_add_cost[FIRST_PSEUDO_REGISTER]; +/* Map of hard regno to pseudo regno currently occupying the hard + reg. */ +static int hard_regno_to_pseudo_regno[FIRST_PSEUDO_REGISTER]; + /* Update the spill cost arrays, considering that pseudo REG is live. */ static void @@ -1675,7 +1764,10 @@ count_pseudo (int reg) int nregs; if (REGNO_REG_SET_P (&pseudos_counted, reg) - || REGNO_REG_SET_P (&spilled_pseudos, reg)) + || REGNO_REG_SET_P (&spilled_pseudos, reg) + /* Ignore spilled pseudo-registers which can be here only if IRA + is used. */ + || (ira_conflicts_p && r < 0)) return; SET_REGNO_REG_SET (&pseudos_counted, reg); @@ -1683,10 +1775,12 @@ count_pseudo (int reg) gcc_assert (r >= 0); spill_add_cost[r] += freq; - nregs = hard_regno_nregs[r][PSEUDO_REGNO_MODE (reg)]; while (nregs-- > 0) - spill_cost[r + nregs] += freq; + { + hard_regno_to_pseudo_regno[r + nregs] = reg; + spill_cost[r + nregs] += freq; + } } /* Calculate the SPILL_COST and SPILL_ADD_COST arrays and determine the @@ -1704,6 +1798,8 @@ order_regs_for_reload (struct insn_chain *chain) memset (spill_cost, 0, sizeof spill_cost); memset (spill_add_cost, 0, sizeof spill_add_cost); + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + hard_regno_to_pseudo_regno[i] = -1; /* Count number of uses of each hard reg by pseudo regs allocated to it and then order them by decreasing use. First exclude hard registers @@ -1746,18 +1842,25 @@ static HARD_REG_SET used_spill_regs_local; static void count_spilled_pseudo (int spilled, int spilled_nregs, int reg) { + int freq = REG_FREQ (reg); int r = reg_renumber[reg]; int nregs = hard_regno_nregs[r][PSEUDO_REGNO_MODE (reg)]; - if (REGNO_REG_SET_P (&spilled_pseudos, reg) + /* Ignore spilled pseudo-registers which can be here only if IRA is + used. */ + if ((ira_conflicts_p && r < 0) + || REGNO_REG_SET_P (&spilled_pseudos, reg) || spilled + spilled_nregs <= r || r + nregs <= spilled) return; SET_REGNO_REG_SET (&spilled_pseudos, reg); - spill_add_cost[r] -= REG_FREQ (reg); + spill_add_cost[r] -= freq; while (nregs-- > 0) - spill_cost[r + nregs] -= REG_FREQ (reg); + { + hard_regno_to_pseudo_regno[r + nregs] = -1; + spill_cost[r + nregs] -= freq; + } } /* Find reload register to use for reload number ORDER. */ @@ -1769,15 +1872,17 @@ find_reg (struct insn_chain *chain, int order) struct reload *rl = rld + rnum; int best_cost = INT_MAX; int best_reg = -1; - unsigned int i, j; + unsigned int i, j, n; int k; HARD_REG_SET not_usable; HARD_REG_SET used_by_other_reload; reg_set_iterator rsi; + static int regno_pseudo_regs[FIRST_PSEUDO_REGISTER]; + static int best_regno_pseudo_regs[FIRST_PSEUDO_REGISTER]; COPY_HARD_REG_SET (not_usable, bad_spill_regs); IOR_HARD_REG_SET (not_usable, bad_spill_regs_global); - IOR_COMPL_HARD_REG_SET (not_usable, reg_class_contents[rl->class]); + IOR_COMPL_HARD_REG_SET (not_usable, reg_class_contents[rl->rclass]); CLEAR_HARD_REG_SET (used_by_other_reload); for (k = 0; k < order; k++) @@ -1791,7 +1896,11 @@ find_reg (struct insn_chain *chain, int order) for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) { +#ifdef REG_ALLOC_ORDER + unsigned int regno = reg_alloc_order[i]; +#else unsigned int regno = i; +#endif if (! TEST_HARD_REG_BIT (not_usable, regno) && ! TEST_HARD_REG_BIT (used_by_other_reload, regno) @@ -1810,6 +1919,38 @@ find_reg (struct insn_chain *chain, int order) } if (! ok) continue; + + if (ira_conflicts_p) + { + /* Ask IRA to find a better pseudo-register for + spilling. */ + for (n = j = 0; j < this_nregs; j++) + { + int r = hard_regno_to_pseudo_regno[regno + j]; + + if (r < 0) + continue; + if (n == 0 || regno_pseudo_regs[n - 1] != r) + regno_pseudo_regs[n++] = r; + } + regno_pseudo_regs[n++] = -1; + if (best_reg < 0 + || ira_better_spill_reload_regno_p (regno_pseudo_regs, + best_regno_pseudo_regs, + rl->in, rl->out, + chain->insn)) + { + best_reg = regno; + for (j = 0;; j++) + { + best_regno_pseudo_regs[j] = regno_pseudo_regs[j]; + if (regno_pseudo_regs[j] < 0) + break; + } + } + continue; + } + if (rl->in && REG_P (rl->in) && REGNO (rl->in) == regno) this_cost--; if (rl->out && REG_P (rl->out) && REGNO (rl->out) == regno) @@ -1857,6 +1998,7 @@ find_reg (struct insn_chain *chain, int order) { gcc_assert (spill_cost[best_reg + i] == 0); gcc_assert (spill_add_cost[best_reg + i] == 0); + gcc_assert (hard_regno_to_pseudo_regno[best_reg + i] == -1); SET_HARD_REG_BIT (used_spill_regs_local, best_reg + i); } return 1; @@ -1918,7 +2060,7 @@ find_reload_regs (struct insn_chain *chain) { if (dump_file) fprintf (dump_file, "reload failure for reload %d\n", r); - spill_failure (chain->insn, rld[r].class); + spill_failure (chain->insn, rld[r].rclass); failure = 1; return; } @@ -1976,16 +2118,16 @@ delete_caller_save_insns (void) INSN should be one of the insns which needed this particular spill reg. */ static void -spill_failure (rtx insn, enum reg_class class) +spill_failure (rtx insn, enum reg_class rclass) { if (asm_noperands (PATTERN (insn)) >= 0) error_for_asm (insn, "can't find a register in class %qs while " "reloading %", - reg_class_names[class]); + reg_class_names[rclass]); else { error ("unable to find a register to spill in class %qs", - reg_class_names[class]); + reg_class_names[rclass]); if (dump_file) { @@ -2026,7 +2168,7 @@ delete_dead_insn (rtx insn) can share one stack slot. */ static void -alter_reg (int i, int from_reg) +alter_reg (int i, int from_reg, bool dont_share_p) { /* When outputting an inline function, this can happen for a reg that isn't actually used. */ @@ -2052,7 +2194,7 @@ alter_reg (int i, int from_reg) && (reg_equiv_invariant[i] == 0 || reg_equiv_init[i] == 0) && reg_equiv_memory_loc[i] == 0) { - rtx x; + rtx x = NULL_RTX; enum machine_mode mode = GET_MODE (regno_reg_rtx[i]); unsigned int inherent_size = PSEUDO_REGNO_BYTES (i); unsigned int inherent_align = GET_MODE_ALIGNMENT (mode); @@ -2060,6 +2202,17 @@ alter_reg (int i, int from_reg) unsigned int min_align = reg_max_ref_width[i] * BITS_PER_UNIT; int adjust = 0; + if (ira_conflicts_p) + { + /* Mark the spill for IRA. */ + SET_REGNO_REG_SET (&spilled_pseudos, i); + if (!dont_share_p) + x = ira_reuse_stack_slot (i, inherent_size, total_size); + } + + if (x) + ; + /* Each pseudo reg has an inherent size which comes from its own mode, and a total size which provides room for paradoxical subregs which refer to the pseudo reg in wider modes. @@ -2068,24 +2221,34 @@ alter_reg (int i, int from_reg) enough inherent space and enough total space. Otherwise, we allocate a new slot, making sure that it has no less inherent space, and no less total space, then the previous slot. */ - if (from_reg == -1) + else if (from_reg == -1 || (!dont_share_p && ira_conflicts_p)) { - alias_set_type alias_set = new_alias_set (); + rtx stack_slot; /* No known place to spill from => no slot to reuse. */ x = assign_stack_local (mode, total_size, min_align > inherent_align || total_size > inherent_size ? -1 : 0); + + stack_slot = x; + + /* Cancel the big-endian correction done in assign_stack_local. + Get the address of the beginning of the slot. This is so we + can do a big-endian correction unconditionally below. */ if (BYTES_BIG_ENDIAN) - /* Cancel the big-endian correction done in assign_stack_local. - Get the address of the beginning of the slot. - This is so we can do a big-endian correction unconditionally - below. */ - adjust = inherent_size - total_size; - - /* Nothing can alias this slot except this pseudo. */ - set_mem_alias_set (x, alias_set); - dse_record_singleton_alias_set (alias_set, mode); + { + adjust = inherent_size - total_size; + if (adjust) + stack_slot + = adjust_address_nv (x, mode_for_size (total_size + * BITS_PER_UNIT, + MODE_INT, 1), + adjust); + } + + if (! dont_share_p && ira_conflicts_p) + /* Inform IRA about allocation a new stack slot. */ + ira_mark_new_stack_slot (stack_slot, i, total_size); } /* Reuse a stack slot if possible. */ @@ -2095,6 +2258,7 @@ alter_reg (int i, int from_reg) >= inherent_size) && MEM_ALIGN (spill_stack_slot[from_reg]) >= min_align) x = spill_stack_slot[from_reg]; + /* Allocate a bigger slot. */ else { @@ -2119,27 +2283,11 @@ alter_reg (int i, int from_reg) || total_size > inherent_size ? -1 : 0); stack_slot = x; - /* All pseudos mapped to this slot can alias each other. */ - if (spill_stack_slot[from_reg]) - { - alias_set_type alias_set - = MEM_ALIAS_SET (spill_stack_slot[from_reg]); - set_mem_alias_set (x, alias_set); - dse_invalidate_singleton_alias_set (alias_set); - } - else - { - alias_set_type alias_set = new_alias_set (); - set_mem_alias_set (x, alias_set); - dse_record_singleton_alias_set (alias_set, mode); - } - + /* Cancel the big-endian correction done in assign_stack_local. + Get the address of the beginning of the slot. This is so we + can do a big-endian correction unconditionally below. */ if (BYTES_BIG_ENDIAN) { - /* Cancel the big-endian correction done in assign_stack_local. - Get the address of the beginning of the slot. - This is so we can do a big-endian correction unconditionally - below. */ adjust = GET_MODE_SIZE (mode) - total_size; if (adjust) stack_slot @@ -2162,25 +2310,8 @@ alter_reg (int i, int from_reg) wrong mode, make a new stack slot. */ x = adjust_address_nv (x, GET_MODE (regno_reg_rtx[i]), adjust); - /* If we have a decl for the original register, set it for the - memory. If this is a shared MEM, make a copy. */ - if (REG_EXPR (regno_reg_rtx[i]) - && DECL_P (REG_EXPR (regno_reg_rtx[i]))) - { - rtx decl = DECL_RTL_IF_SET (REG_EXPR (regno_reg_rtx[i])); - - /* We can do this only for the DECLs home pseudo, not for - any copies of it, since otherwise when the stack slot - is reused, nonoverlapping_memrefs_p might think they - cannot overlap. */ - if (decl && REG_P (decl) && REGNO (decl) == (unsigned) i) - { - if (from_reg != -1 && spill_stack_slot[from_reg] == x) - x = copy_rtx (x); - - set_mem_attrs_from_reg (x, regno_reg_rtx[i]); - } - } + /* Set all of the memory attributes as appropriate for a spill. */ + set_mem_attrs_for_spill (x); /* Save the stack slot for later. */ reg_equiv_memory_loc[i] = x; @@ -2394,7 +2525,7 @@ eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn, enum rtx_code code = GET_CODE (x); struct elim_table *ep; int regno; - rtx new; + rtx new_rtx; int i, j; const char *fmt; int copied = 0; @@ -2441,7 +2572,7 @@ eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn, /* There exists at least one use of REGNO that cannot be eliminated. Prevent the defining insn from being deleted. */ reg_equiv_init[regno] = NULL_RTX; - alter_reg (regno, -1); + alter_reg (regno, -1, true); } return x; @@ -2478,7 +2609,7 @@ eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn, We special-case the commonest situation in eliminate_regs_in_insn, so just replace a PLUS with a PLUS here, unless inside a MEM. */ - if (mem_mode != 0 && GET_CODE (XEXP (x, 1)) == CONST_INT + if (mem_mode != 0 && CONST_INT_P (XEXP (x, 1)) && INTVAL (XEXP (x, 1)) == - ep->previous_offset) return ep->to_rtx; else @@ -2523,15 +2654,15 @@ eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn, && reg_equiv_constant[REGNO (new0)] != 0) new0 = reg_equiv_constant[REGNO (new0)]; - new = form_sum (new0, new1); + new_rtx = form_sum (new0, new1); /* As above, if we are not inside a MEM we do not want to turn a PLUS into something else. We might try to do so here for an addition of 0 if we aren't optimizing. */ - if (! mem_mode && GET_CODE (new) != PLUS) - return gen_rtx_PLUS (GET_MODE (x), new, const0_rtx); + if (! mem_mode && GET_CODE (new_rtx) != PLUS) + return gen_rtx_PLUS (GET_MODE (x), new_rtx, const0_rtx); else - return new; + return new_rtx; } } return x; @@ -2544,7 +2675,7 @@ eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn, We ignore the possibility of overflow here. */ if (REG_P (XEXP (x, 0)) && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER - && GET_CODE (XEXP (x, 1)) == CONST_INT) + && CONST_INT_P (XEXP (x, 1))) for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) if (ep->from_rtx == XEXP (x, 0) && ep->can_eliminate) @@ -2588,18 +2719,18 @@ eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn, /* If we have something in XEXP (x, 0), the usual case, eliminate it. */ if (XEXP (x, 0)) { - new = eliminate_regs_1 (XEXP (x, 0), mem_mode, insn, true); - if (new != XEXP (x, 0)) + new_rtx = eliminate_regs_1 (XEXP (x, 0), mem_mode, insn, true); + if (new_rtx != XEXP (x, 0)) { /* If this is a REG_DEAD note, it is not valid anymore. Using the eliminated version could result in creating a REG_DEAD note for the stack or frame pointer. */ - if (GET_MODE (x) == REG_DEAD) + if (REG_NOTE_KIND (x) == REG_DEAD) return (XEXP (x, 1) ? eliminate_regs_1 (XEXP (x, 1), mem_mode, insn, true) : NULL_RTX); - x = gen_rtx_EXPR_LIST (REG_NOTE_KIND (x), new, XEXP (x, 1)); + x = alloc_reg_note (REG_NOTE_KIND (x), new_rtx, XEXP (x, 1)); } } @@ -2611,10 +2742,10 @@ eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn, strictly needed, but it simplifies the code. */ if (XEXP (x, 1)) { - new = eliminate_regs_1 (XEXP (x, 1), mem_mode, insn, true); - if (new != XEXP (x, 1)) + new_rtx = eliminate_regs_1 (XEXP (x, 1), mem_mode, insn, true); + if (new_rtx != XEXP (x, 1)) return - gen_rtx_fmt_ee (GET_CODE (x), GET_MODE (x), XEXP (x, 0), new); + gen_rtx_fmt_ee (GET_CODE (x), GET_MODE (x), XEXP (x, 0), new_rtx); } return x; @@ -2636,13 +2767,13 @@ eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn, if (GET_CODE (XEXP (x, 1)) == PLUS && XEXP (XEXP (x, 1), 0) == XEXP (x, 0)) { - rtx new = eliminate_regs_1 (XEXP (XEXP (x, 1), 1), mem_mode, + rtx new_rtx = eliminate_regs_1 (XEXP (XEXP (x, 1), 1), mem_mode, insn, true); - if (new != XEXP (XEXP (x, 1), 1)) + if (new_rtx != XEXP (XEXP (x, 1), 1)) return gen_rtx_fmt_ee (code, GET_MODE (x), XEXP (x, 0), gen_rtx_PLUS (GET_MODE (x), - XEXP (x, 0), new)); + XEXP (x, 0), new_rtx)); } return x; @@ -2660,9 +2791,9 @@ eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn, case POPCOUNT: case PARITY: case BSWAP: - new = eliminate_regs_1 (XEXP (x, 0), mem_mode, insn, false); - if (new != XEXP (x, 0)) - return gen_rtx_fmt_e (code, GET_MODE (x), new); + new_rtx = eliminate_regs_1 (XEXP (x, 0), mem_mode, insn, false); + if (new_rtx != XEXP (x, 0)) + return gen_rtx_fmt_e (code, GET_MODE (x), new_rtx); return x; case SUBREG: @@ -2678,17 +2809,17 @@ eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn, && reg_equiv_memory_loc != 0 && reg_equiv_memory_loc[REGNO (SUBREG_REG (x))] != 0) { - new = SUBREG_REG (x); + new_rtx = SUBREG_REG (x); } else - new = eliminate_regs_1 (SUBREG_REG (x), mem_mode, insn, false); + new_rtx = eliminate_regs_1 (SUBREG_REG (x), mem_mode, insn, false); - if (new != SUBREG_REG (x)) + if (new_rtx != SUBREG_REG (x)) { int x_size = GET_MODE_SIZE (GET_MODE (x)); - int new_size = GET_MODE_SIZE (GET_MODE (new)); + int new_size = GET_MODE_SIZE (GET_MODE (new_rtx)); - if (MEM_P (new) + if (MEM_P (new_rtx) && ((x_size < new_size #ifdef WORD_REGISTER_OPERATIONS /* On these machines, combine can create rtl of the form @@ -2704,9 +2835,9 @@ eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn, ) || x_size == new_size) ) - return adjust_address_nv (new, GET_MODE (x), SUBREG_BYTE (x)); + return adjust_address_nv (new_rtx, GET_MODE (x), SUBREG_BYTE (x)); else - return gen_rtx_SUBREG (GET_MODE (x), new, SUBREG_BYTE (x)); + return gen_rtx_SUBREG (GET_MODE (x), new_rtx, SUBREG_BYTE (x)); } return x; @@ -2722,9 +2853,9 @@ eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn, case USE: /* Handle insn_list USE that a call to a pure function may generate. */ - new = eliminate_regs_1 (XEXP (x, 0), 0, insn, false); - if (new != XEXP (x, 0)) - return gen_rtx_USE (GET_MODE (x), new); + new_rtx = eliminate_regs_1 (XEXP (x, 0), VOIDmode, insn, false); + if (new_rtx != XEXP (x, 0)) + return gen_rtx_USE (GET_MODE (x), new_rtx); return x; case CLOBBER: @@ -2743,21 +2874,21 @@ eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn, { if (*fmt == 'e') { - new = eliminate_regs_1 (XEXP (x, i), mem_mode, insn, false); - if (new != XEXP (x, i) && ! copied) + new_rtx = eliminate_regs_1 (XEXP (x, i), mem_mode, insn, false); + if (new_rtx != XEXP (x, i) && ! copied) { x = shallow_copy_rtx (x); copied = 1; } - XEXP (x, i) = new; + XEXP (x, i) = new_rtx; } else if (*fmt == 'E') { int copied_vec = 0; for (j = 0; j < XVECLEN (x, i); j++) { - new = eliminate_regs_1 (XVECEXP (x, i, j), mem_mode, insn, false); - if (new != XVECEXP (x, i, j) && ! copied_vec) + new_rtx = eliminate_regs_1 (XVECEXP (x, i, j), mem_mode, insn, false); + if (new_rtx != XVECEXP (x, i, j) && ! copied_vec) { rtvec new_v = gen_rtvec_v (XVECLEN (x, i), XVEC (x, i)->elem); @@ -2769,7 +2900,7 @@ eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn, XVEC (x, i) = new_v; copied_vec = 1; } - XVECEXP (x, i, j) = new; + XVECEXP (x, i, j) = new_rtx; } } } @@ -2956,15 +3087,15 @@ elimination_effects (rtx x, enum machine_mode mem_mode) if (GET_CODE (src) == PLUS && XEXP (src, 0) == SET_DEST (x) - && GET_CODE (XEXP (src, 1)) == CONST_INT) + && CONST_INT_P (XEXP (src, 1))) ep->offset -= INTVAL (XEXP (src, 1)); else ep->can_eliminate = 0; } } - elimination_effects (SET_DEST (x), 0); - elimination_effects (SET_SRC (x), 0); + elimination_effects (SET_DEST (x), VOIDmode); + elimination_effects (SET_SRC (x), VOIDmode); return; case MEM: @@ -3062,7 +3193,8 @@ eliminate_regs_in_insn (rtx insn, int replace) || GET_CODE (PATTERN (insn)) == CLOBBER || GET_CODE (PATTERN (insn)) == ADDR_VEC || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC - || GET_CODE (PATTERN (insn)) == ASM_INPUT); + || GET_CODE (PATTERN (insn)) == ASM_INPUT + || DEBUG_INSN_P (insn)); return 0; } @@ -3091,7 +3223,7 @@ eliminate_regs_in_insn (rtx insn, int replace) rtx prev_insn, prev_set; if (GET_CODE (base) == PLUS - && GET_CODE (XEXP (base, 1)) == CONST_INT) + && CONST_INT_P (XEXP (base, 1))) { offset += INTVAL (XEXP (base, 1)); base = XEXP (base, 0); @@ -3166,7 +3298,7 @@ eliminate_regs_in_insn (rtx insn, int replace) plus_src = SET_SRC (old_set); /* First see if the source is of the form (plus (...) CST). */ if (plus_src - && GET_CODE (XEXP (plus_src, 1)) == CONST_INT) + && CONST_INT_P (XEXP (plus_src, 1))) plus_cst_src = plus_src; else if (REG_P (SET_SRC (old_set)) || plus_src) @@ -3179,7 +3311,7 @@ eliminate_regs_in_insn (rtx insn, int replace) if ((REG_NOTE_KIND (links) == REG_EQUAL || REG_NOTE_KIND (links) == REG_EQUIV) && GET_CODE (XEXP (links, 0)) == PLUS - && GET_CODE (XEXP (XEXP (links, 0), 1)) == CONST_INT) + && CONST_INT_P (XEXP (XEXP (links, 0), 1))) { plus_cst_src = XEXP (links, 0); break; @@ -3212,7 +3344,7 @@ eliminate_regs_in_insn (rtx insn, int replace) { rtx to_rtx = ep->to_rtx; offset += ep->offset; - offset = trunc_int_for_mode (offset, GET_MODE (reg)); + offset = trunc_int_for_mode (offset, GET_MODE (plus_cst_src)); if (GET_CODE (XEXP (plus_cst_src, 0)) == SUBREG) to_rtx = gen_lowpart (GET_MODE (XEXP (plus_cst_src, 0)), @@ -3262,7 +3394,7 @@ eliminate_regs_in_insn (rtx insn, int replace) } /* Determine the effects of this insn on elimination offsets. */ - elimination_effects (old_body, 0); + elimination_effects (old_body, VOIDmode); /* Eliminate all eliminable registers occurring in operands that can be handled by reload. */ @@ -3303,7 +3435,7 @@ eliminate_regs_in_insn (rtx insn, int replace) in_plus = true; substed_operand[i] - = eliminate_regs_1 (recog_data.operand[i], 0, + = eliminate_regs_1 (recog_data.operand[i], VOIDmode, replace ? insn : NULL_RTX, is_set_src || in_plus); if (substed_operand[i] != orig_operand[i]) @@ -3433,7 +3565,7 @@ eliminate_regs_in_insn (rtx insn, int replace) the pre-passes. */ if (val && REG_NOTES (insn) != 0) REG_NOTES (insn) - = eliminate_regs_1 (REG_NOTES (insn), 0, REG_NOTES (insn), true); + = eliminate_regs_1 (REG_NOTES (insn), VOIDmode, REG_NOTES (insn), true); return val; } @@ -3491,7 +3623,7 @@ mark_not_eliminable (rtx dest, const_rtx x, void *data ATTRIBUTE_UNUSED) && (GET_CODE (x) != SET || GET_CODE (SET_SRC (x)) != PLUS || XEXP (SET_SRC (x), 0) != dest - || GET_CODE (XEXP (SET_SRC (x), 1)) != CONST_INT)) + || !CONST_INT_P (XEXP (SET_SRC (x), 1)))) { reg_eliminate[i].can_eliminate_previous = reg_eliminate[i].can_eliminate = 0; @@ -3614,9 +3746,10 @@ update_eliminables (HARD_REG_SET *pset) struct elim_table *ep; for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) - if ((ep->from == HARD_FRAME_POINTER_REGNUM && FRAME_POINTER_REQUIRED) + if ((ep->from == HARD_FRAME_POINTER_REGNUM + && targetm.frame_pointer_required ()) #ifdef ELIMINABLE_REGS - || ! CAN_ELIMINATE (ep->from, ep->to) + || ! targetm.can_eliminate (ep->from, ep->to) #endif ) ep->can_eliminate = 0; @@ -3663,8 +3796,11 @@ update_eliminables (HARD_REG_SET *pset) frame_pointer_needed = 1; for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) { - if (ep->can_eliminate && ep->from == FRAME_POINTER_REGNUM - && ep->to != HARD_FRAME_POINTER_REGNUM) + if (ep->can_eliminate + && ep->from == FRAME_POINTER_REGNUM + && ep->to != HARD_FRAME_POINTER_REGNUM + && (! SUPPORTS_STACK_ALIGNMENT + || ! crtl->stack_realign_needed)) frame_pointer_needed = 0; if (! ep->can_eliminate && ep->can_eliminate_previous) @@ -3695,7 +3831,9 @@ elimination_target_reg_p (rtx x) return false; } -/* Initialize the table of registers to eliminate. */ +/* Initialize the table of registers to eliminate. + Pre-condition: global flag frame_pointer_needed has been set before + calling this function. */ static void init_elim_table (void) @@ -3708,19 +3846,6 @@ init_elim_table (void) if (!reg_eliminate) reg_eliminate = XCNEWVEC (struct elim_table, NUM_ELIMINABLE_REGS); - /* Does this function require a frame pointer? */ - - frame_pointer_needed = (! flag_omit_frame_pointer - /* ?? If EXIT_IGNORE_STACK is set, we will not save - and restore sp for alloca. So we can't eliminate - the frame pointer in that case. At some point, - we should improve this by emitting the - sp-adjusting insns for this case. */ - || (cfun->calls_alloca - && EXIT_IGNORE_STACK) - || crtl->accesses_prior_frames - || FRAME_POINTER_REQUIRED); - num_eliminable = 0; #ifdef ELIMINABLE_REGS @@ -3730,8 +3855,11 @@ init_elim_table (void) ep->from = ep1->from; ep->to = ep1->to; ep->can_eliminate = ep->can_eliminate_previous - = (CAN_ELIMINATE (ep->from, ep->to) - && ! (ep->to == STACK_POINTER_REGNUM && frame_pointer_needed)); + = (targetm.can_eliminate (ep->from, ep->to) + && ! (ep->to == STACK_POINTER_REGNUM + && frame_pointer_needed + && (! SUPPORTS_STACK_ALIGNMENT + || ! stack_realign_fp))); } #else reg_eliminate[0].from = reg_eliminate_1[0].from; @@ -3822,22 +3950,28 @@ finish_spills (int global) spill_reg_order[i] = -1; EXECUTE_IF_SET_IN_REG_SET (&spilled_pseudos, FIRST_PSEUDO_REGISTER, i, rsi) - { - /* Record the current hard register the pseudo is allocated to in - pseudo_previous_regs so we avoid reallocating it to the same - hard reg in a later pass. */ - gcc_assert (reg_renumber[i] >= 0); - - SET_HARD_REG_BIT (pseudo_previous_regs[i], reg_renumber[i]); - /* Mark it as no longer having a hard register home. */ - reg_renumber[i] = -1; - /* We will need to scan everything again. */ - something_changed = 1; - } + if (! ira_conflicts_p || reg_renumber[i] >= 0) + { + /* Record the current hard register the pseudo is allocated to + in pseudo_previous_regs so we avoid reallocating it to the + same hard reg in a later pass. */ + gcc_assert (reg_renumber[i] >= 0); + + SET_HARD_REG_BIT (pseudo_previous_regs[i], reg_renumber[i]); + /* Mark it as no longer having a hard register home. */ + reg_renumber[i] = -1; + if (ira_conflicts_p) + /* Inform IRA about the change. */ + ira_mark_allocation_change (i); + /* We will need to scan everything again. */ + something_changed = 1; + } /* Retry global register allocation if possible. */ - if (global) + if (global && ira_conflicts_p) { + unsigned int n; + memset (pseudo_forbidden_regs, 0, max_regno * sizeof (HARD_REG_SET)); /* For every insn that needs reloads, set the registers used as spill regs in pseudo_forbidden_regs for every pseudo live across the @@ -3858,24 +3992,24 @@ finish_spills (int global) } } - /* Retry allocating the spilled pseudos. For each reg, merge the - various reg sets that indicate which hard regs can't be used, - and call retry_global_alloc. - We change spill_pseudos here to only contain pseudos that did not - get a new hard register. */ - for (i = FIRST_PSEUDO_REGISTER; i < (unsigned)max_regno; i++) + /* Retry allocating the pseudos spilled in IRA and the + reload. For each reg, merge the various reg sets that + indicate which hard regs can't be used, and call + ira_reassign_pseudos. */ + for (n = 0, i = FIRST_PSEUDO_REGISTER; i < (unsigned) max_regno; i++) if (reg_old_renumber[i] != reg_renumber[i]) { - HARD_REG_SET forbidden; - COPY_HARD_REG_SET (forbidden, bad_spill_regs_global); - IOR_HARD_REG_SET (forbidden, pseudo_forbidden_regs[i]); - IOR_HARD_REG_SET (forbidden, pseudo_previous_regs[i]); - retry_global_alloc (i, forbidden); - if (reg_renumber[i] >= 0) + if (reg_renumber[i] < 0) + temp_pseudo_reg_arr[n++] = i; + else CLEAR_REGNO_REG_SET (&spilled_pseudos, i); } + if (ira_reassign_pseudos (temp_pseudo_reg_arr, n, + bad_spill_regs_global, + pseudo_forbidden_regs, pseudo_previous_regs, + &spilled_pseudos)) + something_changed = 1; } - /* Fix up the register information in the insn chain. This involves deleting those of the spilled pseudos which did not get a new hard register home from the live_{before,after} sets. */ @@ -3884,9 +4018,14 @@ finish_spills (int global) HARD_REG_SET used_by_pseudos; HARD_REG_SET used_by_pseudos2; - AND_COMPL_REG_SET (&chain->live_throughout, &spilled_pseudos); - AND_COMPL_REG_SET (&chain->dead_or_set, &spilled_pseudos); - + if (! ira_conflicts_p) + { + /* Don't do it for IRA because IRA and the reload still can + assign hard registers to the spilled pseudos on next + reload iterations. */ + AND_COMPL_REG_SET (&chain->live_throughout, &spilled_pseudos); + AND_COMPL_REG_SET (&chain->dead_or_set, &spilled_pseudos); + } /* Mark any unallocated hard regs as available for spills. That makes inheritance work somewhat better. */ if (chain->need_reload) @@ -3895,20 +4034,18 @@ finish_spills (int global) REG_SET_TO_HARD_REG_SET (used_by_pseudos2, &chain->dead_or_set); IOR_HARD_REG_SET (used_by_pseudos, used_by_pseudos2); - /* Save the old value for the sanity test below. */ - COPY_HARD_REG_SET (used_by_pseudos2, chain->used_spill_regs); - compute_use_by_pseudos (&used_by_pseudos, &chain->live_throughout); compute_use_by_pseudos (&used_by_pseudos, &chain->dead_or_set); + /* Value of chain->used_spill_regs from previous iteration + may be not included in the value calculated here because + of possible removing caller-saves insns (see function + delete_caller_save_insns. */ COMPL_HARD_REG_SET (chain->used_spill_regs, used_by_pseudos); AND_HARD_REG_SET (chain->used_spill_regs, used_spill_regs); - - /* Make sure we only enlarge the set. */ - gcc_assert (hard_reg_set_subset_p (used_by_pseudos2, - chain->used_spill_regs)); } } + CLEAR_REG_SET (&changed_allocation_pseudos); /* Let alter_reg modify the reg rtx's for the modified pseudos. */ for (i = FIRST_PSEUDO_REGISTER; i < (unsigned)max_regno; i++) { @@ -3916,7 +4053,9 @@ finish_spills (int global) if (reg_old_renumber[i] == regno) continue; - alter_reg (i, reg_old_renumber[i]); + SET_REGNO_REG_SET (&changed_allocation_pseudos, i); + + alter_reg (i, reg_old_renumber[i], false); reg_old_renumber[i] = regno; if (dump_file) { @@ -3993,27 +4132,17 @@ static void fixup_eh_region_note (rtx insn, rtx prev, rtx next) { rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); - unsigned int trap_count; rtx i; if (note == NULL) return; - if (may_trap_p (PATTERN (insn))) - trap_count = 1; - else - { - remove_note (insn, note); - trap_count = 0; - } + if (! may_trap_p (PATTERN (insn))) + remove_note (insn, note); for (i = NEXT_INSN (prev); i != next; i = NEXT_INSN (i)) if (INSN_P (i) && i != insn && may_trap_p (PATTERN (i))) - { - trap_count++; - REG_NOTES (i) - = gen_rtx_EXPR_LIST (REG_EH_REGION, XEXP (note, 0), REG_NOTES (i)); - } + add_reg_note (i, REG_EH_REGION, XEXP (note, 0)); } /* Reload pseudo-registers into hard regs around each insn as needed. @@ -4048,6 +4177,9 @@ reload_as_needed (int live_known) rtx prev = 0; rtx insn = chain->insn; rtx old_next = NEXT_INSN (insn); +#ifdef AUTO_INC_DEC + rtx old_prev = PREV_INSN (insn); +#endif /* If we pass a label, copy the offsets from the label information into the current offsets of each elimination. */ @@ -4216,39 +4348,36 @@ reload_as_needed (int live_known) continue; if (n == 1) { - n = validate_replace_rtx (reload_reg, - gen_rtx_fmt_e (code, - mode, - reload_reg), - p); + rtx replace_reg + = gen_rtx_fmt_e (code, mode, reload_reg); + + validate_replace_rtx_group (reload_reg, + replace_reg, p); + n = verify_changes (0); /* We must also verify that the constraints - are met after the replacement. */ - extract_insn (p); + are met after the replacement. Make sure + extract_insn is only called for an insn + where the replacements were found to be + valid so far. */ if (n) - n = constrain_operands (1); - else - break; - - /* If the constraints were not met, then - undo the replacement. */ - if (!n) { - validate_replace_rtx (gen_rtx_fmt_e (code, - mode, - reload_reg), - reload_reg, p); - break; + extract_insn (p); + n = constrain_operands (1); } + /* If the constraints were not met, then + undo the replacement, else confirm it. */ + if (!n) + cancel_changes (0); + else + confirm_change_group (); } break; } if (n == 1) { - REG_NOTES (p) - = gen_rtx_EXPR_LIST (REG_INC, reload_reg, - REG_NOTES (p)); + add_reg_note (p, REG_INC, reload_reg); /* Mark this as having an output reload so that the REG_INC processing code below won't invalidate the reload for inheritance. */ @@ -4274,6 +4403,43 @@ reload_as_needed (int live_known) SET_REGNO_REG_SET (®_has_output_reload, REGNO (XEXP (in_reg, 0))); } + else if (code == PRE_INC || code == PRE_DEC + || code == POST_INC || code == POST_DEC) + { + int in_regno = REGNO (XEXP (in_reg, 0)); + + if (reg_last_reload_reg[in_regno] != NULL_RTX) + { + int in_hard_regno; + bool forget_p = true; + + in_hard_regno = REGNO (reg_last_reload_reg[in_regno]); + if (TEST_HARD_REG_BIT (reg_reloaded_valid, + in_hard_regno)) + { + for (x = old_prev ? NEXT_INSN (old_prev) : insn; + x != old_next; + x = NEXT_INSN (x)) + if (x == reg_reloaded_insn[in_hard_regno]) + { + forget_p = false; + break; + } + } + /* If for some reasons, we didn't set up + reg_last_reload_reg in this insn, + invalidate inheritance from previous + insns for the incremented/decremented + register. Such registers will be not in + reg_has_output_reload. Invalidate it + also if the corresponding element in + reg_reloaded_insn is also + invalidated. */ + if (forget_p) + forget_old_reloads_1 (XEXP (in_reg, 0), + NULL_RTX, NULL); + } + } } } /* If a pseudo that got a hard register is auto-incremented, @@ -4303,8 +4469,8 @@ reload_as_needed (int live_known) be partially clobbered by the call. */ else if (CALL_P (insn)) { - AND_COMPL_HARD_REG_SET (reg_reloaded_valid, call_used_reg_set); - AND_COMPL_HARD_REG_SET (reg_reloaded_valid, reg_reloaded_call_part_clobbered); + AND_COMPL_HARD_REG_SET (reg_reloaded_valid, call_used_reg_set); + AND_COMPL_HARD_REG_SET (reg_reloaded_valid, reg_reloaded_call_part_clobbered); } } @@ -4975,6 +5141,126 @@ reloads_unique_chain_p (int r1, int r2) return true; } + +/* The recursive function change all occurrences of WHAT in *WHERE + onto REPL. */ +static void +substitute (rtx *where, const_rtx what, rtx repl) +{ + const char *fmt; + int i; + enum rtx_code code; + + if (*where == 0) + return; + + if (*where == what || rtx_equal_p (*where, what)) + { + *where = repl; + return; + } + + code = GET_CODE (*where); + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'E') + { + int j; + + for (j = XVECLEN (*where, i) - 1; j >= 0; j--) + substitute (&XVECEXP (*where, i, j), what, repl); + } + else if (fmt[i] == 'e') + substitute (&XEXP (*where, i), what, repl); + } +} + +/* The function returns TRUE if chain of reload R1 and R2 (in any + order) can be evaluated without usage of intermediate register for + the reload containing another reload. It is important to see + gen_reload to understand what the function is trying to do. As an + example, let us have reload chain + + r2: const + r1: + const + + and reload R2 got reload reg HR. The function returns true if + there is a correct insn HR = HR + . Otherwise, + gen_reload will use intermediate register (and this is the reload + reg for R1) to reload . + + We need this function to find a conflict for chain reloads. In our + example, if HR = HR + is incorrect insn, then we cannot + use HR as a reload register for R2. If we do use it then we get a + wrong code: + + HR = const + HR = + HR = HR + HR + +*/ +static bool +gen_reload_chain_without_interm_reg_p (int r1, int r2) +{ + bool result; + int regno, n, code; + rtx out, in, tem, insn; + rtx last = get_last_insn (); + + /* Make r2 a component of r1. */ + if (reg_mentioned_p (rld[r1].in, rld[r2].in)) + { + n = r1; + r1 = r2; + r2 = n; + } + gcc_assert (reg_mentioned_p (rld[r2].in, rld[r1].in)); + regno = rld[r1].regno >= 0 ? rld[r1].regno : rld[r2].regno; + gcc_assert (regno >= 0); + out = gen_rtx_REG (rld[r1].mode, regno); + in = copy_rtx (rld[r1].in); + substitute (&in, rld[r2].in, gen_rtx_REG (rld[r2].mode, regno)); + + /* If IN is a paradoxical SUBREG, remove it and try to put the + opposite SUBREG on OUT. Likewise for a paradoxical SUBREG on OUT. */ + if (GET_CODE (in) == SUBREG + && (GET_MODE_SIZE (GET_MODE (in)) + > GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))) + && (tem = gen_lowpart_common (GET_MODE (SUBREG_REG (in)), out)) != 0) + in = SUBREG_REG (in), out = tem; + + if (GET_CODE (in) == PLUS + && (REG_P (XEXP (in, 0)) + || GET_CODE (XEXP (in, 0)) == SUBREG + || MEM_P (XEXP (in, 0))) + && (REG_P (XEXP (in, 1)) + || GET_CODE (XEXP (in, 1)) == SUBREG + || CONSTANT_P (XEXP (in, 1)) + || MEM_P (XEXP (in, 1)))) + { + insn = emit_insn (gen_rtx_SET (VOIDmode, out, in)); + code = recog_memoized (insn); + result = false; + + if (code >= 0) + { + extract_insn (insn); + /* We want constrain operands to treat this insn strictly in + its validity determination, i.e., the way it would after + reload has completed. */ + result = constrain_operands (1); + } + + delete_insns_since (last); + return result; + } + + /* It looks like other cases in gen_reload are not possible for + chain reloads or do need an intermediate hard registers. */ + return true; +} + /* Return 1 if the reloads denoted by R1 and R2 cannot share a register. Return 0 otherwise. @@ -5024,7 +5310,8 @@ reloads_conflict (int r1, int r2) case RELOAD_FOR_OPERAND_ADDRESS: return (r2_type == RELOAD_FOR_INPUT || r2_type == RELOAD_FOR_INSN || (r2_type == RELOAD_FOR_OPERAND_ADDRESS - && !reloads_unique_chain_p (r1, r2))); + && (!reloads_unique_chain_p (r1, r2) + || !gen_reload_chain_without_interm_reg_p (r1, r2)))); case RELOAD_FOR_OPADDR_ADDR: return (r2_type == RELOAD_FOR_INPUT @@ -5488,7 +5775,7 @@ allocate_reload_reg (struct insn_chain *chain ATTRIBUTE_UNUSED, int r, for (count = 0; count < n_spills; count++) { - int class = (int) rld[r].class; + int rclass = (int) rld[r].rclass; int regnum; i++; @@ -5505,7 +5792,7 @@ allocate_reload_reg (struct insn_chain *chain ATTRIBUTE_UNUSED, int r, && free_for_value_p (regnum, rld[r].mode, rld[r].opnum, rld[r].when_needed, rld[r].in, rld[r].out, r, 1))) - && TEST_HARD_REG_BIT (reg_class_contents[class], regnum) + && TEST_HARD_REG_BIT (reg_class_contents[rclass], regnum) && HARD_REGNO_MODE_OK (regnum, rld[r].mode) /* Look first for regs to share, then for unshared. But don't share regs used for inherited reloads; they are @@ -5535,7 +5822,7 @@ allocate_reload_reg (struct insn_chain *chain ATTRIBUTE_UNUSED, int r, while (nr > 1) { int regno = regnum + nr - 1; - if (!(TEST_HARD_REG_BIT (reg_class_contents[class], regno) + if (!(TEST_HARD_REG_BIT (reg_class_contents[rclass], regno) && spill_reg_order[regno] >= 0 && reload_reg_free_p (regno, rld[r].opnum, rld[r].when_needed))) @@ -5661,7 +5948,7 @@ choose_reload_regs (struct insn_chain *chain) { max_group_size = MAX (rld[j].nregs, max_group_size); group_class - = reg_class_superunion[(int) rld[j].class][(int) group_class]; + = reg_class_superunion[(int) rld[j].rclass][(int) group_class]; } save_reload_reg_rtx[j] = rld[j].reg_rtx; @@ -5807,7 +6094,7 @@ choose_reload_regs (struct insn_chain *chain) #endif ) { - enum reg_class class = rld[r].class, last_class; + enum reg_class rclass = rld[r].rclass, last_class; rtx last_reg = reg_last_reload_reg[regno]; enum machine_mode need_mode; @@ -5819,27 +6106,28 @@ choose_reload_regs (struct insn_chain *chain) need_mode = mode; else need_mode - = smallest_mode_for_size (GET_MODE_BITSIZE (mode) - + byte * BITS_PER_UNIT, - GET_MODE_CLASS (mode)); + = smallest_mode_for_size + (GET_MODE_BITSIZE (mode) + byte * BITS_PER_UNIT, + GET_MODE_CLASS (mode) == MODE_PARTIAL_INT + ? MODE_INT : GET_MODE_CLASS (mode)); if ((GET_MODE_SIZE (GET_MODE (last_reg)) >= GET_MODE_SIZE (need_mode)) && reg_reloaded_contents[i] == regno && TEST_HARD_REG_BIT (reg_reloaded_valid, i) && HARD_REGNO_MODE_OK (i, rld[r].mode) - && (TEST_HARD_REG_BIT (reg_class_contents[(int) class], i) + && (TEST_HARD_REG_BIT (reg_class_contents[(int) rclass], i) /* Even if we can't use this register as a reload register, we might use it for reload_override_in, if copying it to the desired class is cheap enough. */ - || ((REGISTER_MOVE_COST (mode, last_class, class) - < MEMORY_MOVE_COST (mode, class, 1)) - && (secondary_reload_class (1, class, mode, + || ((REGISTER_MOVE_COST (mode, last_class, rclass) + < MEMORY_MOVE_COST (mode, rclass, 1)) + && (secondary_reload_class (1, rclass, mode, last_reg) == NO_REGS) #ifdef SECONDARY_MEMORY_NEEDED - && ! SECONDARY_MEMORY_NEEDED (last_class, class, + && ! SECONDARY_MEMORY_NEEDED (last_class, rclass, mode) #endif )) @@ -5871,7 +6159,7 @@ choose_reload_regs (struct insn_chain *chain) bad_for_class = 0; for (k = 0; k < nr; k++) - bad_for_class |= ! TEST_HARD_REG_BIT (reg_class_contents[(int) rld[r].class], + bad_for_class |= ! TEST_HARD_REG_BIT (reg_class_contents[(int) rld[r].rclass], i+k); /* We found a register that contains the @@ -5953,7 +6241,7 @@ choose_reload_regs (struct insn_chain *chain) || REG_P (rld[r].in) || MEM_P (rld[r].in)) && (rld[r].nregs == max_group_size - || ! reg_classes_intersect_p (rld[r].class, group_class))) + || ! reg_classes_intersect_p (rld[r].rclass, group_class))) search_equiv = rld[r].in; /* If this is an output reload from a simple move insn, look if an equivalence for the input is available. */ @@ -5970,7 +6258,7 @@ choose_reload_regs (struct insn_chain *chain) if (search_equiv) { rtx equiv - = find_equiv_reg (search_equiv, insn, rld[r].class, + = find_equiv_reg (search_equiv, insn, rld[r].rclass, -1, NULL, 0, rld[r].mode); int regno = 0; @@ -6011,7 +6299,7 @@ choose_reload_regs (struct insn_chain *chain) { regs_used |= TEST_HARD_REG_BIT (reload_reg_used_at_all, i); - bad_for_class |= ! TEST_HARD_REG_BIT (reg_class_contents[(int) rld[r].class], + bad_for_class |= ! TEST_HARD_REG_BIT (reg_class_contents[(int) rld[r].rclass], i); } @@ -6097,6 +6385,7 @@ choose_reload_regs (struct insn_chain *chain) int nr = hard_regno_nregs[regno][rld[r].mode]; int k; rld[r].reg_rtx = equiv; + reload_spill_index[r] = regno; reload_inherited[r] = 1; /* If reg_reloaded_valid is not set for this register, @@ -6149,9 +6438,9 @@ choose_reload_regs (struct insn_chain *chain) || rld[s].optional) continue; - if ((rld[s].class != rld[r].class - && reg_classes_intersect_p (rld[r].class, - rld[s].class)) + if ((rld[s].rclass != rld[r].rclass + && reg_classes_intersect_p (rld[r].rclass, + rld[s].rclass)) || rld[s].nregs < rld[r].nregs) break; } @@ -6695,7 +6984,7 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl, rl->when_needed, old, rl->out, j, 0)) { rtx temp = PREV_INSN (insn); - while (temp && NOTE_P (temp)) + while (temp && (NOTE_P (temp) || DEBUG_INSN_P (temp))) temp = PREV_INSN (temp); if (temp && NONJUMP_INSN_P (temp) @@ -6732,9 +7021,19 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl, && REG_N_SETS (REGNO (old)) == 1) { reg_renumber[REGNO (old)] = REGNO (reloadreg); - alter_reg (REGNO (old), -1); + if (ira_conflicts_p) + /* Inform IRA about the change. */ + ira_mark_allocation_change (REGNO (old)); + alter_reg (REGNO (old), -1, false); } special = 1; + + /* Adjust any debug insns between temp and insn. */ + while ((temp = NEXT_INSN (temp)) != insn) + if (DEBUG_INSN_P (temp)) + replace_rtx (PATTERN (temp), old, reloadreg); + else + gcc_assert (NOTE_P (temp)); } else { @@ -6832,7 +7131,7 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl, sri.icode = CODE_FOR_nothing; sri.prev_sri = NULL; - new_class = targetm.secondary_reload (1, real_oldequiv, rl->class, + new_class = targetm.secondary_reload (1, real_oldequiv, rl->rclass, mode, &sri); if (new_class == NO_REGS && sri.icode == CODE_FOR_nothing) @@ -6840,10 +7139,17 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl, else if (new_class == NO_REGS) { if (reload_adjust_reg_for_icode (&second_reload_reg, - third_reload_reg, sri.icode)) - icode = sri.icode, third_reload_reg = 0; + third_reload_reg, + (enum insn_code) sri.icode)) + { + icode = (enum insn_code) sri.icode; + third_reload_reg = 0; + } else - oldequiv = old, real_oldequiv = real_old; + { + oldequiv = old; + real_oldequiv = real_old; + } } else if (sri.icode != CODE_FOR_nothing) /* We currently lack a way to express this in reloads. */ @@ -6859,9 +7165,15 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl, if (reload_adjust_reg_for_temp (&second_reload_reg, third_reload_reg, new_class, mode)) - third_reload_reg = 0, tertiary_icode = sri2.icode; + { + third_reload_reg = 0; + tertiary_icode = (enum insn_code) sri2.icode; + } else - oldequiv = old, real_oldequiv = real_old; + { + oldequiv = old; + real_oldequiv = real_old; + } } else if (new_t_class == NO_REGS && sri2.icode != CODE_FOR_nothing) { @@ -6870,13 +7182,17 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl, if (reload_adjust_reg_for_temp (&intermediate, NULL, new_class, mode) && reload_adjust_reg_for_icode (&third_reload_reg, NULL, - sri2.icode)) + ((enum insn_code) + sri2.icode))) { second_reload_reg = intermediate; - tertiary_icode = sri2.icode; + tertiary_icode = (enum insn_code) sri2.icode; } else - oldequiv = old, real_oldequiv = real_old; + { + oldequiv = old; + real_oldequiv = real_old; + } } else if (new_t_class != NO_REGS && sri2.icode == CODE_FOR_nothing) { @@ -6888,14 +7204,20 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl, new_t_class, mode)) { second_reload_reg = intermediate; - tertiary_icode = sri2.icode; + tertiary_icode = (enum insn_code) sri2.icode; } else - oldequiv = old, real_oldequiv = real_old; + { + oldequiv = old; + real_oldequiv = real_old; + } } else - /* This could be handled more intelligently too. */ - oldequiv = old, real_oldequiv = real_old; + { + /* This could be handled more intelligently too. */ + oldequiv = old; + real_oldequiv = real_old; + } } } @@ -7022,7 +7344,7 @@ emit_output_reload_insns (struct insn_chain *chain, struct reload *rl, && reg_equiv_mem[REGNO (old)] != 0) real_old = reg_equiv_mem[REGNO (old)]; - if (secondary_reload_class (0, rl->class, mode, real_old) != NO_REGS) + if (secondary_reload_class (0, rl->rclass, mode, real_old) != NO_REGS) { rtx second_reloadreg = reloadreg; reloadreg = rld[secondary_reload].reg_rtx; @@ -8017,9 +8339,11 @@ gen_reload (rtx out, rtx in, int opnum, enum reload_type type) #ifdef SECONDARY_MEMORY_NEEDED /* If we need a memory location to do the move, do it that way. */ - else if ((REG_P (in) || GET_CODE (in) == SUBREG) + else if ((REG_P (in) + || (GET_CODE (in) == SUBREG && REG_P (SUBREG_REG (in)))) && reg_or_subregno (in) < FIRST_PSEUDO_REGISTER - && (REG_P (out) || GET_CODE (out) == SUBREG) + && (REG_P (out) + || (GET_CODE (out) == SUBREG && REG_P (SUBREG_REG (out)))) && reg_or_subregno (out) < FIRST_PSEUDO_REGISTER && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (reg_or_subregno (in)), REGNO_REG_CLASS (reg_or_subregno (out)), @@ -8165,9 +8489,9 @@ delete_output_reload (rtx insn, int j, int last_reload_reg, rtx new_reload_reg) reg, 0); if (substed) n_occurrences += count_occurrences (PATTERN (insn), - eliminate_regs (substed, 0, + eliminate_regs (substed, VOIDmode, NULL_RTX), 0); - for (i1 = reg_equiv_alt_mem_list [REGNO (reg)]; i1; i1 = XEXP (i1, 1)) + for (i1 = reg_equiv_alt_mem_list[REGNO (reg)]; i1; i1 = XEXP (i1, 1)) { gcc_assert (!rtx_equal_p (XEXP (i1, 0), substed)); n_occurrences += count_occurrences (PATTERN (insn), XEXP (i1, 0), 0); @@ -8268,7 +8592,10 @@ delete_output_reload (rtx insn, int j, int last_reload_reg, rtx new_reload_reg) /* For the debugging info, say the pseudo lives in this reload reg. */ reg_renumber[REGNO (reg)] = REGNO (new_reload_reg); - alter_reg (REGNO (reg), -1); + if (ira_conflicts_p) + /* Inform IRA about the change. */ + ira_mark_allocation_change (REGNO (reg)); + alter_reg (REGNO (reg), -1, false); } else { @@ -8301,8 +8628,8 @@ delete_address_reloads (rtx dead_insn, rtx current_insn) set2 = single_set (prev); if (! set || ! set2 || GET_CODE (SET_SRC (set)) != PLUS || GET_CODE (SET_SRC (set2)) != PLUS - || GET_CODE (XEXP (SET_SRC (set), 1)) != CONST_INT - || GET_CODE (XEXP (SET_SRC (set2), 1)) != CONST_INT) + || !CONST_INT_P (XEXP (SET_SRC (set), 1)) + || !CONST_INT_P (XEXP (SET_SRC (set2), 1))) return; dst = SET_DEST (set); if (! rtx_equal_p (dst, SET_DEST (set2)) @@ -8527,7 +8854,7 @@ inc_for_reload (rtx reloadreg, rtx in, rtx value, int inc_amount) emit_insn (gen_add2_insn (reloadreg, inc)); store = emit_insn (gen_move_insn (incloc, reloadreg)); - if (GET_CODE (inc) == CONST_INT) + if (CONST_INT_P (inc)) emit_insn (gen_add2_insn (reloadreg, GEN_INT (-INTVAL (inc)))); else emit_insn (gen_sub2_insn (reloadreg, inc)); @@ -8546,8 +8873,7 @@ add_auto_inc_notes (rtx insn, rtx x) if (code == MEM && auto_inc_p (XEXP (x, 0))) { - REG_NOTES (insn) - = gen_rtx_EXPR_LIST (REG_INC, XEXP (XEXP (x, 0), 0), REG_NOTES (insn)); + add_reg_note (insn, REG_INC, XEXP (XEXP (x, 0), 0)); return; } @@ -8574,9 +8900,7 @@ copy_eh_notes (rtx insn, rtx x) for (; x != 0; x = NEXT_INSN (x)) { if (may_trap_p (PATTERN (x))) - REG_NOTES (x) - = gen_rtx_EXPR_LIST (REG_EH_REGION, XEXP (eh_note, 0), - REG_NOTES (x)); + add_reg_note (x, REG_EH_REGION, XEXP (eh_note, 0)); } } }