diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2015-04-22 10:21:45 +0000 |
---|---|---|
committer | <> | 2015-04-25 21:44:09 +0000 |
commit | f80b5ea1605c9f9408c5aa386ba71c16d918ebbf (patch) | |
tree | bb7eafaa81fc4b8c5c215bc08d517fd158db234a /gcc/lra-eliminations.c | |
parent | c27a97d04853380f1e80525391b3f0d156ed4c84 (diff) | |
download | gcc-tarball-f80b5ea1605c9f9408c5aa386ba71c16d918ebbf.tar.gz |
Imported from /home/lorry/working-area/delta_gcc-tarball/gcc-5.1.0.tar.bz2.gcc-5.1.0
Diffstat (limited to 'gcc/lra-eliminations.c')
-rw-r--r-- | gcc/lra-eliminations.c | 182 |
1 files changed, 119 insertions, 63 deletions
diff --git a/gcc/lra-eliminations.c b/gcc/lra-eliminations.c index 2787820355..64eec4a003 100644 --- a/gcc/lra-eliminations.c +++ b/gcc/lra-eliminations.c @@ -1,5 +1,5 @@ /* Code for RTL register eliminations. - Copyright (C) 2010-2014 Free Software Foundation, Inc. + Copyright (C) 2010-2015 Free Software Foundation, Inc. Contributed by Vladimir Makarov <vmakarov@redhat.com>. This file is part of GCC. @@ -65,8 +65,33 @@ along with GCC; see the file COPYING3. If not see #include "output.h" #include "addresses.h" #include "target.h" +#include "hashtab.h" +#include "hash-set.h" +#include "vec.h" +#include "machmode.h" +#include "input.h" #include "function.h" +#include "symtab.h" +#include "flags.h" +#include "statistics.h" +#include "double-int.h" +#include "real.h" +#include "fixed-value.h" +#include "alias.h" +#include "wide-int.h" +#include "inchash.h" +#include "tree.h" +#include "expmed.h" +#include "dojump.h" +#include "explow.h" +#include "calls.h" +#include "emit-rtl.h" +#include "varasm.h" +#include "stmt.h" #include "expr.h" +#include "predict.h" +#include "dominance.h" +#include "cfg.h" #include "basic-block.h" #include "except.h" #include "optabs.h" @@ -77,7 +102,7 @@ along with GCC; see the file COPYING3. If not see /* This structure is used to record information about hard register eliminations. */ -struct elim_table +struct lra_elim_table { /* Hard register number to be eliminated. */ int from; @@ -105,7 +130,7 @@ struct elim_table 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. */ -static struct elim_table *reg_eliminate = 0; +static struct lra_elim_table *reg_eliminate = 0; /* This is an intermediate structure to initialize the table. It has exactly the members provided by ELIMINABLE_REGS. */ @@ -131,7 +156,7 @@ static const struct elim_table_1 static void print_elim_table (FILE *f) { - struct elim_table *ep; + struct lra_elim_table *ep; for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) fprintf (f, "%s eliminate %d to %d (offset=" HOST_WIDE_INT_PRINT_DEC @@ -151,24 +176,26 @@ lra_debug_elim_table (void) VALUE. Setup FRAME_POINTER_NEEDED if elimination from frame pointer to stack pointer is not possible anymore. */ static void -setup_can_eliminate (struct elim_table *ep, bool value) +setup_can_eliminate (struct lra_elim_table *ep, bool value) { ep->can_eliminate = ep->prev_can_eliminate = value; if (! value && ep->from == FRAME_POINTER_REGNUM && ep->to == STACK_POINTER_REGNUM) frame_pointer_needed = 1; + if (!frame_pointer_needed) + REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM) = 0; } /* Map: eliminable "from" register -> its current elimination, or NULL if none. The elimination table may contain more than one elimination for the same hard register, but this map specifies the one that we are currently using. */ -static struct elim_table *elimination_map[FIRST_PSEUDO_REGISTER]; +static struct lra_elim_table *elimination_map[FIRST_PSEUDO_REGISTER]; /* When an eliminable hard register becomes not eliminable, we use the following special structure to restore original offsets for the register. */ -static struct elim_table self_elim_table; +static struct lra_elim_table self_elim_table; /* Offsets should be used to restore original offsets for eliminable hard register which just became not eliminable. Zero, @@ -184,7 +211,7 @@ static void setup_elimination_map (void) { int i; - struct elim_table *ep; + struct lra_elim_table *ep; for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) elimination_map[i] = NULL; @@ -205,7 +232,7 @@ static rtx form_sum (rtx x, rtx y) { rtx tem; - enum machine_mode mode = GET_MODE (x); + machine_mode mode = GET_MODE (x); if (mode == VOIDmode) mode = GET_MODE (y); @@ -249,7 +276,7 @@ form_sum (rtx x, rtx y) int lra_get_elimination_hard_regno (int hard_regno) { - struct elim_table *ep; + struct lra_elim_table *ep; if (hard_regno < 0 || hard_regno >= FIRST_PSEUDO_REGISTER) return hard_regno; @@ -260,11 +287,11 @@ lra_get_elimination_hard_regno (int hard_regno) /* Return elimination which will be used for hard reg REG, NULL otherwise. */ -static struct elim_table * +static struct lra_elim_table * get_elimination (rtx reg) { int hard_regno; - struct elim_table *ep; + struct lra_elim_table *ep; HOST_WIDE_INT offset; lra_assert (REG_P (reg)); @@ -290,7 +317,8 @@ get_elimination (rtx reg) a change in the offset between the eliminable register and its substitution if UPDATE_P, or the full offset if FULL_P, or otherwise zero. If FULL_P, we also use the SP offsets for - elimination to SP. + elimination to SP. If UPDATE_P, use UPDATE_SP_OFFSET for updating + offsets of register elimnable to SP. 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 @@ -302,11 +330,12 @@ get_elimination (rtx reg) If we make full substitution to SP for non-null INSN, add the insn sp offset. */ rtx -lra_eliminate_regs_1 (rtx insn, rtx x, enum machine_mode mem_mode, - bool subst_p, bool update_p, bool full_p) +lra_eliminate_regs_1 (rtx_insn *insn, rtx x, machine_mode mem_mode, + bool subst_p, bool update_p, + HOST_WIDE_INT update_sp_offset, bool full_p) { enum rtx_code code = GET_CODE (x); - struct elim_table *ep; + struct lra_elim_table *ep; rtx new_rtx; int i, j; const char *fmt; @@ -338,7 +367,10 @@ lra_eliminate_regs_1 (rtx insn, rtx x, enum machine_mode mem_mode, rtx to = subst_p ? ep->to_rtx : ep->from_rtx; if (update_p) - return plus_constant (Pmode, to, ep->offset - ep->previous_offset); + return plus_constant (Pmode, to, + ep->offset - ep->previous_offset + + (ep->to_rtx == stack_pointer_rtx + ? update_sp_offset : 0)); else if (full_p) return plus_constant (Pmode, to, ep->offset @@ -365,7 +397,10 @@ lra_eliminate_regs_1 (rtx insn, rtx x, enum machine_mode mem_mode, return gen_rtx_PLUS (Pmode, to, XEXP (x, 1)); offset = (update_p - ? ep->offset - ep->previous_offset : ep->offset); + ? ep->offset - ep->previous_offset + + (ep->to_rtx == stack_pointer_rtx + ? update_sp_offset : 0) + : ep->offset); if (full_p && insn != NULL_RTX && ep->to_rtx == stack_pointer_rtx) offset -= lra_get_insn_recog_data (insn)->sp_offset; if (CONST_INT_P (XEXP (x, 1)) @@ -394,9 +429,11 @@ lra_eliminate_regs_1 (rtx insn, rtx x, enum machine_mode mem_mode, { rtx new0 = lra_eliminate_regs_1 (insn, XEXP (x, 0), mem_mode, - subst_p, update_p, full_p); + subst_p, update_p, + update_sp_offset, full_p); rtx new1 = lra_eliminate_regs_1 (insn, XEXP (x, 1), mem_mode, - subst_p, update_p, full_p); + subst_p, update_p, + update_sp_offset, full_p); if (new0 != XEXP (x, 0) || new1 != XEXP (x, 1)) return form_sum (new0, new1); @@ -415,11 +452,12 @@ lra_eliminate_regs_1 (rtx insn, rtx x, enum machine_mode mem_mode, rtx to = subst_p ? ep->to_rtx : ep->from_rtx; if (update_p) - return - plus_constant (Pmode, - gen_rtx_MULT (Pmode, to, XEXP (x, 1)), - (ep->offset - ep->previous_offset) - * INTVAL (XEXP (x, 1))); + return plus_constant (Pmode, + gen_rtx_MULT (Pmode, to, XEXP (x, 1)), + (ep->offset - ep->previous_offset + + (ep->to_rtx == stack_pointer_rtx + ? update_sp_offset : 0)) + * INTVAL (XEXP (x, 1))); else if (full_p) { HOST_WIDE_INT offset = ep->offset; @@ -451,10 +489,12 @@ lra_eliminate_regs_1 (rtx insn, rtx x, enum machine_mode mem_mode, case LE: case LT: case LEU: case LTU: { rtx new0 = lra_eliminate_regs_1 (insn, XEXP (x, 0), mem_mode, - subst_p, update_p, full_p); + subst_p, update_p, + update_sp_offset, full_p); rtx new1 = XEXP (x, 1) ? lra_eliminate_regs_1 (insn, XEXP (x, 1), mem_mode, - subst_p, update_p, full_p) : 0; + subst_p, update_p, + update_sp_offset, full_p) : 0; if (new0 != XEXP (x, 0) || new1 != XEXP (x, 1)) return gen_rtx_fmt_ee (code, GET_MODE (x), new0, new1); @@ -467,7 +507,8 @@ lra_eliminate_regs_1 (rtx insn, rtx x, enum machine_mode mem_mode, if (XEXP (x, 0)) { new_rtx = lra_eliminate_regs_1 (insn, XEXP (x, 0), mem_mode, - subst_p, update_p, full_p); + subst_p, update_p, + update_sp_offset, full_p); if (new_rtx != XEXP (x, 0)) { /* If this is a REG_DEAD note, it is not valid anymore. @@ -476,7 +517,8 @@ lra_eliminate_regs_1 (rtx insn, rtx x, enum machine_mode mem_mode, if (REG_NOTE_KIND (x) == REG_DEAD) return (XEXP (x, 1) ? lra_eliminate_regs_1 (insn, XEXP (x, 1), mem_mode, - subst_p, update_p, full_p) + subst_p, update_p, + update_sp_offset, full_p) : NULL_RTX); x = alloc_reg_note (REG_NOTE_KIND (x), new_rtx, XEXP (x, 1)); @@ -493,7 +535,8 @@ lra_eliminate_regs_1 (rtx insn, rtx x, enum machine_mode mem_mode, if (XEXP (x, 1)) { new_rtx = lra_eliminate_regs_1 (insn, XEXP (x, 1), mem_mode, - subst_p, update_p, full_p); + subst_p, update_p, + update_sp_offset, full_p); if (new_rtx != XEXP (x, 1)) return gen_rtx_fmt_ee (GET_CODE (x), GET_MODE (x), @@ -520,8 +563,8 @@ lra_eliminate_regs_1 (rtx insn, rtx x, enum machine_mode mem_mode, && XEXP (XEXP (x, 1), 0) == XEXP (x, 0)) { rtx new_rtx = lra_eliminate_regs_1 (insn, XEXP (XEXP (x, 1), 1), - mem_mode, - subst_p, update_p, full_p); + mem_mode, subst_p, update_p, + update_sp_offset, full_p); if (new_rtx != XEXP (XEXP (x, 1), 1)) return gen_rtx_fmt_ee (code, GET_MODE (x), XEXP (x, 0), @@ -545,14 +588,16 @@ lra_eliminate_regs_1 (rtx insn, rtx x, enum machine_mode mem_mode, case PARITY: case BSWAP: new_rtx = lra_eliminate_regs_1 (insn, XEXP (x, 0), mem_mode, - subst_p, update_p, full_p); + subst_p, update_p, + update_sp_offset, full_p); if (new_rtx != XEXP (x, 0)) return gen_rtx_fmt_e (code, GET_MODE (x), new_rtx); return x; case SUBREG: new_rtx = lra_eliminate_regs_1 (insn, SUBREG_REG (x), mem_mode, - subst_p, update_p, full_p); + subst_p, update_p, + update_sp_offset, full_p); if (new_rtx != SUBREG_REG (x)) { @@ -590,12 +635,12 @@ lra_eliminate_regs_1 (rtx insn, rtx x, enum machine_mode mem_mode, replace_equiv_address_nv (x, lra_eliminate_regs_1 (insn, XEXP (x, 0), GET_MODE (x), - subst_p, update_p, full_p)); + subst_p, update_p, update_sp_offset, full_p)); case USE: /* Handle insn_list USE that a call to a pure function may generate. */ new_rtx = lra_eliminate_regs_1 (insn, XEXP (x, 0), VOIDmode, - subst_p, update_p, full_p); + subst_p, update_p, update_sp_offset, full_p); if (new_rtx != XEXP (x, 0)) return gen_rtx_USE (GET_MODE (x), new_rtx); return x; @@ -616,7 +661,8 @@ lra_eliminate_regs_1 (rtx insn, rtx x, enum machine_mode mem_mode, if (*fmt == 'e') { new_rtx = lra_eliminate_regs_1 (insn, XEXP (x, i), mem_mode, - subst_p, update_p, full_p); + subst_p, update_p, + update_sp_offset, full_p); if (new_rtx != XEXP (x, i) && ! copied) { x = shallow_copy_rtx (x); @@ -630,7 +676,8 @@ lra_eliminate_regs_1 (rtx insn, rtx x, enum machine_mode mem_mode, for (j = 0; j < XVECLEN (x, i); j++) { new_rtx = lra_eliminate_regs_1 (insn, XVECEXP (x, i, j), mem_mode, - subst_p, update_p, full_p); + subst_p, update_p, + update_sp_offset, full_p); if (new_rtx != XVECEXP (x, i, j) && ! copied_vec) { rtvec new_v = gen_rtvec_v (XVECLEN (x, i), @@ -654,10 +701,10 @@ lra_eliminate_regs_1 (rtx insn, rtx x, enum machine_mode mem_mode, /* This function is used externally in subsequent passes of GCC. It always does a full elimination of X. */ rtx -lra_eliminate_regs (rtx x, enum machine_mode mem_mode, +lra_eliminate_regs (rtx x, machine_mode mem_mode, rtx insn ATTRIBUTE_UNUSED) { - return lra_eliminate_regs_1 (NULL_RTX, x, mem_mode, true, false, true); + return lra_eliminate_regs_1 (NULL, x, mem_mode, true, false, 0, true); } /* Stack pointer offset before the current insn relative to one at the @@ -671,10 +718,10 @@ static HOST_WIDE_INT curr_sp_change; MEM_MODE is the mode of an enclosing MEM rtx, or VOIDmode if not within a MEM. */ static void -mark_not_eliminable (rtx x, enum machine_mode mem_mode) +mark_not_eliminable (rtx x, machine_mode mem_mode) { enum rtx_code code = GET_CODE (x); - struct elim_table *ep; + struct lra_elim_table *ep; int i, j; const char *fmt; @@ -842,13 +889,15 @@ remove_reg_equal_offset_note (rtx insn, rtx what) If REPLACE_P is false, just update the offsets while keeping the base register the same. If FIRST_P, use the sp offset for - elimination to sp. Attach the note about used elimination for - insns setting frame pointer to update elimination easy (without - parsing already generated elimination insns to find offset - previously used) in future. */ + elimination to sp. Otherwise, use UPDATE_SP_OFFSET for this. + Attach the note about used elimination for insns setting frame + pointer to update elimination easy (without parsing already + generated elimination insns to find offset previously used) in + future. */ -static void -eliminate_regs_in_insn (rtx insn, bool replace_p, bool first_p) +void +eliminate_regs_in_insn (rtx_insn *insn, bool replace_p, bool first_p, + HOST_WIDE_INT update_sp_offset) { int icode = recog_memoized (insn); rtx old_set = single_set (insn); @@ -856,7 +905,7 @@ eliminate_regs_in_insn (rtx insn, bool replace_p, bool first_p) int i; rtx substed_operand[MAX_RECOG_OPERANDS]; rtx orig_operand[MAX_RECOG_OPERANDS]; - struct elim_table *ep; + struct lra_elim_table *ep; rtx plus_src, plus_cst_src; lra_insn_recog_data_t id; struct lra_static_insn_data *static_id; @@ -978,8 +1027,13 @@ eliminate_regs_in_insn (rtx insn, bool replace_p, bool first_p) if (! replace_p) { offset += (ep->offset - ep->previous_offset); - if (first_p && ep->to_rtx == stack_pointer_rtx) - offset -= lra_get_insn_recog_data (insn)->sp_offset; + if (ep->to_rtx == stack_pointer_rtx) + { + if (first_p) + offset -= lra_get_insn_recog_data (insn)->sp_offset; + else + offset += update_sp_offset; + } offset = trunc_int_for_mode (offset, GET_MODE (plus_cst_src)); } @@ -1053,7 +1107,7 @@ eliminate_regs_in_insn (rtx insn, bool replace_p, bool first_p) substed_operand[i] = lra_eliminate_regs_1 (insn, *id->operand_loc[i], VOIDmode, replace_p, ! replace_p && ! first_p, - first_p); + update_sp_offset, first_p); if (substed_operand[i] != orig_operand[i]) validate_p = true; } @@ -1086,7 +1140,7 @@ spill_pseudos (HARD_REG_SET set) { int i; bitmap_head to_process; - rtx insn; + rtx_insn *insn; if (hard_reg_set_empty_p (set)) return; @@ -1130,7 +1184,7 @@ static bool update_reg_eliminate (bitmap insns_with_changed_offsets) { bool prev, result; - struct elim_table *ep, *ep1; + struct lra_elim_table *ep, *ep1; HARD_REG_SET temp_hard_reg_set; /* Clear self elimination offsets. */ @@ -1164,7 +1218,9 @@ update_reg_eliminate (bitmap insns_with_changed_offsets) ep->from, ep->to); /* If after processing RTL we decides that SP can be used as a result of elimination, it can not be changed. */ - gcc_assert (ep->to_rtx != stack_pointer_rtx); + gcc_assert ((ep->to_rtx != stack_pointer_rtx) + || (ep->from < FIRST_PSEUDO_REGISTER + && fixed_regs [ep->from])); /* Mark that is not eliminable anymore. */ elimination_map[ep->from] = NULL; for (ep1 = ep + 1; ep1 < ®_eliminate[NUM_ELIMINABLE_REGS]; ep1++) @@ -1235,14 +1291,14 @@ update_reg_eliminate (bitmap insns_with_changed_offsets) static void init_elim_table (void) { - struct elim_table *ep; + struct lra_elim_table *ep; #ifdef ELIMINABLE_REGS bool value_p; const struct elim_table_1 *ep1; #endif if (!reg_eliminate) - reg_eliminate = XCNEWVEC (struct elim_table, NUM_ELIMINABLE_REGS); + reg_eliminate = XCNEWVEC (struct lra_elim_table, NUM_ELIMINABLE_REGS); memset (self_elim_offsets, 0, sizeof (self_elim_offsets)); /* Initiate member values which will be never changed. */ @@ -1290,8 +1346,8 @@ init_elimination (void) { bool stop_to_sp_elimination_p; basic_block bb; - rtx insn; - struct elim_table *ep; + rtx_insn *insn; + struct lra_elim_table *ep; init_elim_table (); FOR_EACH_BB_FN (bb, cfun) @@ -1325,7 +1381,7 @@ void lra_eliminate_reg_if_possible (rtx *loc) { int regno; - struct elim_table *ep; + struct lra_elim_table *ep; lra_assert (REG_P (*loc)); if ((regno = REGNO (*loc)) >= FIRST_PSEUDO_REGISTER @@ -1339,9 +1395,9 @@ lra_eliminate_reg_if_possible (rtx *loc) the insn for subsequent processing in the constraint pass, update the insn info. */ static void -process_insn_for_elimination (rtx insn, bool final_p, bool first_p) +process_insn_for_elimination (rtx_insn *insn, bool final_p, bool first_p) { - eliminate_regs_in_insn (insn, final_p, first_p); + eliminate_regs_in_insn (insn, final_p, first_p, 0); if (! final_p) { /* Check that insn changed its code. This is a case when a move @@ -1369,7 +1425,7 @@ lra_eliminate (bool final_p, bool first_p) unsigned int uid; bitmap_head insns_with_changed_offsets; bitmap_iterator bi; - struct elim_table *ep; + struct lra_elim_table *ep; gcc_assert (! final_p || ! first_p); |