From d73ebecc7b78aab160af96b9738b81241e8eecd8 Mon Sep 17 00:00:00 2001
From: shivac <shivac@marvell.com>
Date: Tue, 3 May 2016 14:07:11 +0800
Subject: [PATCH 7/7] To identify READ_WRITE_REG as loop induction variable

	modified:   loop-iv.c
---
 gcc/loop-iv.c | 210 +++++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 186 insertions(+), 24 deletions(-)

diff --git a/gcc/loop-iv.c b/gcc/loop-iv.c
index fecaf8f..10d9fed 100644
--- a/gcc/loop-iv.c
+++ b/gcc/loop-iv.c
@@ -350,10 +350,6 @@ iv_get_reaching_def (rtx_insn *insn, rtx reg, df_ref *def)
 
   adef = DF_REF_CHAIN (use)->ref;
 
-  /* We do not handle setting only part of the register.  */
-  if (DF_REF_FLAGS (adef) & DF_REF_READ_WRITE)
-    return GRD_INVALID;
-
   def_insn = DF_REF_INSN (adef);
   def_bb = DF_REF_BB (adef);
   use_bb = BLOCK_FOR_INSN (insn);
@@ -622,6 +618,87 @@ iv_shift (struct rtx_iv *iv, rtx mby)
   return true;
 }
 
+/* Return memory rtx if the REG is a read/write register
+   for memory reference in INSN.  */
+
+static rtx
+read_write_reg_mem (df_ref def, rtx_insn *insn)
+{
+  rtx reg = DF_REF_REG (def);
+  subrtx_var_iterator::array_type array;
+
+  if (!(DF_REF_FLAGS (def) & DF_REF_READ_WRITE))
+    return NULL_RTX;
+
+  FOR_EACH_SUBRTX_VAR (iter, array, PATTERN (insn), ALL)
+    {
+      rtx x = *iter;
+      if (GET_CODE (x) == MEM)
+	{
+	  enum rtx_code addr_code = GET_CODE (XEXP (x, 0));
+	  if (addr_code == POST_INC
+	      || addr_code == POST_DEC
+	      || addr_code == PRE_INC
+	      || addr_code == PRE_DEC)
+	    {
+	      if (rtx_equal_p (reg, XEXP (XEXP (x, 0), 0)))
+		return x;
+	    }
+	  if (addr_code == POST_MODIFY
+	      || addr_code == PRE_MODIFY)
+	    {
+	      rtx modify = XEXP (x, 0);
+	      if (rtx_equal_p (reg, XEXP (modify, 0))
+		  && rtx_equal_p (reg, XEXP (XEXP (modify, 1), 0))
+		  && CONST_INT_P (XEXP (XEXP (modify, 1), 1)))
+		return x;
+	    }
+	}
+    }
+  return NULL_RTX;
+}
+
+/* Return rtx expression in INSN which calculate REG result.  */
+
+static rtx
+get_reg_calculate_expr (rtx_insn *insn, rtx reg)
+{
+  int i;
+  rtx set, pattern, expr;
+
+  pattern = PATTERN (insn);
+
+  /* For identifying ivs, we can actually ignore any other
+     SETs occurring in parallel, so look for one with the
+     correct SET_DEST.  */
+  if (GET_CODE (pattern) == PARALLEL)
+    {
+      for (i = XVECLEN (pattern, 0) - 1; i >= 0; i--)
+	if (GET_CODE (XVECEXP (pattern, 0, i)) == SET)
+	  {
+	    if (SET_DEST (XVECEXP (pattern, 0, i)) == reg)
+	      {
+		pattern = XVECEXP (pattern, 0, i);
+		return SET_SRC (pattern);
+	      }
+	  }
+    }
+
+  set = single_set (insn);
+
+  if (!set)
+    return NULL_RTX;
+
+  expr = find_reg_equal_equiv_note (insn);
+
+  if (expr)
+    expr = XEXP (expr, 0);
+  else
+    expr = SET_SRC (set);
+
+  return expr;
+}
+
 /* The recursive part of get_biv_step.  Gets the value of the single value
    defined by DEF wrto initial value of REG inside loop, in shape described
    at get_biv_step.  */
