diff options
author | Alexandre Oliva <aoliva@redhat.com> | 2018-02-28 05:25:34 +0000 |
---|---|---|
committer | Alexandre Oliva <aoliva@gcc.gnu.org> | 2018-02-28 05:25:34 +0000 |
commit | 408e89356c698a8dd3731f38b1f6d9f01212fa34 (patch) | |
tree | 40df4cf8fec16353d624d51f5666f0b4d39adef8 /gcc/auto-inc-dec.c | |
parent | 8cda97ab52eae061d34167a1f786b43a21e7521b (diff) | |
download | gcc-408e89356c698a8dd3731f38b1f6d9f01212fa34.tar.gz |
[PR81611] turn inc-and-use-of-dead-orig into auto-inc
When the addressing modes available on the machine don't allow offsets
in addresses, odds are that post-increments will be represented in
trees and RTL as:
y <= x + 1
... *(x) ...
x <= y
so deal with it by turning such RTL as:
(set y (plus x n))
... (mem x) ...
without intervening uses of y into
(set y x)
... (mem (post_add y n)) ...
so as to create auto-inc addresses that we'd otherwise miss.
for gcc/ChangeLog
PR rtl-optimization/81611
* auto-inc-dec.c (attempt_change): Move dead note from
mem_insn if it's the next use of regno
(find_address): Take address use of reg holding
non-incremented value. Add parm to limit search to the named
reg only.
(merge_in_block): Attempt to use a mem insn that is the next
use of the original regno.
From-SVN: r258053
Diffstat (limited to 'gcc/auto-inc-dec.c')
-rw-r--r-- | gcc/auto-inc-dec.c | 140 |
1 files changed, 130 insertions, 10 deletions
diff --git a/gcc/auto-inc-dec.c b/gcc/auto-inc-dec.c index d02fa9d081c..e6dc1c30d71 100644 --- a/gcc/auto-inc-dec.c +++ b/gcc/auto-inc-dec.c @@ -508,7 +508,11 @@ attempt_change (rtx new_addr, rtx inc_reg) before the memory reference. */ gcc_assert (mov_insn); emit_insn_before (mov_insn, inc_insn.insn); - move_dead_notes (mov_insn, inc_insn.insn, inc_insn.reg0); + regno = REGNO (inc_insn.reg0); + if (reg_next_use[regno] == mem_insn.insn) + move_dead_notes (mov_insn, mem_insn.insn, inc_insn.reg0); + else + move_dead_notes (mov_insn, inc_insn.insn, inc_insn.reg0); regno = REGNO (inc_insn.reg_res); reg_next_def[regno] = mov_insn; @@ -825,13 +829,15 @@ parse_add_or_inc (rtx_insn *insn, bool before_mem) /* A recursive function that checks all of the mem uses in ADDRESS_OF_X to see if any single one of them is compatible with - what has been found in inc_insn. + what has been found in inc_insn. To avoid accidental matches, we + will only find MEMs with FINDREG, be it inc_insn.reg_res, be it + inc_insn.reg0. -1 is returned for success. 0 is returned if nothing was found and 1 is returned for failure. */ static int -find_address (rtx *address_of_x) +find_address (rtx *address_of_x, rtx findreg) { rtx x = *address_of_x; enum rtx_code code = GET_CODE (x); @@ -840,9 +846,10 @@ find_address (rtx *address_of_x) int value = 0; int tem; - if (code == MEM && rtx_equal_p (XEXP (x, 0), inc_insn.reg_res)) + if (code == MEM && findreg == inc_insn.reg_res + && rtx_equal_p (XEXP (x, 0), inc_insn.reg_res)) { - /* Match with *reg0. */ + /* Match with *reg_res. */ mem_insn.mem_loc = address_of_x; mem_insn.reg0 = inc_insn.reg_res; mem_insn.reg1_is_const = true; @@ -850,7 +857,21 @@ find_address (rtx *address_of_x) mem_insn.reg1 = GEN_INT (0); return -1; } - if (code == MEM && GET_CODE (XEXP (x, 0)) == PLUS + if (code == MEM && inc_insn.reg1_is_const && inc_insn.reg0 + && findreg == inc_insn.reg0 + && rtx_equal_p (XEXP (x, 0), inc_insn.reg0)) + { + /* Match with *reg0, assumed to be equivalent to + *(reg_res - reg1_val); callers must check whether this is the case. */ + mem_insn.mem_loc = address_of_x; + mem_insn.reg0 = inc_insn.reg_res; + mem_insn.reg1_is_const = true; + mem_insn.reg1_val = -inc_insn.reg1_val; + mem_insn.reg1 = GEN_INT (mem_insn.reg1_val); + return -1; + } + if (code == MEM && findreg == inc_insn.reg_res + && GET_CODE (XEXP (x, 0)) == PLUS && rtx_equal_p (XEXP (XEXP (x, 0), 0), inc_insn.reg_res)) { rtx b = XEXP (XEXP (x, 0), 1); @@ -879,7 +900,7 @@ find_address (rtx *address_of_x) { /* If REG occurs inside a MEM used in a bit-field reference, that is unacceptable. */ - if (find_address (&XEXP (x, 0))) + if (find_address (&XEXP (x, 0), findreg)) return 1; } @@ -891,7 +912,7 @@ find_address (rtx *address_of_x) { if (fmt[i] == 'e') { - tem = find_address (&XEXP (x, i)); + tem = find_address (&XEXP (x, i), findreg); /* If this is the first use, let it go so the rest of the insn can be checked. */ if (value == 0) @@ -905,7 +926,7 @@ find_address (rtx *address_of_x) int j; for (j = XVECLEN (x, i) - 1; j >= 0; j--) { - tem = find_address (&XVECEXP (x, i, j)); + tem = find_address (&XVECEXP (x, i, j), findreg); /* If this is the first use, let it go so the rest of the insn can be checked. */ if (value == 0) @@ -1360,7 +1381,106 @@ merge_in_block (int max_reg, basic_block bb) if (dump_file) dump_inc_insn (dump_file); - if (ok && find_address (&PATTERN (mem_insn.insn)) == -1) + if (ok && find_address (&PATTERN (mem_insn.insn), + inc_insn.reg_res) == -1) + { + if (dump_file) + dump_mem_insn (dump_file); + if (try_merge ()) + { + success_in_block++; + insn_is_add_or_inc = false; + } + } + } + + if (insn_is_add_or_inc + /* find_address will only recognize an address + with a reg0 that's not reg_res when + reg1_is_const, so cut it off early if we + already know it won't match. */ + && inc_insn.reg1_is_const + && inc_insn.reg0 + && inc_insn.reg0 != inc_insn.reg_res) + { + /* If we identified an inc_insn that uses two + different pseudos, it's of the form + + (set reg_res (plus reg0 reg1)) + + where reg1 is a constant (*). + + The next use of reg_res was not idenfied by + find_address as a mem_insn that we could turn + into auto-inc, so see if we find a suitable + MEM in the next use of reg0, as long as it's + before any subsequent use of reg_res: + + ... (mem (... reg0 ...)) ... + + ... reg_res ... + + In this case, we can turn the plus into a + copy, and the reg0 in the MEM address into a + post_inc of reg_res: + + (set reg_res reg0) + + ... (mem (... (post_add reg_res reg1) ...)) ... + + reg_res will then have the correct value at + subsequent uses, and reg0 will remain + unchanged. + + (*) We could support non-const reg1, but then + we'd have to check that reg1 remains + unchanged all the way to the modified MEM, + and we'd have to extend find_address to + represent a non-const negated reg1. */ + regno = REGNO (inc_insn.reg0); + rtx_insn *reg0_use = get_next_ref (regno, bb, + reg_next_use); + + /* Give up if the next use of reg0 is after the next + use of reg_res (same insn is ok; we might have + found a MEM with reg_res before, and that failed, + but now we try reg0, which might work), or defs + of reg_res (same insn is not ok, we'd introduce + another def in the same insn) or reg0. */ + if (reg0_use) + { + int luid = DF_INSN_LUID (reg0_use); + + /* It might seem pointless to introduce an + auto-inc if there's no subsequent use of + reg_res (i.e., mem_insn.insn == NULL), but + the next use might be in the next iteration + of a loop, and it won't hurt if we make the + change even if it's not needed. */ + if (mem_insn.insn + && luid > DF_INSN_LUID (mem_insn.insn)) + reg0_use = NULL; + + rtx_insn *other_insn + = get_next_ref (REGNO (inc_insn.reg_res), bb, + reg_next_def); + + if (other_insn && luid >= DF_INSN_LUID (other_insn)) + reg0_use = NULL; + + other_insn + = get_next_ref (REGNO (inc_insn.reg0), bb, + reg_next_def); + + if (other_insn && luid > DF_INSN_LUID (other_insn)) + reg0_use = NULL; + } + + mem_insn.insn = reg0_use; + + if (mem_insn.insn + && find_address (&PATTERN (mem_insn.insn), + inc_insn.reg0) == -1) { if (dump_file) dump_mem_insn (dump_file); |