> use INTEGRAL_TYPE_P.

Done.

> but you do not actually _use_ vr_outer.  Do you think that if
> vr_outer is a VR_RANGE then the outer operation may not
> possibly have wrapped?  That's a false conclusion.

These were remains of a previous version.  vr_outer is indeed not needed
anymore; removed.

> wi::add overload with the overflow flag?  ISTR you want to handle "negative"
> unsigned constants somehow, but then I don't see how the above works.
> I'd say if wmin/wmax interpreted as signed are positive and then using
> a signed op to add w1 results in a still positive number you're fine
> (you don't seem
> to restrict the widening cast to either zero- or sign-extending).

Changed to using wi:add overload now.

In essence, three cases are being handled:
 - wrapped_range --> do not simplify
 - !wrapped_range && ovf ("negative" unsigned) --> simplify and combine
with sign extension in the outer type
 - !wrapped_range && !ovf ("positive" unsigned) --> simplify and combine
with zero extension in the outer type.

Regards
 Robin
diff --git a/gcc/match.pd b/gcc/match.pd
index 80a17ba..ec1af69 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -1290,6 +1290,116 @@ 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 (INTEGRAL_TYPE_P (type)
+		&& TYPE_PRECISION (type) > TYPE_PRECISION (TREE_TYPE (@3)))
+	    (with
+	    {
+	      tree cst;
+	      tree inner_type = TREE_TYPE (@3);
+	      wide_int wmin0, wmax0;
+
+	      bool ovf = true;
+	      bool ovf_undef = TYPE_OVERFLOW_UNDEFINED (inner_type);
+
+	      enum value_range_type vr0 =
+		get_range_info (@0, &wmin0, &wmax0);
+
+	      bool wrapped_range = true;
+
+	      /* Convert combined constant to tree of outer type if
+		 there was no overflow in the original inner operation.  */
+	      if (ovf_undef || vr0 == VR_RANGE)
+	      {
+		wide_int w1 = @1;
+		wide_int w2 = @2;
+
+		if (inner_op == MINUS_EXPR)
+		  w1 = wi::neg (w1);
+
+		if (outer_op == MINUS_EXPR)
+		  w2 = wi::neg (w2);
+
+		bool ovf;
+
+		if (!ovf_undef && vr0 == VR_RANGE)
+		  {
+		    bool max_ovf;
+		    bool min_ovf;
+
+		    signop sgn = TYPE_SIGN (inner_type);
+		    wi::add (wmin0, w1, sgn, &min_ovf);
+		    wi::add (wmax0, w1, sgn, &max_ovf);
+
+		    ovf = min_ovf || max_ovf;
+		    wrapped_range = ((min_ovf && !max_ovf)
+				   || (!min_ovf && max_ovf));
+		  }
+
+		/* Extend @1 to TYPE. */
+		w1 = w1.from (w1, TYPE_PRECISION (type),
+			      ovf ? SIGNED : TYPE_SIGN (inner_type));
+
+		/* Combine in outer, larger type.  */
+		wide_int combined_cst;
+		combined_cst = wi::add (w1, w2);
+
+		cst = wide_int_to_tree (type, combined_cst);
+	      }
+	    }
+        (if (ovf_undef || !wrapped_range)
+	 (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 (INTEGRAL_TYPE_P (TREE_TYPE (@0))
+	   && INTEGRAL_TYPE_P (type)
+	   && TYPE_PRECISION (type) > TYPE_PRECISION (TREE_TYPE (@0)))
+       /* Perform binary operation inside the cast if the constant fits
+	  and there is no overflow.  */
+       (with
+	{
+	  bool wrapped_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)
+	      {
+		bool min_ovf;
+		wi::add (wmin0, w1, sgn, &min_ovf);
+
+		bool max_ovf;
+		wi::add (wmax0, w1, sgn, &max_ovf);
+
+		wrapped_range = (min_ovf && !max_ovf) || (!min_ovf && max_ovf);
+	      }
+	  }
+	}
+       (if (cst_inner && !wrapped_range)
+	(convert (outer_op @0 { cst_inner; })))
+       ))))
+#endif
+
   /* ~A + A -> -1 */
   (simplify
    (plus:c (bit_not @0) @0)

Reply via email to