From 408e89356c698a8dd3731f38b1f6d9f01212fa34 Mon Sep 17 00:00:00 2001 From: Alexandre Oliva Date: Wed, 28 Feb 2018 05:25:34 +0000 Subject: [PATCH] [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 --- gcc/ChangeLog | 11 ++++ gcc/auto-inc-dec.c | 140 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 141 insertions(+), 10 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f99e782d8ae..8eedfcaaf82 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2018-02-28 Alexandre Oliva + + 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. + 2018-02-27 Martin Sebor PR c++/83871 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); -- 2.30.2