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);