@@ -632,22 +709,20 @@ get_biv_step_1 (df_ref def, rtx reg,
 		enum iv_extend_code *extend, machine_mode outer_mode,
 		rtx *outer_step)
 {
-  rtx set, rhs, op0 = NULL_RTX, op1 = NULL_RTX;
+  rtx rhs, op0 = NULL_RTX, op1 = NULL_RTX;
   rtx next, nextr;
-  enum rtx_code code;
+  enum rtx_code code, addr_code;
   rtx_insn *insn = DF_REF_INSN (def);
   df_ref next_def;
   enum iv_grd_result res;
 
-  set = single_set (insn);
-  if (!set)
-    return false;
+  rhs = read_write_reg_mem (def, insn);
 
-  rhs = find_reg_equal_equiv_note (insn);
-  if (rhs)
-    rhs = XEXP (rhs, 0);
-  else
-    rhs = SET_SRC (set);
+  if (!rhs)
+    rhs = get_reg_calculate_expr (insn, reg);
+
+  if (!rhs)
+    return false;
 
   code = GET_CODE (rhs);
   switch (code)
@@ -700,6 +775,21 @@ get_biv_step_1 (df_ref def, rtx reg,
       next = op0;
       break;
 
+    /* Allow READ_WRITE memory reference register
+       identify as IV.  */
+    case MEM:
+      op0 = XEXP (rhs, 0);
+      addr_code = GET_CODE (op0);
+      if (addr_code != POST_INC
+	  && addr_code != POST_DEC
+	  && addr_code != PRE_INC
+	  && addr_code != PRE_DEC
+	  && addr_code != PRE_MODIFY
+	  && addr_code != POST_MODIFY)
+	return false;
+      next = XEXP (op0, 0);
+      break;
+
     default:
       return false;
     }
@@ -777,6 +867,26 @@ get_biv_step_1 (df_ref def, rtx reg,
       *extend = (code == SIGN_EXTEND) ? IV_SIGN_EXTEND : IV_ZERO_EXTEND;
       break;
 
+    /* Get inner_step by mode size for READ_WRITE
+       memory reference register.  */
+    case MEM:
+      gcc_assert (GET_CODE (op0) == POST_INC
+		  || GET_CODE (op0) == POST_DEC
+		  || GET_CODE (op0) == PRE_INC
+		  || GET_CODE (op0) == PRE_DEC
+		  || GET_CODE (op0) == PRE_MODIFY
+		  || GET_CODE (op0) == POST_MODIFY);
+
+      if (GET_CODE (op0) == POST_INC
+	  || GET_CODE (op0) == PRE_INC)
+	*inner_step = GEN_INT (GET_MODE_SIZE (GET_MODE (rhs)));
+      else if (GET_CODE (op0) == POST_DEC
+	       || GET_CODE (op0) == PRE_DEC)
+	*inner_step = GEN_INT (-GET_MODE_SIZE (GET_MODE (rhs)));
+      else
+	*inner_step = XEXP (XEXP (op0, 1), 1);
+      break;
+
     default:
       return false;
     }
@@ -936,14 +1046,13 @@ iv_analyze_expr (rtx_insn *insn, rtx rhs, machine_mode mode,
   rtx op0 = NULL_RTX, op1 = NULL_RTX;
   struct rtx_iv iv0, iv1;
   enum rtx_code code = GET_CODE (rhs);
+  enum rtx_code addr_code;
   machine_mode omode = mode;
 
   iv->mode = VOIDmode;
   iv->base = NULL_RTX;
   iv->step = NULL_RTX;
 
-  gcc_assert (GET_MODE (rhs) == mode || GET_MODE (rhs) == VOIDmode);
-
   if (CONSTANT_P (rhs)
       || REG_P (rhs)
       || code == SUBREG)
@@ -995,6 +1104,33 @@ iv_analyze_expr (rtx_insn *insn, rtx rhs, machine_mode mode,
 	return false;
       break;
 
+    case MEM:
+      op0 = XEXP (rhs, 0);
+      omode = GET_MODE (op0);
+      addr_code = GET_CODE (op0);
+
+      if (addr_code != POST_INC
+	  && addr_code != POST_DEC
+	  && addr_code != PRE_INC
+	  && addr_code != PRE_DEC
+	  && addr_code != PRE_MODIFY
+	  && addr_code != POST_MODIFY)
+	return false;
+      break;
+
+    case POST_INC:
+    case POST_DEC:
+    case PRE_INC:
+    case PRE_DEC:
+      op0 = XEXP (rhs, 0);
+      break;
+
+    case PRE_MODIFY:
+    case POST_MODIFY:
+      op0 = XEXP (rhs, 0);
+      op1 = XEXP (rhs, 1);
+      break;
+
     default:
       return false;
     }
@@ -1040,6 +1176,9 @@ iv_analyze_expr (rtx_insn *insn, rtx rhs, machine_mode mode,
 	return false;
       break;
 
+    case MEM:
+      break;
+
     default:
       break;
     }
@@ -1085,15 +1224,13 @@ iv_analyze_def (df_ref def, struct rtx_iv *iv)
   if (!set)
     return false;
 
-  if (!REG_P (SET_DEST (set)))
-    return false;
+  rhs = read_write_reg_mem (def, insn);
 
-  gcc_assert (SET_DEST (set) == reg);
-  rhs = find_reg_equal_equiv_note (insn);
-  if (rhs)
-    rhs = XEXP (rhs, 0);
-  else
-    rhs = SET_SRC (set);
+  if (!rhs)
+    rhs = get_reg_calculate_expr (insn, reg);
+
+  if (!rhs)
+    return false;
 
   iv_analyze_expr (insn, rhs, GET_MODE (reg), iv);
   record_iv (def, iv);
@@ -2314,6 +2451,7 @@ iv_number_of_iterations (struct loop *loop, rtx_insn *insn, rtx condition,
 			 struct niter_desc *desc)
 {
   rtx op0, op1, delta, step, bound, may_xform, tmp, tmp0, tmp1;
+  rtx op0_const = NULL_RTX;
   struct rtx_iv iv0, iv1;
   rtx assumption, may_not_xform;
   enum rtx_code cond;
@@ -2354,12 +2492,36 @@ iv_number_of_iterations (struct loop *loop, rtx_insn *insn, rtx condition,
     goto fail;
 
   op0 = XEXP (condition, 0);
+
+  /* We would use loop induction variable analysis
+     to get loop iteration count in SMS pass
+     which should work with/without doloop pass
+     active or not.
+
+     With doloop pass enabled, doloop pass would
+     generate pattern as (ne (REG - 1), 0).
+     we recognize it by following code
+     and setting op0 = REG, op1 = 1.  */
+  if (GET_CODE (op0) == PLUS
+      && CONST_INT_P (XEXP (op0, 1))
+      && REG_P (XEXP (op0, 0)))
+    {
+      op0_const = XEXP (op0, 1);
+      op0 = XEXP (op0, 0);
+    }
+
   if (!iv_analyze (insn, op0, &iv0))
     goto fail;
   if (iv0.extend_mode == VOIDmode)
     iv0.mode = iv0.extend_mode = mode;
 
   op1 = XEXP (condition, 1);
+
+  /* Transfer constant in (ne (REG - 1), 0) to (ne (REG), 1)
+     op1 = 0 - (-1) = 1.  */
+  if (CONST_INT_P (op1) && op0_const)
+    op1 = GEN_INT (INTVAL (op1) - INTVAL (op0_const));
+
   if (!iv_analyze (insn, op1, &iv1))
     goto fail;
   if (iv1.extend_mode == VOIDmode)
-- 
2.5.0

