> ideally you'd use a wide-int here and defer the tree allocation to the result

Did that in the attached version.

> So I guess we never run into the outer_op == minus case as the above is
> clearly wrong for that?

Right, damn, not only was the treatment for this missing but it was
bogus in the other pattern as well.  Since we are mostly dealing with
PLUS_EXPR anyways it's probably better to defer the MINUS_EXPR case for
now.  This will also slim down the patterns a bit.

> try to keep vertical spacing in patterns minimal -- I belive that patterns
> should be small enough to fit in a terminal window (24 lines).

I find using the expanded wrapped_range condition in the simplification
somewhat cumbersome, especially because I need the condition to evaluate
to true by default making the initialization unintuitive.  Yet, I guess
setting wrapped_range = true was not terribly intuitive either...

Regards
 Robin
diff --git a/gcc/match.pd b/gcc/match.pd
index 80a17ba..ed497cf 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -1290,6 +1290,79 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
     (if (cst && !TREE_OVERFLOW (cst))
      (plus { cst; } @0))))
 
+/* ((T)(A + CST1)) + CST2 -> (T)(A) + CST  */
+#if GIMPLE
+  (simplify
+    (plus (convert (plus@3 @0 INTEGER_CST@1)) INTEGER_CST@2)
+      (if (INTEGRAL_TYPE_P (type)
+           && TYPE_PRECISION (type) > TYPE_PRECISION (TREE_TYPE (@3)))
+       /* Combine CST1 and CST2 to CST and convert to outer type if
+          (A + CST1)'s range does not wrap.  */
+       (with
+       {
+         tree inner_type = TREE_TYPE (@3);
+         wide_int wmin0, wmax0;
+         wide_int w1 = @1;
+         wide_int w2 = @2;
+         wide_int combined_cst;
+
+         bool ovf_undef = TYPE_OVERFLOW_UNDEFINED (inner_type);
+         bool min_ovf = true, max_ovf = false;
+
+         enum value_range_type vr0 =
+           get_range_info (@0, &wmin0, &wmax0);
+
+         if (ovf_undef || vr0 == VR_RANGE)
+           {
+             bool ovf = true;
+             if (!ovf_undef && vr0 == VR_RANGE)
+	       {
+		 wi::add (wmin0, w1, TYPE_SIGN (inner_type), &min_ovf);
+		 wi::add (wmax0, w1, TYPE_SIGN (inner_type), &max_ovf);
+		 ovf = min_ovf || max_ovf;
+	       }
+
+             /* Extend CST1 to TYPE. */
+             w1 = w1.from (w1, TYPE_PRECISION (type),
+			   ovf ? SIGNED : TYPE_SIGN (inner_type));
+           }
+       }
+   (if (ovf_undef || !((min_ovf && !max_ovf) || (!min_ovf && max_ovf)))
+    (plus (convert @0) { wide_int_to_tree (type, wi::add (w1, w2)); }
+     )))))
+#endif
+
+/* ((T)(A)) + CST -> (T)(A + CST)  */
+#if GIMPLE
+  (simplify
+   (plus (convert SSA_NAME@0) INTEGER_CST@1)
+    (if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
+         && INTEGRAL_TYPE_P (type)
+         && TYPE_PRECISION (type) > TYPE_PRECISION (TREE_TYPE (@0))
+         && int_fits_type_p (@1, TREE_TYPE (@0)))
+     /* Perform binary operation inside the cast if the constant fits
+        and (A + CST)'s range does not wrap.  */
+     (with
+      {
+        bool min_ovf = true, max_ovf = false;
+        tree inner_type = TREE_TYPE (@0);
+
+        wide_int w1 = @1;
+        w1 = w1.from (w1, TYPE_PRECISION (inner_type), TYPE_SIGN
+      		(inner_type));
+
+        wide_int wmin0, wmax0;
+        if (get_range_info (@0, &wmin0, &wmax0) == VR_RANGE)
+          {
+            wi::add (wmin0, w1, TYPE_SIGN (inner_type), &min_ovf);
+            wi::add (wmax0, w1, TYPE_SIGN (inner_type), &max_ovf);
+          }
+      }
+     (if (!((min_ovf && !max_ovf) || (!min_ovf && max_ovf)) )
+      (convert (plus @0 { {wide_int_to_tree (TREE_TYPE (@0), w1)}; })))
+     )))
+#endif
+
   /* ~A + A -> -1 */
   (simplify
    (plus:c (bit_not @0) @0)

Reply via email to