Thanks,
Feng

________________________________________
From: Feng Xue OS <f...@os.amperecomputing.com>
Sent: Thursday, September 3, 2020 5:29 PM
To: Richard Biener; gcc-patches@gcc.gnu.org
Subject: Re: [PATCH 2/2 V3] Simplify plusminus-mult-with-convert expr in 
forwprop (PR 94234)

Attach patch file.

Feng
________________________________________
From: Gcc-patches <gcc-patches-boun...@gcc.gnu.org> on behalf of Feng Xue OS 
via Gcc-patches <gcc-patches@gcc.gnu.org>
Sent: Thursday, September 3, 2020 5:27 PM
To: Richard Biener; gcc-patches@gcc.gnu.org
Subject: [PATCH 2/2 V3] Simplify plusminus-mult-with-convert expr in forwprop 
(PR 94234)

This patch is to handle simplification of plusminus-mult-with-convert expression
as ((T) X) +- ((T) Y), in which at least one of (X, Y) is result of 
multiplication.
This is done in forwprop pass. We try to transform it to (T) (X +- Y), and 
resort
to gimple-matcher to fold (X +- Y) instead of manually code pattern recognition.

Regards,
Feng
---
2020-09-03  Feng Xue  <f...@os.amperecomputing.com>

gcc/
        PR tree-optimization/94234
        * tree-ssa-forwprop.c (simplify_plusminus_mult_with_convert): New
        function.
        (fwprop_ssa_val): Move it before its new caller.
        (pass_forwprop::execute): Add call to
        simplify_plusminus_mult_with_convert.

gcc/testsuite/
        PR tree-optimization/94234
        * gcc.dg/pr94234-3.c: New test.
From 98c4b97989207dcef5742e9cb451799feafd125e Mon Sep 17 00:00:00 2001
From: Feng Xue <f...@os.amperecomputing.com>
Date: Mon, 17 Aug 2020 23:00:35 +0800
Subject: [PATCH] tree-optimization/94234 - simplify
 plusminus-mult-with-convert in forwprop

For expression as ((T) X) +- ((T) Y), and at lease of (X, Y) is result of
multification, try to transform it to (T) (X +- Y), and apply simplification
on (X +- Y) if possible. In this way, we can avoid creating almost duplicated
rule to handle plusminus-mult-with-convert variant.

2020-09-03  Feng Xue  <f...@os.amperecomputing.com>

gcc/
	PR tree-optimization/94234
	* tree-ssa-forwprop.c (simplify_plusminus_mult_with_convert): New
	function.
	(fwprop_ssa_val): Move it before its new caller.
	(pass_forwprop::execute): Add call to
	simplify_plusminus_mult_with_convert.

gcc/testsuite/
	PR tree-optimization/94234
 	* gcc.dg/pr94234-3.c: New test.
---
 gcc/testsuite/gcc.dg/pr94234-3.c |  42 ++++++++
 gcc/tree-ssa-forwprop.c          | 168 +++++++++++++++++++++++++++----
 2 files changed, 191 insertions(+), 19 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr94234-3.c

diff --git a/gcc/testsuite/gcc.dg/pr94234-3.c b/gcc/testsuite/gcc.dg/pr94234-3.c
new file mode 100644
index 00000000000..9bb9b46bd96
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr94234-3.c
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-forwprop1" } */
+
+typedef __SIZE_TYPE__ size_t;
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+
+ptrdiff_t foo1 (char *a, size_t n)
+{
+  char *b1 = a + 8 * n;
+  char *b2 = a + 8 * (n - 1);
+
+  return b1 - b2;
+}
+
+int use_ptr (char *a, char *b);
+
+ptrdiff_t foo2 (char *a, size_t n)
+{
+  char *b1 = a + 8 * (n - 1);
+  char *b2 = a + 8 * n;
+
+  use_ptr (b1, b2);
+
+  return b1 - b2;
+}
+
+int use_int (int i);
+
+unsigned goo (unsigned m_param, unsigned n_param)
+{
+  unsigned b1 = m_param * (n_param + 2);
+  unsigned b2 = m_param * (n_param + 1);
+  int r = (int)(b1) - (int)(b2);
+
+  use_int (r);
+
+  return r;
+}
+
+/* { dg-final { scan-tree-dump-times "return 8;" 1 "forwprop1" } } */
+/* { dg-final { scan-tree-dump-times "return -8;" 1 "forwprop1" } } */
+/* { dg-final { scan-tree-dump-times "return m_param" 1 "forwprop1" } } */
diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c
index e2d008dfb92..7b9d46ec919 100644
--- a/gcc/tree-ssa-forwprop.c
+++ b/gcc/tree-ssa-forwprop.c
@@ -338,6 +338,25 @@ remove_prop_source_from_use (tree name)
   return cfg_changed;
 }
 
