This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 2/3] Simplify wrapped binops


match.pd part of the patch.

gcc/ChangeLog:

2017-05-18  Robin Dapp  <rdapp@linux.vnet.ibm.com>

	* match.pd: Simplify wrapped binary operations.
	* tree-vrp.c (extract_range_from_binary_expr_1): Add overflow
	parameter.
	(extract_range_from_binary_expr): Likewise.
	* tree-vrp.h: Export.
diff --git a/gcc/match.pd b/gcc/match.pd
index 80a17ba..3fa18b9 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -1290,6 +1290,85 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
     (if (cst && !TREE_OVERFLOW (cst))
      (plus { cst; } @0))))
 
+/* ((T)(A +- CST)) +- CST -> (T)(A) +- CST)  */
+#if GIMPLE
+   (for outer_op (plus minus)
+     (for inner_op (plus minus)
+       (simplify
+	 (outer_op (convert (inner_op@3 @0 INTEGER_CST@1)) INTEGER_CST@2)
+	   (if (TREE_CODE (type) == INTEGER_TYPE
+		&& TYPE_PRECISION (type) > TYPE_PRECISION (TREE_TYPE (@3)))
+	    (with
+	    {
+	      bool ovf = true;
+
+	      tree cst = NULL_TREE;
+	      tree inner_type = TREE_TYPE (@3);
+	      value_range vr = VR_INITIALIZER;
+
+	      /* Convert combined constant to tree of outer type if
+		 there was no overflow in the original operation.  */
+	      wide_int minv, maxv;
+	      if (TYPE_OVERFLOW_UNDEFINED (inner_type)
+		  || (extract_range_from_binary_expr (&vr, inner_op,
+		    inner_type, @0, @1, &ovf), vr.type == VR_RANGE))
+	      {
+		wide_int w1 = @1;
+		wide_int w2 = @2;
+
+		wide_int combined_cst;
+
+		/* Extend @1 to TYPE. */
+		w1 = w1.from (w1, TYPE_PRECISION (type),
+			      ovf ? SIGNED : TYPE_SIGN (TREE_TYPE (@1)));
+
+		if (inner_op == MINUS_EXPR)
+		  w1 = wi::neg (w1);
+
+		if (outer_op == MINUS_EXPR)
+		  w2 = wi::neg (w2);
+
+		/* Combine in outer, larger type.  */
+		combined_cst = wi::add (w1, w2);
+
+		cst = wide_int_to_tree (type, combined_cst);
+	      }
+	    }
+	(if (cst)
+	 (outer_op (convert @0) { cst; }))
+	)))))
+#endif
+
+/* ((T)(A)) +- CST -> (T)(A +- CST)  */
+#if GIMPLE
+   (for outer_op (plus minus)
+    (simplify
+     (outer_op (convert @0) INTEGER_CST@2)
+      (if (TYPE_PRECISION (type) > TYPE_PRECISION (TREE_TYPE (@0))
+	   && TREE_CODE (TREE_TYPE (@0)) == INTEGER_TYPE
+	   && TREE_CODE (type) == INTEGER_TYPE)
+       /* Perform binary operation inside the cast if the constant fits
+	  and there is no overflow.  */
+       (with
+	{
+	  bool ovf = true;
+	  tree cst_inner = NULL_TREE;
+	  value_range vr = VR_INITIALIZER;
+
+	  bool fits = int_fits_type_p (@2, TREE_TYPE (@0));
+	  if (fits)
+	  {
+	    tree cst_inner = fold_convert (TREE_TYPE (@0), @2);
+
+	    extract_range_from_binary_expr (&vr, outer_op, TREE_TYPE (@0),
+					    @0, cst_inner, &ovf);
+	  }
+	}
+	(if (vr.type == VR_RANGE && cst_inner)
+	 (convert (outer_op @0 { cst_inner; })))
+	))))
+#endif
+
   /* ~A + A -> -1 */
   (simplify
    (plus:c (bit_not @0) @0)
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 0db8a3c..00f99a8 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -63,8 +63,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "domwalk.h"
 #include "tree-cfgcleanup.h"
 
-#define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }
-
 /* Allocation pools for tree-vrp allocations.  */
 static object_allocator<value_range> vrp_value_range_pool ("Tree VRP value ranges");
 static bitmap_obstack vrp_equiv_obstack;
@@ -1940,7 +1938,8 @@ extract_range_from_multiplicative_op_1 (value_range *vr,
 static void
 extract_range_from_binary_expr_1 (value_range *vr,
 				  enum tree_code code, tree expr_type,
-				  value_range *vr0_, value_range *vr1_)
+				  value_range *vr0_, value_range *vr1_,
+				  bool *ovf)
 {
   value_range vr0 = *vr0_, vr1 = *vr1_;
   value_range vrtem0 = VR_INITIALIZER, vrtem1 = VR_INITIALIZER;
@@ -2012,12 +2011,13 @@ extract_range_from_binary_expr_1 (value_range *vr,
   if (vr0.type == VR_ANTI_RANGE
       && ranges_from_anti_range (&vr0, &vrtem0, &vrtem1))
     {
-      extract_range_from_binary_expr_1 (vr, code, expr_type, &vrtem0, vr1_);
+      extract_range_from_binary_expr_1 (vr, code, expr_type, &vrtem0, vr1_,
+					ovf);
       if (vrtem1.type != VR_UNDEFINED)
 	{
 	  value_range vrres = VR_INITIALIZER;
 	  extract_range_from_binary_expr_1 (&vrres, code, expr_type,
-					    &vrtem1, vr1_);
+					    &vrtem1, vr1_, ovf);
 	  vrp_meet (vr, &vrres);
 	}
       return;
@@ -2026,12 +2026,13 @@ extract_range_from_binary_expr_1 (value_range *vr,
   if (vr1.type == VR_ANTI_RANGE
       && ranges_from_anti_range (&vr1, &vrtem0, &vrtem1))
     {
-      extract_range_from_binary_expr_1 (vr, code, expr_type, vr0_, &vrtem0);
+      extract_range_from_binary_expr_1 (vr, code, expr_type, vr0_, &vrtem0,
+					ovf);
       if (vrtem1.type != VR_UNDEFINED)
 	{
 	  value_range vrres = VR_INITIALIZER;
 	  extract_range_from_binary_expr_1 (&vrres, code, expr_type,
-					    vr0_, &vrtem1);
+					    vr0_, &vrtem1, ovf);
 	  vrp_meet (vr, &vrres);
 	}
       return;
@@ -2270,6 +2271,10 @@ extract_range_from_binary_expr_1 (value_range *vr,
 		max_ovf = 1;
 	    }
 
+	  if (ovf != NULL)
+	    *ovf = (min_ovf == 1 && max_ovf == 1)
+	      || (min_ovf == -1 && max_ovf == -1);
+
 	  /* If we have overflow for the constant part and the resulting
 	     range will be symbolic, drop to VR_VARYING.  */
 	  if ((min_ovf && sym_min_op0 != sym_min_op1)
@@ -2589,7 +2594,7 @@ extract_range_from_binary_expr_1 (value_range *vr,
 	      saved_flag_wrapv = flag_wrapv;
 	      flag_wrapv = 1;
 	      extract_range_from_binary_expr_1 (vr, MULT_EXPR, expr_type,
-						&vr0, &vr1p);
+						&vr0, &vr1p, ovf);
 	      flag_wrapv = saved_flag_wrapv;
 	      return;
 	    }
@@ -3012,14 +3017,24 @@ extract_range_from_binary_expr_1 (value_range *vr,
     set_value_range (vr, type, min, max, NULL);
 }
 
+static void
+extract_range_from_binary_expr_1 (value_range *vr,
+				  enum tree_code code, tree expr_type,
+				  value_range *vr0_, value_range *vr1_)
+{
+  extract_range_from_binary_expr_1 (vr, code, expr_type,
+				    vr0_, vr1_, NULL);
+}
+
 /* Extract range information from a binary expression OP0 CODE OP1 based on
    the ranges of each of its operands with resulting type EXPR_TYPE.
    The resulting range is stored in *VR.  */
 
-static void
+void
 extract_range_from_binary_expr (value_range *vr,
 				enum tree_code code,
-				tree expr_type, tree op0, tree op1)
+				tree expr_type, tree op0, tree op1,
+				bool *ovf)
 {
   value_range vr0 = VR_INITIALIZER;
   value_range vr1 = VR_INITIALIZER;
@@ -3027,20 +3042,38 @@ extract_range_from_binary_expr (value_range *vr,
   /* Get value ranges for each operand.  For constant operands, create
      a new value range with the operand to simplify processing.  */
   if (TREE_CODE (op0) == SSA_NAME)
-    vr0 = *(get_value_range (op0));
+    {
+      value_range *vtmp = get_value_range (op0);
+      if (ovf != NULL && vtmp == NULL)
+	{
+	  vr->type = VR_VARYING;
+	  return;
+	}
+      else
+	vr0 = *vtmp;
+    }
   else if (is_gimple_min_invariant (op0))
     set_value_range_to_value (&vr0, op0, NULL);
   else
     set_value_range_to_varying (&vr0);
 
   if (TREE_CODE (op1) == SSA_NAME)
-    vr1 = *(get_value_range (op1));
+    {
+      value_range *vtmp = get_value_range (op1);
+      if (ovf != NULL && vtmp == NULL)
+	{
+	  vr->type = VR_VARYING;
+	  return;
+	}
+      else
+	vr1 = *vtmp;
+    }
   else if (is_gimple_min_invariant (op1))
     set_value_range_to_value (&vr1, op1, NULL);
   else
     set_value_range_to_varying (&vr1);
 
-  extract_range_from_binary_expr_1 (vr, code, expr_type, &vr0, &vr1);
+  extract_range_from_binary_expr_1 (vr, code, expr_type, &vr0, &vr1, ovf);
 
   /* Try harder for PLUS and MINUS if the range of one operand is symbolic
      and based on the other operand, for example if it was deduced from a
@@ -3068,7 +3101,7 @@ extract_range_from_binary_expr (value_range *vr,
       else
 	set_value_range (&n_vr1, VR_RANGE, op1, op1, NULL);
 
-      extract_range_from_binary_expr_1 (vr, code, expr_type, &vr0, &n_vr1);
+      extract_range_from_binary_expr_1 (vr, code, expr_type, &vr0, &n_vr1, ovf);
     }
 
   if (vr->type == VR_VARYING
@@ -3092,7 +3125,7 @@ extract_range_from_binary_expr (value_range *vr,
       else
 	set_value_range (&n_vr0, VR_RANGE, op0, op0, NULL);
 
-      extract_range_from_binary_expr_1 (vr, code, expr_type, &n_vr0, &vr1);
+      extract_range_from_binary_expr_1 (vr, code, expr_type, &n_vr0, &vr1, ovf);
     }
 
   /* If we didn't derive a range for MINUS_EXPR, and
@@ -3111,6 +3144,14 @@ extract_range_from_binary_expr (value_range *vr,
       set_value_range_to_nonnull (vr, TREE_TYPE (op0));
 }
 
+void
+extract_range_from_binary_expr (value_range *vr,
+				enum tree_code code,
+				tree expr_type, tree op0, tree op1)
+{
+  extract_range_from_binary_expr (vr, code, expr_type, op0, op1, NULL);
+}
+
 /* Extract range information from a unary operation CODE based on
    the range of its operand *VR0 with type OP0_TYPE with resulting type TYPE.
    The resulting range is stored in *VR.  */
diff --git a/gcc/tree-vrp.h b/gcc/tree-vrp.h
index ef2c68a..ad55ad2 100644
--- a/gcc/tree-vrp.h
+++ b/gcc/tree-vrp.h
@@ -56,4 +56,9 @@ extern void extract_range_from_unary_expr (value_range *vr,
 					   tree type,
 					   value_range *vr0_,
 					   tree op0_type);
+extern void extract_range_from_binary_expr (value_range *vr,
+				enum tree_code code,
+				tree expr_type, tree op0, tree op1,
+				bool *ovf);
 
+#define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]