Re: [PATCH 2/3] Simplify wrapped binops

2017-07-15 Thread Marc Glisse

On Wed, 5 Jul 2017, Robin Dapp wrote:


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).



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


I suppose it's more a matter of considering too many things at the same
time for me...  I was still thinking of including more cases than
necessary for the regression.  Guess the attached version will do as
well and should not contain any more surprises.  If needed, I'll add
additional cases some time.


What happens for (long)(X+10)+LONG_MAX where X has type int and is in 
[-30, -20]? It looks like wi::add will overflow and you will generate 
X+negative which overflows at runtime.


(It looks like you don't need to name @3, you could just use the type of 
@0 instead)


--
Marc Glisse


Re: [PATCH 2/3] Simplify wrapped binops

2017-07-05 Thread Robin Dapp
[3/3] Tests

--

gcc/testsuite/ChangeLog:

2017-07-05  Robin Dapp  

* gcc.dg/wrapped-binop-simplify-signed-1.c: New test.
* gcc.dg/wrapped-binop-simplify-signed-2.c: New test.
* gcc.dg/wrapped-binop-simplify-unsigned-1.c: New test.
* gcc.dg/wrapped-binop-simplify-unsigned-2.c: New test.
diff --git a/gcc/testsuite/gcc.dg/wrapped-binop-simplify-signed-1.c b/gcc/testsuite/gcc.dg/wrapped-binop-simplify-signed-1.c
new file mode 100644
index 000..2571a07
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/wrapped-binop-simplify-signed-1.c
@@ -0,0 +1,65 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-ccp1-details" } */
+/* { dg-final { scan-tree-dump-times "gimple_simplified to" 12 "ccp1" } } */
+
+#include 
+
+long foo(int a)
+{
+  return (long)(a - 2) + 1;
+}
+
+long bar(int a)
+{
+  return (long)(a + 3) - 1;
+}
+
+long baz(int a)
+{
+  return (long)(a - 1) + 2;
+}
+
+long baf(int a)
+{
+  return (long)(a + 1) - 2;
+}
+
+long bak(int a)
+{
+  return (long)(a + 1) + 3;
+}
+
+long bal(int a)
+{
+  return (long)(a - 7) - 4;
+}
+
+long bam(int a)
+{
+  return (long)(a - 1) - INT_MAX;
+}
+
+long bam2(int a)
+{
+  return (long)(a + 1) + INT_MAX;
+}
+
+long ban(int a)
+{
+  return (long)(a - 1) + INT_MIN;
+}
+
+long ban2(int a)
+{
+  return (long)(a + 1) - INT_MIN;
+}
+
+unsigned long baq(int a)
+{
+  return (unsigned long)(a + 1) - 1;
+}
+
+unsigned long baq2(int a)
+{
+  return (unsigned long)(a - 2) + 1;
+}
diff --git a/gcc/testsuite/gcc.dg/wrapped-binop-simplify-signed-2.c b/gcc/testsuite/gcc.dg/wrapped-binop-simplify-signed-2.c
new file mode 100644
index 000..5c897ba
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/wrapped-binop-simplify-signed-2.c
@@ -0,0 +1,39 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+#include 
+#include 
+
+int aa = -3;
+
+__attribute__((noinline))
+long foo (int a)
+{
+  return (long)(a - INT_MIN) + 1;
+}
+
+__attribute__((noinline))
+long foo2 (int a)
+{
+  if (a > -10 && a < 10)
+return (long)(a + 2) - 1;
+}
+
+__attribute__((noinline))
+long foo3 (int a)
+{
+  if (a > -10 && a < 10)
+return (long)(a) - 3;
+}
+
+int main()
+{
+  volatile long h = foo (aa);
+  assert (h == 2147483646);
+
+  volatile long i = foo2 (aa);
+  assert (i == -2);
+
+  volatile long j = foo3 (aa);
+  assert (j == -6);
+}
diff --git a/gcc/testsuite/gcc.dg/wrapped-binop-simplify-unsigned-1.c b/gcc/testsuite/gcc.dg/wrapped-binop-simplify-unsigned-1.c
new file mode 100644
index 000..04a7ca49
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/wrapped-binop-simplify-unsigned-1.c
@@ -0,0 +1,43 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp-details -fdump-tree-ccp2-details -fdump-tree-vrp1-details" } */
+/* { dg-final { scan-tree-dump-times "gimple_simplified to" 2 "evrp" } } */
+/* { dg-final { scan-tree-dump-times "Match-and-simplified" 2 "ccp2" } } */
+/* { dg-final { scan-tree-dump-times "gimple_simplified to" 3 "vrp1" } } */
+
+#include 
+
+unsigned long oof2(unsigned int a)
+{
+  if (a > 0)
+return (unsigned long)(a - 1) + 1;
+}
+
+unsigned long bah (unsigned int a)
+{
+  if (a > 0)
+return (unsigned long)(a - 1) - 1;
+}
+
+long baq3(unsigned int a)
+{
+  if (a > 0)
+return (long)(a - 1) + 1;
+}
+
+unsigned long bap(unsigned int a)
+{
+  if (a < UINT_MAX)
+return (unsigned long)(a + 1) + ULONG_MAX;
+}
+
+unsigned long bar3(unsigned int a)
+{
+  if (a < UINT_MAX)
+return (unsigned long)(a + 1) - 5;
+}
+
+unsigned long bar4(unsigned int a)
+{
+  if (a < UINT_MAX)
+return (unsigned long)(a + 1) - 6;
+}
diff --git a/gcc/testsuite/gcc.dg/wrapped-binop-simplify-unsigned-2.c b/gcc/testsuite/gcc.dg/wrapped-binop-simplify-unsigned-2.c
new file mode 100644
index 000..46290e7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/wrapped-binop-simplify-unsigned-2.c
@@ -0,0 +1,125 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+#include 
+#include 
+
+unsigned int a = 3;
+int aa = 3;
+int bb = 1;
+int cc = 4;
+unsigned int dd = 0;
+unsigned int ee = 4294967294u;
+
+__attribute__((noinline))
+unsigned long foo1 (unsigned int a)
+{
+  return (unsigned long)(UINT_MAX + 1) - 1;
+}
+
+__attribute__((noinline))
+unsigned long foo2 (unsigned int a)
+{
+  if (a < 4)
+return (unsigned long)(a - 4) + 1;
+}
+
+__attribute__((noinline))
+unsigned long foo3 (unsigned int a)
+{
+  if (a > 2)
+return (unsigned long)(a + UINT_MAX - 4) + 2;
+}
+
+__attribute__((noinline))
+unsigned long foo4 (unsigned int a)
+{
+  if (a > 2)
+return (unsigned long)(a - UINT_MAX) + UINT_MAX;
+}
+
+__attribute__((noinline))
+unsigned long foo5 (unsigned int a)
+{
+  if (a > 2)
+return (unsigned long)(a + UINT_MAX) - UINT_MAX;
+}
+
+__attribute__((noinline))
+long foo6 (unsigned int a)
+{
+  if (a > 2)
+return (long)(a - 4) + 1;
+}
+
+__attribute__((noinline))
+long foo7 (unsigned int a)
+{
+  if (a > 2)
+return (long)(a + UINT_MAX) + 1;
+}
+
+__attribute__((noinline))
+unsigned long foo8 (unsigned int a)
+{
+  if (a < 2)
+   

Re: [PATCH 2/3] Simplify wrapped binops

2017-07-05 Thread Robin Dapp
> 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).

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

