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]

Re: [PATCH 2/3] Simplify wrapped binops


>> Currently, extract_... () does that all that for me, is it really too
>> expensive to call? I guess, using get_range_info first and calling
>> extract when get_range_info returns a VR_RANGE is not really a favorable
>> thing to do either? :)
> Not only the cost, we should avoid introducing more interfaces while
> old ones can do the work.  Anyway, it's Richard's call here.

I rewrote the match.pd patterns to use get_range_info () now, keeping
track of an "ok" overflow (both min and max overflow) and one which does
not allow us to continue (min xor max overflow, split/anti range).  Test
suite on s390x has no regressions, bootstrap is ok, x86 running.

Regards
 Robin

--

gcc/ChangeLog:

2017-06-19  Robin Dapp  <rdapp@linux.vnet.ibm.com>

        * match.pd: Simplify wrapped binary operations.
diff --git a/gcc/match.pd b/gcc/match.pd
index 80a17ba..66c37f6 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -1290,6 +1290,128 @@ 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
+	    {
+	      tree cst = NULL_TREE;
+	      tree inner_type = TREE_TYPE (@3);
+	      wide_int wmin, wmax;
+	      wide_int wmin0, wmax0;
+
+	      bool ovf = true;
+	      bool ovf_undef = TYPE_OVERFLOW_UNDEFINED (inner_type);
+
+	      enum value_range_type vr_outer =
+		get_range_info (@3, &wmin, &wmax);
+	      enum value_range_type vr0 =
+		get_range_info (@0, &wmin0, &wmax0);
+
+	      /* Convert combined constant to tree of outer type if
+		 there was no overflow in the original operation.  */
+	      if (ovf_undef || vr_outer == VR_RANGE)
+	      {
+		wide_int w1 = @1;
+		wide_int w2 = @2;
+
+		if (ovf_undef || vr0 == VR_RANGE)
+		  {
+		    if (inner_op == MINUS_EXPR)
+		      w1 = wi::neg (w1);
+
+		    if (outer_op == MINUS_EXPR)
+		      w2 = wi::neg (w2);
+
+		    bool split_range = true;
+
+		    if (!ovf_undef && vr0 == VR_RANGE)
+		      {
+			int max_ovf = 0;
+			int min_ovf = 0;
+
+			signop sgn = TYPE_SIGN (inner_type);
+
+			wmin = wi::add (wmin0, w1);
+			min_ovf = wi::cmp (wmin, w1, sgn) < 0;
+
+			wmax = wi::add (wmax0, w1);
+			max_ovf = wi::cmp (wmax, w1, sgn) < 0;
+
+			ovf = min_ovf || max_ovf;
+
+			split_range = ((min_ovf && !max_ovf)
+				       || (!min_ovf && max_ovf));
+		      }
+
+		    if (ovf_undef || !split_range)
+		      {
+			/* Extend @1 to TYPE. */
+			w1 = w1.from (w1, TYPE_PRECISION (type),
+				      ovf ? SIGNED : TYPE_SIGN (TREE_TYPE (@1)));
+
+			/* Combine in outer, larger type.  */
+			wide_int combined_cst;
+			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 SSA_NAME@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 split_range = true;
+	  tree cst_inner = NULL_TREE;
+	  enum value_range_type vr = VR_VARYING;
+	  tree inner_type = TREE_TYPE (@0);
+
+	  if (int_fits_type_p (@2, inner_type))
+	  {
+	    cst_inner = fold_convert (inner_type, @2);
+
+	    wide_int wmin0, wmax0;
+	    wide_int w1 = cst_inner;
+	    signop sgn = TYPE_SIGN (inner_type);
+	    vr = get_range_info (@0, &wmin0, &wmax0);
+
+	    if (vr == VR_RANGE)
+	      {
+		wide_int wmin = wi::add (wmin0, w1);
+		bool min_ovf = wi::cmp (wmin, w1, sgn) < 0;
+
+		wide_int wmax = wi::add (wmax0, w1);
+		bool max_ovf = wi::cmp (wmax, w1, sgn) < 0;
+
+		split_range = (min_ovf && !max_ovf) || (!min_ovf && max_ovf);
+	      }
+	  }
+	}
+	(if (cst_inner && !split_range)
+	 (convert (outer_op @0 { cst_inner; })))
+	))))
+#endif
+
   /* ~A + A -> -1 */
   (simplify
    (plus:c (bit_not @0) @0)

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