Mercurial > hg > CbC > CbC_gcc
diff gcc/auto-inc-dec.c @ 131:84e7813d76e9
gcc-8.2
author | mir3636 |
---|---|
date | Thu, 25 Oct 2018 07:37:49 +0900 |
parents | 04ced10e8804 |
children | 1830386684a0 |
line wrap: on
line diff
--- a/gcc/auto-inc-dec.c Fri Oct 27 22:46:09 2017 +0900 +++ b/gcc/auto-inc-dec.c Thu Oct 25 07:37:49 2018 +0900 @@ -1,5 +1,5 @@ /* Discovery of auto-inc and auto-dec instructions. - Copyright (C) 2006-2017 Free Software Foundation, Inc. + Copyright (C) 2006-2018 Free Software Foundation, Inc. Contributed by Kenneth Zadeck <zadeck@naturalbridge.com> This file is part of GCC. @@ -152,14 +152,14 @@ static rtx mem_tmp; static enum inc_state -set_inc_state (HOST_WIDE_INT val, int size) +set_inc_state (HOST_WIDE_INT val, poly_int64 size) { if (val == 0) return INC_ZERO; if (val < 0) - return (val == -size) ? INC_NEG_SIZE : INC_NEG_ANY; + return known_eq (val, -size) ? INC_NEG_SIZE : INC_NEG_ANY; else - return (val == size) ? INC_POS_SIZE : INC_POS_ANY; + return known_eq (val, size) ? INC_POS_SIZE : INC_POS_ANY; } /* The DECISION_TABLE that describes what form, if any, the increment @@ -508,7 +508,11 @@ 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; @@ -601,7 +605,7 @@ inc_insn.reg_res : mem_insn.reg0; /* The width of the mem being accessed. */ - int size = GET_MODE_SIZE (GET_MODE (mem)); + poly_int64 size = GET_MODE_SIZE (GET_MODE (mem)); rtx_insn *last_insn = NULL; machine_mode reg_mode = GET_MODE (inc_reg); @@ -825,13 +829,15 @@ /* 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 @@ 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 @@ 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 @@ { /* 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 @@ { 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 @@ 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 @@ 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);