[PR81611] turn inc-and-use-of-dead-orig into auto-inc
authorAlexandre Oliva <aoliva@redhat.com>
Wed, 28 Feb 2018 05:25:34 +0000 (05:25 +0000)
committerAlexandre Oliva <aoliva@gcc.gnu.org>
Wed, 28 Feb 2018 05:25:34 +0000 (05:25 +0000)
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
gcc/auto-inc-dec.c

index f99e782d8aee0a658651ec1dd3e15a8ca8f6015a..8eedfcaaf82781b8f6acccbe8f0ba056da02cf47 100644 (file)
@@ -1,3 +1,14 @@
+2018-02-28  Alexandre Oliva <aoliva@redhat.com>
+
+       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  <msebor@redhat.com>
 
        PR c++/83871
index d02fa9d081c73708ef40244c81dc0eaba659c607..e6dc1c30d716fcfe44b7a09eeb0dfe5fa1c86c3b 100644 (file)
@@ -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);