diff mbox

[2/3] Simplify wrapped binops

Message ID 0a2a7c03-e47a-fabd-e535-30e19a64b563@linux.vnet.ibm.com
State New
Headers show

Commit Message

Robin Dapp June 28, 2017, 2:34 p.m. UTC
> 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

Comments

Richard Biener July 3, 2017, 1:10 p.m. UTC | #1
On Wed, Jun 28, 2017 at 4:34 PM, Robin Dapp <rdapp@linux.vnet.ibm.com> wrote
>> 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...

+     /* 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;

While the initialization value doesn't matter (wi::add will overwrite it)
better initialize both to false ;)  Ah, you mean because we want to
transform only if get_range_info returned VR_RANGE.  Indeed somewhat
unintuitive (but still the best variant for now).

+        wide_int w1 = @1;
+        w1 = w1.from (w1, TYPE_PRECISION (inner_type), TYPE_SIGN
+               (inner_type));

I think wi::from (@1, ....) should work as well.

+     (if (!((min_ovf && !max_ovf) || (!min_ovf && max_ovf)) )
+      (convert (plus @0 { {wide_int_to_tree (TREE_TYPE (@0), w1)}; })))

so I'm still missing a comment on why min_ovf && max_ovf is ok.
The simple-minded would have written

   (if  (! min_ovf && ! max_ovf)
...

I'd like to see testcase(s) with this patch, preferably exactly also for the
case of min_ovf && max_ovf.  That said, consider (long)[0xfffffffe,
0xffffffff] + 2
which should have min_ovf and max_ovf which results in [0x0, 0x1] in type
unsigned int but [0x100000000, 0x100000001] in type long.

Richard.

> Regards
>  Robin
diff mbox

Patch

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)