+/* Primitive "lattice" function for gimple_simplify.  */
+
+static tree
+fwprop_ssa_val (tree name)
+{
+  /* First valueize NAME.  */
+  if (TREE_CODE (name) == SSA_NAME
+      && SSA_NAME_VERSION (name) < lattice.length ())
+    {
+      tree val = lattice[SSA_NAME_VERSION (name)];
+      if (val)
+	name = val;
+    }
+  /* We continue matching along SSA use-def edges for SSA names
+     that are not single-use.  Currently there are no patterns
+     that would cause any issues with that.  */
+  return name;
+}
+
 /* Return the rhs of a gassign *STMT in a form of a single tree,
    converted to type TYPE.
 
@@ -1821,6 +1840,133 @@ simplify_rotate (gimple_stmt_iterator *gsi)
   return true;
 }
 
+/* Given ((T) X) +- ((T) Y), and at least one of (X, Y) is result of
+   multiplication, if the expr can be transformed to (T) (X +- Y) in terms of
+   two's complement computation, apply simplification on (X +- Y) if it is
+   possible.  As a prerequisite, outer result type (T) has precision not more
+   than that of inner operand type.  */
+
+static bool
+simplify_plusminus_mult_with_convert (gimple_stmt_iterator *gsi)
+{
+  gimple *stmt = gsi_stmt (*gsi);
+  tree lhs = gimple_assign_lhs (stmt);
+  tree rtype = TREE_TYPE (lhs);
+  tree ctype = NULL_TREE;
+  enum tree_code code = gimple_assign_rhs_code (stmt);
+
+  if (code != PLUS_EXPR && code != MINUS_EXPR)
+    return false;
+
+  /* Skip arithemtic operations that need to preserve overflow for trapping
+     or sanitization.  */
+  if (!INTEGRAL_TYPE_P (rtype)
+      || TYPE_OVERFLOW_TRAPS (rtype) || TYPE_OVERFLOW_SANITIZED (rtype))
+    return false;
+
+  tree arg[2] = { gimple_assign_rhs1 (stmt), gimple_assign_rhs2 (stmt) };
+  bool any_single_use = false;
+  bool has_mult = false;
+
+  for (int i = 0; i < 2; i++)
+    {
+      if (TREE_CODE (arg[i]) == SSA_NAME)
+	{
+	  tree def_arg, tem;
+	  enum tree_code def_code;
+
+	  defcodefor_name (arg[i], &def_code, &def_arg, NULL);
+
+	  if (!CONVERT_EXPR_CODE_P (def_code))
+	    return false;
+
+	  if (!ctype)
+	    {
+	      ctype = TREE_TYPE (def_arg);
+
+	      if (!INTEGRAL_TYPE_P (ctype)
+		  || TYPE_PRECISION (ctype) < TYPE_PRECISION (rtype))
+		return false;
+
+	      if (i)
+		{
+		  /* The other operand should be a constant, convert it to
+		     inner operand type. */
+		  arg[0] = wide_int_to_tree (ctype, wi::to_wide (arg[0]));
+		}
+	    }
+	  else if (!types_compatible_p (ctype, TREE_TYPE (def_arg)))
+	    return false;
+
+	  defcodefor_name (def_arg, &def_code, &tem, NULL);
+
+	  if (def_code == MULT_EXPR)
+	    has_mult = true;
+
+	  if (has_single_use (arg[i]))
+	    any_single_use = true;
+
+	  arg[i] = def_arg;
+	}
+      else if (TREE_CODE (arg[i]) == INTEGER_CST)
+	{
+	  if (!ctype)
+	    return false;
+
+	  /* This operand is a constant, convert it to inner operand type. */
+	  arg[i] = wide_int_to_tree (ctype, wi::to_wide (arg[i]));
+	}
+      else
+	return false;
+    }
+
+  if (!has_mult)
+    return false;
+
+  gimple_seq seq = NULL;
+  gimple_seq *pseq = any_single_use ? &seq : NULL;
+  gimple *g;
+  tree val;
+
+  if (TYPE_OVERFLOW_WRAPS (ctype))
+    /* Arithmetic operation on inner operands is using two's complement
+       representation in both overflow and normal cases, UB will not occur
+       and type conversion is trivial.  */
+    ;
+  else if (TYPE_SIGN (ctype) == TYPE_SIGN (rtype))
+    /* Both outer result type and inner operand type are signed.  Here outer
+       result type should be TYPE_OVERFLOW_UNDEFINED, and inner operand type
+       also does not incur overflow since it is larger.  It is UB-safe to do
+       arithmetic operation on large signed type, and truncate to small
+       signed type.  */
+    ;
+  else
+    /* Outer result type is unsigned, while inner operand type is signed. We
+       only consider a case, in which final simplification result on inner
+       operands is a simple value (constant or existing SSA).  In this
+       situation, although operation on inner operands is of signed type, it
+       computes value for outer unsigned type. So we need not to care about
+       its overflowness.  */
+    pseq = NULL;
+
+  if (!(val = gimple_simplify (code, ctype, arg[0], arg[1], pseq,
+			       fwprop_ssa_val)))
+    return false;
+
+  if (TREE_CODE (val) == INTEGER_CST)
+    g = gimple_build_assign (lhs, NOP_EXPR,
+			     wide_int_to_tree (rtype, wi::to_wide (val)));
+  else if (TREE_CODE (val) == SSA_NAME)
+    g = gimple_build_assign (lhs, NOP_EXPR, val);
+  else
+    return false;
+
+  if (seq)
+    gsi_insert_seq_before (gsi, seq, GSI_SAME_STMT);
+
+  gsi_replace (gsi, g, false);
+  return true;
+}
 
 /* Check whether an array contains a valid ctz table.  */
 static bool
