| /* 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, 2008, 2009 |
| Free Software Foundation, Inc. |
| |
| This file is part of GCC. |
| |
| GCC is free software; you can redistribute it and/or modify it under |
| the terms of the GNU General Public License as published by the Free |
| Software Foundation; either version 3, or (at your option) any later |
| version. |
| |
| GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
| WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| #include "config.h" |
| #include "system.h" |
| #include "coretypes.h" |
| #include "tm.h" |
| |
| #include "machmode.h" |
| #include "hard-reg-set.h" |
| #include "rtl.h" |
| #include "tm_p.h" |
| #include "obstack.h" |
| #include "insn-config.h" |
| #include "flags.h" |
| #include "function.h" |
| #include "expr.h" |
| #include "optabs.h" |
| #include "regs.h" |
| #include "addresses.h" |
| #include "basic-block.h" |
| #include "reload.h" |
| #include "recog.h" |
| #include "output.h" |
| #include "real.h" |
| #include "toplev.h" |
| #include "except.h" |
| #include "tree.h" |
| #include "ira.h" |
| #include "df.h" |
| #include "target.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 |
| each insn is valid (operands required to be in registers really |
| are in registers of the proper class) and fixes up invalid ones |
| by copying values temporarily into registers for the insns |
| that need them. |
| |
| The results of register allocation are described by the vector |
| reg_renumber; the insns still contain pseudo regs, but reg_renumber |
| can be used to find which hard reg, if any, a pseudo reg is in. |
| |
| The technique we always use is to free up a few hard regs that are |
| called ``reload regs'', and for each place where a pseudo reg |
| must be in a hard reg, copy it temporarily into one of the reload regs. |
| |
| Reload regs are allocated locally for every instruction that needs |
| reloads. When there are pseudos which are allocated to a register that |
| has been chosen as a reload reg, such pseudos must be ``spilled''. |
| This means that they go to other hard regs, or to stack slots if no other |
| available hard regs can be found. Spilling can invalidate more |
| insns, requiring additional need for reloads, so we must keep checking |
| until the process stabilizes. |
| |
| For machines with different classes of registers, we must keep track |
| of the register class needed for each reload, and make sure that |
| we allocate enough reload registers of each class. |
| |
| The file reload.c contains the code that checks one insn for |
| validity and reports the reloads that it needs. This file |
| is in charge of scanning the entire rtl code, accumulating the |
| reload needs, spilling, assigning reload registers to use for |
| fixing up each insn, and generating the new insns to copy values |
| into the reload registers. */ |
| |
| /* 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; |
| |
| /* Elt N nonzero if reg_last_reload_reg[N] has been set in this insn |
| for an output reload that stores into reg N. */ |
| static regset_head reg_has_output_reload; |
| |
| /* Indicates which hard regs are reload-registers for an 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; |
| |
| /* During reload_as_needed, element N contains the last pseudo regno reloaded |
| into hard register N. If that pseudo reg occupied more than one register, |
| reg_reloaded_contents points to that pseudo for each spill register in |
| use; all of these must remain set for an inheritance to occur. */ |
| static int reg_reloaded_contents[FIRST_PSEUDO_REGISTER]; |
| |
| /* During reload_as_needed, element N contains the insn for which |
| hard register N was last used. Its contents are significant only |
| when reg_reloaded_valid is set for this register. */ |
| static rtx reg_reloaded_insn[FIRST_PSEUDO_REGISTER]; |
| |
| /* Indicate if reg_reloaded_insn / reg_reloaded_contents is valid. */ |
| static HARD_REG_SET reg_reloaded_valid; |
| /* Indicate if the register was dead at the end of the reload. |
| This is only valid if reg_reloaded_contents is set and valid. */ |
| static HARD_REG_SET reg_reloaded_dead; |
| |
| /* Indicate whether the register's current value is one that is not |
| safe to retain across a call, even for registers that are normally |
| call-saved. This is only meaningful for members of reg_reloaded_valid. */ |
| static HARD_REG_SET reg_reloaded_call_part_clobbered; |
| |
| /* Number of spill-regs so far; number of valid elements of spill_regs. */ |
| static int n_spills; |
| |
| /* In parallel with spill_regs, contains REG rtx's for those regs. |
| Holds the last rtx used for any given reg, or 0 if it has never |
| been used for spilling yet. This rtx is reused, provided it has |
| the proper mode. */ |
| static rtx spill_reg_rtx[FIRST_PSEUDO_REGISTER]; |
| |
| /* In parallel with spill_regs, contains nonzero for a spill reg |
| that was stored after the last time it was used. |
| The precise value is the insn generated to do the store. */ |
| static rtx spill_reg_store[FIRST_PSEUDO_REGISTER]; |
| |
| /* This is the register that was stored with spill_reg_store. This is a |
| copy of reload_out / reload_out_reg when the value was stored; if |
| reload_out is a MEM, spill_reg_stored_to will be set to reload_out_reg. */ |
| static rtx spill_reg_stored_to[FIRST_PSEUDO_REGISTER]; |
| |
| /* This table is the inverse mapping of spill_regs: |
| indexed by hard reg number, |
| it contains the position of that reg in spill_regs, |
| or -1 for something that is not in spill_regs. |
| |
| ?!? This is no longer accurate. */ |
| static short spill_reg_order[FIRST_PSEUDO_REGISTER]; |
| |
| /* This reg set indicates registers that can't be used as spill registers for |
| the currently processed insn. These are the hard registers which are live |
| during the insn, but not allocated to pseudos, as well as fixed |
| registers. */ |
| static HARD_REG_SET bad_spill_regs; |
| |
| /* These are the hard registers that can't be used as spill register for any |
| insn. This includes registers used for user variables and registers that |
| we can't eliminate. A register that appears in this set also can't be used |
| to retry register allocation. */ |
| static HARD_REG_SET bad_spill_regs_global; |
| |
| /* Describes order of use of registers for reloading |
| of spilled pseudo-registers. `n_spills' is the number of |
| elements that are actually valid; new ones are added at the end. |
| |
| Both spill_regs and spill_reg_order are used on two occasions: |
| once during find_reload_regs, where they keep track of the spill registers |
| for a single insn, but also during reload_as_needed where they show all |
| the registers ever used by reload. For the latter case, the information |
| is calculated during finish_spills. */ |
| static short spill_regs[FIRST_PSEUDO_REGISTER]; |
| |
| /* This vector of reg sets indicates, for each pseudo, which hard registers |
| may not be used for retrying global allocation because the register was |
| formerly spilled from one of them. If we allowed reallocating a pseudo to |
| a register that it was already allocated to, reload might not |
| terminate. */ |
| static HARD_REG_SET *pseudo_previous_regs; |
| |
| /* This vector of reg sets indicates, for each pseudo, which hard |
| registers may not be used for retrying global allocation because they |
| are used as spill registers during one of the insns in which the |
| pseudo is live. */ |
| static HARD_REG_SET *pseudo_forbidden_regs; |
| |
| /* All hard regs that have been used as spill registers for any insn are |
| marked in this set. */ |
| static HARD_REG_SET used_spill_regs; |
| |
| /* Index of last register assigned as a spill register. We allocate in |
| 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]; |
| |
| /* Width allocated so far for that stack slot. */ |
| 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; |
| |
| /* First uid used by insns created by reload in this function. |
| Used in find_equiv_reg. */ |
| int reload_first_uid; |
| |
| /* Flag set by local-alloc or global-alloc if anything is live in |
| a call-clobbered reg across calls. */ |
| int caller_save_needed; |
| |
| /* Set to 1 while reload_as_needed is operating. |
| 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. */ |
| static struct obstack reload_obstack; |
| |
| /* Points to the beginning of the reload_obstack. All insn_chain structures |
| are allocated first. */ |
| static char *reload_startobj; |
| |
| /* The point after all insn_chain structures. Used to quickly deallocate |
| memory allocated in copy_reloads during calculate_needs_all_insns. */ |
| static char *reload_firstobj; |
| |
| /* This points before all local rtl generated by register elimination. |
| Used to quickly free all memory after processing one insn. */ |
| static char *reload_insn_firstobj; |
| |
| /* List of insn_chain instructions, one for every insn that reload needs to |
| examine. */ |
| struct insn_chain *reload_insn_chain; |
| |
| /* List of all insns needing reloads. */ |
| static struct insn_chain *insns_need_reload; |
| |
| /* This structure is used to record information about register eliminations. |
| Each array entry describes one possible way of eliminating a register |
| in favor of another. If there is more than one way of eliminating a |
| particular register, the most preferred should be specified first. */ |
| |
| struct elim_table |
| { |
| int from; /* Register number to be eliminated. */ |
| 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. */ |
| 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. */ |
| rtx from_rtx; /* REG rtx for the register to be eliminated. |
| We cannot simply compare the number since |
| we might then spuriously replace a hard |
| register corresponding to a pseudo |
| assigned to the reg to be eliminated. */ |
| rtx to_rtx; /* REG rtx for the replacement. */ |
| }; |
| |
| static struct elim_table *reg_eliminate = 0; |
| |
| /* This is an intermediate structure to initialize the table. It has |
| exactly the members provided by ELIMINABLE_REGS. */ |
| static const struct elim_table_1 |
| { |
| const int from; |
| const int to; |
| } reg_eliminate_1[] = |
| |
| /* If a set of eliminable registers was specified, define the table from it. |
| Otherwise, default to the normal case of the frame pointer being |
| replaced by the stack pointer. */ |
| |
| #ifdef ELIMINABLE_REGS |
| ELIMINABLE_REGS; |
| #else |
| {{ FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}}; |
| #endif |
| |
| #define NUM_ELIMINABLE_REGS ARRAY_SIZE (reg_eliminate_1) |
| |
| /* Record the number of pending eliminations that have an offset not equal |
| to their initial offset. If nonzero, we use a new copy of each |
| replacement result in any insns encountered. */ |
| int num_not_at_initial_offset; |
| |
| /* Count the number of registers that we may be able to eliminate. */ |
| static int num_eliminable; |
| /* And the number of registers that are equivalent to a constant that |
| can be eliminated to frame_pointer / arg_pointer + constant. */ |
| static int num_eliminable_invariants; |
| |
| /* For each label, we record the offset of each elimination. If we reach |
| a label by more than one path and an offset differs, we cannot do the |
| elimination. This information is indexed by the difference of the |
| number of the label and the first label number. We can't offset the |
| pointer itself as this can cause problems on machines with segmented |
| memory. The first table is an array of flags that records whether we |
| have yet encountered a label and the second table is an array of arrays, |
| one entry in the latter array for each elimination. */ |
| |
| static int first_label_num; |
| static char *offsets_known_at; |
| static HOST_WIDE_INT (*offsets_at)[NUM_ELIMINABLE_REGS]; |
| |
| /* Number of labels in the current function. */ |
| |
| static int num_labels; |
| |
| static void replace_pseudos_in (rtx *, enum machine_mode, rtx); |
| static void maybe_fix_stack_asms (void); |
| static void copy_reloads (struct insn_chain *); |
| static void calculate_needs_all_insns (int); |
| static int find_reg (struct insn_chain *, int); |
| static void find_reload_regs (struct insn_chain *); |
| static void select_reload_regs (void); |
| 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, bool); |
| static void set_label_offsets (rtx, rtx, int); |
| static void check_eliminable_occurrences (rtx); |
| static void elimination_effects (rtx, enum machine_mode); |
| static int eliminate_regs_in_insn (rtx, int); |
| static void update_eliminable_offsets (void); |
| static void mark_not_eliminable (rtx, const_rtx, void *); |
| 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_elim_table (void); |
| static void update_eliminables (HARD_REG_SET *); |
| static void spill_hard_reg (unsigned int, int); |
| static int finish_spills (int); |
| static void scan_paradoxical_subregs (rtx); |
| static void count_pseudo (int); |
| static void order_regs_for_reload (struct insn_chain *); |
| static void reload_as_needed (int); |
| static void forget_old_reloads_1 (rtx, const_rtx, void *); |
| static void forget_marked_reloads (regset); |
| static int reload_reg_class_lower (const void *, const void *); |
| static void mark_reload_reg_in_use (unsigned int, int, enum reload_type, |
| enum machine_mode); |
| static void clear_reload_reg_in_use (unsigned int, int, enum reload_type, |
| enum machine_mode); |
| static int reload_reg_free_p (unsigned int, int, enum reload_type); |
| static int reload_reg_free_for_value_p (int, int, int, enum reload_type, |
| rtx, rtx, int, int); |
| static int free_for_value_p (int, enum machine_mode, int, enum reload_type, |
| rtx, rtx, int, int); |
| static int reload_reg_reaches_end_p (unsigned int, int, enum reload_type); |
| static int allocate_reload_reg (struct insn_chain *, int, int); |
| static int conflicts_with_override (rtx); |
| 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 *, |
| int); |
| static void do_input_reload (struct insn_chain *, struct reload *, int); |
| static void do_output_reload (struct insn_chain *, struct reload *, int); |
| 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); |
| #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); |
| |
| /* Initialize the reload pass. This is called at the beginning of compilation |
| and may be called again if the target is reinitialized. */ |
| |
| void |
| init_reload (void) |
| { |
| int i; |
| |
| /* Often (MEM (REG n)) is still valid even if (REG n) is put on the stack. |
| Set spill_indirect_levels to the number of levels such addressing is |
| permitted, zero if it is not permitted at all. */ |
| |
| rtx tem |
| = gen_rtx_MEM (Pmode, |
| gen_rtx_PLUS (Pmode, |
| gen_rtx_REG (Pmode, |
| LAST_VIRTUAL_REGISTER + 1), |
| GEN_INT (4))); |
| spill_indirect_levels = 0; |
| |
| while (memory_address_p (QImode, tem)) |
| { |
| spill_indirect_levels++; |
| tem = gen_rtx_MEM (Pmode, tem); |
| } |
| |
| /* See if indirect addressing is valid for (MEM (SYMBOL_REF ...)). */ |
| |
| tem = gen_rtx_MEM (Pmode, gen_rtx_SYMBOL_REF (Pmode, "foo")); |
| indirect_symref_ok = memory_address_p (QImode, tem); |
| |
| /* See if reg+reg is a valid (and offsettable) address. */ |
| |
| for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) |
| { |
| tem = gen_rtx_PLUS (Pmode, |
| gen_rtx_REG (Pmode, HARD_FRAME_POINTER_REGNUM), |
| gen_rtx_REG (Pmode, i)); |
| |
| /* This way, we make sure that reg+reg is an offsettable address. */ |
| tem = plus_constant (tem, 4); |
| |
| if (memory_address_p (QImode, tem)) |
| { |
| double_reg_address_ok = 1; |
| break; |
| } |
| } |
| |
| /* Initialize obstack for our rtl allocation. */ |
| gcc_obstack_init (&reload_obstack); |
| reload_startobj = XOBNEWVAR (&reload_obstack, char, 0); |
| |
| INIT_REG_SET (&spilled_pseudos); |
| INIT_REG_SET (&changed_allocation_pseudos); |
| INIT_REG_SET (&pseudos_counted); |
| } |
| |
| /* List of insn chains that are currently unused. */ |
| static struct insn_chain *unused_insn_chains = 0; |
| |
| /* Allocate an empty insn_chain structure. */ |
| struct insn_chain * |
| new_insn_chain (void) |
| { |
| struct insn_chain *c; |
| |
| if (unused_insn_chains == 0) |
| { |
| c = XOBNEW (&reload_obstack, struct insn_chain); |
| INIT_REG_SET (&c->live_throughout); |
| INIT_REG_SET (&c->dead_or_set); |
| } |
| else |
| { |
| c = unused_insn_chains; |
| unused_insn_chains = c->next; |
| } |
| c->is_caller_save_insn = 0; |
| c->need_operand_change = 0; |
| c->need_reload = 0; |
| c->need_elim = 0; |
| return c; |
| } |
| |
| /* Small utility function to set all regs in hard reg set TO which are |
| allocated to pseudos in regset FROM. */ |
| |
| void |
| compute_use_by_pseudos (HARD_REG_SET *to, regset from) |
| { |
| unsigned int regno; |
| reg_set_iterator rsi; |
| |
| EXECUTE_IF_SET_IN_REG_SET (from, FIRST_PSEUDO_REGISTER, regno, rsi) |
| { |
| int r = reg_renumber[regno]; |
| |
| if (r < 0) |
| { |
| /* 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); |
| } |
| } |
| |
| /* Replace all pseudos found in LOC with their corresponding |
| equivalences. */ |
| |
| static void |
| replace_pseudos_in (rtx *loc, enum machine_mode mem_mode, rtx usage) |
| { |
| rtx x = *loc; |
| enum rtx_code code; |
| const char *fmt; |
| int i, j; |
| |
| if (! x) |
| return; |
| |
| code = GET_CODE (x); |
| if (code == REG) |
| { |
| unsigned int regno = REGNO (x); |
| |
| if (regno < FIRST_PSEUDO_REGISTER) |
| return; |
| |
| x = eliminate_regs (x, mem_mode, usage); |
| if (x != *loc) |
| { |
| *loc = x; |
| replace_pseudos_in (loc, mem_mode, 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]); |
| else |
| { |
| gcc_assert (!REG_P (regno_reg_rtx[regno]) |
| || REGNO (regno_reg_rtx[regno]) != regno); |
| *loc = regno_reg_rtx[regno]; |
| } |
| |
| return; |
| } |
| else if (code == MEM) |
| { |
| replace_pseudos_in (& XEXP (x, 0), GET_MODE (x), usage); |
| return; |
| } |
| |
| /* Process each of our operands recursively. */ |
| fmt = GET_RTX_FORMAT (code); |
| for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++) |
| if (*fmt == 'e') |
| replace_pseudos_in (&XEXP (x, i), mem_mode, usage); |
| else if (*fmt == 'E') |
| for (j = 0; j < XVECLEN (x, i); j++) |
| replace_pseudos_in (& XVECEXP (x, i, j), mem_mode, usage); |
| } |
| |
| /* Determine if the current function has an exception receiver block |
| that reaches the exit block via non-exceptional edges */ |
| |
| static bool |
| has_nonexceptional_receiver (void) |
| { |
| edge e; |
| edge_iterator ei; |
| basic_block *tos, *worklist, bb; |
| |
| /* 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); |
| |
| FOR_EACH_BB (bb) |
| bb->flags &= ~BB_REACHABLE; |
| |
| /* 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) |
| { |
| bb = *--tos; |
| |
| FOR_EACH_EDGE (e, ei, bb->preds) |
| if (!(e->flags & EDGE_ABNORMAL)) |
| { |
| basic_block src = e->src; |
| |
| if (!(src->flags & BB_REACHABLE)) |
| { |
| src->flags |= BB_REACHABLE; |
| *tos++ = src; |
| } |
| } |
| } |
| free (worklist); |
| |
| /* 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; |
| |
| /* No exceptional block reached exit unexceptionally. */ |
| return false; |
| } |
| |
| |
| /* Global variables used by reload and its subroutines. */ |
| |
| /* 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; |
| |
| /* 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. |
| |
| GLOBAL nonzero means we were called from global_alloc |
| and should attempt to reallocate any pseudoregs that we |
| displace from hard regs we will use for reloads. |
| 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. */ |
| |
| int |
| reload (rtx first, int global) |
| { |
| int i, n; |
| rtx insn; |
| struct elim_table *ep; |
| basic_block bb; |
| |
| /* Make sure even insns with volatile mem refs are recognizable. */ |
| init_recog (); |
| |
| failure = 0; |
| |
| reload_firstobj = XOBNEWVAR (&reload_obstack, char, 0); |
| |
| /* Make sure that the last insn in the chain |
| is not something that needs reloading. */ |
| emit_note (NOTE_INSN_DELETED); |
| |
| /* Enable find_equiv_reg to distinguish insns made by reload. */ |
| reload_first_uid = get_max_uid (); |
| |
| #ifdef SECONDARY_MEMORY_NEEDED |
| /* Initialize the secondary memory table. */ |
| clear_secondary_mem (); |
| #endif |
| |
| /* We don't have a stack slot for any spill reg yet. */ |
| memset (spill_stack_slot, 0, sizeof spill_stack_slot); |
| memset (spill_stack_slot_width, 0, sizeof spill_stack_slot_width); |
| |
| /* Initialize the save area information for caller-save, in case some |
| are needed. */ |
| init_save_areas (); |
| |
| /* Compute which hard registers are now in use |
| as homes for pseudo registers. |
| This is done here rather than (eg) in global_alloc |
| because this point is reached even if not optimizing. */ |
| for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) |
| mark_home_live (i); |
| |
| /* A function that has a nonlocal label that can reach the exit |
| block via non-exceptional paths must save all call-saved |
| registers. */ |
| if (cfun->has_nonlocal_label |
| && has_nonexceptional_receiver ()) |
| crtl->saves_all_registers = 1; |
| |
| if (crtl->saves_all_registers) |
| for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) |
| if (! call_used_regs[i] && ! fixed_regs[i] && ! LOCAL_REGNO (i)) |
| df_set_regs_ever_live (i, true); |
| |
| /* 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. */ |
| |
| 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); |
| 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)); |
| pseudo_forbidden_regs = XNEWVEC (HARD_REG_SET, max_regno); |
| pseudo_previous_regs = XCNEWVEC (HARD_REG_SET, max_regno); |
| |
| 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_elim_table (); |
| |
| 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. */ |
| /* 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)); |
| |
| /* 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. */ |
| |
| temp_pseudo_reg_arr = XNEWVEC (int, max_regno - LAST_VIRTUAL_REGISTER - 1); |
| for (n = 0, i = LAST_VIRTUAL_REGISTER + 1; i < max_regno; i++) |
| temp_pseudo_reg_arr[n++] = i; |
| |
| if (ira_conflicts_p) |
| /* Ask IRA to order pseudo-registers for better stack slot |
| sharing. */ |
| ira_sort_regnos_for_alter_reg (temp_pseudo_reg_arr, n, reg_max_ref_width); |
| |
| for (i = 0; i < n; i++) |
| alter_reg (temp_pseudo_reg_arr[i], -1, false); |
| |
| /* If we have some registers we think can be eliminated, scan all insns to |
| see if there is an insn that sets one of these registers to something |
| other than itself plus a constant. If so, the register cannot be |
| eliminated. Doing this scan here eliminates an extra pass through the |
| main reload loop in the most common case where register elimination |
| cannot be done. */ |
| for (insn = first; insn && num_eliminable; insn = NEXT_INSN (insn)) |
| if (INSN_P (insn)) |
| note_stores (PATTERN (insn), mark_not_eliminable, NULL); |
| |
| maybe_fix_stack_asms (); |
| |
| insns_need_reload = 0; |
| something_needs_elimination = 0; |
| |
| /* Initialize to -1, which means take the first spill register. */ |
| last_spill_reg = -1; |
| |
| /* Spill any hard regs that we know we can't eliminate. */ |
| CLEAR_HARD_REG_SET (used_spill_regs); |
| /* There can be multiple ways to eliminate a register; |
| they should be listed adjacently. |
| Elimination for any register fails only if all possible ways fail. */ |
| for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ) |
| { |
| int from = ep->from; |
| int can_eliminate = 0; |
| do |
| { |
| can_eliminate |= ep->can_eliminate; |
| ep++; |
| } |
| while (ep < ®_eliminate[NUM_ELIMINABLE_REGS] && ep->from == from); |
| if (! can_eliminate) |
| spill_hard_reg (from, 1); |
| } |
| |
| #if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM |
| if (frame_pointer_needed) |
| spill_hard_reg (HARD_FRAME_POINTER_REGNUM, 1); |
| #endif |
| finish_spills (global); |
| |
| /* From now on, we may need to generate moves differently. We may also |
| allow modifications of insns which cause them to not be recognized. |
| Any such modifications will be cleaned up during reload itself. */ |
| reload_in_progress = 1; |
| |
| /* This loop scans the entire function each go-round |
| and repeats until one repetition spills no additional hard regs. */ |
| for (;;) |
| { |
| int something_changed; |
| int did_spill; |
| HOST_WIDE_INT starting_frame_size; |
| |
| starting_frame_size = get_frame_size (); |
| |
| set_initial_elim_offsets (); |
| set_initial_label_offsets (); |
| |
| /* For each pseudo register that has an equivalent location defined, |
| try to eliminate any eliminable registers (such as the frame pointer) |
| assuming initial offsets for the replacement register, which |
| is the normal case. |
| |
| If the resulting location is directly addressable, substitute |
| the MEM we just got directly for the old REG. |
| |
| If it is not addressable but is a constant or the sum of a hard reg |
| and constant, it is probably not addressable because the constant is |
| out of range, in that case record the address; we will generate |
| hairy code to compute the address in a register each time it is |
| needed. Similarly if it is a hard register, but one that is not |
| valid as an address register. |
| |
| If the location is not addressable, but does not have one of the |
| above forms, assign a stack slot. We have to do this to avoid the |
| potential of producing lots of reloads if, e.g., a location involves |
| a pseudo that didn't get a hard register and has an equivalent memory |
| location that also involves a pseudo that didn't get a hard register. |
| |
| Perhaps at some point we will improve reload_when_needed handling |
| 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]) |
| { |
| rtx x = eliminate_regs (reg_equiv_memory_loc[i], 0, 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; |
| else if (CONSTANT_P (XEXP (x, 0)) |
| || (REG_P (XEXP (x, 0)) |
| && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER) |
| || (GET_CODE (XEXP (x, 0)) == PLUS |
| && REG_P (XEXP (XEXP (x, 0), 0)) |
| && (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; |
| else |
| { |
| /* Make a new stack slot. Then indicate that something |
| changed so we go back and recompute offsets for |
| eliminable registers because the allocation of memory |
| 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, true); |
| } |
| } |
| |
| if (caller_save_needed) |
| setup_save_areas (); |
| |
| /* If we allocated another stack slot, redo elimination bookkeeping. */ |
| if (starting_frame_size != get_frame_size ()) |
| continue; |
| if (starting_frame_size && crtl->stack_alignment_needed) |
| { |
| /* If we have a stack frame, we must align it now. The |
| stack size may be a part of the offset computation for |
| register elimination. So if this changes the stack size, |
| then repeat the elimination bookkeeping. We don't |
| realign when there is no stack, as that will cause a |
| stack frame when none is needed should |
| STARTING_FRAME_OFFSET not be already aligned to |
| STACK_BOUNDARY. */ |
| assign_stack_local (BLKmode, 0, crtl->stack_alignment_needed); |
| if (starting_frame_size != get_frame_size ()) |
| continue; |
| } |
| |
| if (caller_save_needed) |
| { |
| save_call_clobbered_regs (); |
| /* That might have allocated new insn_chain structures. */ |
| reload_firstobj = XOBNEWVAR (&reload_obstack, char, 0); |
| } |
| |
| calculate_needs_all_insns (global); |
| |
| 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 ()) |
| something_changed = 1; |
| |
| /* Even if the frame size remained the same, we might still have |
| 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 ()) |
| something_changed = 1; |
| |
| { |
| HARD_REG_SET to_spill; |
| CLEAR_HARD_REG_SET (to_spill); |
| update_eliminables (&to_spill); |
| AND_COMPL_HARD_REG_SET (used_spill_regs, to_spill); |
| |
| for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) |
| if (TEST_HARD_REG_BIT (to_spill, i)) |
| { |
| spill_hard_reg (i, 1); |
| did_spill = 1; |
| |
| /* Regardless of the state of spills, if we previously had |
| a register that we thought we could eliminate, but now can |
| not eliminate, we must run another pass. |
| |
| Consider pseudos which have an entry in reg_equiv_* which |
| reference an eliminable register. We must make another pass |
| to update reg_equiv_* so that we do not substitute in the |
| old value from when we thought the elimination could be |
| performed. */ |
| something_changed = 1; |
| } |
| } |
| |
| select_reload_regs (); |
| if (failure) |
| goto failed; |
| |
| if (insns_need_reload != 0 || did_spill) |
| something_changed |= finish_spills (global); |
| |
| if (! something_changed) |
| break; |
| |
| if (caller_save_needed) |
| delete_caller_save_insns (); |
| |
| obstack_free (&reload_obstack, reload_firstobj); |
| } |
| |
| /* If global-alloc was run, notify it of any register eliminations we have |
| done. */ |
| if (global) |
| for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) |
| if (ep->can_eliminate) |
| mark_elimination (ep->from, ep->to); |
| |
| /* If a pseudo has no hard reg, delete the insns that made the equivalence. |
| If that insn didn't set the register (i.e., it copied the register to |
| memory), just delete that insn instead of the equivalencing insn plus |
| anything now dead. If we call delete_dead_insn on that insn, we may |
| delete the insn that actually sets the register if the register dies |
| there and that is incorrect. */ |
| |
| for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) |
| { |
| if (reg_renumber[i] < 0 && reg_equiv_init[i] != 0) |
| { |
| rtx list; |
| for (list = reg_equiv_init[i]; list; list = XEXP (list, 1)) |
| { |
| rtx equiv_insn = XEXP (list, 0); |
| |
| /* If we already deleted the insn or if it may trap, we can't |
| delete it. The latter case shouldn't happen, but can |
| if an insn has a variable address, gets a REG_EH_REGION |
| note added to it, and then gets converted into a load |
| from a constant address. */ |
| if (NOTE_P (equiv_insn) |
| || can_throw_internal (equiv_insn)) |
| ; |
| else if (reg_set_p (regno_reg_rtx[i], PATTERN (equiv_insn))) |
| delete_dead_insn (equiv_insn); |
| else |
| SET_INSN_DELETED (equiv_insn); |
| } |
| } |
| } |
| |
| /* Use the reload registers where necessary |
| by generating move instructions to move the must-be-register |
| values into or out of the reload registers. */ |
| |
| if (insns_need_reload != 0 || something_needs_elimination |
| || something_needs_operands_changed) |
| { |
| HOST_WIDE_INT old_frame_size = get_frame_size (); |
| |
| reload_as_needed (global); |
| |
| gcc_assert (old_frame_size == get_frame_size ()); |
| |
| gcc_assert (verify_initial_elim_offsets ()); |
| } |
| |
| /* If we were able to eliminate the frame pointer, show that it is no |
| longer live at the start of any basic block. If it ls live by |
| virtue of being in a pseudo, that pseudo will be marked live |
| and hence the frame pointer will be known to be live via that |
| pseudo. */ |
| |
| 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; |
| |
| /* Now eliminate all pseudo regs by modifying them into |
| their equivalent memory references. |
| The REG-rtx's for the pseudos are modified in place, |
| so all insns that used to refer to them now refer to memory. |
| |
| For a reg that has a reg_equiv_address, all those insns |
| were changed by reloading so that no insns refer to it any longer; |
| but the DECL_RTL of a variable decl may refer to it, |
| and if so this causes the debugging info to mention the variable. */ |
| |
| for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) |
| { |
| rtx addr = 0; |
| |
| if (reg_equiv_mem[i]) |
| addr = XEXP (reg_equiv_mem[i], 0); |
| |
| if (reg_equiv_address[i]) |
| addr = reg_equiv_address[i]; |
| |
| if (addr) |
| { |
| if (reg_renumber[i] < 0) |
| { |
| rtx reg = regno_reg_rtx[i]; |
| |
| 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]); |
| else |
| { |
| MEM_IN_STRUCT_P (reg) = MEM_SCALAR_P (reg) = 0; |
| MEM_ATTRS (reg) = 0; |
| } |
| MEM_NOTRAP_P (reg) = 1; |
| } |
| else if (reg_equiv_mem[i]) |
| XEXP (reg_equiv_mem[i], 0) = addr; |
| } |
| } |
| |
| /* We must set reload_completed now since the cleanup_subreg_operands call |
| below will re-recognize each insn and reload may have generated insns |
| which are only valid during and after reload. */ |
| reload_completed = 1; |
| |
| /* Make a pass over all the insns and delete all USEs which we inserted |
| only to tag a REG_EQUAL note on them. Remove all REG_DEAD and REG_UNUSED |
| notes. Delete all CLOBBER insns, except those that refer to the return |
| value and the special mem:BLK CLOBBERs added to prevent the scheduler |
| from misarranging variable-array code, and simplify (subreg (reg)) |
| operands. Strip and regenerate REG_INC notes that may have been moved |
| around. */ |
| |
| for (insn = first; insn; insn = NEXT_INSN (insn)) |
| if (INSN_P (insn)) |
| { |
| rtx *pnote; |
| |
| if (CALL_P (insn)) |
| replace_pseudos_in (& CALL_INSN_FUNCTION_USAGE (insn), |
| VOIDmode, CALL_INSN_FUNCTION_USAGE (insn)); |
| |
| if ((GET_CODE (PATTERN (insn)) == USE |
| /* We mark with QImode USEs introduced by reload itself. */ |
| && (GET_MODE (insn) == QImode |
| || find_reg_note (insn, REG_EQUAL, NULL_RTX))) |
| || (GET_CODE (PATTERN (insn)) == CLOBBER |
| && (!MEM_P (XEXP (PATTERN (insn), 0)) |
| || GET_MODE (XEXP (PATTERN (insn), 0)) != BLKmode |
| || (GET_CODE (XEXP (XEXP (PATTERN (insn), 0), 0)) != SCRATCH |
| && XEXP (XEXP (PATTERN (insn), 0), 0) |
| != stack_pointer_rtx)) |
| && (!REG_P (XEXP (PATTERN (insn), 0)) |
| || ! REG_FUNCTION_VALUE_P (XEXP (PATTERN (insn), 0))))) |
| { |
| delete_insn (insn); |
| continue; |
| } |
| |
| /* Some CLOBBERs may survive until here and still reference unassigned |
| pseudos with const equivalent, which may in turn cause ICE in later |
| passes if the reference remains in place. */ |
| if (GET_CODE (PATTERN (insn)) == CLOBBER) |
| replace_pseudos_in (& XEXP (PATTERN (insn), 0), |
| VOIDmode, PATTERN (insn)); |
| |
| /* Discard obvious no-ops, even without -O. This optimization |
| is fast and doesn't interfere with debugging. */ |
| if (NONJUMP_INSN_P (insn) |
| && GET_CODE (PATTERN (insn)) == SET |
| && REG_P (SET_SRC (PATTERN (insn))) |
| && REG_P (SET_DEST (PATTERN (insn))) |
| && (REGNO (SET_SRC (PATTERN (insn))) |
| == REGNO (SET_DEST (PATTERN (insn))))) |
| { |
| delete_insn (insn); |
| continue; |
| } |
| |
| pnote = ®_NOTES (insn); |
| while (*pnote != 0) |
| { |
| if (REG_NOTE_KIND (*pnote) == REG_DEAD |
| || REG_NOTE_KIND (*pnote) == REG_UNUSED |
| || REG_NOTE_KIND (*pnote) == REG_INC) |
| *pnote = XEXP (*pnote, 1); |
| else |
| pnote = &XEXP (*pnote, 1); |
| } |
| |
| #ifdef AUTO_INC_DEC |
| add_auto_inc_notes (insn, PATTERN (insn)); |
| #endif |
| |
| /* Simplify (subreg (reg)) if it appears as an operand. */ |
| cleanup_subreg_operands (insn); |
| |
| /* Clean up invalid ASMs so that they don't confuse later passes. |
| See PR 21299. */ |
| if (asm_noperands (PATTERN (insn)) >= 0) |
| { |
| extract_insn (insn); |
| if (!constrain_operands (1)) |
| { |
| error_for_asm (insn, |
| "%<asm%> operand has impossible constraints"); |
| delete_insn (insn); |
| continue; |
| } |
| } |
| } |
| |
| /* 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; |
| |
| for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) |
| if (df_regs_ever_live_p (i) && ! fixed_regs[i] && call_used_regs[i]) |
| size += UNITS_PER_WORD; |
| |
| if (size > STACK_CHECK_MAX_FRAME_SIZE) |
| { |
| warning (0, "frame size too large for reliable stack checking"); |
| if (! verbose_warned) |
| { |
| warning (0, "try reducing the number of local variables"); |
| verbose_warned = 1; |
| } |
| } |
| } |
| |
| /* 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; |
| |
| free (temp_pseudo_reg_arr); |
| |
| if (offsets_known_at) |
| free (offsets_known_at); |
| if (offsets_at) |
| free (offsets_at); |
| |
| 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); |
| |
| 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); |
| free (pseudo_forbidden_regs); |
| |
| CLEAR_HARD_REG_SET (used_spill_regs); |
| for (i = 0; i < n_spills; i++) |
| SET_HARD_REG_BIT (used_spill_regs, spill_regs[i]); |
| |
| /* Free all the insn_chain structures at once. */ |
| obstack_free (&reload_obstack, reload_startobj); |
| unused_insn_chains = 0; |
| fixup_abnormal_edges (); |
| |
| /* Replacing pseudos with their memory equivalents might have |
| created shared rtx. Subsequent passes would get confused |
| by this, so unshare everything here. */ |
| unshare_all_rtl_again (first); |
| |
| #ifdef STACK_BOUNDARY |
| /* init_emit has set the alignment of the hard frame pointer |
| to STACK_BOUNDARY. It is very likely no longer valid if |
| the hard frame pointer was used for register allocation. */ |
| if (!frame_pointer_needed) |
| REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM) = BITS_PER_UNIT; |
| #endif |
| |
| return failure; |
| } |
| |
| /* Yet another special case. Unfortunately, reg-stack forces people to |
| write incorrect clobbers in asm statements. These clobbers must not |
| cause the register to appear in bad_spill_regs, otherwise we'll call |
| fatal_insn later. We clear the corresponding regnos in the live |
| register sets to avoid this. |
| The whole thing is rather sick, I'm afraid. */ |
| |
| static void |
| maybe_fix_stack_asms (void) |
| { |
| #ifdef STACK_REGS |
| const char *constraints[MAX_RECOG_OPERANDS]; |
| enum machine_mode operand_mode[MAX_RECOG_OPERANDS]; |
| struct insn_chain *chain; |
| |
| for (chain = reload_insn_chain; chain != 0; chain = chain->next) |
| { |
| int i, noperands; |
| HARD_REG_SET clobbered, allowed; |
| rtx pat; |
| |
| if (! INSN_P (chain->insn) |
| || (noperands = asm_noperands (PATTERN (chain->insn))) < 0) |
| continue; |
| pat = PATTERN (chain->insn); |
| if (GET_CODE (pat) != PARALLEL) |
| continue; |
| |
| CLEAR_HARD_REG_SET (clobbered); |
| CLEAR_HARD_REG_SET (allowed); |
| |
| /* First, make a mask of all stack regs that are clobbered. */ |
| for (i = 0; i < XVECLEN (pat, 0); i++) |
| { |
| rtx t = XVECEXP (pat, 0, i); |
| if (GET_CODE (t) == CLOBBER && STACK_REG_P (XEXP (t, 0))) |
| SET_HARD_REG_BIT (clobbered, REGNO (XEXP (t, 0))); |
| } |
| |
| /* Get the operand values and constraints out of the insn. */ |
| decode_asm_operands (pat, recog_data.operand, recog_data.operand_loc, |
| constraints, operand_mode, NULL); |
| |
| /* For every operand, see what registers are allowed. */ |
| for (i = 0; i < noperands; i++) |
| { |
| const char *p = constraints[i]; |
| /* For every alternative, we compute the class of registers allowed |
| for reloading in CLS, and merge its contents into the reg set |
| ALLOWED. */ |
| int cls = (int) NO_REGS; |
| |
| for (;;) |
| { |
| char c = *p; |
| |
| if (c == '\0' || c == ',' || c == '#') |
| { |
| /* End of one alternative - mark the regs in the current |
| class, and reset the class. */ |
| IOR_HARD_REG_SET (allowed, reg_class_contents[cls]); |
| cls = NO_REGS; |
| p++; |
| if (c == '#') |
| do { |
| c = *p++; |
| } while (c != '\0' && c != ','); |
| if (c == '\0') |
| break; |
| continue; |
| } |
| |
| switch (c) |
| { |
| case '=': case '+': case '*': case '%': case '?': case '!': |
| case '0': case '1': case '2': case '3': case '4': case '<': |
| case '>': case 'V': case 'o': case '&': case 'E': case 'F': |
| case 's': case 'i': case 'n': case 'X': case 'I': case 'J': |
| case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': |
| case TARGET_MEM_CONSTRAINT: |
| break; |
| |
| case 'p': |
| cls = (int) reg_class_subunion[cls] |
| [(int) base_reg_class (VOIDmode, ADDRESS, SCRATCH)]; |
| break; |
| |
| case 'g': |
| case 'r': |
| cls = (int) reg_class_subunion[cls][(int) GENERAL_REGS]; |
| break; |
| |
| default: |
| if (EXTRA_ADDRESS_CONSTRAINT (c, p)) |
| cls = (int) reg_class_subunion[cls] |
| [(int) base_reg_class (VOIDmode, ADDRESS, SCRATCH)]; |
| else |
| cls = (int) reg_class_subunion[cls] |
| [(int) REG_CLASS_FROM_CONSTRAINT (c, p)]; |
| } |
| p += CONSTRAINT_LEN (c, p); |
| } |
| } |
| /* Those of the registers which are clobbered, but allowed by the |
| constraints, must be usable as reload registers. So clear them |
| out of the life information. */ |
| AND_HARD_REG_SET (allowed, clobbered); |
| for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) |
| if (TEST_HARD_REG_BIT (allowed, i)) |
| { |
| CLEAR_REGNO_REG_SET (&chain->live_throughout, i); |
| CLEAR_REGNO_REG_SET (&chain->dead_or_set, i); |
| } |
| } |
| |
| #endif |
| } |
| |
| /* Copy the global variables n_reloads and rld into the corresponding elts |
| of CHAIN. */ |
| static void |
| copy_reloads (struct insn_chain *chain) |
| { |
| chain->n_reloads = n_reloads; |
| chain->rld = XOBNEWVEC (&reload_obstack, struct reload, n_reloads); |
| memcpy (chain->rld, rld, n_reloads * sizeof (struct reload)); |
| reload_insn_firstobj = XOBNEWVAR (&reload_obstack, char, 0); |
| } |
| |
| /* Walk the chain of insns, and determine for each whether it needs reloads |
| and/or eliminations. Build the corresponding insns_need_reload list, and |
| set something_needs_elimination as appropriate. */ |
| static void |
| calculate_needs_all_insns (int global) |
| { |
| struct insn_chain **pprev_reload = &insns_need_reload; |
| struct insn_chain *chain, *next = 0; |
| |
| something_needs_elimination = 0; |
| |
| reload_insn_firstobj = XOBNEWVAR (&reload_obstack, char, 0); |
| for (chain = reload_insn_chain; chain != 0; chain = next) |
| { |
| rtx insn = chain->insn; |
| |
| next = chain->next; |
| |
| /* Clear out the shortcuts. */ |
| chain->n_reloads = 0; |
| chain->need_elim = 0; |
| chain->need_reload = 0; |
| chain->need_operand_change = 0; |
| |
| /* 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 old_body = PATTERN (insn); |
| int old_code = INSN_CODE (insn); |
| rtx old_notes = REG_NOTES (insn); |
| int did_elimination = 0; |
| int operands_changed = 0; |
| 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))])) |
| && reg_equiv_init[REGNO (SET_DEST (set))]) |
| continue; |
| |
| /* If needed, eliminate any eliminable registers. */ |
| if (num_eliminable || num_eliminable_invariants) |
| did_elimination = eliminate_regs_in_insn (insn, 0); |
| |
| /* Analyze the instruction. */ |
| operands_changed = find_reloads (insn, 0, spill_indirect_levels, |
| global, spill_reg_order); |
| |
| /* If a no-op set needs more than one reload, this is likely |
| to be something that needs input address reloads. We |
| can't get rid of this cleanly later, and it is of no use |
| anyway, so discard it now. |
| We only do this when expensive_optimizations is enabled, |
| since this complements reload inheritance / output |
| reload deletion, and it can make debugging harder. */ |
| if (flag_expensive_optimizations && n_reloads > 1) |
| { |
| 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) |
| || (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) |
| chain->prev->next = next; |
| else |
| reload_insn_chain = next; |
| if (next) |
| next->prev = chain->prev; |
| chain->next = unused_insn_chains; |
| unused_insn_chains = chain; |
| continue; |
| } |
| } |
| if (num_eliminable) |
| update_eliminable_offsets (); |
| |
| /* Remember for later shortcuts which insns had any reloads or |
| register eliminations. */ |
| chain->need_elim = did_elimination; |
| chain->need_reload = n_reloads > 0; |
| chain->need_operand_change = operands_changed; |
| |
| /* Discard any register replacements done. */ |
| if (did_elimination) |
| { |
| obstack_free (&reload_obstack, reload_insn_firstobj); |
| PATTERN (insn) = old_body; |
| INSN_CODE (insn) = old_code; |
| REG_NOTES (insn) = old_notes; |
| something_needs_elimination = 1; |
| } |
| |
| something_needs_operands_changed |= operands_changed; |
| |
| if (n_reloads != 0) |
| { |
| copy_reloads (chain); |
| *pprev_reload = chain; |
| pprev_reload = &chain->next_need_reload; |
| } |
| } |
| } |
| *pprev_reload = 0; |
| } |
| |
| /* Comparison function for qsort to decide which of two reloads |
| should be handled first. *P1 and *P2 are the reload numbers. */ |
| |
| static int |
| reload_reg_class_lower (const void *r1p, const void *r2p) |
| { |
| int r1 = *(const short *) r1p, r2 = *(const short *) r2p; |
| int t; |
| |
| /* Consider required reloads before optional ones. */ |
| t = rld[r1].optional - rld[r2].optional; |
| if (t != 0) |
| return t; |
| |
| /* Count all solitary classes before non-solitary ones. */ |
| t = ((reg_class_size[(int) rld[r2].rclass] == 1) |
| - (reg_class_size[(int) rld[r1].rclass] == 1)); |
| if (t != 0) |
| return t; |
| |
| /* Aside from solitaires, consider all multi-reg groups first. */ |
| t = rld[r2].nregs - rld[r1].nregs; |
| if (t != 0) |
| return t; |
| |
| /* Consider reloads in order of increasing reg-class number. */ |
| t = (int) rld[r1].rclass - (int) rld[r2].rclass; |
| if (t != 0) |
| return t; |
| |
| /* If reloads are equally urgent, sort by reload number, |
| so that the results of qsort leave nothing to chance. */ |
| return r1 - r2; |
| } |
| |
| /* The cost of spilling each hard reg. */ |
| static int spill_cost[FIRST_PSEUDO_REGISTER]; |
| |
| /* When spilling multiple hard registers, we use SPILL_COST for the first |
| spilled hard reg and SPILL_ADD_COST for subsequent regs. SPILL_ADD_COST |
| 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 |
| count_pseudo (int reg) |
| { |
| int freq = REG_FREQ (reg); |
| int r = reg_renumber[reg]; |
| int nregs; |
| |
| if (REGNO_REG_SET_P (&pseudos_counted, 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); |
| |
| gcc_assert (r >= 0); |
| |
| spill_add_cost[r] += freq; |
| nregs = hard_regno_nregs[r][PSEUDO_REGNO_MODE (reg)]; |
| while (nregs-- > 0) |
| { |
| 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 |
| contents of BAD_SPILL_REGS for the insn described by CHAIN. */ |
| |
| static void |
| order_regs_for_reload (struct insn_chain *chain) |
| { |
| unsigned i; |
| HARD_REG_SET used_by_pseudos; |
| HARD_REG_SET used_by_pseudos2; |
| reg_set_iterator rsi; |
| |
| COPY_HARD_REG_SET (bad_spill_regs, fixed_reg_set); |
| |
| 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 |
| that are live in or across this insn. */ |
| |
| REG_SET_TO_HARD_REG_SET (used_by_pseudos, &chain->live_throughout); |
| REG_SET_TO_HARD_REG_SET (used_by_pseudos2, &chain->dead_or_set); |
| IOR_HARD_REG_SET (bad_spill_regs, used_by_pseudos); |
| IOR_HARD_REG_SET (bad_spill_regs, used_by_pseudos2); |
| |
| /* Now find out which pseudos are allocated to it, and update |
| hard_reg_n_uses. */ |
| CLEAR_REG_SET (&pseudos_counted); |
| |
| EXECUTE_IF_SET_IN_REG_SET |
| (&chain->live_throughout, FIRST_PSEUDO_REGISTER, i, rsi) |
| { |
| count_pseudo (i); |
| } |
| EXECUTE_IF_SET_IN_REG_SET |
| (&chain->dead_or_set, FIRST_PSEUDO_REGISTER, i, rsi) |
| { |
| count_pseudo (i); |
| } |
| CLEAR_REG_SET (&pseudos_counted); |
| } |
| |
| /* Vector of reload-numbers showing the order in which the reloads should |
| be processed. */ |
| static short reload_order[MAX_RELOADS]; |
| |
| /* This is used to keep track of the spill regs used in one insn. */ |
| static HARD_REG_SET used_spill_regs_local; |
| |
| /* We decided to spill hard register SPILLED, which has a size of |
| SPILLED_NREGS. Determine how pseudo REG, which is live during the insn, |
| is affected. We will add it to SPILLED_PSEUDOS if necessary, and we will |
| update SPILL_COST/SPILL_ADD_COST. */ |
| |
| 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)]; |
| |
| /* 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] -= freq; |
| while (nregs-- > 0) |
| { |
| hard_regno_to_pseudo_regno[r + nregs] = -1; |
| spill_cost[r + nregs] -= freq; |
| } |
| } |
| |
| /* Find reload register to use for reload number ORDER. */ |
| |
| static int |
| find_reg (struct insn_chain *chain, int order) |
| { |
| int rnum = reload_order[order]; |
| struct reload *rl = rld + rnum; |
| int best_cost = INT_MAX; |
| int best_reg = -1; |
| 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->rclass]); |
| |
| CLEAR_HARD_REG_SET (used_by_other_reload); |
| for (k = 0; k < order; k++) |
| { |
| int other = reload_order[k]; |
| |
| if (rld[other].regno >= 0 && reloads_conflict (other, rnum)) |
| for (j = 0; j < rld[other].nregs; j++) |
| SET_HARD_REG_BIT (used_by_other_reload, rld[other].regno + j); |
| } |
| |
| 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) |
| && HARD_REGNO_MODE_OK (regno, rl->mode)) |
| { |
| int this_cost = spill_cost[regno]; |
| int ok = 1; |
| unsigned int this_nregs = hard_regno_nregs[regno][rl->mode]; |
| |
| for (j = 1; j < this_nregs; j++) |
| { |
| this_cost += spill_add_cost[regno + j]; |
| if ((TEST_HARD_REG_BIT (not_usable, regno + j)) |
| || TEST_HARD_REG_BIT (used_by_other_reload, regno + j)) |
| ok = 0; |
| } |
| 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) |
| this_cost--; |
| if (this_cost < best_cost |
| /* Among registers with equal cost, prefer caller-saved ones, or |
| use REG_ALLOC_ORDER if it is defined. */ |
| || (this_cost == best_cost |
| #ifdef REG_ALLOC_ORDER |
| && (inv_reg_alloc_order[regno] |
| < inv_reg_alloc_order[best_reg]) |
| #else |
| && call_used_regs[regno] |
| && ! call_used_regs[best_reg] |
| #endif |
| )) |
| { |
| best_reg = regno; |
| best_cost = this_cost; |
| } |
| } |
| } |
| if (best_reg == -1) |
| return 0; |
| |
| if (dump_file) |
| fprintf (dump_file, "Using reg %d for reload %d\n", best_reg, rnum); |
| |
| rl->nregs = hard_regno_nregs[best_reg][rl->mode]; |
| rl->regno = best_reg; |
| |
| EXECUTE_IF_SET_IN_REG_SET |
| (&chain->live_throughout, FIRST_PSEUDO_REGISTER, j, rsi) |
| { |
| count_spilled_pseudo (best_reg, rl->nregs, j); |
| } |
| |
| EXECUTE_IF_SET_IN_REG_SET |
| (&chain->dead_or_set, FIRST_PSEUDO_REGISTER, j, rsi) |
| { |
| count_spilled_pseudo (best_reg, rl->nregs, j); |
| } |
| |
| for (i = 0; i < rl->nregs; i++) |
| { |
| 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; |
| } |
| |
| /* Find more reload regs to satisfy the remaining need of an insn, which |
| is given by CHAIN. |
| Do it by ascending class number, since otherwise a reg |
| might be spilled for a big class and might fail to count |
| for a smaller class even though it belongs to that class. */ |
| |
| static void |
| find_reload_regs (struct insn_chain *chain) |
| { |
| int i; |
| |
| /* In order to be certain of getting the registers we need, |
| we must sort the reloads into order of increasing register class. |
| Then our grabbing of reload registers will parallel the process |
| that provided the reload registers. */ |
| for (i = 0; i < chain->n_reloads; i++) |
| { |
| /* Show whether this reload already has a hard reg. */ |
| if (chain->rld[i].reg_rtx) |
| { |
| int regno = REGNO (chain->rld[i].reg_rtx); |
| chain->rld[i].regno = regno; |
| chain->rld[i].nregs |
| = hard_regno_nregs[regno][GET_MODE (chain->rld[i].reg_rtx)]; |
| } |
| else |
| chain->rld[i].regno = -1; |
| reload_order[i] = i; |
| } |
| |
| n_reloads = chain->n_reloads; |
| memcpy (rld, chain->rld, n_reloads * sizeof (struct reload)); |
| |
| CLEAR_HARD_REG_SET (used_spill_regs_local); |
| |
| if (dump_file) |
| fprintf (dump_file, "Spilling for insn %d.\n", INSN_UID (chain->insn)); |
| |
| qsort (reload_order, n_reloads, sizeof (short), reload_reg_class_lower); |
| |
| /* Compute the order of preference for hard registers to spill. */ |
| |
| order_regs_for_reload (chain); |
| |
| for (i = 0; i < n_reloads; i++) |
| { |
| int r = reload_order[i]; |
| |
| /* Ignore reloads that got marked inoperative. */ |
| if ((rld[r].out != 0 || rld[r].in != 0 || rld[r].secondary_p) |
| && ! rld[r].optional |
| && rld[r].regno == -1) |
| if (! find_reg (chain, i)) |
| { |
| if (dump_file) |
| fprintf (dump_file, "reload failure for reload %d\n", r); |
| spill_failure (chain->insn, rld[r].rclass); |
| failure = 1; |
| return; |
| } |
| } |
| |
| COPY_HARD_REG_SET (chain->used_spill_regs, used_spill_regs_local); |
| IOR_HARD_REG_SET (used_spill_regs, used_spill_regs_local); |
| |
| memcpy (chain->rld, rld, n_reloads * sizeof (struct reload)); |
| } |
| |
| static void |
| select_reload_regs (void) |
| { |
| struct insn_chain *chain; |
| |
| /* Try to satisfy the needs for each insn. */ |
| for (chain = insns_need_reload; chain != 0; |
| chain = chain->next_need_reload) |
| find_reload_regs (chain); |
| } |
| |
| /* Delete all insns that were inserted by emit_caller_save_insns during |
| this iteration. */ |
| static void |
| delete_caller_save_insns (void) |
| { |
| struct insn_chain *c = reload_insn_chain; |
| |
| while (c != 0) |
| { |
| while (c != 0 && c->is_caller_save_insn) |
| { |
| struct insn_chain *next = c->next; |
| rtx insn = c->insn; |
| |
| if (c == reload_insn_chain) |
| reload_insn_chain = next; |
| delete_insn (insn); |
| |
| if (next) |
| next->prev = c->prev; |
| if (c->prev) |
| c->prev->next = next; |
| c->next = unused_insn_chains; |
| unused_insn_chains = c; |
| c = next; |
| } |
| if (c != 0) |
| c = c->next; |
| } |
| } |
| |
| /* Handle the failure to find a register to spill. |
| INSN should be one of the insns which needed this particular spill reg. */ |
| |
| static void |
| spill_failure (rtx insn, enum reg_class rclass) |
| { |
| if (asm_noperands (PATTERN (insn)) >= 0) |
| error_for_asm (insn, "can't find a register in class %qs while " |
| "reloading %<asm%>", |
| reg_class_names[rclass]); |
| else |
| { |
| error ("unable to find a register to spill in class %qs", |
| reg_class_names[rclass]); |
| |
| if (dump_file) |
| { |
| fprintf (dump_file, "\nReloads for insn # %d\n", INSN_UID (insn)); |
| debug_reload_to_stream (dump_file); |
| } |
| fatal_insn ("this is the insn:", insn); |
| } |
| } |
| |
| /* Delete an unneeded INSN and any previous insns who sole purpose is loading |
| data that is dead in INSN. */ |
| |
| static void |
| delete_dead_insn (rtx insn) |
| { |
| rtx prev = prev_real_insn (insn); |
| rtx prev_dest; |
| |
| /* If the previous insn sets a register that dies in our insn, delete it |
| too. */ |
| 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); |
| |
| SET_INSN_DELETED (insn); |
| } |
| |
| /* Modify the home of pseudo-reg I. |
| The new home is present in reg_renumber[I]. |
| |
| FROM_REG may be the hard reg that the pseudo-reg is being spilled from; |
| or it may be -1, meaning there is none or it is not relevant. |
| This is used so that all pseudos spilled from a given hard reg |
| can share one stack slot. */ |
| |
| static void |
| 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. */ |
| if (regno_reg_rtx[i] == 0) |
| return; |
| |
| /* If the reg got changed to a MEM at rtl-generation time, |
| ignore it. */ |
| if (!REG_P (regno_reg_rtx[i])) |
| return; |
| |
| /* Modify the reg-rtx to contain the new hard reg |
| number or else to contain its pseudo reg number. */ |
| SET_REGNO (regno_reg_rtx[i], |
| reg_renumber[i] >= 0 ? reg_renumber[i] : i); |
| |
| /* If we have a pseudo that is needed but has no hard reg or equivalent, |
| allocate a stack slot for it. */ |
| |
| 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) |
| { |
| 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); |
| unsigned int total_size = MAX (inherent_size, reg_max_ref_width[i]); |
| unsigned int min_align = reg_max_ref_width[i] * BITS_PER_UNIT; |
| int adjust = 0; |
| |
| if (ira_conflicts_p) |
| { |
| /* Mark the spill for IRA. */ |
| SET_REGNO_REG_SET (&spilled_pseudos, i); |
| if (!dont_share_p) |
| x = ira_reuse_stack_slot (i, inherent_size, total_size); |
| } |
| |
| if (x) |
| ; |
| |
| /* Each pseudo reg has an inherent size which comes from its own mode, |
| and a total size which provides room for paradoxical subregs |
| which refer to the pseudo reg in wider modes. |
| |
| We can use a slot already allocated if it provides both |
| 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. */ |
| else if (from_reg == -1 || (!dont_share_p && ira_conflicts_p)) |
| { |
| 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) |
| { |
| 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. */ |
| else if (spill_stack_slot[from_reg] != 0 |
| && spill_stack_slot_width[from_reg] >= total_size |
| && (GET_MODE_SIZE (GET_MODE (spill_stack_slot[from_reg])) |
| >= inherent_size) |
| && MEM_ALIGN (spill_stack_slot[from_reg]) >= min_align) |
| x = spill_stack_slot[from_reg]; |
| |
| /* Allocate a bigger slot. */ |
| else |
| { |
| /* Compute maximum size needed, both for inherent size |
| and for total size. */ |
| rtx stack_slot; |
| |
| if (spill_stack_slot[from_reg]) |
| { |
| if (GET_MODE_SIZE (GET_MODE (spill_stack_slot[from_reg])) |
| > inherent_size) |
| mode = GET_MODE (spill_stack_slot[from_reg]); |
| if (spill_stack_slot_width[from_reg] > total_size) |
| total_size = spill_stack_slot_width[from_reg]; |
| if (MEM_ALIGN (spill_stack_slot[from_reg]) > min_align) |
| min_align = MEM_ALIGN (spill_stack_slot[from_reg]); |
| } |
| |
| /* Make a slot with that size. */ |
| 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) |
| { |
| adjust = GET_MODE_SIZE (mode) - total_size; |
| if (adjust) |
| stack_slot |
| = adjust_address_nv (x, mode_for_size (total_size |
| * BITS_PER_UNIT, |
| MODE_INT, 1), |
| adjust); |
| } |
| |
| spill_stack_slot[from_reg] = stack_slot; |
| spill_stack_slot_width[from_reg] = total_size; |
| } |
| |
| /* On a big endian machine, the "address" of the slot |
| is the address of the low part that fits its inherent mode. */ |
| if (BYTES_BIG_ENDIAN && inherent_size < total_size) |
| adjust += (total_size - inherent_size); |
| |
| /* If we have any adjustment to make, or if the stack slot is the |
| wrong mode, make a new stack slot. */ |
| x = adjust_address_nv (x, GET_MODE (regno_reg_rtx[i]), adjust); |
| |
| /* 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; |
| } |
| } |
| |
| /* Mark the slots in regs_ever_live for the hard regs used by |
| pseudo-reg number REGNO, accessed in MODE. */ |
| |
| static void |
| mark_home_live_1 (int regno, enum machine_mode mode) |
| { |
| int i, lim; |
| |
| i = reg_renumber[regno]; |
| if (i < 0) |
| return; |
| lim = end_hard_regno (mode, i); |
| while (i < lim) |
| df_set_regs_ever_live(i++, true); |
| } |
| |
| /* Mark the slots in regs_ever_live for the hard regs |
| used by pseudo-reg number REGNO. */ |
| |
| void |
| mark_home_live (int regno) |
| { |
| if (reg_renumber[regno] >= 0) |
| mark_home_live_1 (regno, PSEUDO_REGNO_MODE (regno)); |
| } |
| |
| /* This function handles the tracking of elimination offsets around branches. |
| |
| X is a piece of RTL being scanned. |
| |
| INSN is the insn that it came from, if any. |
| |
| INITIAL_P is nonzero if we are to set the offset to be the initial |
| offset and zero if we are setting the offset of the label to be the |
| current offset. */ |
| |
| static void |
| set_label_offsets (rtx x, rtx insn, int initial_p) |
| { |
| enum rtx_code code = GET_CODE (x); |
| rtx tem; |
| unsigned int i; |
| struct elim_table *p; |
| |
| switch (code) |
| { |
| case LABEL_REF: |
| if (LABEL_REF_NONLOCAL_P (x)) |
| return; |
| |
| x = XEXP (x, 0); |
| |
| /* ... fall through ... */ |
| |
| case CODE_LABEL: |
| /* If we know nothing about this label, set the desired offsets. Note |
| that this sets the offset at a label to be the offset before a label |
| if we don't know anything about the label. This is not correct for |
| the label after a BARRIER, but is the best guess we can make. If |
| we guessed wrong, we will suppress an elimination that might have |
| been possible had we been able to guess correctly. */ |
| |
| if (! offsets_known_at[CODE_LABEL_NUMBER (x) - first_label_num]) |
| { |
| for (i = 0; i < NUM_ELIMINABLE_REGS; i++) |
| offsets_at[CODE_LABEL_NUMBER (x) - first_label_num][i] |
| = (initial_p ? reg_eliminate[i].initial_offset |
| : reg_eliminate[i].offset); |
| offsets_known_at[CODE_LABEL_NUMBER (x) - first_label_num] = 1; |
| } |
| |
| /* Otherwise, if this is the definition of a label and it is |
| preceded by a BARRIER, set our offsets to the known offset of |
| that label. */ |
| |
| else if (x == insn |
| && (tem = prev_nonnote_insn (insn)) != 0 |
| && BARRIER_P (tem)) |
| set_offsets_for_label (insn); |
| else |
| /* If neither of the above cases is true, compare each offset |
| with those previously recorded and suppress any eliminations |
| where the offsets disagree. */ |
| |
| for (i = 0; i < NUM_ELIMINABLE_REGS; i++) |
| if (offsets_at[CODE_LABEL_NUMBER (x) - first_label_num][i] |
| != (initial_p ? reg_eliminate[i].initial_offset |
| : reg_eliminate[i].offset)) |
| reg_eliminate[i].can_eliminate = 0; |
| |
| return; |
| |
| case JUMP_INSN: |
| set_label_offsets (PATTERN (insn), insn, initial_p); |
| |
| /* ... fall through ... */ |
| |
| case INSN: |
| case CALL_INSN: |
| /* Any labels mentioned in REG_LABEL_OPERAND notes can be branched |
| to indirectly and hence must have all eliminations at their |
| initial offsets. */ |
| for (tem = REG_NOTES (x); tem; tem = XEXP (tem, 1)) |
| if (REG_NOTE_KIND (tem) == REG_LABEL_OPERAND) |
| set_label_offsets (XEXP (tem, 0), insn, 1); |
| return; |
| |
| case PARALLEL: |
| case ADDR_VEC: |
| case ADDR_DIFF_VEC: |
| /* Each of the labels in the parallel or address vector must be |
| at their initial offsets. We want the first field for PARALLEL |
| and ADDR_VEC and the second field for ADDR_DIFF_VEC. */ |
| |
| for (i = 0; i < (unsigned) XVECLEN (x, code == ADDR_DIFF_VEC); i++) |
| set_label_offsets (XVECEXP (x, code == ADDR_DIFF_VEC, i), |
| insn, initial_p); |
| return; |
| |
| case SET: |
| /* We only care about setting PC. If the source is not RETURN, |
| IF_THEN_ELSE, or a label, disable any eliminations not at |
| their initial offsets. Similarly if any arm of the IF_THEN_ELSE |
| isn't one of those possibilities. For branches to a label, |
| call ourselves recursively. |
| |
| Note that this can disable elimination unnecessarily when we have |
| a non-local goto since it will look like a non-constant jump to |
| someplace in the current function. This isn't a significant |
| problem since such jumps will normally be when all elimination |
| pairs are back to their initial offsets. */ |
| |
| if (SET_DEST (x) != pc_rtx) |
| return; |
| |
| switch (GET_CODE (SET_SRC (x))) |
| { |
| case PC: |
| case RETURN: |
| return; |
| |
| case LABEL_REF: |
| set_label_offsets (SET_SRC (x), insn, initial_p); |
| return; |
| |
| case IF_THEN_ELSE: |
| tem = XEXP (SET_SRC (x), 1); |
| if (GET_CODE (tem) == LABEL_REF) |
| set_label_offsets (XEXP (tem, 0), insn, initial_p); |
| else if (GET_CODE (tem) != PC && GET_CODE (tem) != RETURN) |
| break; |
| |
| tem = XEXP (SET_SRC (x), 2); |
| if (GET_CODE (tem) == LABEL_REF) |
| set_label_offsets (XEXP (tem, 0), insn, initial_p); |
| else if (GET_CODE (tem) != PC && GET_CODE (tem) != RETURN) |
| break; |
| return; |
| |
| default: |
| break; |
| } |
| |
| /* If we reach here, all eliminations must be at their initial |
| offset because we are doing a jump to a variable address. */ |
| for (p = reg_eliminate; p < ®_eliminate[NUM_ELIMINABLE_REGS]; p++) |
| if (p->offset != p->initial_offset) |
| p->can_eliminate = 0; |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| /* 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 |
| to record the fact that a register is referenced outside a MEM. |
| |
| If INSN is an insn, it is the insn containing X. If we replace a REG |
| in a SET_DEST with an equivalent MEM and INSN is nonzero, write a |
| CLOBBER of the pseudo after INSN so find_equiv_regs will know that |
| the REG is being modified. |
| |
| Alternatively, INSN may be a note (an EXPR_LIST or INSN_LIST). |
| That's used when we eliminate in expressions stored in notes. |
| This means, do not set ref_outside_mem even if the reference |
| is outside of MEMs. |
| |
| 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 |
| encounter, return the actual location so that find_reloads will do |
| the proper thing. */ |
| |
| static rtx |
| eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn, |
| bool may_use_invariant) |
| { |
| enum rtx_code code = GET_CODE (x); |
| struct elim_table *ep; |
| int regno; |
| rtx new_rtx; |
| int i, j; |
| const char *fmt; |
| int copied = 0; |
| |
| if (! current_function_decl) |
| return x; |
| |
| switch (code) |
| { |
| case CONST_INT: |
| case CONST_DOUBLE: |
| case CONST_FIXED: |
| case CONST_VECTOR: |
| case CONST: |
| case SYMBOL_REF: |
| case CODE_LABEL: |
| case PC: |
| case CC0: |
| case ASM_INPUT: |
| case ADDR_VEC: |
| case ADDR_DIFF_VEC: |
| case RETURN: |
| return x; |
| |
| case REG: |
| regno = REGNO (x); |
| |
| /* First handle the case where we encounter a bare register that |
| is eliminable. Replace it with a PLUS. */ |
| if (regno < FIRST_PSEUDO_REGISTER) |
| { |
| for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; |
| ep++) |
| if (ep->from_rtx == x && ep->can_eliminate) |
| return plus_constant (ep->to_rtx, ep->previous_offset); |
| |
| } |
| else if (reg_renumber && reg_renumber[regno] < 0 |
| && reg_equiv_invariant && reg_equiv_invariant[regno]) |
| { |
| if (may_use_invariant) |
| return eliminate_regs_1 (copy_rtx (reg_equiv_invariant[regno]), |
| mem_mode, insn, true); |
| /* 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, true); |
| } |
| return x; |
| |
| /* You might think handling MINUS in a manner similar to PLUS is a |
| good idea. It is not. It has been tried multiple times and every |
| time the change has had to have been reverted. |
| |
| Other parts of reload know a PLUS is special (gen_reload for example) |
| and require special code to handle code a reloaded PLUS operand. |
| |
| Also consider backends where the flags register is clobbered by a |
| MINUS, but we can emit a PLUS that does not clobber flags (IA-32, |
| lea instruction comes to mind). If we try to reload a MINUS, we |
| may kill the flags register that was holding a useful value. |
| |
| So, please before trying to handle MINUS, consider reload as a |
| whole instead of this little section as well as the backend issues. */ |
| case PLUS: |
| /* If this is the sum of an eliminable register and a constant, rework |
| the sum. */ |
| if (REG_P (XEXP (x, 0)) |
| && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER |
| && CONSTANT_P (XEXP (x, 1))) |
| { |
| for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; |
| ep++) |
| if (ep->from_rtx == XEXP (x, 0) && ep->can_eliminate) |
| { |
| /* The only time we want to replace a PLUS with a REG (this |
| occurs when the constant operand of the PLUS is the negative |
| of the offset) is when we are inside a MEM. We won't want |
| to do so at other times because that would change the |
| structure of the insn in a way that reload can't handle. |
| 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 |
| && INTVAL (XEXP (x, 1)) == - ep->previous_offset) |
| return ep->to_rtx; |
| else |
| return gen_rtx_PLUS (Pmode, ep->to_rtx, |
| plus_constant (XEXP (x, 1), |
| ep->previous_offset)); |
| } |
| |
| /* If the register is not eliminable, we are done since the other |
| operand is a constant. */ |
| return x; |
| } |
| |
| /* If this is part of an address, we want to bring any constant to the |
| outermost PLUS. We will do this by doing register replacement in |
| our operands and seeing if a constant shows up in one of them. |
| |
| Note that there is no risk of modifying the structure of the insn, |
| since we only get called for its operands, thus we are either |
| modifying the address inside a MEM, or something like an address |
| 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); |
| |
| if (reg_renumber && (new0 != XEXP (x, 0) || new1 != XEXP (x, 1))) |
| { |
| /* If one side is a PLUS and the other side is a pseudo that |
| didn't get a hard register but has a reg_equiv_constant, |
| we must replace the constant here since it may no longer |
| be in the position of any operand. */ |
| 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)]; |
| 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)]; |
| |
| new_rtx = form_sum (new0, new1); |
| |
| /* As above, if we are not inside a MEM we do not want to |
| turn a PLUS into something else. We might try to do so here |
| for an addition of 0 if we aren't optimizing. */ |
| if (! mem_mode && GET_CODE (new_rtx) != PLUS) |
| return gen_rtx_PLUS (GET_MODE (x), new_rtx, const0_rtx); |
| else |
| return new_rtx; |
| } |
| } |
| return x; |
| |
| case MULT: |
| /* If this is the product of an eliminable register and a |
| constant, apply the distribute law and move the constant out |
| so that we have (plus (mult ..) ..). This is needed in order |
| to keep load-address insns valid. This case is pathological. |
| 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) |
| 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. */ |
| && ! (insn != 0 && (GET_CODE (insn) == EXPR_LIST |
| || GET_CODE (insn) == INSN_LIST))) |
| ep->ref_outside_mem = 1; |
| |
| return |
| plus_constant (gen_rtx_MULT (Pmode, ep->to_rtx, XEXP (x, 1)), |
| ep->previous_offset * INTVAL (XEXP (x, 1))); |
| } |
| |
| /* ... fall through ... */ |
| |
| case CALL: |
| case COMPARE: |
| /* See comments before PLUS about handling MINUS. */ |
| case MINUS: |
| case DIV: case UDIV: |
| case MOD: case UMOD: |
| case AND: case IOR: case XOR: |
| case ROTATERT: case ROTATE: |
| case ASHIFTRT: case LSHIFTRT: case ASHIFT: |
| case NE: case EQ: |
| 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 new1 = XEXP (x, 1) |
| ? eliminate_regs_1 (XEXP (x, 1), mem_mode, insn, false) : 0; |
| |
| if (new0 != XEXP (x, 0) || new1 != XEXP (x, 1)) |
| return gen_rtx_fmt_ee (code, GET_MODE (x), new0, new1); |
| } |
| return x; |
| |
| case EXPR_LIST: |
| /* If we have something in XEXP (x, 0), the usual case, eliminate it. */ |
| if (XEXP (x, 0)) |
| { |
| new_rtx = eliminate_regs_1 (XEXP (x, 0), mem_mode, insn, true); |
| if (new_rtx != XEXP (x, 0)) |
| { |
| /* If this is a REG_DEAD note, it is not valid anymore. |
| Using the eliminated version could result in creating a |
| REG_DEAD note for the stack or frame pointer. */ |
| if (REG_NOTE_KIND (x) == REG_DEAD) |
| return (XEXP (x, 1) |
| ? eliminate_regs_1 (XEXP (x, 1), mem_mode, insn, true) |
| : NULL_RTX); |
| |
| x = gen_rtx_EXPR_LIST (REG_NOTE_KIND (x), new_rtx, XEXP (x, 1)); |
| } |
| } |
| |
| /* ... fall through ... */ |
| |
| case INSN_LIST: |
| /* Now do eliminations in the rest of the chain. If this was |
| an EXPR_LIST, this might result in allocating more memory than is |
| strictly needed, but it simplifies the code. */ |
| if (XEXP (x, 1)) |
| { |
| new_rtx = eliminate_regs_1 (XEXP (x, 1), mem_mode, insn, true); |
| if (new_rtx != XEXP (x, 1)) |
| return |
| gen_rtx_fmt_ee (GET_CODE (x), GET_MODE (x), XEXP (x, 0), new_rtx); |
| } |
| return x; |
| |
| case PRE_INC: |
| case POST_INC: |
| case PRE_DEC: |
| case POST_DEC: |
| /* We do not support elimination of a register that is modified. |
| elimination_effects has already make sure that this does not |
| happen. */ |
| return x; |
| |
| case PRE_MODIFY: |
| case POST_MODIFY: |
| /* We do not support elimination of a register that is modified. |
| elimination_effects has already make sure that this does not |
| happen. The only remaining case we need to consider here is |
| that the increment value may be an eliminable register. */ |
| if (GET_CODE (XEXP (x, 1)) == PLUS |
| && XEXP (XEXP (x, 1), 0) == XEXP (x, 0)) |
| { |
| rtx new_rtx = eliminate_regs_1 (XEXP (XEXP (x, 1), 1), mem_mode, |
| insn, true); |
| |
| 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_rtx)); |
| } |
| return x; |
| |
| case STRICT_LOW_PART: |
| case NEG: case NOT: |
| case SIGN_EXTEND: case ZERO_EXTEND: |
| case TRUNCATE: case FLOAT_EXTEND: case FLOAT_TRUNCATE: |
| case FLOAT: case FIX: |
| case UNSIGNED_FIX: case UNSIGNED_FLOAT: |
| case ABS: |
| case SQRT: |
| case FFS: |
| case CLZ: |
| case CTZ: |
| case POPCOUNT: |
| case PARITY: |
| case BSWAP: |
| new_rtx = eliminate_regs_1 (XEXP (x, 0), mem_mode, insn, false); |
| if (new_rtx != XEXP (x, 0)) |
| return gen_rtx_fmt_e (code, GET_MODE (x), new_rtx); |
| return x; |
| |
| case SUBREG: |
| /* Similar to above processing, but preserve SUBREG_BYTE. |
| Convert (subreg (mem)) to (mem) if not paradoxical. |
| Also, if we have a non-paradoxical (subreg (pseudo)) and the |
| pseudo didn't get a hard reg, we must replace this with the |
| 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) |
| { |
| new_rtx = SUBREG_REG (x); |
| } |
| else |
| new_rtx = eliminate_regs_1 (SUBREG_REG (x), mem_mode, insn, false); |
| |
| if (new_rtx != SUBREG_REG (x)) |
| { |
| int x_size = GET_MODE_SIZE (GET_MODE (x)); |
| int new_size = GET_MODE_SIZE (GET_MODE (new_rtx)); |
| |
| if (MEM_P (new_rtx) |
| && ((x_size < new_size |
| #ifdef WORD_REGISTER_OPERATIONS |
| /* On these machines, combine can create rtl of the form |
| (set (subreg:m1 (reg:m2 R) 0) ...) |
| where m1 < m2, and expects something interesting to |
| happen to the entire word. Moreover, it will use the |
| (reg:m2 R) later, expecting all bits to be preserved. |
| So if the number of words is the same, preserve the |
| subreg so that push_reload can see it. */ |
| && ! ((x_size - 1) / UNITS_PER_WORD |
| == (new_size -1 ) / UNITS_PER_WORD) |
| #endif |
| ) |
| || x_size == new_size) |
| ) |
| return adjust_address_nv (new_rtx, GET_MODE (x), SUBREG_BYTE (x)); |
| else |
| return gen_rtx_SUBREG (GET_MODE (x), new_rtx, SUBREG_BYTE (x)); |
| } |
| |
| return x; |
| |
| case MEM: |
| /* 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)); |
| |
| case USE: |
| /* Handle insn_list USE that a call to a pure function may generate. */ |
| new_rtx = eliminate_regs_1 (XEXP (x, 0), 0, insn, false); |
| if (new_rtx != XEXP (x, 0)) |
| return gen_rtx_USE (GET_MODE (x), new_rtx); |
| return x; |
| |
| case CLOBBER: |
| case ASM_OPERANDS: |
| case SET: |
| gcc_unreachable (); |
| |
| default: |
| break; |
| } |
| |
| /* Process each of our operands recursively. If any have changed, make a |
| copy of the rtx. */ |
| fmt = GET_RTX_FORMAT (code); |
| for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++) |
| { |
| if (*fmt == 'e') |
| { |
| new_rtx = eliminate_regs_1 (XEXP (x, i), mem_mode, insn, false); |
| if (new_rtx != XEXP (x, i) && ! copied) |
| { |
| x = shallow_copy_rtx (x); |
| copied = 1; |
| } |
| XEXP (x, i) = new_rtx; |
| } |
| else if (*fmt == 'E') |
| { |
| int copied_vec = 0; |
| for (j = 0; j < XVECLEN (x, i); j++) |
| { |
| new_rtx = eliminate_regs_1 (XVECEXP (x, i, j), mem_mode, insn, false); |
| if (new_rtx != XVECEXP (x, i, j) && ! copied_vec) |
| { |
| rtvec new_v = gen_rtvec_v (XVECLEN (x, i), |
| XVEC (x, i)->elem); |
| if (! copied) |
| { |
| x = shallow_copy_rtx (x); |
| copied = 1; |
| } |
| XVEC (x, i) = new_v; |
| copied_vec = 1; |
| } |
| XVECEXP (x, i, j) = new_rtx; |
| } |
| } |
| } |
| |
| return x; |
| } |
| |
| rtx |
| eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn) |
| { |
| return eliminate_regs_1 (x, mem_mode, insn, false); |
| } |
| |
| /* Scan rtx X for modifications of elimination target registers. Update |
| the table of eliminables to reflect the changed state. MEM_MODE is |
| the mode of an enclosing MEM rtx, or VOIDmode if not within a MEM. */ |
| |
| static void |
| elimination_effects (rtx x, enum machine_mode mem_mode) |
| { |
| enum rtx_code code = GET_CODE (x); |
| struct elim_table *ep; |
| int regno; |
| int i, j; |
| const char *fmt; |
| |
| switch (code) |
| { |
| case CONST_INT: |
| case CONST_DOUBLE: |
| case CONST_FIXED: |
| case CONST_VECTOR: |
| case CONST: |
| case SYMBOL_REF: |
| case CODE_LABEL: |
| case PC: |
| case CC0: |
| case ASM_INPUT: |
| case ADDR_VEC: |
| case ADDR_DIFF_VEC: |
| case RETURN: |
| return; |
| |
| case REG: |
| regno = REGNO (x); |
| |
| /* First handle the case where we encounter a bare register that |
| is eliminable. Replace it with a PLUS. */ |
| if (regno < FIRST_PSEUDO_REGISTER) |
| { |
| for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; |
| ep++) |
| if (ep->from_rtx == x && ep->can_eliminate) |
| { |
| if (! mem_mode) |
| ep->ref_outside_mem = 1; |
| return; |
| } |
| |
| } |
| 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); |
| return; |
| |
| case PRE_INC: |
| case POST_INC: |
| case PRE_DEC: |
| case POST_DEC: |
| case POST_MODIFY: |
| case PRE_MODIFY: |
| /* If we modify the source of an elimination rule, disable it. */ |
| for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) |
| if (ep->from_rtx == XEXP (x, 0)) |
| ep->can_eliminate = 0; |
| |
| /* If we modify the target of an elimination rule by adding a constant, |
| update its offset. If we modify the target in any other way, we'll |
| have to disable the rule as well. */ |
| for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) |
| if (ep->to_rtx == XEXP (x, 0)) |
| { |
| int size = GET_MODE_SIZE (mem_mode); |
| |
| /* If more bytes than MEM_MODE are pushed, account for them. */ |
| #ifdef PUSH_ROUNDING |
| if (ep->to_rtx == stack_pointer_rtx) |
| size = PUSH_ROUNDING (size); |
| #endif |
| if (code == PRE_DEC || code == POST_DEC) |
| ep->offset += size; |
| else if (code == PRE_INC || code == POST_INC) |
| ep->offset -= size; |
| else if (code == PRE_MODIFY || code == POST_MODIFY) |
| { |
| if (GET_CODE (XEXP (x, 1)) == PLUS |
| && XEXP (x, 0) == XEXP (XEXP (x, 1), 0) |
| && CONST_INT_P (XEXP (XEXP (x, 1), 1))) |
| ep->offset -= INTVAL (XEXP (XEXP (x, 1), 1)); |
| else |
| ep->can_eliminate = 0; |
| } |
| } |
| |
| /* These two aren't unary operators. */ |
| if (code == POST_MODIFY || code == PRE_MODIFY) |
| break; |
| |
| /* Fall through to generic unary operation case. */ |
| case STRICT_LOW_PART: |
| case NEG: case NOT: |
| case SIGN_EXTEND: case ZERO_EXTEND: |
| case TRUNCATE: case FLOAT_EXTEND: case FLOAT_TRUNCATE: |
| case FLOAT: case FIX: |
| case UNSIGNED_FIX: case UNSIGNED_FLOAT: |
| case ABS: |
| case SQRT: |
| case FFS: |
| case CLZ: |
| case CTZ: |
| case POPCOUNT: |
| case PARITY: |
| case BSWAP: |
| elimination_effects (XEXP (x, 0), mem_mode); |
| return; |
| |
| case SUBREG: |
| 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) |
| return; |
| |
| elimination_effects (SUBREG_REG (x), mem_mode); |
| return; |
| |
| case USE: |
| /* If using a register that is the source of an eliminate we still |
| think can be performed, note it cannot be performed since we don't |
| know how this register is used. */ |
| for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) |
| if (ep->from_rtx == XEXP (x, 0)) |
| ep->can_eliminate = 0; |
| |
| elimination_effects (XEXP (x, 0), mem_mode); |
| return; |
| |
| case CLOBBER: |
| /* If clobbering a register that is the replacement register for an |
| elimination we still think can be performed, note that it cannot |
| be performed. Otherwise, we need not be concerned about it. */ |
| for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) |
| if (ep->to_rtx == XEXP (x, 0)) |
| ep->can_eliminate = 0; |
| |
| elimination_effects (XEXP (x, 0), mem_mode); |
| return; |
| |
| case SET: |
| /* Check for setting a register that we know about. */ |
| if (REG_P (SET_DEST (x))) |
| { |
| /* See if this is setting the replacement register for an |
| elimination. |
| |
| If DEST is the hard frame pointer, we do nothing because we |
| assume that all assignments to the frame pointer are for |
| non-local gotos and are being done at a time when they are valid |
| and do not disturb anything else. Some machines want to |
| eliminate a fake argument pointer (or even a fake frame pointer) |
| with either the real frame or the stack pointer. Assignments to |
| the hard frame pointer must not prevent this elimination. */ |
| |
| for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; |
| ep++) |
| if (ep->to_rtx == SET_DEST (x) |
| && SET_DEST (x) != hard_frame_pointer_rtx) |
| { |
| /* If it is being incremented, adjust the offset. Otherwise, |
| this elimination can't be done. */ |
| rtx src = SET_SRC (x); |
| |
| if (GET_CODE (src) == PLUS |
| && XEXP (src, 0) == SET_DEST (x) |
| && GET_CODE (XEXP (src, 1)) == CONST_INT) |
| ep->offset -= INTVAL (XEXP (src, 1)); |
| else |
| ep->can_eliminate = 0; |
| } |
| } |
| |
| elimination_effects (SET_DEST (x), 0); |
| elimination_effects (SET_SRC (x), 0); |
| return; |
| |
| case MEM: |
| /* Our only special processing is to pass the mode of the MEM to our |
| recursive call. */ |
| elimination_effects (XEXP (x, 0), GET_MODE (x)); |
| return; |
| |
| default: |
| break; |
| } |
| |
| fmt = GET_RTX_FORMAT (code); |
| for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++) |
| { |
| if (*fmt == 'e') |
| elimination_effects (XEXP (x, i), mem_mode); |
| else if (*fmt == 'E') |
| for (j = 0; j < XVECLEN (x, i); j++) |
| elimination_effects (XVECEXP (x, i, j), mem_mode); |
| } |
| } |
| |
| /* Descend through rtx X and verify that no references to eliminable registers |
| remain. If any do remain, mark the involved register as not |
| eliminable. */ |
| |
| static void |
| check_eliminable_occurrences (rtx x) |
| { |
| const char *fmt; |
| int i; |
| enum rtx_code code; |
| |
| if (x == 0) |
| return; |
| |
| code = GET_CODE (x); |
| |
| if (code == REG && REGNO (x) < FIRST_PSEUDO_REGISTER) |
| { |
| struct elim_table *ep; |
| |
| for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) |
| if (ep->from_rtx == x) |
| ep->can_eliminate = 0; |
| return; |
| } |
| |
| fmt = GET_RTX_FORMAT (code); |
| for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++) |
| { |
| if (*fmt == 'e') |
| check_eliminable_occurrences (XEXP (x, i)); |
| else if (*fmt == 'E') |
| { |
| int j; |
| for (j = 0; j < XVECLEN (x, i); j++) |
| check_eliminable_occurrences (XVECEXP (x, i, j)); |
| } |
| } |
| } |
| |
| /* Scan INSN and eliminate all eliminable registers in it. |
| |
| If REPLACE is nonzero, do the replacement destructively. Also |
| delete the insn as dead it if it is setting an eliminable register. |
| |
| If REPLACE is zero, do all our allocations in reload_obstack. |
| |
| If no eliminations were done and this insn doesn't require any elimination |
| processing (these are not identical conditions: it might be updating sp, |
| but not referencing fp; this needs to be seen during reload_as_needed so |
| that the offset between fp and sp can be taken into consideration), zero |
| is returned. Otherwise, 1 is returned. */ |
| |
| static int |
| eliminate_regs_in_insn (rtx insn, int replace) |
| { |
| 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); |
| rtx new_body; |
| int val = 0; |
| int i; |
| rtx substed_operand[MAX_RECOG_OPERANDS]; |
| rtx orig_operand[MAX_RECOG_OPERANDS]; |
| struct elim_table *ep; |
| rtx plus_src, plus_cst_src; |
| |
<