X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Freload1.c;h=499412c0ba418068c60f539c5d7e9e4fe41e6523;hb=2169f33bdc9db9199850a22ce70730c68227b2db;hp=b1e90884712ea2986cf72e74631cbb76928b9925;hpb=f7f3687cd07233d61a39999aeef414ef02b4d936;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/reload1.c b/gcc/reload1.c index b1e90884712..499412c0ba4 100644 --- a/gcc/reload1.c +++ b/gcc/reload1.c @@ -1,7 +1,7 @@ /* 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 - Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, + 2011 Free Software Foundation, Inc. This file is part of GCC. @@ -26,10 +26,11 @@ along with GCC; see the file COPYING3. If not see #include "machmode.h" #include "hard-reg-set.h" -#include "rtl.h" +#include "rtl-error.h" #include "tm_p.h" #include "obstack.h" #include "insn-config.h" +#include "ggc.h" #include "flags.h" #include "function.h" #include "expr.h" @@ -37,16 +38,15 @@ along with GCC; see the file COPYING3. If not see #include "regs.h" #include "addresses.h" #include "basic-block.h" +#include "df.h" #include "reload.h" #include "recog.h" #include "output.h" -#include "real.h" -#include "toplev.h" #include "except.h" #include "tree.h" -#include "df.h" +#include "ira.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 @@ -82,6 +82,14 @@ along with GCC; see the file COPYING3. If not see fixing up each insn, and generating the new insns to copy values into the reload registers. */ +struct target_reload default_target_reload; +#if SWITCHABLE_TARGET +struct target_reload *this_target_reload = &default_target_reload; +#endif + +#define spill_indirect_levels \ + (this_target_reload->x_spill_indirect_levels) + /* During reload_as_needed, element N contains a REG rtx for the hard reg into which reg N has been reloaded (perhaps for a previous insn). */ static rtx *reg_last_reload_reg; @@ -94,48 +102,9 @@ static regset_head reg_has_output_reload; in the current insn. */ static HARD_REG_SET reg_is_output_reload; -/* Element N is the constant value to which pseudo reg N is equivalent, - or zero if pseudo reg N is not equivalent to a constant. - find_reloads looks at this in order to replace pseudo reg N - with the constant it stands for. */ -rtx *reg_equiv_constant; - -/* Element N is an invariant value to which pseudo reg N is equivalent. - eliminate_regs_in_insn uses this to replace pseudos in particular - contexts. */ -rtx *reg_equiv_invariant; - -/* Element N is a memory location to which pseudo reg N is equivalent, - prior to any register elimination (such as frame pointer to stack - pointer). Depending on whether or not it is a valid address, this value - is transferred to either reg_equiv_address or reg_equiv_mem. */ -rtx *reg_equiv_memory_loc; - -/* We allocate reg_equiv_memory_loc inside a varray so that the garbage - collector can keep track of what is inside. */ -VEC(rtx,gc) *reg_equiv_memory_loc_vec; - -/* Element N is the address of stack slot to which pseudo reg N is equivalent. - This is used when the address is not valid as a memory address - (because its displacement is too big for the machine.) */ -rtx *reg_equiv_address; - -/* Element N is the memory slot to which pseudo reg N is equivalent, - or zero if pseudo reg N is not equivalent to a memory slot. */ -rtx *reg_equiv_mem; - -/* Element N is an EXPR_LIST of REG_EQUIVs containing MEMs with - alternate representations of the location of pseudo reg N. */ -rtx *reg_equiv_alt_mem_list; - /* Widest width in which each pseudo reg is referred to (via subreg). */ static unsigned int *reg_max_ref_width; -/* Element N is the list of insns that initialized reg N from its equivalent - constant or memory slot. */ -rtx *reg_equiv_init; -int reg_equiv_init_size; - /* Vector to remember old contents of reg_renumber before spilling. */ static short *reg_old_renumber; @@ -232,22 +201,6 @@ static HARD_REG_SET used_spill_regs; a round-robin fashion. */ static int last_spill_reg; -/* Nonzero if indirect addressing is supported on the machine; this means - that spilling (REG n) does not require reloading it into a register in - order to do (MEM (REG n)) or (MEM (PLUS (REG n) (CONST_INT c))). The - value indicates the level of indirect addressing supported, e.g., two - means that (MEM (MEM (REG n))) is also valid if (REG n) does not get - a hard register. */ -static char spill_indirect_levels; - -/* Nonzero if indirect addressing is supported when the innermost MEM is - of the form (MEM (SYMBOL_REF sym)). It is assumed that the level to - which these are valid is the same as spill_indirect_levels, above. */ -char indirect_symref_ok; - -/* Nonzero if an address (plus (reg frame_pointer) (reg ...)) is valid. */ -char double_reg_address_ok; - /* Record the stack slot for each spilled hard register. */ static rtx spill_stack_slot[FIRST_PSEUDO_REGISTER]; @@ -257,6 +210,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; @@ -273,12 +229,6 @@ int caller_save_needed; Required by some machines to handle any generated moves differently. */ int reload_in_progress = 0; -/* These arrays record the insn_code of insns that may be needed to - perform input and output reloads of special objects. They provide a - place to pass a scratch register. */ -enum insn_code reload_in_optab[NUM_MACHINE_MODES]; -enum insn_code reload_out_optab[NUM_MACHINE_MODES]; - /* This obstack is used for allocation of rtl during register elimination. The allocated storage can be freed once find_reloads has processed the insn. */ @@ -300,6 +250,10 @@ static char *reload_insn_firstobj; examine. */ struct insn_chain *reload_insn_chain; +/* TRUE if we potentially left dead insns in the insn stream and want to + run DCE immediately after reload, FALSE otherwise. */ +static bool need_dce; + /* List of all insns needing reloads. */ static struct insn_chain *insns_need_reload; @@ -314,8 +268,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. */ @@ -373,6 +328,23 @@ static int first_label_num; static char *offsets_known_at; static HOST_WIDE_INT (*offsets_at)[NUM_ELIMINABLE_REGS]; +VEC(reg_equivs_t,gc) *reg_equivs; + +/* Stack of addresses where an rtx has been changed. We can undo the + changes by popping items off the stack and restoring the original + value at each location. + + We use this simplistic undo capability rather than copy_rtx as copy_rtx + will not make a deep copy of a normally sharable rtx, such as + (const (plus (symbol_ref) (const_int))). If such an expression appears + as R1 in gen_reload_chain_without_interm_reg_p, then a shared + rtx expression would be changed. See PR 42431. */ + +typedef rtx *rtx_p; +DEF_VEC_P(rtx_p); +DEF_VEC_ALLOC_P(rtx_p,heap); +static VEC(rtx_p,heap) *substitute_stack; + /* Number of labels in the current function. */ static int num_labels; @@ -389,10 +361,11 @@ 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); +static rtx eliminate_regs_1 (rtx, enum machine_mode, rtx, bool, bool); static int eliminate_regs_in_insn (rtx, int); static void update_eliminable_offsets (void); static void mark_not_eliminable (rtx, const_rtx, void *); @@ -400,8 +373,11 @@ static void set_initial_elim_offsets (void); static bool verify_initial_elim_offsets (void); static void set_initial_label_offsets (void); static void set_offsets_for_label (rtx); +static void init_eliminable_invariants (rtx, bool); static void init_elim_table (void); +static void free_reg_equiv (void); static void update_eliminables (HARD_REG_SET *); +static void elimination_costs_in_insn (rtx); static void spill_hard_reg (unsigned int, int); static int finish_spills (int); static void scan_paradoxical_subregs (rtx); @@ -427,7 +403,6 @@ static void failed_reload (rtx, int); static int set_reload_reg (int, int); static void choose_reload_regs_init (struct insn_chain *, rtx *); static void choose_reload_regs (struct insn_chain *); -static void merge_assigned_reloads (rtx); static void emit_input_reload_insns (struct insn_chain *, struct reload *, rtx, int); static void emit_output_reload_insns (struct insn_chain *, struct reload *, @@ -438,11 +413,12 @@ static void emit_reload_insns (struct insn_chain *); static void delete_output_reload (rtx, int, int, rtx); static void delete_address_reloads (rtx, rtx); static void delete_address_reloads_1 (rtx, rtx, rtx); -static rtx inc_for_reload (rtx, rtx, rtx, int); +static void inc_for_reload (rtx, rtx, rtx, int); #ifdef AUTO_INC_DEC 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 +477,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 +523,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); @@ -579,7 +556,7 @@ replace_pseudos_in (rtx *loc, enum machine_mode mem_mode, rtx usage) if (regno < FIRST_PSEUDO_REGISTER) return; - x = eliminate_regs (x, mem_mode, usage); + x = eliminate_regs_1 (x, mem_mode, usage, true, false); if (x != *loc) { *loc = x; @@ -587,12 +564,14 @@ replace_pseudos_in (rtx *loc, enum machine_mode mem_mode, rtx usage) return; } - if (reg_equiv_constant[regno]) - *loc = reg_equiv_constant[regno]; - else if (reg_equiv_mem[regno]) - *loc = reg_equiv_mem[regno]; - else if (reg_equiv_address[regno]) - *loc = gen_rtx_MEM (GET_MODE (x), reg_equiv_address[regno]); + if (reg_equiv_constant (regno)) + *loc = reg_equiv_constant (regno); + else if (reg_equiv_invariant (regno)) + *loc = reg_equiv_invariant (regno); + else if (reg_equiv_mem (regno)) + *loc = reg_equiv_mem (regno); + else if (reg_equiv_address (regno)) + *loc = gen_rtx_MEM (GET_MODE (x), reg_equiv_address (regno)); else { gcc_assert (!REG_P (regno_reg_rtx[regno]) @@ -631,7 +610,7 @@ has_nonexceptional_receiver (void) /* If we're not optimizing, then just err on the safe side. */ if (!optimize) return true; - + /* First determine which blocks can reach exit via normal paths. */ tos = worklist = XNEWVEC (basic_block, n_basic_blocks + 1); @@ -641,7 +620,7 @@ has_nonexceptional_receiver (void) /* Place the exit block on our worklist. */ EXIT_BLOCK_PTR->flags |= BB_REACHABLE; *tos++ = EXIT_BLOCK_PTR; - + /* Iterate: find everything reachable from what we've already seen. */ while (tos != worklist) { @@ -664,26 +643,52 @@ has_nonexceptional_receiver (void) /* Now see if there's a reachable block with an exceptional incoming edge. */ FOR_EACH_BB (bb) - if (bb->flags & BB_REACHABLE) - FOR_EACH_EDGE (e, ei, bb->preds) - if (e->flags & EDGE_ABNORMAL) - return true; + if (bb->flags & BB_REACHABLE && bb_has_abnormal_pred (bb)) + return true; /* No exceptional block reached exit unexceptionally. */ return false; } +/* Grow (or allocate) the REG_EQUIVS array from its current size (which may be + zero elements) to MAX_REG_NUM elements. + + Initialize all new fields to NULL and update REG_EQUIVS_SIZE. */ +void +grow_reg_equivs (void) +{ + int old_size = VEC_length (reg_equivs_t, reg_equivs); + int max_regno = max_reg_num (); + int i; + + VEC_reserve (reg_equivs_t, gc, reg_equivs, max_regno); + for (i = old_size; i < max_regno; i++) + { + VEC_quick_insert (reg_equivs_t, reg_equivs, i, 0); + memset (VEC_index (reg_equivs_t, reg_equivs, i), 0, sizeof (reg_equivs_t)); + } + +} + /* Global variables used by reload and its subroutines. */ +/* The current basic block while in calculate_elim_costs_all_insns. */ +static basic_block elim_bb; + /* Set during calculate_needs if an insn needs register elimination. */ static int something_needs_elimination; /* Set during calculate_needs if an insn needs an operand changed. */ static int something_needs_operands_changed; +/* Set by alter_regs if we spilled a register to the stack. */ +static bool something_was_spilled; /* 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. @@ -694,16 +699,18 @@ static int failure; If GLOBAL is zero, we do not have enough information to do that, so any pseudo reg that is spilled must go to the stack. - Return value is nonzero if reload failed - and we must not do any more for this function. */ + Return value is TRUE if reload likely left dead insns in the + stream and a DCE pass should be run to elimiante them. Else the + return value is FALSE. */ -int +bool reload (rtx first, int global) { - int i; + int i, n; rtx insn; struct elim_table *ep; basic_block bb; + bool inserted; /* Make sure even insns with volatile mem refs are recognizable. */ init_recog (); @@ -761,11 +768,7 @@ reload (rtx first, int global) Record memory equivalents in reg_mem_equiv so they can be substituted eventually by altering the REG-rtx's. */ - reg_equiv_constant = XCNEWVEC (rtx, max_regno); - reg_equiv_invariant = XCNEWVEC (rtx, max_regno); - reg_equiv_mem = XCNEWVEC (rtx, max_regno); - reg_equiv_alt_mem_list = XCNEWVEC (rtx, max_regno); - reg_equiv_address = XCNEWVEC (rtx, max_regno); + grow_reg_equivs (); reg_max_ref_width = XCNEWVEC (unsigned int, max_regno); reg_old_renumber = XCNEWVEC (short, max_regno); memcpy (reg_old_renumber, reg_renumber, max_regno * sizeof (short)); @@ -774,121 +777,24 @@ reload (rtx first, int global) CLEAR_HARD_REG_SET (bad_spill_regs_global); - /* Look for REG_EQUIV notes; record what each pseudo is equivalent - to. Also find all paradoxical subregs and find largest such for - each pseudo. */ - - num_eliminable_invariants = 0; - for (insn = first; insn; insn = NEXT_INSN (insn)) - { - rtx set = single_set (insn); - - /* We may introduce USEs that we want to remove at the end, so - we'll mark them with QImode. Make sure there are no - previously-marked insns left by say regmove. */ - if (INSN_P (insn) && GET_CODE (PATTERN (insn)) == USE - && GET_MODE (insn) != VOIDmode) - PUT_MODE (insn, VOIDmode); - - if (INSN_P (insn)) - scan_paradoxical_subregs (PATTERN (insn)); - - if (set != 0 && REG_P (SET_DEST (set))) - { - rtx note = find_reg_note (insn, REG_EQUIV, NULL_RTX); - rtx x; - - if (! note) - continue; - - i = REGNO (SET_DEST (set)); - x = XEXP (note, 0); - - if (i <= LAST_VIRTUAL_REGISTER) - continue; - - if (! function_invariant_p (x) - || ! flag_pic - /* A function invariant is often CONSTANT_P but may - include a register. We promise to only pass - CONSTANT_P objects to LEGITIMATE_PIC_OPERAND_P. */ - || (CONSTANT_P (x) - && LEGITIMATE_PIC_OPERAND_P (x))) - { - /* It can happen that a REG_EQUIV note contains a MEM - that is not a legitimate memory operand. As later - stages of reload assume that all addresses found - in the reg_equiv_* arrays were originally legitimate, - we ignore such REG_EQUIV notes. */ - if (memory_operand (x, VOIDmode)) - { - /* Always unshare the equivalence, so we can - substitute into this insn without touching the - equivalence. */ - reg_equiv_memory_loc[i] = copy_rtx (x); - } - else if (function_invariant_p (x)) - { - if (GET_CODE (x) == PLUS) - { - /* This is PLUS of frame pointer and a constant, - and might be shared. Unshare it. */ - reg_equiv_invariant[i] = copy_rtx (x); - num_eliminable_invariants++; - } - else if (x == frame_pointer_rtx || x == arg_pointer_rtx) - { - reg_equiv_invariant[i] = x; - num_eliminable_invariants++; - } - else if (LEGITIMATE_CONSTANT_P (x)) - reg_equiv_constant[i] = x; - else - { - reg_equiv_memory_loc[i] - = force_const_mem (GET_MODE (SET_DEST (set)), x); - if (! reg_equiv_memory_loc[i]) - reg_equiv_init[i] = NULL_RTX; - } - } - else - { - reg_equiv_init[i] = NULL_RTX; - continue; - } - } - else - reg_equiv_init[i] = NULL_RTX; - } - } - - if (dump_file) - for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) - if (reg_equiv_init[i]) - { - fprintf (dump_file, "init_insns for %u: ", i); - print_inline_rtx (dump_file, reg_equiv_init[i], 20); - fprintf (dump_file, "\n"); - } - + init_eliminable_invariants (first, true); init_elim_table (); - first_label_num = get_first_label_num (); - num_labels = max_label_num () - first_label_num; + /* 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. */ - /* Allocate the tables used to store offset information at labels. */ - /* We used to use alloca here, but the size of what it would try to - allocate would occasionally cause it to exceed the stack limit and - cause a core dump. */ - 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)); + 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; - /* 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. */ + 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 = LAST_VIRTUAL_REGISTER + 1; i < max_regno; i++) - alter_reg (i, -1); + 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 @@ -927,7 +833,7 @@ reload (rtx first, int global) spill_hard_reg (from, 1); } -#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM +#if !HARD_FRAME_POINTER_IS_FRAME_POINTER if (frame_pointer_needed) spill_hard_reg (HARD_FRAME_POINTER_REGNUM, 1); #endif @@ -947,6 +853,7 @@ reload (rtx first, int global) HOST_WIDE_INT starting_frame_size; starting_frame_size = get_frame_size (); + something_was_spilled = false; set_initial_elim_offsets (); set_initial_label_offsets (); @@ -976,13 +883,15 @@ reload (rtx first, int global) so this problem goes away. But that's very hairy. */ for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) - if (reg_renumber[i] < 0 && reg_equiv_memory_loc[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))) - reg_equiv_mem[i] = x, reg_equiv_address[i] = 0; + if (strict_memory_address_addr_space_p + (GET_MODE (regno_reg_rtx[i]), XEXP (x, 0), + MEM_ADDR_SPACE (x))) + reg_equiv_mem (i) = x, reg_equiv_address (i) = 0; else if (CONSTANT_P (XEXP (x, 0)) || (REG_P (XEXP (x, 0)) && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER) @@ -991,7 +900,7 @@ reload (rtx first, int global) && (REGNO (XEXP (XEXP (x, 0), 0)) < FIRST_PSEUDO_REGISTER) && CONSTANT_P (XEXP (XEXP (x, 0), 1)))) - reg_equiv_address[i] = XEXP (x, 0), reg_equiv_mem[i] = 0; + reg_equiv_address (i) = XEXP (x, 0), reg_equiv_mem (i) = 0; else { /* Make a new stack slot. Then indicate that something @@ -1000,9 +909,9 @@ reload (rtx first, int global) below might change some offset. reg_equiv_{mem,address} will be set up for this pseudo on the next pass around the loop. */ - reg_equiv_memory_loc[i] = 0; - reg_equiv_init[i] = 0; - alter_reg (i, -1); + reg_equiv_memory_loc (i) = 0; + reg_equiv_init (i) = 0; + alter_reg (i, -1, true); } } @@ -1010,7 +919,7 @@ reload (rtx first, int global) setup_save_areas (); /* If we allocated another stack slot, redo elimination bookkeeping. */ - if (starting_frame_size != get_frame_size ()) + if (something_was_spilled || starting_frame_size != get_frame_size ()) continue; if (starting_frame_size && crtl->stack_alignment_needed) { @@ -1036,18 +945,23 @@ 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; /* If we allocated any new memory locations, make another pass since it might have changed elimination offsets. */ - if (starting_frame_size != get_frame_size ()) + if (something_was_spilled || starting_frame_size != get_frame_size ()) something_changed = 1; /* Even if the frame size remained the same, we might still have - changed elimination offsets, e.g. if find_reloads called + changed elimination offsets, e.g. if find_reloads called force_const_mem requiring the back end to allocate a constant pool base register that needs to be saved on the stack. */ else if (!verify_initial_elim_offsets ()) @@ -1110,10 +1024,10 @@ reload (rtx first, int global) for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) { - if (reg_renumber[i] < 0 && reg_equiv_init[i] != 0) + if (reg_renumber[i] < 0 && reg_equiv_init (i) != 0) { rtx list; - for (list = reg_equiv_init[i]; list; list = XEXP (list, 1)) + for (list = reg_equiv_init (i); list; list = XEXP (list, 1)) { rtx equiv_insn = XEXP (list, 0); @@ -1158,11 +1072,12 @@ reload (rtx first, int global) if (! frame_pointer_needed) FOR_EACH_BB (bb) bitmap_clear_bit (df_get_live_in (bb), HARD_FRAME_POINTER_REGNUM); - + /* Come here (with failure set nonzero) if we can't get enough spill regs. */ failed: + CLEAR_REG_SET (&changed_allocation_pseudos); CLEAR_REG_SET (&spilled_pseudos); reload_in_progress = 0; @@ -1180,11 +1095,11 @@ reload (rtx first, int global) { rtx addr = 0; - if (reg_equiv_mem[i]) - addr = XEXP (reg_equiv_mem[i], 0); + if (reg_equiv_mem (i)) + addr = XEXP (reg_equiv_mem (i), 0); - if (reg_equiv_address[i]) - addr = reg_equiv_address[i]; + if (reg_equiv_address (i)) + addr = reg_equiv_address (i); if (addr) { @@ -1195,8 +1110,8 @@ reload (rtx first, int global) REG_USERVAR_P (reg) = 0; PUT_CODE (reg, MEM); XEXP (reg, 0) = addr; - if (reg_equiv_memory_loc[i]) - MEM_COPY_ATTRIBUTES (reg, reg_equiv_memory_loc[i]); + if (reg_equiv_memory_loc (i)) + MEM_COPY_ATTRIBUTES (reg, reg_equiv_memory_loc (i)); else { MEM_IN_STRUCT_P (reg) = MEM_SCALAR_P (reg) = 0; @@ -1204,8 +1119,54 @@ reload (rtx first, int global) } MEM_NOTRAP_P (reg) = 1; } - else if (reg_equiv_mem[i]) - XEXP (reg_equiv_mem[i], 0) = addr; + 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, next; + + 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); + else if (reg && REG_P (reg) && (int)REGNO (reg) != i) + equiv = reg; + + if (equiv == reg) + continue; + + for (use = DF_REG_USE_CHAIN (i); use; use = next) + { + insn = DF_REF_INSN (use); + + /* Make sure the next ref is for a different instruction, + so that we're not affected by the rescan. */ + next = DF_REF_NEXT_REG (use); + while (next && DF_REF_INSN (next) == insn) + next = DF_REF_NEXT_REG (next); + + if (DEBUG_INSN_P (insn)) + { + if (!equiv) + { + INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC (); + df_insn_rescan_debug_internal (insn); + } + else + INSN_VAR_LOCATION_LOC (insn) + = simplify_replace_rtx (INSN_VAR_LOCATION_LOC (insn), + reg, equiv); + } + } } } @@ -1301,9 +1262,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; @@ -1323,29 +1284,11 @@ reload (rtx first, int global) } } - /* Indicate that we no longer have known memory locations or constants. */ - if (reg_equiv_constant) - free (reg_equiv_constant); - if (reg_equiv_invariant) - free (reg_equiv_invariant); - reg_equiv_constant = 0; - reg_equiv_invariant = 0; - VEC_free (rtx, gc, reg_equiv_memory_loc_vec); - reg_equiv_memory_loc = 0; - - if (offsets_known_at) - free (offsets_known_at); - if (offsets_at) - free (offsets_at); + free (temp_pseudo_reg_arr); - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - if (reg_equiv_alt_mem_list[i]) - free_EXPR_LIST_list (®_equiv_alt_mem_list[i]); - free (reg_equiv_alt_mem_list); + /* Indicate that we no longer have known memory locations or constants. */ + free_reg_equiv (); - free (reg_equiv_mem); - reg_equiv_init = 0; - free (reg_equiv_address); free (reg_max_ref_width); free (reg_old_renumber); free (pseudo_previous_regs); @@ -1358,7 +1301,21 @@ reload (rtx first, int global) /* Free all the insn_chain structures at once. */ obstack_free (&reload_obstack, reload_startobj); unused_insn_chains = 0; - fixup_abnormal_edges (); + + inserted = fixup_abnormal_edges (); + + /* We've possibly turned single trapping insn into multiple ones. */ + if (cfun->can_throw_non_call_exceptions) + { + sbitmap blocks; + blocks = sbitmap_alloc (last_basic_block); + sbitmap_ones (blocks); + find_many_sub_basic_blocks (blocks); + sbitmap_free (blocks); + } + + if (inserted) + commit_edge_insertions (); /* Replacing pseudos with their memory equivalents might have created shared rtx. Subsequent passes would get confused @@ -1373,7 +1330,13 @@ reload (rtx first, int global) REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM) = BITS_PER_UNIT; #endif - return failure; + VEC_free (rtx_p, heap, substitute_stack); + + gcc_assert (bitmap_empty_p (&spilled_pseudos)); + + reload_completed = !failure; + + return need_dce; } /* Yet another special case. Unfortunately, reg-stack forces people to @@ -1549,9 +1512,9 @@ calculate_needs_all_insns (int global) /* Skip insns that only set an equivalence. */ if (set && REG_P (SET_DEST (set)) && reg_renumber[REGNO (SET_DEST (set))] < 0 - && (reg_equiv_constant[REGNO (SET_DEST (set))] - || (reg_equiv_invariant[REGNO (SET_DEST (set))])) - && reg_equiv_init[REGNO (SET_DEST (set))]) + && (reg_equiv_constant (REGNO (SET_DEST (set))) + || (reg_equiv_invariant (REGNO (SET_DEST (set))))) + && reg_equiv_init (REGNO (SET_DEST (set)))) continue; /* If needed, eliminate any eliminable registers. */ @@ -1573,10 +1536,22 @@ 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) @@ -1622,6 +1597,99 @@ calculate_needs_all_insns (int global) *pprev_reload = 0; } +/* This function is called from the register allocator to set up estimates + for the cost of eliminating pseudos which have REG_EQUIV equivalences to + an invariant. The structure is similar to calculate_needs_all_insns. */ + +void +calculate_elim_costs_all_insns (void) +{ + int *reg_equiv_init_cost; + basic_block bb; + int i; + + reg_equiv_init_cost = XCNEWVEC (int, max_regno); + init_elim_table (); + init_eliminable_invariants (get_insns (), false); + + set_initial_elim_offsets (); + set_initial_label_offsets (); + + FOR_EACH_BB (bb) + { + rtx insn; + elim_bb = bb; + + FOR_BB_INSNS (bb, insn) + { + /* If this is a label, a JUMP_INSN, or has REG_NOTES (which might + include REG_LABEL_OPERAND and REG_LABEL_TARGET), we need to see + what effects this has on the known offsets at labels. */ + + if (LABEL_P (insn) || JUMP_P (insn) + || (INSN_P (insn) && REG_NOTES (insn) != 0)) + set_label_offsets (insn, insn, 0); + + if (INSN_P (insn)) + { + rtx set = single_set (insn); + + /* Skip insns that only set an equivalence. */ + if (set && REG_P (SET_DEST (set)) + && reg_renumber[REGNO (SET_DEST (set))] < 0 + && (reg_equiv_constant (REGNO (SET_DEST (set))) + || reg_equiv_invariant (REGNO (SET_DEST (set))))) + { + unsigned regno = REGNO (SET_DEST (set)); + rtx init = reg_equiv_init (regno); + if (init) + { + rtx t = eliminate_regs_1 (SET_SRC (set), VOIDmode, insn, + false, true); + int cost = rtx_cost (t, SET, + optimize_bb_for_speed_p (bb)); + int freq = REG_FREQ_FROM_BB (bb); + + reg_equiv_init_cost[regno] = cost * freq; + continue; + } + } + /* If needed, eliminate any eliminable registers. */ + if (num_eliminable || num_eliminable_invariants) + elimination_costs_in_insn (insn); + + if (num_eliminable) + update_eliminable_offsets (); + } + } + } + for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) + { + if (reg_equiv_invariant (i)) + { + if (reg_equiv_init (i)) + { + int cost = reg_equiv_init_cost[i]; + if (dump_file) + fprintf (dump_file, + "Reg %d has equivalence, initial gains %d\n", i, cost); + if (cost != 0) + ira_adjust_equiv_reg_cost (i, cost); + } + else + { + if (dump_file) + fprintf (dump_file, + "Reg %d had equivalence, but can't be eliminated\n", + i); + ira_adjust_equiv_reg_cost (i, 0); + } + } + } + + free (reg_equiv_init_cost); +} + /* Comparison function for qsort to decide which of two reloads should be handled first. *P1 and *P2 are the reload numbers. */ @@ -1637,8 +1705,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 +1716,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 +1733,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 +1747,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 +1758,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 +1781,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 +1825,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 +1855,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 +1879,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 +1902,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 +1981,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 +2043,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 +2101,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 " + 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) { @@ -2002,17 +2127,22 @@ spill_failure (rtx insn, enum reg_class class) static void delete_dead_insn (rtx insn) { - rtx prev = prev_real_insn (insn); + rtx prev = prev_active_insn (insn); rtx prev_dest; - /* If the previous insn sets a register that dies in our insn, delete it - too. */ + /* If the previous insn sets a register that dies in our insn make + a note that we want to run DCE immediately after reload. + + We used to delete the previous insn & recurse, but that's wrong for + block local equivalences. Instead of trying to figure out the exact + circumstances where we can delete the potentially dead insns, just + let DCE do the job. */ if (prev && GET_CODE (PATTERN (prev)) == SET && (prev_dest = SET_DEST (PATTERN (prev)), REG_P (prev_dest)) && reg_mentioned_p (prev_dest, PATTERN (insn)) && find_regno_note (insn, REG_DEAD, REGNO (prev_dest)) && ! side_effects_p (SET_SRC (PATTERN (prev)))) - delete_dead_insn (prev); + need_dce = 1; SET_INSN_DELETED (insn); } @@ -2026,7 +2156,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. */ @@ -2048,11 +2178,12 @@ alter_reg (int i, int from_reg) if (reg_renumber[i] < 0 && REG_N_REFS (i) > 0 - && reg_equiv_constant[i] == 0 - && (reg_equiv_invariant[i] == 0 || reg_equiv_init[i] == 0) - && reg_equiv_memory_loc[i] == 0) + && reg_equiv_constant (i) == 0 + && (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 +2191,19 @@ alter_reg (int i, int from_reg) unsigned int min_align = reg_max_ref_width[i] * BITS_PER_UNIT; int adjust = 0; + something_was_spilled = true; + + 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 +2212,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 +2249,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 +2274,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,28 +2301,11 @@ 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; + reg_equiv_memory_loc (i) = x; } } @@ -2362,10 +2484,40 @@ set_label_offsets (rtx x, rtx insn, int initial_p) } } -/* Scan X and replace any eliminable registers (such as fp) with a - replacement (such as sp), plus an offset. +/* Called through for_each_rtx, this function examines every reg that occurs + in PX and adjusts the costs for its elimination which are gathered by IRA. + DATA is the insn in which PX occurs. We do not recurse into MEM + expressions. */ - MEM_MODE is the mode of an enclosing MEM. We need this to know how +static int +note_reg_elim_costly (rtx *px, void *data) +{ + rtx insn = (rtx)data; + rtx x = *px; + + if (MEM_P (x)) + return -1; + + if (REG_P (x) + && REGNO (x) >= FIRST_PSEUDO_REGISTER + && reg_equiv_init (REGNO (x)) + && reg_equiv_invariant (REGNO (x))) + { + rtx t = reg_equiv_invariant (REGNO (x)); + rtx new_rtx = eliminate_regs_1 (t, Pmode, insn, true, true); + int cost = rtx_cost (new_rtx, SET, optimize_bb_for_speed_p (elim_bb)); + int freq = REG_FREQ_FROM_BB (elim_bb); + + if (cost != 0) + ira_adjust_equiv_reg_cost (REGNO (x), -cost * freq); + } + return 0; +} + +/* Scan X and replace any eliminable registers (such as fp) with a + replacement (such as sp), plus an offset. + + MEM_MODE is the mode of an enclosing MEM. We need this to know how much to adjust a register for, e.g., PRE_DEC. Also, if we are inside a MEM, we are allowed to replace a sum of a register and the constant zero with the register, which we cannot do outside a MEM. In addition, we need @@ -2381,6 +2533,9 @@ set_label_offsets (rtx x, rtx insn, int initial_p) This means, do not set ref_outside_mem even if the reference is outside of MEMs. + If FOR_COSTS is true, we are being called before reload in order to + estimate the costs of keeping registers with an equivalence unallocated. + REG_EQUIV_MEM and REG_EQUIV_ADDRESS contain address that have had replacements done assuming all offsets are at their initial values. If they are not, or if REG_EQUIV_ADDRESS is nonzero for a pseudo we @@ -2389,12 +2544,12 @@ set_label_offsets (rtx x, rtx insn, int initial_p) static rtx eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn, - bool may_use_invariant) + bool may_use_invariant, bool for_costs) { 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; @@ -2433,15 +2588,17 @@ eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn, } else if (reg_renumber && reg_renumber[regno] < 0 - && reg_equiv_invariant && reg_equiv_invariant[regno]) + && reg_equivs + && reg_equiv_invariant (regno)) { - if (may_use_invariant) - return eliminate_regs_1 (copy_rtx (reg_equiv_invariant[regno]), - mem_mode, insn, true); + if (may_use_invariant || (insn && DEBUG_INSN_P (insn))) + return eliminate_regs_1 (copy_rtx (reg_equiv_invariant (regno)), + mem_mode, insn, true, for_costs); /* 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); + reg_equiv_init (regno) = NULL_RTX; + if (!for_costs) + alter_reg (regno, -1, true); } return x; @@ -2478,7 +2635,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 @@ -2502,8 +2659,10 @@ eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn, operand of a load-address insn. */ { - rtx new0 = eliminate_regs_1 (XEXP (x, 0), mem_mode, insn, true); - rtx new1 = eliminate_regs_1 (XEXP (x, 1), mem_mode, insn, true); + rtx new0 = eliminate_regs_1 (XEXP (x, 0), mem_mode, insn, true, + for_costs); + rtx new1 = eliminate_regs_1 (XEXP (x, 1), mem_mode, insn, true, + for_costs); if (reg_renumber && (new0 != XEXP (x, 0) || new1 != XEXP (x, 1))) { @@ -2514,24 +2673,24 @@ eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn, if (GET_CODE (new0) == PLUS && REG_P (new1) && REGNO (new1) >= FIRST_PSEUDO_REGISTER && reg_renumber[REGNO (new1)] < 0 - && reg_equiv_constant != 0 - && reg_equiv_constant[REGNO (new1)] != 0) - new1 = reg_equiv_constant[REGNO (new1)]; + && reg_equivs + && reg_equiv_constant (REGNO (new1)) != 0) + new1 = reg_equiv_constant (REGNO (new1)); else if (GET_CODE (new1) == PLUS && REG_P (new0) && REGNO (new0) >= FIRST_PSEUDO_REGISTER && reg_renumber[REGNO (new0)] < 0 - && reg_equiv_constant[REGNO (new0)] != 0) - new0 = reg_equiv_constant[REGNO (new0)]; + && reg_equiv_constant (REGNO (new0)) != 0) + new0 = reg_equiv_constant (REGNO (new0)); - new = form_sum (new0, new1); + new_rtx = form_sum (GET_MODE (x), 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,15 +2703,17 @@ 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) { if (! mem_mode - /* Refs inside notes don't count for this purpose. */ + /* Refs inside notes or in DEBUG_INSNs don't count for + this purpose. */ && ! (insn != 0 && (GET_CODE (insn) == EXPR_LIST - || GET_CODE (insn) == INSN_LIST))) + || GET_CODE (insn) == INSN_LIST + || DEBUG_INSN_P (insn)))) ep->ref_outside_mem = 1; return @@ -2575,9 +2736,11 @@ eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn, case GE: case GT: case GEU: case GTU: case LE: case LT: case LEU: case LTU: { - rtx new0 = eliminate_regs_1 (XEXP (x, 0), mem_mode, insn, false); + rtx new0 = eliminate_regs_1 (XEXP (x, 0), mem_mode, insn, false, + for_costs); rtx new1 = XEXP (x, 1) - ? eliminate_regs_1 (XEXP (x, 1), mem_mode, insn, false) : 0; + ? eliminate_regs_1 (XEXP (x, 1), mem_mode, insn, false, + for_costs) : 0; if (new0 != XEXP (x, 0) || new1 != XEXP (x, 1)) return gen_rtx_fmt_ee (code, GET_MODE (x), new0, new1); @@ -2588,18 +2751,20 @@ 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, + for_costs); + 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) + ? eliminate_regs_1 (XEXP (x, 1), mem_mode, insn, true, + for_costs) : 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 +2776,11 @@ 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, + for_costs); + 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 +2802,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, - insn, true); + rtx new_rtx = eliminate_regs_1 (XEXP (XEXP (x, 1), 1), mem_mode, + insn, true, for_costs); - 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 +2826,10 @@ 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, + for_costs); + if (new_rtx != XEXP (x, 0)) + return gen_rtx_fmt_e (code, GET_MODE (x), new_rtx); return x; case SUBREG: @@ -2673,22 +2840,21 @@ eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn, eliminated version of the memory location because push_reload may do the replacement in certain circumstances. */ if (REG_P (SUBREG_REG (x)) - && (GET_MODE_SIZE (GET_MODE (x)) - <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))) - && reg_equiv_memory_loc != 0 - && reg_equiv_memory_loc[REGNO (SUBREG_REG (x))] != 0) + && !paradoxical_subreg_p (x) + && reg_equivs + && 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, for_costs); - 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 +2870,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; @@ -2715,20 +2881,29 @@ eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn, /* Our only special processing is to pass the mode of the MEM to our recursive call and copy the flags. While we are here, handle this case more efficiently. */ - return - replace_equiv_address_nv (x, - eliminate_regs_1 (XEXP (x, 0), GET_MODE (x), - insn, true)); + + new_rtx = eliminate_regs_1 (XEXP (x, 0), GET_MODE (x), insn, true, + for_costs); + if (for_costs + && memory_address_p (GET_MODE (x), XEXP (x, 0)) + && !memory_address_p (GET_MODE (x), new_rtx)) + for_each_rtx (&XEXP (x, 0), note_reg_elim_costly, insn); + + return replace_equiv_address_nv (x, new_rtx); 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, + for_costs); + if (new_rtx != XEXP (x, 0)) + return gen_rtx_USE (GET_MODE (x), new_rtx); return x; case CLOBBER: case ASM_OPERANDS: + gcc_assert (insn && DEBUG_INSN_P (insn)); + break; + case SET: gcc_unreachable (); @@ -2743,21 +2918,23 @@ 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, + for_costs); + 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, + for_costs); + if (new_rtx != XVECEXP (x, i, j) && ! copied_vec) { rtvec new_v = gen_rtvec_v (XVECLEN (x, i), XVEC (x, i)->elem); @@ -2769,7 +2946,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; } } } @@ -2780,7 +2957,7 @@ eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn, rtx eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn) { - return eliminate_regs_1 (x, mem_mode, insn, false); + return eliminate_regs_1 (x, mem_mode, insn, false, false); } /* Scan rtx X for modifications of elimination target registers. Update @@ -2830,10 +3007,11 @@ elimination_effects (rtx x, enum machine_mode mem_mode) } } - else if (reg_renumber[regno] < 0 && reg_equiv_constant - && reg_equiv_constant[regno] - && ! function_invariant_p (reg_equiv_constant[regno])) - elimination_effects (reg_equiv_constant[regno], mem_mode); + else if (reg_renumber[regno] < 0 + && reg_equivs != 0 + && reg_equiv_constant (regno) + && ! function_invariant_p (reg_equiv_constant (regno))) + elimination_effects (reg_equiv_constant (regno), mem_mode); return; case PRE_INC: @@ -2901,8 +3079,8 @@ elimination_effects (rtx x, enum machine_mode mem_mode) if (REG_P (SUBREG_REG (x)) && (GET_MODE_SIZE (GET_MODE (x)) <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))) - && reg_equiv_memory_loc != 0 - && reg_equiv_memory_loc[REGNO (SUBREG_REG (x))] != 0) + && reg_equivs != 0 + && reg_equiv_memory_loc (REGNO (SUBREG_REG (x))) != 0) return; elimination_effects (SUBREG_REG (x), mem_mode); @@ -2956,15 +3134,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 +3240,11 @@ 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)); + if (DEBUG_INSN_P (insn)) + INSN_VAR_LOCATION_LOC (insn) + = eliminate_regs (INSN_VAR_LOCATION_LOC (insn), VOIDmode, insn); return 0; } @@ -3073,7 +3255,7 @@ eliminate_regs_in_insn (rtx insn, int replace) for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) if (ep->from_rtx == SET_DEST (old_set) && ep->can_eliminate) { -#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM +#if !HARD_FRAME_POINTER_IS_FRAME_POINTER /* If this is setting the frame pointer register to the hardware frame pointer register and this is an elimination that will be done (tested above), this insn is really @@ -3091,7 +3273,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 +3348,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 +3361,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 +3394,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)), @@ -3239,7 +3421,7 @@ eliminate_regs_in_insn (rtx insn, int replace) /* First see if this insn remains valid when we make the change. If not, try to replace the whole pattern with a simple set (this may help if the original insn was a - PARALLEL that was only recognized as single_set due to + PARALLEL that was only recognized as single_set due to REG_UNUSED notes). If this isn't valid either, keep the INSN_CODE the same and let reload fix it up. */ if (!validate_change (insn, &SET_SRC (old_set), new_src, 0)) @@ -3262,7 +3444,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. */ @@ -3294,7 +3476,8 @@ eliminate_regs_in_insn (rtx insn, int replace) /* Companion to the above plus substitution, we can allow invariants as the source of a plain move. */ is_set_src = false; - if (old_set && recog_data.operand_loc[i] == &SET_SRC (old_set)) + if (old_set + && recog_data.operand_loc[i] == &SET_SRC (old_set)) is_set_src = true; in_plus = false; if (plus_src @@ -3303,9 +3486,9 @@ 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); + is_set_src || in_plus, false); if (substed_operand[i] != orig_operand[i]) val = 1; /* Terminate the search in check_eliminable_occurrences at @@ -3396,7 +3579,10 @@ eliminate_regs_in_insn (rtx insn, int replace) { /* Restore the old body. */ for (i = 0; i < recog_data.n_operands; i++) - *recog_data.operand_loc[i] = orig_operand[i]; + /* Restoring a top-level match_parallel would clobber the new_body + we installed in the insn. */ + if (recog_data.operand_loc[i] != &PATTERN (insn)) + *recog_data.operand_loc[i] = orig_operand[i]; for (i = 0; i < recog_data.n_dups; i++) *recog_data.dup_loc[i] = orig_operand[(int) recog_data.dup_num[i]]; } @@ -3433,11 +3619,167 @@ 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, + false); return val; } +/* Like eliminate_regs_in_insn, but only estimate costs for the use of the + register allocator. INSN is the instruction we need to examine, we perform + eliminations in its operands and record cases where eliminating a reg with + an invariant equivalence would add extra cost. */ + +static void +elimination_costs_in_insn (rtx insn) +{ + int icode = recog_memoized (insn); + rtx old_body = PATTERN (insn); + int insn_is_asm = asm_noperands (old_body) >= 0; + rtx old_set = single_set (insn); + int i; + rtx orig_operand[MAX_RECOG_OPERANDS]; + rtx orig_dup[MAX_RECOG_OPERANDS]; + struct elim_table *ep; + rtx plus_src, plus_cst_src; + bool sets_reg_p; + + if (! insn_is_asm && icode < 0) + { + gcc_assert (GET_CODE (PATTERN (insn)) == USE + || GET_CODE (PATTERN (insn)) == CLOBBER + || GET_CODE (PATTERN (insn)) == ADDR_VEC + || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC + || GET_CODE (PATTERN (insn)) == ASM_INPUT + || DEBUG_INSN_P (insn)); + return; + } + + if (old_set != 0 && REG_P (SET_DEST (old_set)) + && REGNO (SET_DEST (old_set)) < FIRST_PSEUDO_REGISTER) + { + /* Check for setting an eliminable register. */ + for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) + if (ep->from_rtx == SET_DEST (old_set) && ep->can_eliminate) + return; + } + + /* We allow one special case which happens to work on all machines we + currently support: a single set with the source or a REG_EQUAL + note being a PLUS of an eliminable register and a constant. */ + plus_src = plus_cst_src = 0; + sets_reg_p = false; + if (old_set && REG_P (SET_DEST (old_set))) + { + sets_reg_p = true; + if (GET_CODE (SET_SRC (old_set)) == PLUS) + plus_src = SET_SRC (old_set); + /* First see if the source is of the form (plus (...) CST). */ + if (plus_src + && CONST_INT_P (XEXP (plus_src, 1))) + plus_cst_src = plus_src; + else if (REG_P (SET_SRC (old_set)) + || plus_src) + { + /* Otherwise, see if we have a REG_EQUAL note of the form + (plus (...) CST). */ + rtx links; + for (links = REG_NOTES (insn); links; links = XEXP (links, 1)) + { + if ((REG_NOTE_KIND (links) == REG_EQUAL + || REG_NOTE_KIND (links) == REG_EQUIV) + && GET_CODE (XEXP (links, 0)) == PLUS + && CONST_INT_P (XEXP (XEXP (links, 0), 1))) + { + plus_cst_src = XEXP (links, 0); + break; + } + } + } + } + + /* Determine the effects of this insn on elimination offsets. */ + elimination_effects (old_body, VOIDmode); + + /* Eliminate all eliminable registers occurring in operands that + can be handled by reload. */ + extract_insn (insn); + for (i = 0; i < recog_data.n_dups; i++) + orig_dup[i] = *recog_data.dup_loc[i]; + + for (i = 0; i < recog_data.n_operands; i++) + { + orig_operand[i] = recog_data.operand[i]; + + /* For an asm statement, every operand is eliminable. */ + if (insn_is_asm || insn_data[icode].operand[i].eliminable) + { + bool is_set_src, in_plus; + + /* Check for setting a register that we know about. */ + if (recog_data.operand_type[i] != OP_IN + && REG_P (orig_operand[i])) + { + /* If we are assigning to a register that can be eliminated, it + must be as part of a PARALLEL, since the code above handles + single SETs. We must indicate that we can no longer + eliminate this reg. */ + for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; + ep++) + if (ep->from_rtx == orig_operand[i]) + ep->can_eliminate = 0; + } + + /* Companion to the above plus substitution, we can allow + invariants as the source of a plain move. */ + is_set_src = false; + if (old_set && recog_data.operand_loc[i] == &SET_SRC (old_set)) + is_set_src = true; + if (is_set_src && !sets_reg_p) + note_reg_elim_costly (&SET_SRC (old_set), insn); + in_plus = false; + if (plus_src && sets_reg_p + && (recog_data.operand_loc[i] == &XEXP (plus_src, 0) + || recog_data.operand_loc[i] == &XEXP (plus_src, 1))) + in_plus = true; + + eliminate_regs_1 (recog_data.operand[i], VOIDmode, + NULL_RTX, + is_set_src || in_plus, true); + /* Terminate the search in check_eliminable_occurrences at + this point. */ + *recog_data.operand_loc[i] = 0; + } + } + + for (i = 0; i < recog_data.n_dups; i++) + *recog_data.dup_loc[i] + = *recog_data.operand_loc[(int) recog_data.dup_num[i]]; + + /* If any eliminable remain, they aren't eliminable anymore. */ + check_eliminable_occurrences (old_body); + + /* Restore the old body. */ + for (i = 0; i < recog_data.n_operands; i++) + *recog_data.operand_loc[i] = orig_operand[i]; + for (i = 0; i < recog_data.n_dups; i++) + *recog_data.dup_loc[i] = orig_dup[i]; + + /* Update all elimination pairs to reflect the status after the current + insn. The changes we make were determined by the earlier call to + elimination_effects. */ + + for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) + { + if (ep->previous_offset != ep->offset && ep->ref_outside_mem) + ep->can_eliminate = 0; + + ep->ref_outside_mem = 0; + } + + return; +} + /* Loop through all elimination pairs. Recalculate the number not at initial offset. @@ -3491,7 +3833,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 +3956,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 +4006,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 +4041,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 +4056,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 +4065,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; @@ -3751,6 +4089,155 @@ init_elim_table (void) ep->to_rtx = gen_rtx_REG (Pmode, ep->to); } } + +/* Find all the pseudo registers that didn't get hard regs + but do have known equivalent constants or memory slots. + These include parameters (known equivalent to parameter slots) + and cse'd or loop-moved constant memory addresses. + + Record constant equivalents in reg_equiv_constant + so they will be substituted by find_reloads. + Record memory equivalents in reg_mem_equiv so they can + be substituted eventually by altering the REG-rtx's. */ + +static void +init_eliminable_invariants (rtx first, bool do_subregs) +{ + int i; + rtx insn; + + grow_reg_equivs (); + if (do_subregs) + reg_max_ref_width = XCNEWVEC (unsigned int, max_regno); + else + reg_max_ref_width = NULL; + + num_eliminable_invariants = 0; + + first_label_num = get_first_label_num (); + num_labels = max_label_num () - first_label_num; + + /* Allocate the tables used to store offset information at labels. */ + 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)); + +/* Look for REG_EQUIV notes; record what each pseudo is equivalent + to. If DO_SUBREGS is true, also find all paradoxical subregs and + find largest such for each pseudo. FIRST is the head of the insn + list. */ + + for (insn = first; insn; insn = NEXT_INSN (insn)) + { + rtx set = single_set (insn); + + /* We may introduce USEs that we want to remove at the end, so + we'll mark them with QImode. Make sure there are no + previously-marked insns left by say regmove. */ + if (INSN_P (insn) && GET_CODE (PATTERN (insn)) == USE + && GET_MODE (insn) != VOIDmode) + PUT_MODE (insn, VOIDmode); + + if (do_subregs && NONDEBUG_INSN_P (insn)) + scan_paradoxical_subregs (PATTERN (insn)); + + if (set != 0 && REG_P (SET_DEST (set))) + { + rtx note = find_reg_note (insn, REG_EQUIV, NULL_RTX); + rtx x; + + if (! note) + continue; + + i = REGNO (SET_DEST (set)); + x = XEXP (note, 0); + + if (i <= LAST_VIRTUAL_REGISTER) + continue; + + /* If flag_pic and we have constant, verify it's legitimate. */ + if (!CONSTANT_P (x) + || !flag_pic || LEGITIMATE_PIC_OPERAND_P (x)) + { + /* It can happen that a REG_EQUIV note contains a MEM + that is not a legitimate memory operand. As later + stages of reload assume that all addresses found + in the reg_equiv_* arrays were originally legitimate, + we ignore such REG_EQUIV notes. */ + if (memory_operand (x, VOIDmode)) + { + /* Always unshare the equivalence, so we can + substitute into this insn without touching the + equivalence. */ + reg_equiv_memory_loc (i) = copy_rtx (x); + } + else if (function_invariant_p (x)) + { + enum machine_mode mode; + + mode = GET_MODE (SET_DEST (set)); + if (GET_CODE (x) == PLUS) + { + /* This is PLUS of frame pointer and a constant, + and might be shared. Unshare it. */ + reg_equiv_invariant (i) = copy_rtx (x); + num_eliminable_invariants++; + } + else if (x == frame_pointer_rtx || x == arg_pointer_rtx) + { + reg_equiv_invariant (i) = x; + num_eliminable_invariants++; + } + else if (targetm.legitimate_constant_p (mode, x)) + reg_equiv_constant (i) = x; + else + { + reg_equiv_memory_loc (i) = force_const_mem (mode, x); + if (! reg_equiv_memory_loc (i)) + reg_equiv_init (i) = NULL_RTX; + } + } + else + { + reg_equiv_init (i) = NULL_RTX; + continue; + } + } + else + reg_equiv_init (i) = NULL_RTX; + } + } + + if (dump_file) + for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) + if (reg_equiv_init (i)) + { + fprintf (dump_file, "init_insns for %u: ", i); + print_inline_rtx (dump_file, reg_equiv_init (i), 20); + fprintf (dump_file, "\n"); + } +} + +/* Indicate that we no longer have known memory locations or constants. + Free all data involved in tracking these. */ + +static void +free_reg_equiv (void) +{ + int i; + + + free (offsets_known_at); + free (offsets_at); + offsets_at = 0; + offsets_known_at = 0; + + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (reg_equiv_alt_mem_list (i)) + free_EXPR_LIST_list (®_equiv_alt_mem_list (i)); + VEC_free (reg_equivs_t, gc, reg_equivs); + reg_equivs = NULL; + +} /* Kick all pseudos out of hard register REGNO. @@ -3822,22 +4309,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 +4351,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 +4377,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 +4393,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 +4412,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) { @@ -3984,6 +4482,40 @@ scan_paradoxical_subregs (rtx x) } } } + +/* *OP_PTR and *OTHER_PTR are two operands to a conceptual reload. + If *OP_PTR is a paradoxical subreg, try to remove that subreg + and apply the corresponding narrowing subreg to *OTHER_PTR. + Return true if the operands were changed, false otherwise. */ + +static bool +strip_paradoxical_subreg (rtx *op_ptr, rtx *other_ptr) +{ + rtx op, inner, other, tem; + + op = *op_ptr; + if (!paradoxical_subreg_p (op)) + return false; + inner = SUBREG_REG (op); + + other = *other_ptr; + tem = gen_lowpart_common (GET_MODE (inner), other); + if (!tem) + return false; + + /* If the lowpart operation turned a hard register into a subreg, + rather than simplifying it to another hard register, then the + mode change cannot be properly represented. For example, OTHER + might be valid in its current mode, but not in the new one. */ + if (GET_CODE (tem) == SUBREG + && REG_P (other) + && HARD_REGISTER_P (other)) + return false; + + *op_ptr = inner; + *other_ptr = tem; + return true; +} /* A subroutine of reload_as_needed. If INSN has a REG_EH_REGION note, examine all of the reload insns between PREV and NEXT exclusive, and @@ -3993,27 +4525,11 @@ 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; - } - - 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)); - } + if (note == NULL) + return; + if (!insn_could_throw_p (insn)) + remove_note (insn, note); + copy_reg_eh_region_note_forward (note, NEXT_INSN (prev), next); } /* Reload pseudo-registers into hard regs around each insn as needed. @@ -4048,6 +4564,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. */ @@ -4120,12 +4639,6 @@ reload_as_needed (int live_known) Record the choices of reload reg in reload_reg_rtx. */ choose_reload_regs (chain); - /* Merge any reloads that we didn't combine for fear of - increasing the number of spill registers needed but now - discover can be safely merged. */ - if (SMALL_REGISTER_CLASSES) - merge_assigned_reloads (insn); - /* Generate the insns to reload operands into or out of their reload regs. */ emit_reload_insns (chain); @@ -4137,7 +4650,7 @@ reload_as_needed (int live_known) subst_reloads (insn); /* Adjust the exception region notes for loads and stores. */ - if (flag_non_call_exceptions && !CALL_P (insn)) + if (cfun->can_throw_non_call_exceptions && !CALL_P (insn)) fixup_eh_region_note (insn, prev, next); /* If this was an ASM, make sure that all the reload insns @@ -4216,39 +4729,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 +4784,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 +4850,15 @@ 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); + + /* If this is a call to a setjmp-type function, we must not + reuse any reload reg contents across the call; that will + just be clobbered by other uses of the register in later + code, before the longjmp. */ + if (find_reg_note (insn, REG_SETJMP, NULL_RTX)) + CLEAR_HARD_REG_SET (reg_reloaded_valid); } } @@ -4318,7 +4872,7 @@ reload_as_needed (int live_known) unless X is an output reload reg of the current insn. X may be a hard reg (the reload reg) - or it may be a pseudo reg that was reloaded from. + or it may be a pseudo reg that was reloaded from. When DATA is non-NULL just mark the registers in regset to be forgotten later. */ @@ -4456,60 +5010,54 @@ static void mark_reload_reg_in_use (unsigned int regno, int opnum, enum reload_type type, enum machine_mode mode) { - unsigned int nregs = hard_regno_nregs[regno][mode]; - unsigned int i; - - for (i = regno; i < nregs + regno; i++) + switch (type) { - switch (type) - { - case RELOAD_OTHER: - SET_HARD_REG_BIT (reload_reg_used, i); - break; - - case RELOAD_FOR_INPUT_ADDRESS: - SET_HARD_REG_BIT (reload_reg_used_in_input_addr[opnum], i); - break; + case RELOAD_OTHER: + add_to_hard_reg_set (&reload_reg_used, mode, regno); + break; - case RELOAD_FOR_INPADDR_ADDRESS: - SET_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[opnum], i); - break; + case RELOAD_FOR_INPUT_ADDRESS: + add_to_hard_reg_set (&reload_reg_used_in_input_addr[opnum], mode, regno); + break; - case RELOAD_FOR_OUTPUT_ADDRESS: - SET_HARD_REG_BIT (reload_reg_used_in_output_addr[opnum], i); - break; + case RELOAD_FOR_INPADDR_ADDRESS: + add_to_hard_reg_set (&reload_reg_used_in_inpaddr_addr[opnum], mode, regno); + break; - case RELOAD_FOR_OUTADDR_ADDRESS: - SET_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[opnum], i); - break; + case RELOAD_FOR_OUTPUT_ADDRESS: + add_to_hard_reg_set (&reload_reg_used_in_output_addr[opnum], mode, regno); + break; - case RELOAD_FOR_OPERAND_ADDRESS: - SET_HARD_REG_BIT (reload_reg_used_in_op_addr, i); - break; + case RELOAD_FOR_OUTADDR_ADDRESS: + add_to_hard_reg_set (&reload_reg_used_in_outaddr_addr[opnum], mode, regno); + break; - case RELOAD_FOR_OPADDR_ADDR: - SET_HARD_REG_BIT (reload_reg_used_in_op_addr_reload, i); - break; + case RELOAD_FOR_OPERAND_ADDRESS: + add_to_hard_reg_set (&reload_reg_used_in_op_addr, mode, regno); + break; - case RELOAD_FOR_OTHER_ADDRESS: - SET_HARD_REG_BIT (reload_reg_used_in_other_addr, i); - break; + case RELOAD_FOR_OPADDR_ADDR: + add_to_hard_reg_set (&reload_reg_used_in_op_addr_reload, mode, regno); + break; - case RELOAD_FOR_INPUT: - SET_HARD_REG_BIT (reload_reg_used_in_input[opnum], i); - break; + case RELOAD_FOR_OTHER_ADDRESS: + add_to_hard_reg_set (&reload_reg_used_in_other_addr, mode, regno); + break; - case RELOAD_FOR_OUTPUT: - SET_HARD_REG_BIT (reload_reg_used_in_output[opnum], i); - break; + case RELOAD_FOR_INPUT: + add_to_hard_reg_set (&reload_reg_used_in_input[opnum], mode, regno); + break; - case RELOAD_FOR_INSN: - SET_HARD_REG_BIT (reload_reg_used_in_insn, i); - break; - } + case RELOAD_FOR_OUTPUT: + add_to_hard_reg_set (&reload_reg_used_in_output[opnum], mode, regno); + break; - SET_HARD_REG_BIT (reload_reg_used_at_all, i); + case RELOAD_FOR_INSN: + add_to_hard_reg_set (&reload_reg_used_in_insn, mode, regno); + break; } + + add_to_hard_reg_set (&reload_reg_used_at_all, mode, regno); } /* Similarly, but show REGNO is no longer in use for a reload. */ @@ -4975,6 +5523,129 @@ reloads_unique_chain_p (int r1, int r2) return true; } +/* The recursive function change all occurrences of WHAT in *WHERE + to 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)) + { + /* Record the location of the changed rtx. */ + VEC_safe_push (rtx_p, heap, substitute_stack, where); + *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) +{ + /* Assume other cases in gen_reload are not possible for + chain reloads or do need an intermediate hard registers. */ + bool result = true; + int regno, n, code; + rtx out, in, 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 = 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. */ + strip_paradoxical_subreg (&in, &out); + + 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); + } + + /* Restore the original value at each changed address within R1. */ + while (!VEC_empty (rtx_p, substitute_stack)) + { + rtx *where = VEC_pop (rtx_p, substitute_stack); + *where = rld[r2].in; + } + + return result; +} + /* Return 1 if the reloads denoted by R1 and R2 cannot share a register. Return 0 otherwise. @@ -5024,7 +5695,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 @@ -5347,7 +6019,7 @@ function_invariant_p (const_rtx x) return 1; if (GET_CODE (x) == PLUS && (XEXP (x, 0) == frame_pointer_rtx || XEXP (x, 0) == arg_pointer_rtx) - && CONSTANT_P (XEXP (x, 1))) + && GET_CODE (XEXP (x, 1)) == CONST_INT) return 1; return 0; } @@ -5392,7 +6064,9 @@ failed_reload (rtx insn, int r) static int set_reload_reg (int i, int r) { - int regno; + /* regno is 'set but not used' if HARD_REGNO_MODE_OK doesn't use its first + parameter. */ + int regno ATTRIBUTE_UNUSED; rtx reg = spill_reg_rtx[i]; if (reg == 0 || GET_MODE (reg) != rld[r].mode) @@ -5469,15 +6143,17 @@ allocate_reload_reg (struct insn_chain *chain ATTRIBUTE_UNUSED, int r, take any reg in the right class and not in use. If we want a consecutive group, here is where we look for it. - We use two passes so we can first look for reload regs to + We use three passes so we can first look for reload regs to reuse, which are already in use for other reloads in this insn, - and only then use additional registers. + and only then use additional registers which are not "bad", then + finally any register. + I think that maximizing reuse is needed to make sure we don't run out of reload regs. Suppose we have three reloads, and reloads A and B can share regs. These need two regs. Suppose A and B are given different regs. That leaves none for C. */ - for (pass = 0; pass < 2; pass++) + for (pass = 0; pass < 3; pass++) { /* I is the index in spill_regs. We advance it round-robin between insns to use all spill regs @@ -5488,7 +6164,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 +6181,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 @@ -5517,6 +6193,13 @@ allocate_reload_reg (struct insn_chain *chain ATTRIBUTE_UNUSED, int r, regnum)))) { int nr = hard_regno_nregs[regnum][rld[r].mode]; + + /* During the second pass we want to avoid reload registers + which are "bad" for this reload. */ + if (pass == 1 + && ira_bad_reload_regno (regnum, rld[r].in, rld[r].out)) + continue; + /* Avoid the problem where spilling a GENERAL_OR_FP_REG (on 68000) got us two FP regs. If NR is 1, we would reject both of them. */ @@ -5535,7 +6218,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))) @@ -5547,7 +6230,7 @@ allocate_reload_reg (struct insn_chain *chain ATTRIBUTE_UNUSED, int r, } } - /* If we found something on pass 1, omit pass 2. */ + /* If we found something on the current pass, omit later passes. */ if (count < n_spills) break; } @@ -5661,7 +6344,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; @@ -5798,6 +6481,8 @@ choose_reload_regs (struct insn_chain *chain) if (regno >= 0 && reg_last_reload_reg[regno] != 0 + && (GET_MODE_SIZE (GET_MODE (reg_last_reload_reg[regno])) + >= GET_MODE_SIZE (mode) + byte) #ifdef CANNOT_CHANGE_MODE_CLASS /* Verify that the register it's in can be used in mode MODE. */ @@ -5807,39 +6492,28 @@ 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; i = REGNO (last_reg); i += subreg_regno_offset (i, GET_MODE (last_reg), byte, mode); last_class = REGNO_REG_CLASS (i); - if (byte == 0) - need_mode = mode; - else - need_mode - = smallest_mode_for_size (GET_MODE_BITSIZE (mode) - + byte * BITS_PER_UNIT, - GET_MODE_CLASS (mode)); - - if ((GET_MODE_SIZE (GET_MODE (last_reg)) - >= GET_MODE_SIZE (need_mode)) - && reg_reloaded_contents[i] == regno + if (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, true)) + && (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 +6545,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,24 +6627,13 @@ 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. */ - else if (inheritance && rld[r].in == 0 && rld[r].out != 0) - { - rtx set = single_set (insn); - - if (set - && rtx_equal_p (rld[r].out, SET_DEST (set)) - && CONSTANT_P (SET_SRC (set))) - search_equiv = SET_SRC (set); - } 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 +6674,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 +6760,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 +6813,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; } @@ -6314,11 +6978,7 @@ choose_reload_regs (struct insn_chain *chain) nregno + nr); if (i >= 0) - { - nr = hard_regno_nregs[i][rld[r].mode]; - while (--nr >= 0) - SET_HARD_REG_BIT (reg_is_output_reload, i + nr); - } + add_to_hard_reg_set (®_is_output_reload, rld[r].mode, i); gcc_assert (rld[r].when_needed == RELOAD_OTHER || rld[r].when_needed == RELOAD_FOR_OUTPUT @@ -6345,152 +7005,6 @@ deallocate_reload_reg (int r) reload_spill_index[r] = -1; } -/* If SMALL_REGISTER_CLASSES is nonzero, we may not have merged two - reloads of the same item for fear that we might not have enough reload - registers. However, normally they will get the same reload register - and hence actually need not be loaded twice. - - Here we check for the most common case of this phenomenon: when we have - a number of reloads for the same object, each of which were allocated - the same reload_reg_rtx, that reload_reg_rtx is not used for any other - reload, and is not modified in the insn itself. If we find such, - merge all the reloads and set the resulting reload to RELOAD_OTHER. - This will not increase the number of spill registers needed and will - prevent redundant code. */ - -static void -merge_assigned_reloads (rtx insn) -{ - int i, j; - - /* Scan all the reloads looking for ones that only load values and - are not already RELOAD_OTHER and ones whose reload_reg_rtx are - assigned and not modified by INSN. */ - - for (i = 0; i < n_reloads; i++) - { - int conflicting_input = 0; - int max_input_address_opnum = -1; - int min_conflicting_input_opnum = MAX_RECOG_OPERANDS; - - if (rld[i].in == 0 || rld[i].when_needed == RELOAD_OTHER - || rld[i].out != 0 || rld[i].reg_rtx == 0 - || reg_set_p (rld[i].reg_rtx, insn)) - continue; - - /* Look at all other reloads. Ensure that the only use of this - reload_reg_rtx is in a reload that just loads the same value - as we do. Note that any secondary reloads must be of the identical - class since the values, modes, and result registers are the - same, so we need not do anything with any secondary reloads. */ - - for (j = 0; j < n_reloads; j++) - { - if (i == j || rld[j].reg_rtx == 0 - || ! reg_overlap_mentioned_p (rld[j].reg_rtx, - rld[i].reg_rtx)) - continue; - - if (rld[j].when_needed == RELOAD_FOR_INPUT_ADDRESS - && rld[j].opnum > max_input_address_opnum) - max_input_address_opnum = rld[j].opnum; - - /* If the reload regs aren't exactly the same (e.g, different modes) - or if the values are different, we can't merge this reload. - But if it is an input reload, we might still merge - RELOAD_FOR_INPUT_ADDRESS and RELOAD_FOR_OTHER_ADDRESS reloads. */ - - if (! rtx_equal_p (rld[i].reg_rtx, rld[j].reg_rtx) - || rld[j].out != 0 || rld[j].in == 0 - || ! rtx_equal_p (rld[i].in, rld[j].in)) - { - if (rld[j].when_needed != RELOAD_FOR_INPUT - || ((rld[i].when_needed != RELOAD_FOR_INPUT_ADDRESS - || rld[i].opnum > rld[j].opnum) - && rld[i].when_needed != RELOAD_FOR_OTHER_ADDRESS)) - break; - conflicting_input = 1; - if (min_conflicting_input_opnum > rld[j].opnum) - min_conflicting_input_opnum = rld[j].opnum; - } - } - - /* If all is OK, merge the reloads. Only set this to RELOAD_OTHER if - we, in fact, found any matching reloads. */ - - if (j == n_reloads - && max_input_address_opnum <= min_conflicting_input_opnum) - { - gcc_assert (rld[i].when_needed != RELOAD_FOR_OUTPUT); - - for (j = 0; j < n_reloads; j++) - if (i != j && rld[j].reg_rtx != 0 - && rtx_equal_p (rld[i].reg_rtx, rld[j].reg_rtx) - && (! conflicting_input - || rld[j].when_needed == RELOAD_FOR_INPUT_ADDRESS - || rld[j].when_needed == RELOAD_FOR_OTHER_ADDRESS)) - { - rld[i].when_needed = RELOAD_OTHER; - rld[j].in = 0; - reload_spill_index[j] = -1; - transfer_replacements (i, j); - } - - /* If this is now RELOAD_OTHER, look for any reloads that - load parts of this operand and set them to - RELOAD_FOR_OTHER_ADDRESS if they were for inputs, - RELOAD_OTHER for outputs. Note that this test is - equivalent to looking for reloads for this operand - number. - - We must take special care with RELOAD_FOR_OUTPUT_ADDRESS; - it may share registers with a RELOAD_FOR_INPUT, so we can - not change it to RELOAD_FOR_OTHER_ADDRESS. We should - never need to, since we do not modify RELOAD_FOR_OUTPUT. - - It is possible that the RELOAD_FOR_OPERAND_ADDRESS - instruction is assigned the same register as the earlier - RELOAD_FOR_OTHER_ADDRESS instruction. Merging these two - instructions will cause the RELOAD_FOR_OTHER_ADDRESS - instruction to be deleted later on. */ - - if (rld[i].when_needed == RELOAD_OTHER) - for (j = 0; j < n_reloads; j++) - if (rld[j].in != 0 - && rld[j].when_needed != RELOAD_OTHER - && rld[j].when_needed != RELOAD_FOR_OTHER_ADDRESS - && rld[j].when_needed != RELOAD_FOR_OUTPUT_ADDRESS - && rld[j].when_needed != RELOAD_FOR_OPERAND_ADDRESS - && (! conflicting_input - || rld[j].when_needed == RELOAD_FOR_INPUT_ADDRESS - || rld[j].when_needed == RELOAD_FOR_INPADDR_ADDRESS) - && reg_overlap_mentioned_for_reload_p (rld[j].in, - rld[i].in)) - { - int k; - - rld[j].when_needed - = ((rld[j].when_needed == RELOAD_FOR_INPUT_ADDRESS - || rld[j].when_needed == RELOAD_FOR_INPADDR_ADDRESS) - ? RELOAD_FOR_OTHER_ADDRESS : RELOAD_OTHER); - - /* Check to see if we accidentally converted two - reloads that use the same reload register with - different inputs to the same type. If so, the - resulting code won't work. */ - if (rld[j].reg_rtx) - for (k = 0; k < j; k++) - gcc_assert (rld[k].in == 0 || rld[k].reg_rtx == 0 - || rld[k].when_needed != rld[j].when_needed - || !rtx_equal_p (rld[k].reg_rtx, - rld[j].reg_rtx) - || rtx_equal_p (rld[k].in, - rld[j].in)); - } - } - } -} - /* These arrays are filled by emit_reload_insns and its subroutines. */ static rtx input_reload_insns[MAX_RECOG_OPERANDS]; static rtx other_input_address_reload_insns = 0; @@ -6663,22 +7177,12 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl, old = XEXP (rl->in_reg, 0); - if (optimize && REG_P (oldequiv) - && REGNO (oldequiv) < FIRST_PSEUDO_REGISTER - && spill_reg_store[REGNO (oldequiv)] - && REG_P (old) - && (dead_or_set_p (insn, - spill_reg_stored_to[REGNO (oldequiv)]) - || rtx_equal_p (spill_reg_stored_to[REGNO (oldequiv)], - old))) - delete_output_reload (insn, j, REGNO (oldequiv), reloadreg); - /* Prevent normal processing of this reload. */ special = 1; - /* Output a special code sequence for this case. */ - new_spill_reg_store[REGNO (reloadreg)] - = inc_for_reload (reloadreg, oldequiv, rl->out, - rl->inc); + /* Output a special code sequence for this case, and forget about + spill reg information. */ + new_spill_reg_store[REGNO (reloadreg)] = NULL; + inc_for_reload (reloadreg, oldequiv, rl->out, rl->inc); } /* If we are reloading a pseudo-register that was set by the previous @@ -6695,7 +7199,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 +7236,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 { @@ -6785,15 +7299,15 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl, tmp = SUBREG_REG (tmp); if (REG_P (tmp) && REGNO (tmp) >= FIRST_PSEUDO_REGISTER - && (reg_equiv_memory_loc[REGNO (tmp)] != 0 - || reg_equiv_constant[REGNO (tmp)] != 0)) + && (reg_equiv_memory_loc (REGNO (tmp)) != 0 + || reg_equiv_constant (REGNO (tmp)) != 0)) { - if (! reg_equiv_mem[REGNO (tmp)] + if (! reg_equiv_mem (REGNO (tmp)) || num_not_at_initial_offset || GET_CODE (oldequiv) == SUBREG) real_oldequiv = rl->in; else - real_oldequiv = reg_equiv_mem[REGNO (tmp)]; + real_oldequiv = reg_equiv_mem (REGNO (tmp)); } tmp = old; @@ -6801,15 +7315,15 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl, tmp = SUBREG_REG (tmp); if (REG_P (tmp) && REGNO (tmp) >= FIRST_PSEUDO_REGISTER - && (reg_equiv_memory_loc[REGNO (tmp)] != 0 - || reg_equiv_constant[REGNO (tmp)] != 0)) + && (reg_equiv_memory_loc (REGNO (tmp)) != 0 + || reg_equiv_constant (REGNO (tmp)) != 0)) { - if (! reg_equiv_mem[REGNO (tmp)] + if (! reg_equiv_mem (REGNO (tmp)) || num_not_at_initial_offset || GET_CODE (old) == SUBREG) real_old = rl->in; else - real_old = reg_equiv_mem[REGNO (tmp)]; + real_old = reg_equiv_mem (REGNO (tmp)); } second_reload_reg = rld[secondary_reload].reg_rtx; @@ -6832,18 +7346,27 @@ 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, - mode, &sri); + new_class + = (enum reg_class) targetm.secondary_reload (1, real_oldequiv, + rl->rclass, mode, + &sri); if (new_class == NO_REGS && sri.icode == CODE_FOR_nothing) second_reload_reg = 0; 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. */ @@ -6852,16 +7375,24 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl, { sri2.icode = CODE_FOR_nothing; sri2.prev_sri = &sri; - new_t_class = targetm.secondary_reload (1, real_oldequiv, - new_class, mode, &sri); + new_t_class + = (enum reg_class) targetm.secondary_reload (1, real_oldequiv, + new_class, mode, + &sri); if (new_t_class == NO_REGS && sri2.icode == CODE_FOR_nothing) { 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 +7401,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 +7423,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; + } } } @@ -6952,27 +7493,25 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl, if ((REG_P (oldequiv) && REGNO (oldequiv) >= FIRST_PSEUDO_REGISTER - && (reg_equiv_memory_loc[REGNO (oldequiv)] != 0 - || reg_equiv_constant[REGNO (oldequiv)] != 0)) + && (reg_equiv_memory_loc (REGNO (oldequiv)) != 0 + || reg_equiv_constant (REGNO (oldequiv)) != 0)) || (GET_CODE (oldequiv) == SUBREG && REG_P (SUBREG_REG (oldequiv)) && (REGNO (SUBREG_REG (oldequiv)) >= FIRST_PSEUDO_REGISTER) - && ((reg_equiv_memory_loc - [REGNO (SUBREG_REG (oldequiv))] != 0) - || (reg_equiv_constant - [REGNO (SUBREG_REG (oldequiv))] != 0))) + && ((reg_equiv_memory_loc (REGNO (SUBREG_REG (oldequiv))) != 0) + || (reg_equiv_constant (REGNO (SUBREG_REG (oldequiv))) != 0))) || (CONSTANT_P (oldequiv) - && (PREFERRED_RELOAD_CLASS (oldequiv, - REGNO_REG_CLASS (REGNO (reloadreg))) + && (targetm.preferred_reload_class (oldequiv, + REGNO_REG_CLASS (REGNO (reloadreg))) == NO_REGS))) real_oldequiv = rl->in; gen_reload (reloadreg, real_oldequiv, rl->opnum, rl->when_needed); } - if (flag_non_call_exceptions) - copy_eh_notes (insn, get_insns ()); + if (cfun->can_throw_non_call_exceptions) + copy_reg_eh_region_note_forward (insn, get_insns (), NULL); /* End this sequence. */ *where = get_insns (); @@ -7019,10 +7558,10 @@ emit_output_reload_insns (struct insn_chain *chain, struct reload *rl, int tertiary_reload = rld[secondary_reload].secondary_out_reload; if (REG_P (old) && REGNO (old) >= FIRST_PSEUDO_REGISTER - && reg_equiv_mem[REGNO (old)] != 0) - real_old = reg_equiv_mem[REGNO (old)]; + && 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; @@ -7056,7 +7595,6 @@ emit_output_reload_insns (struct insn_chain *chain, struct reload *rl, if (tertiary_icode != CODE_FOR_nothing) { rtx third_reloadreg = rld[tertiary_reload].reg_rtx; - rtx tem; /* Copy primary reload reg to secondary reload reg. (Note that these have been swapped above, then @@ -7065,13 +7603,7 @@ emit_output_reload_insns (struct insn_chain *chain, struct reload *rl, /* If REAL_OLD is a paradoxical SUBREG, remove it and try to put the opposite SUBREG on RELOADREG. */ - if (GET_CODE (real_old) == SUBREG - && (GET_MODE_SIZE (GET_MODE (real_old)) - > GET_MODE_SIZE (GET_MODE (SUBREG_REG (real_old)))) - && 0 != (tem = gen_lowpart_common - (GET_MODE (SUBREG_REG (real_old)), - reloadreg))) - real_old = SUBREG_REG (real_old), reloadreg = tem; + strip_paradoxical_subreg (&real_old, &reloadreg); gen_reload (reloadreg, second_reloadreg, rl->opnum, rl->when_needed); @@ -7191,8 +7723,8 @@ emit_output_reload_insns (struct insn_chain *chain, struct reload *rl, else output_reload_insns[rl->opnum] = get_insns (); - if (flag_non_call_exceptions) - copy_eh_notes (insn, get_insns ()); + if (cfun->can_throw_non_call_exceptions) + copy_reg_eh_region_note_forward (insn, get_insns (), NULL); end_sequence (); } @@ -7560,10 +8092,22 @@ emit_reload_insns (struct insn_chain *chain) /* Maybe the spill reg contains a copy of reload_out. */ if (rld[r].out != 0 && (REG_P (rld[r].out) -#ifdef AUTO_INC_DEC - || ! rld[r].out_reg -#endif - || REG_P (rld[r].out_reg))) + || (rld[r].out_reg + ? REG_P (rld[r].out_reg) + /* The reload value is an auto-modification of + some kind. For PRE_INC, POST_INC, PRE_DEC + and POST_DEC, we record an equivalence + between the reload register and the operand + on the optimistic assumption that we can make + the equivalence hold. reload_as_needed must + then either make it hold or invalidate the + equivalence. + + PRE_MODIFY and POST_MODIFY addresses are reloaded + somewhat differently, and allowing them here leads + to problems. */ + : (GET_CODE (rld[r].out) != POST_MODIFY + && GET_CODE (rld[r].out) != PRE_MODIFY)))) { rtx reg; enum machine_mode mode; @@ -7804,7 +8348,7 @@ emit_reload_insns (struct insn_chain *chain) SET_HARD_REG_BIT (reg_reloaded_valid, src_regno + k); if (HARD_REGNO_CALL_PART_CLOBBERED (src_regno + k, mode)) - SET_HARD_REG_BIT (reg_reloaded_call_part_clobbered, + SET_HARD_REG_BIT (reg_reloaded_call_part_clobbered, src_regno + k); else CLEAR_HARD_REG_BIT (reg_reloaded_call_part_clobbered, @@ -7816,7 +8360,7 @@ emit_reload_insns (struct insn_chain *chain) CLEAR_HARD_REG_BIT (reg_reloaded_died, src_regno); } reg_last_reload_reg[out_regno] = src_reg; - /* We have to set reg_has_output_reload here, or else + /* We have to set reg_has_output_reload here, or else forget_old_reloads_1 will clear reg_last_reload_reg right away. */ SET_REGNO_REG_SET (®_has_output_reload, @@ -7875,16 +8419,8 @@ gen_reload (rtx out, rtx in, int opnum, enum reload_type type) /* 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; - else if (GET_CODE (out) == SUBREG - && (GET_MODE_SIZE (GET_MODE (out)) - > GET_MODE_SIZE (GET_MODE (SUBREG_REG (out)))) - && (tem = gen_lowpart_common (GET_MODE (SUBREG_REG (out)), in)) != 0) - out = SUBREG_REG (out), in = tem; + if (!strip_paradoxical_subreg (&in, &out)) + strip_paradoxical_subreg (&out, &in); /* How to do this reload can get quite tricky. Normally, we are being asked to reload a simple operand, such as a MEM, a constant, or a pseudo @@ -7941,7 +8477,7 @@ gen_reload (rtx out, rtx in, int opnum, enum reload_type type) not valid than to dummy things up. */ rtx op0, op1, tem, insn; - int code; + enum insn_code code; op0 = find_replacement (&XEXP (in, 0)); op1 = find_replacement (&XEXP (in, 1)); @@ -7979,14 +8515,13 @@ gen_reload (rtx out, rtx in, int opnum, enum reload_type type) DEFINE_PEEPHOLE should be specified that recognizes the sequence we emit below. */ - code = (int) optab_handler (add_optab, GET_MODE (out))->insn_code; + code = optab_handler (add_optab, GET_MODE (out)); if (CONSTANT_P (op1) || MEM_P (op1) || GET_CODE (op1) == SUBREG || (REG_P (op1) && REGNO (op1) >= FIRST_PSEUDO_REGISTER) || (code != CODE_FOR_nothing - && ! ((*insn_data[code].operand[2].predicate) - (op1, insn_data[code].operand[2].mode)))) + && !insn_operand_matches (code, 2, op1))) tem = op0, op0 = op1, op1 = tem; gen_reload (out, op0, opnum, type); @@ -8017,9 +8552,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)), @@ -8076,7 +8613,7 @@ gen_reload (rtx out, rtx in, int opnum, enum reload_type type) return insn; } - fatal_insn ("Failure trying to reload:", set); + fatal_insn ("failure trying to reload:", set); } /* If IN is a simple operand, use gen_move_insn. */ else if (OBJECT_P (in) || GET_CODE (in) == SUBREG) @@ -8124,6 +8661,8 @@ delete_output_reload (rtx insn, int j, int last_reload_reg, rtx new_reload_reg) int n_inherited = 0; rtx i1; rtx substed; + unsigned regno; + int nregs; /* It is possible that this reload has been only used to set another reload we eliminated earlier and thus deleted this instruction too. */ @@ -8134,7 +8673,7 @@ delete_output_reload (rtx insn, int j, int last_reload_reg, rtx new_reload_reg) while (GET_CODE (reg) == SUBREG) reg = SUBREG_REG (reg); - substed = reg_equiv_memory_loc[REGNO (reg)]; + substed = reg_equiv_memory_loc (REGNO (reg)); /* This is unsafe if the operand occurs more often in the current insn than it is inherited. */ @@ -8165,9 +8704,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); @@ -8175,6 +8714,12 @@ delete_output_reload (rtx insn, int j, int last_reload_reg, rtx new_reload_reg) if (n_occurrences > n_inherited) return; + regno = REGNO (reg); + if (regno >= FIRST_PSEUDO_REGISTER) + nregs = 1; + else + nregs = hard_regno_nregs[regno][GET_MODE (reg)]; + /* If the pseudo-reg we are reloading is no longer referenced anywhere between the store into it and here, and we're within the same basic block, then the value can only @@ -8186,7 +8731,7 @@ delete_output_reload (rtx insn, int j, int last_reload_reg, rtx new_reload_reg) if (NOTE_INSN_BASIC_BLOCK_P (i1)) return; if ((NONJUMP_INSN_P (i1) || CALL_P (i1)) - && reg_mentioned_p (reg, PATTERN (i1))) + && refers_to_regno_p (regno, regno + nregs, PATTERN (i1), NULL)) { /* If this is USE in front of INSN, we only have to check that there are no more references than accounted for by inheritance. */ @@ -8268,7 +8813,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 +8849,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)) @@ -8430,11 +8978,9 @@ delete_address_reloads_1 (rtx dead_insn, rtx x, rtx current_insn) IN is either identical to VALUE, or some cheaper place to reload from. INC_AMOUNT is the number to increment or decrement by (always positive). - This cannot be deduced from VALUE. + This cannot be deduced from VALUE. */ - Return the instruction that stores into RELOADREG. */ - -static rtx +static void inc_for_reload (rtx reloadreg, rtx in, rtx value, int inc_amount) { /* REG or MEM to be copied and incremented. */ @@ -8446,7 +8992,6 @@ inc_for_reload (rtx reloadreg, rtx in, rtx value, int inc_amount) rtx inc; rtx add_insn; int code; - rtx store; rtx real_in = in == value ? incloc : in; /* No hard register is equivalent to this register after @@ -8495,8 +9040,7 @@ inc_for_reload (rtx reloadreg, rtx in, rtx value, int inc_amount) if (! post) emit_insn (gen_move_insn (reloadreg, incloc)); - - return add_insn; + return; } } delete_insns_since (last); @@ -8512,7 +9056,7 @@ inc_for_reload (rtx reloadreg, rtx in, rtx value, int inc_amount) if (in != reloadreg) emit_insn (gen_move_insn (reloadreg, real_in)); emit_insn (gen_add2_insn (reloadreg, inc)); - store = emit_insn (gen_move_insn (incloc, reloadreg)); + emit_insn (gen_move_insn (incloc, reloadreg)); } else { @@ -8526,14 +9070,12 @@ inc_for_reload (rtx reloadreg, rtx in, rtx value, int inc_amount) the original value. */ emit_insn (gen_add2_insn (reloadreg, inc)); - store = emit_insn (gen_move_insn (incloc, reloadreg)); - if (GET_CODE (inc) == CONST_INT) + emit_insn (gen_move_insn (incloc, reloadreg)); + if (CONST_INT_P (inc)) emit_insn (gen_add2_insn (reloadreg, GEN_INT (-INTVAL (inc)))); else emit_insn (gen_sub2_insn (reloadreg, inc)); } - - return store; } #ifdef AUTO_INC_DEC @@ -8546,8 +9088,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; } @@ -8563,131 +9104,3 @@ add_auto_inc_notes (rtx insn, rtx x) } } #endif - -/* Copy EH notes from an insn to its reloads. */ -static void -copy_eh_notes (rtx insn, rtx x) -{ - rtx eh_note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); - if (eh_note) - { - 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)); - } - } -} - -/* This is used by reload pass, that does emit some instructions after - abnormal calls moving basic block end, but in fact it wants to emit - them on the edge. Looks for abnormal call edges, find backward the - proper call and fix the damage. - - Similar handle instructions throwing exceptions internally. */ -void -fixup_abnormal_edges (void) -{ - bool inserted = false; - basic_block bb; - - FOR_EACH_BB (bb) - { - edge e; - edge_iterator ei; - - /* Look for cases we are interested in - calls or instructions causing - exceptions. */ - FOR_EACH_EDGE (e, ei, bb->succs) - { - if (e->flags & EDGE_ABNORMAL_CALL) - break; - if ((e->flags & (EDGE_ABNORMAL | EDGE_EH)) - == (EDGE_ABNORMAL | EDGE_EH)) - break; - } - if (e && !CALL_P (BB_END (bb)) - && !can_throw_internal (BB_END (bb))) - { - rtx insn; - - /* Get past the new insns generated. Allow notes, as the insns - may be already deleted. */ - insn = BB_END (bb); - while ((NONJUMP_INSN_P (insn) || NOTE_P (insn)) - && !can_throw_internal (insn) - && insn != BB_HEAD (bb)) - insn = PREV_INSN (insn); - - if (CALL_P (insn) || can_throw_internal (insn)) - { - rtx stop, next; - - stop = NEXT_INSN (BB_END (bb)); - BB_END (bb) = insn; - insn = NEXT_INSN (insn); - - FOR_EACH_EDGE (e, ei, bb->succs) - if (e->flags & EDGE_FALLTHRU) - break; - - while (insn && insn != stop) - { - next = NEXT_INSN (insn); - if (INSN_P (insn)) - { - delete_insn (insn); - - /* Sometimes there's still the return value USE. - If it's placed after a trapping call (i.e. that - call is the last insn anyway), we have no fallthru - edge. Simply delete this use and don't try to insert - on the non-existent edge. */ - if (GET_CODE (PATTERN (insn)) != USE) - { - /* We're not deleting it, we're moving it. */ - INSN_DELETED_P (insn) = 0; - PREV_INSN (insn) = NULL_RTX; - NEXT_INSN (insn) = NULL_RTX; - - insert_insn_on_edge (insn, e); - inserted = true; - } - } - else if (!BARRIER_P (insn)) - set_block_for_insn (insn, NULL); - insn = next; - } - } - - /* It may be that we don't find any such trapping insn. In this - case we discovered quite late that the insn that had been - marked as can_throw_internal in fact couldn't trap at all. - So we should in fact delete the EH edges out of the block. */ - else - purge_dead_edges (bb); - } - } - - /* We've possibly turned single trapping insn into multiple ones. */ - if (flag_non_call_exceptions) - { - sbitmap blocks; - blocks = sbitmap_alloc (last_basic_block); - sbitmap_ones (blocks); - find_many_sub_basic_blocks (blocks); - sbitmap_free (blocks); - } - - if (inserted) - commit_edge_insertions (); - -#ifdef ENABLE_CHECKING - /* Verify that we didn't turn one trapping insn into many, and that - we found and corrected all of the problems wrt fixups on the - fallthru edge. */ - verify_flow_info (); -#endif -}