@@ -2640,25 +2786,6 @@ simplify_vector_constructor (gimple_stmt_iterator *gsi)
 }
 
 
-/* Primitive "lattice" function for gimple_simplify.  */
-
-static tree
-fwprop_ssa_val (tree name)
-{
-  /* First valueize NAME.  */
-  if (TREE_CODE (name) == SSA_NAME
-      && SSA_NAME_VERSION (name) < lattice.length ())
-    {
-      tree val = lattice[SSA_NAME_VERSION (name)];
-      if (val)
-	name = val;
-    }
-  /* We continue matching along SSA use-def edges for SSA names
-     that are not single-use.  Currently there are no patterns
-     that would cause any issues with that.  */
-  return name;
-}
-
 /* Main entry point for the forward propagation and statement combine
    optimizer.  */
 
@@ -3154,6 +3281,9 @@ pass_forwprop::execute (function *fun)
 			      || code == BIT_XOR_EXPR)
 			     && simplify_rotate (&gsi))
 		      changed = true;
+		    else if (TREE_CODE_CLASS (code) == tcc_binary
+			     && simplify_plusminus_mult_with_convert (&gsi))
+		      changed = true;
 		    else if (code == VEC_PERM_EXPR)
 		      {
 			int did_something = simplify_permutation (&gsi);
-- 
2.17.1

Reply via email to