I suppose it's more a matter of considering too many things at the same
time for me...  I was still thinking of including more cases than
necessary for the regression.  Guess the attached version will do as
well and should not contain any more surprises.  If needed, I'll add
additional cases some time.

Tests in a followup message.

Regards
 Robin
diff --git a/gcc/match.pd b/gcc/match.pd
index 80a17ba..3acf8be 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -1290,6 +1290,70 @@ 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 overflow.  */
+   (with
+   {
+ tree inner_type = TREE_TYPE (@3);
+ wide_int wmin0, wmax0;
+ wide_int w1 = @1;
+
+ bool ovf_undef = TYPE_OVERFLOW_UNDEFINED (inner_type);
+ bool min_ovf = true, max_ovf = true;
+
+ enum value_range_type vr0 = get_range_info (@0, , );
+
+ if (ovf_undef || vr0 == VR_RANGE)
+   {
+ if (!ovf_undef && vr0 == VR_RANGE)
+	   {
+		 wi::add (wmin0, w1, TYPE_SIGN (inner_type), _ovf);
+		 wi::add (wmax0, w1, TYPE_SIGN (inner_type), _ovf);
+	   }
+	 w1 = w1.from (@1, TYPE_PRECISION (type), TYPE_SIGN (inner_type));
+   }
+   }
+   (if (ovf_undef || !(min_ovf || max_ovf))
+(plus (convert @0) { wide_int_to_tree (type, wi::add (w1, @2)); }
+ )
+#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 overflow.  */
+ (with
+  {
+bool min_ovf = true, max_ovf = true;
+tree inner_type = TREE_TYPE (@0);
+
+wide_int w1 = w1.from (@1, TYPE_PRECISION (inner_type), TYPE_SIGN
+  		(inner_type));
+
+wide_int wmin0, wmax0;
+if (get_range_info (@0, , ) == VR_RANGE)
+  {
+wi::add (wmin0, w1, TYPE_SIGN (inner_type), _ovf);
+wi::add (wmax0, w1, TYPE_SIGN (inner_type), _ovf);
+  }
+  }
+ (if (!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)


Re: [PATCH 2/3] Simplify wrapped binops

2017-07-03 Thread Richard Biener
On Wed, Jun 28, 2017 at 4:34 PM, Robin Dapp  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)[0xfffe,
0x] + 2
which should have min_ovf and max_ovf which results in [0x0, 0x1] in type
unsigned int but [0x1, 0x10001] in type long.

Richard.

> Regards
>  Robin


Re: [PATCH 2/3] Simplify wrapped binops

2017-06-28 Thread Robin Dapp
> 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, , );
+
+ if (ovf_undef || vr0 == VR_RANGE)
+   {
+ bool ovf = true;
+ if (!ovf_undef && vr0 == VR_RANGE)
+	   {
+		 wi::add (wmin0, w1, TYPE_SIGN (inner_type), _ovf);
+		 wi::add (wmax0, w1, TYPE_SIGN (inner_type), _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, , ) == VR_RANGE)
+  {
+wi::add (wmin0, w1, TYPE_SIGN (inner_type), _ovf);
+wi::add (wmax0, w1, TYPE_SIGN (inner_type), _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)


Re: [PATCH 2/3] Simplify wrapped binops

2017-06-27 Thread Richard Biener
On Wed, Jun 21, 2017 at 1:44 PM, Robin Dapp  wrote:
>> 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.

Let's split this and look at the simpler case:

+/* ((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))

do

  && get_range_info (...) == VR_RANGE)

here. That avoids vr and its initialization and you get all of the "work" when
you know it will eventually succeed.

+ {
+   cst_inner = fold_convert (inner_type, @2);

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

 wide_int wi = wi::from (@2, TYPE_PRECISION (inner_type),
  TYPE_SIGN (inner_type));

+   wide_int wmin0, wmax0;
+   wide_int w1 = cst_inner;
+   signop sgn = TYPE_SIGN (inner_type);
+   vr = get_range_info (@0, , );
+
+   if (vr == VR_RANGE)
+ {
+   bool min_ovf;
+   wi::add (wmin0, w1, sgn, _ovf);
+
+   bool max_ovf;
+   wi::add (wmax0, w1, sgn, _ovf);

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

The comment above says "if there is no overflow" but below you allow
min_ovf && max_ovf without any further explanation.

+   wrapped_range = (min_ovf && !max_ovf) || (!min_ovf && max_ovf);
+ }
+ }
+   }
+   (if (cst_inner && !wrapped_range)
+   (convert (outer_op @0 { cst_inner; })))

thus

(if ((min_ovf && !max_ovf) || )
 (convert (outer_op @0 { wide_int_to_tree (inner_type, w1); } 

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

Richard.

+   
+#endif


> Regards
>  Robin


Re: [PATCH 2/3] Simplify wrapped binops

2017-06-27 Thread Robin Dapp
Ping.



Re: [PATCH 2/3] Simplify wrapped binops

2017-06-21 Thread Robin Dapp
> 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, , );
+
+	  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, _ovf);
+		wi::add (wmax0, w1, sgn, _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, , );
+
+	if (vr == VR_RANGE)
+	  {
+		bool min_ovf;
+		wi::add (wmin0, w1, sgn, _ovf);
+
+		bool max_ovf;
+		wi::add (wmax0, w1, sgn, _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)


Re: [PATCH 2/3] Simplify wrapped binops

2017-06-20 Thread Richard Biener
On Tue, Jun 20, 2017 at 3:08 PM, Robin Dapp  wrote:
>>> 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.

+  (if (TREE_CODE (type) == INTEGER_TYPE
+   && TYPE_PRECISION (type) > TYPE_PRECISION (TREE_TYPE (@3)))
+   (with

use INTEGRAL_TYPE_P.

+ bool ovf_undef = TYPE_OVERFLOW_UNDEFINED (inner_type);
+

so this is overflow behavior of the inner op.

+ /* Convert combined constant to tree of outer type if
+there was no overflow in the original operation.  */

"in the original inner operation."

you then go on and use ovf_undef also for the outer operation:

+ if (ovf_undef || vr_outer == VR_RANGE)
+ {

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.

But I don't see how overflow in the original outer operation matters
and the code lacks comments as to explaining that as well.

So if you have a vr0 then you can compute whether the inner
operation cannot overflow.  You do this here:

+   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));

ah, here's the use of the outer value-range.  This lacks a comment
(and it looks fishy given the outer value-range is a conservative approximation
and thus could be [-INF, +INF]).  Why's this not using the
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).

+   if (ovf_undef || !split_range)
+ {
+   /* Extend @1 to TYPE. */
+   w1 = w1.from (w1, TYPE_PRECISION (type),
+ ovf ? SIGNED : TYPE_SIGN
(TREE_TYPE (@1)));

ideally you could always interpret w1 as signed?

+   /* Combine in outer, larger type.  */
+   wide_int combined_cst;
+   combined_cst = wi::add (w1, w2);

+(if (cst)
+(outer_op (convert @0) { cst; }))
+   )

bogus indent.

+/* ((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)

INTEGRAL_TYPE_P and do that first before looking at TYPE_PRECISION.

+   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);

similar why not use wi:add overload with the overflow flag?

Btw, I find

  (with
   {
 tree x = NULL;
  if (...) x = non-NULL;
   }
   (if (x)
(

ugly.  Use

   (with
{
  ...
}
(if (...)
 (... { non-NULL } )

or sth like that which makes control flow more easily visible.

Richard.


> Regards
>  Robin
>
> --
>
> gcc/ChangeLog:
>
> 2017-06-19  Robin Dapp  
>
> * match.pd: Simplify wrapped binary operations.


Re: [PATCH 2/3] Simplify wrapped binops

2017-06-20 Thread Robin Dapp
>> 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  

* 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, , );
+	  enum value_range_type vr0 =
+		get_range_info (@0, , );
+
+	  /* 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, , );
+
+	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)


Re: [PATCH 2/3] Simplify wrapped binops

2017-05-19 Thread Richard Biener
On Fri, May 19, 2017 at 12:13 PM, Bin.Cheng  wrote:
> On Fri, May 19, 2017 at 11:09 AM, Robin Dapp  wrote:
>>> I can guess what is happening here.  It's a 40 bits unsigned long long
>>> field, (s.b-8) will be like:
>>> _1 = s.b
>>> _2 = _1 + 0xf8
>>> Also get_range_info returns value range [0, 0xFF] for _1.
>>> You'd need to check if _1(with range [0, 0xFF]) + 0xf8
>>> overflows against precision of the bit-field which is 40 bits
>>> precision.  The failure might because overflowness is checked against
>>> unsigned long long's precision which is 64 bits.
>>
 Also, is there a possibility to know if there was an "ok" overflow or
 not from get_range_info ()'s output? Would I have to compare the result
 with the involved variable's range?
>>> I think you have to check it manually against max/min value of that
>>> type precision.
>>
>> 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.

Using get_range_info and wi:: is prefered, I didn't look into the issue you
are running into but wi:: do have proper bit-precision tracking.  Maybe
the overflow checks are not implemented correctly there though.

Richard.

> Thanks,
> bin
>>
>> Regards
>>  Robin
>>


Re: [PATCH 2/3] Simplify wrapped binops

2017-05-19 Thread Bin.Cheng
On Fri, May 19, 2017 at 11:09 AM, Robin Dapp  wrote:
>> I can guess what is happening here.  It's a 40 bits unsigned long long
>> field, (s.b-8) will be like:
>> _1 = s.b
>> _2 = _1 + 0xf8
>> Also get_range_info returns value range [0, 0xFF] for _1.
>> You'd need to check if _1(with range [0, 0xFF]) + 0xf8
>> overflows against precision of the bit-field which is 40 bits
>> precision.  The failure might because overflowness is checked against
>> unsigned long long's precision which is 64 bits.
>
>>> Also, is there a possibility to know if there was an "ok" overflow or
>>> not from get_range_info ()'s output? Would I have to compare the result
>>> with the involved variable's range?
>> I think you have to check it manually against max/min value of that
>> type precision.
>
> 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.

Thanks,
bin
>
> Regards
>  Robin
>


Re: [PATCH 2/3] Simplify wrapped binops

2017-05-19 Thread Robin Dapp
> I can guess what is happening here.  It's a 40 bits unsigned long long
> field, (s.b-8) will be like:
> _1 = s.b
> _2 = _1 + 0xf8
> Also get_range_info returns value range [0, 0xFF] for _1.
> You'd need to check if _1(with range [0, 0xFF]) + 0xf8
> overflows against precision of the bit-field which is 40 bits
> precision.  The failure might because overflowness is checked against
> unsigned long long's precision which is 64 bits.

>> Also, is there a possibility to know if there was an "ok" overflow or
>> not from get_range_info ()'s output? Would I have to compare the result
>> with the involved variable's range?
> I think you have to check it manually against max/min value of that
> type precision.

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? :)

Regards
 Robin



Re: [PATCH 2/3] Simplify wrapped binops

2017-05-18 Thread Bin.Cheng
On Thu, May 18, 2017 at 5:08 PM, Robin Dapp  wrote:
>> Any reason to expose tree-vrp.c internal interface here?  The function
>> looks quite expensive.  Overflow check can be done by get_range_info
>> and simple wi::cmp calls.  Existing code like in
>> tree-ssa-loop-niters.c already does that.  Also could you avoid using
>> comma expressions in condition please? It only makes the code harder
>> to be read.
>
> I tried get_range_info () as well and got a FAIL in
> gcc.c-torture/execute/bitfld-5.c.
> where get_range_info () returns a VR_RANGE but extract...() gives
> VR_VARYING.  The test case relies on not simplifying, i.e. would expect
> a VR_VARYING here but I didn't look into it more.
I can guess what is happening here.  It's a 40 bits unsigned long long
field, (s.b-8) will be like:
_1 = s.b
_2 = _1 + 0xf8
Also get_range_info returns value range [0, 0xFF] for _1.
You'd need to check if _1(with range [0, 0xFF]) + 0xf8
overflows against precision of the bit-field which is 40 bits
precision.  The failure might because overflowness is checked against
unsigned long long's precision which is 64 bits.

>
> Also, is there a possibility to know if there was an "ok" overflow or
> not from get_range_info ()'s output? Would I have to compare the result
> with the involved variable's range?
I think you have to check it manually against max/min value of that
type precision.

Thanks,
bin
>
> Regards
>  Robin
>


Re: [PATCH 2/3] Simplify wrapped binops

2017-05-18 Thread Robin Dapp
> Any reason to expose tree-vrp.c internal interface here?  The function
> looks quite expensive.  Overflow check can be done by get_range_info
> and simple wi::cmp calls.  Existing code like in
> tree-ssa-loop-niters.c already does that.  Also could you avoid using
> comma expressions in condition please? It only makes the code harder
> to be read.

I tried get_range_info () as well and got a FAIL in
gcc.c-torture/execute/bitfld-5.c.
where get_range_info () returns a VR_RANGE but extract...() gives
VR_VARYING.  The test case relies on not simplifying, i.e. would expect
a VR_VARYING here but I didn't look into it more.

Also, is there a possibility to know if there was an "ok" overflow or
not from get_range_info ()'s output? Would I have to compare the result
with the involved variable's range?

Regards
 Robin



Re: [PATCH 2/3] Simplify wrapped binops

2017-05-18 Thread Bin.Cheng
On Thu, May 18, 2017 at 3:47 PM, Robin Dapp  wrote:
> match.pd part of the patch.
>
> gcc/ChangeLog:
>
> 2017-05-18  Robin Dapp  
>
> * 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.

Hi,
I didn't follow this issue from the beginning, so might asking stupid questions.

> 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 (, inner_op,
> +inner_type, @0, @1, ), vr.type == VR_RANGE))
Any reason to expose tree-vrp.c internal interface here?  The function
looks quite expensive.  Overflow check can be done by get_range_info
and simple wi::cmp calls.  Existing code like in
tree-ssa-loop-niters.c already does that.  Also could you avoid using
comma expressions in condition please? It only makes the code harder
to be read.

Thanks,
bin


[PATCH 2/3] Simplify wrapped binops

2017-05-18 Thread Robin Dapp
match.pd part of the patch.

gcc/ChangeLog:

2017-05-18  Robin Dapp  

* 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 (, inner_op,
+		inner_type, @0, @1, ), 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 (, outer_op, TREE_TYPE (@0),
+	@0, cst_inner, );
+	  }
+	}
+	(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 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 (, , ))
 {
-  extract_range_from_binary_expr_1 (vr, code, expr_type, , vr1_);
+  extract_range_from_binary_expr_1 (vr, code, expr_type, , vr1_,
+	ovf);
   if (vrtem1.type != VR_UNDEFINED)
 	{
 	  value_range vrres = VR_INITIALIZER;
 	  extract_range_from_binary_expr_1 (, code, expr_type,
-	, vr1_);
+	, vr1_, ovf);
 	  vrp_meet (vr, );
 	}
   return;
@@ -2026,12 +2026,13 @@ extract_range_from_binary_expr_1 (value_range *vr,
   if (vr1.type == VR_ANTI_RANGE
   && ranges_from_anti_range (, , ))
 {
-  extract_range_from_binary_expr_1 (vr, code, expr_type, vr0_, );
+  extract_range_from_binary_expr_1 (vr, code, expr_type, vr0_, ,
+	ovf);
   if (vrtem1.type != VR_UNDEFINED)
 	{
 	  value_range vrres = VR_INITIALIZER;
 	  extract_range_from_binary_expr_1 (, code, expr_type,
-	vr0_, );
+	vr0_, , ovf);
 	  vrp_meet (vr, );
 	}
   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