diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 12 | ||||
-rw-r--r-- | gcc/reload.c | 38 | ||||
-rw-r--r-- | gcc/reload.h | 1 | ||||
-rw-r--r-- | gcc/reload1.c | 15 |
4 files changed, 66 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 240bddb..9794ce2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2006-08-17 Alexandre Oliva <aoliva@redhat.com> + + PR target/28146 + * reload.h (reg_equiv_alt_mem_list): New declaration. + * reload1.c (reg_equiv_alt_mem_list): New definition. + (reload): Initialize it and release it. + (delete_output_reload): Use it. + * reload.c (push_reg_equiv_alt_mem): New function. + (find_reloads_toplev): Call it. + (find_reloads_address, find_reloads_address_1): Likewise. + (find_reloads_subreg_address): Likewise. + 2006-08-17 Maxim Kuvyrkov <mkuvyrkov@ispras.ru> PR rtl-optimization/28489 diff --git a/gcc/reload.c b/gcc/reload.c index c8c48b1..e1a4abc 100644 --- a/gcc/reload.c +++ b/gcc/reload.c @@ -283,6 +283,23 @@ static int find_inc_amount (rtx, rtx); static int refers_to_mem_for_reload_p (rtx); static int refers_to_regno_for_reload_p (unsigned int, unsigned int, rtx, rtx *); + +/* Add NEW to reg_equiv_alt_mem_list[REGNO] if it's not present in the + list yet. */ + +static void +push_reg_equiv_alt_mem (int regno, rtx mem) +{ + rtx it; + + for (it = reg_equiv_alt_mem_list [regno]; it; it = XEXP (it, 1)) + if (rtx_equal_p (XEXP (it, 0), mem)) + return; + + reg_equiv_alt_mem_list [regno] + = alloc_EXPR_LIST (REG_EQUIV, mem, + reg_equiv_alt_mem_list [regno]); +} /* Determine if any secondary reloads are needed for loading (if IN_P is nonzero) or storing (if IN_P is zero) X to or from a reload register of @@ -4553,6 +4570,8 @@ find_reloads_toplev (rtx x, int opnum, enum reload_type type, x = mem; i = find_reloads_address (GET_MODE (x), &x, XEXP (x, 0), &XEXP (x, 0), opnum, type, ind_levels, insn); + if (x != mem) + push_reg_equiv_alt_mem (regno, x); if (address_reloaded) *address_reloaded = i; } @@ -4761,9 +4780,13 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad, tem = make_memloc (ad, regno); if (! strict_memory_address_p (GET_MODE (tem), XEXP (tem, 0))) { + rtx orig = tem; + find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0), &XEXP (tem, 0), opnum, ADDR_TYPE (type), ind_levels, insn); + if (tem != orig) + push_reg_equiv_alt_mem (regno, tem); } /* We can avoid a reload if the register's equivalent memory expression is valid as an indirect memory address. @@ -5545,6 +5568,8 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context, if (reg_equiv_address[regno] || ! rtx_equal_p (tem, reg_equiv_mem[regno])) { + rtx orig = tem; + /* First reload the memory location's address. We can't use ADDR_TYPE (type) here, because we need to write back the value after reading it, hence we actually @@ -5554,6 +5579,9 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context, RELOAD_OTHER, ind_levels, insn); + if (tem != orig) + push_reg_equiv_alt_mem (regno, tem); + /* Then reload the memory location into a base register. */ reloadnum = push_reload (tem, tem, &XEXP (x, 0), @@ -5609,6 +5637,8 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context, if (reg_equiv_address[regno] || ! rtx_equal_p (tem, reg_equiv_mem[regno])) { + rtx orig = tem; + /* First reload the memory location's address. We can't use ADDR_TYPE (type) here, because we need to write back the value after reading it, hence we actually @@ -5616,6 +5646,8 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context, find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0), &XEXP (tem, 0), opnum, type, ind_levels, insn); + if (tem != orig) + push_reg_equiv_alt_mem (regno, tem); /* Put this inside a new increment-expression. */ x = gen_rtx_fmt_e (GET_CODE (x), GET_MODE (x), tem); /* Proceed to reload that, as if it contained a register. */ @@ -5806,6 +5838,8 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context, find_reloads_address (GET_MODE (x), &x, XEXP (x, 0), &XEXP (x, 0), opnum, ADDR_TYPE (type), ind_levels, insn); + if (x != tem) + push_reg_equiv_alt_mem (regno, x); } } @@ -5993,6 +6027,7 @@ find_reloads_subreg_address (rtx x, int force_replace, int opnum, unsigned outer_size = GET_MODE_SIZE (GET_MODE (x)); unsigned inner_size = GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))); int offset; + rtx orig = tem; /* For big-endian paradoxical subregs, SUBREG_BYTE does not hold the correct (negative) byte offset. */ @@ -6028,6 +6063,9 @@ find_reloads_subreg_address (rtx x, int force_replace, int opnum, find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0), &XEXP (tem, 0), opnum, type, ind_levels, insn); + /* ??? Do we need to handle nonzero offsets somehow? */ + if (!offset && tem != orig) + push_reg_equiv_alt_mem (regno, tem); /* If this is not a toplevel operand, find_reloads doesn't see this substitution. We have to emit a USE of the pseudo so diff --git a/gcc/reload.h b/gcc/reload.h index fbb315e..6de5e847 100644 --- a/gcc/reload.h +++ b/gcc/reload.h @@ -161,6 +161,7 @@ extern rtx *reg_equiv_invariant; extern rtx *reg_equiv_memory_loc; extern rtx *reg_equiv_address; extern rtx *reg_equiv_mem; +extern rtx *reg_equiv_alt_mem_list; /* Element N is the list of insns that initialized reg N from its equivalent constant or memory slot. */ diff --git a/gcc/reload1.c b/gcc/reload1.c index 210b007..8ce042f 100644 --- a/gcc/reload1.c +++ b/gcc/reload1.c @@ -123,6 +123,10 @@ rtx *reg_equiv_address; 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; @@ -703,6 +707,7 @@ reload (rtx first, int global) 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); @@ -1260,6 +1265,11 @@ reload (rtx first, int global) 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); @@ -7849,6 +7859,11 @@ delete_output_reload (rtx insn, int j, int last_reload_reg) n_occurrences += count_occurrences (PATTERN (insn), eliminate_regs (substed, 0, NULL_RTX), 0); + for (i1 = reg_equiv_alt_mem_list [REGNO (reg)]; i1; i1 = XEXP (i1, 1)) + { + gcc_assert (!rtx_equal_p (XEXP (i1, 0), substed)); + n_occurrences += count_occurrences (PATTERN (insn), XEXP (i1, 0), 0); + } if (n_occurrences > n_inherited) return; |