Allow some NOP conversions in (X+CST1)+CST2 in match.pd
authorMarc Glisse <marc.glisse@inria.fr>
Thu, 25 May 2017 08:45:48 +0000 (10:45 +0200)
committerMarc Glisse <glisse@gcc.gnu.org>
Thu, 25 May 2017 08:45:48 +0000 (08:45 +0000)
2017-05-25  Marc Glisse  <marc.glisse@inria.fr>

gcc/
* match.pd ((A +- CST1) +- CST2): Allow some conversions.
* tree.c (drop_tree_overflow): Handle COMPLEX_CST and VECTOR_CST.

gcc/testsuite/
* gcc.dg/tree-ssa/addadd.c: New file.

From-SVN: r248448

gcc/ChangeLog
gcc/match.pd
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/addadd.c [new file with mode: 0644]
gcc/tree.c

index 5445bd5fd1fd0d1bf9b47333ef008dfe997445f5..cf75376b851b9cb78e63aca55ffe16a41a248905 100644 (file)
@@ -1,3 +1,8 @@
+2017-05-25  Marc Glisse  <marc.glisse@inria.fr>
+
+       * match.pd ((A +- CST1) +- CST2): Allow some conversions.
+       * tree.c (drop_tree_overflow): Handle COMPLEX_CST and VECTOR_CST.
+
 2017-05-25  Marc Glisse  <marc.glisse@inria.fr>
 
        * fold-const.c (fold_binary_loc) [(A & C) == D]: Remove transformation.
index 618b2ec3da83c6a9a2bcbc91710825144482b8c3..77271a016198a58fc5411f2e056207166d96a92b 100644 (file)
@@ -1299,15 +1299,39 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   /* (A +- CST1) +- CST2 -> A + CST3  */
   (for outer_op (plus minus)
    (for inner_op (plus minus)
+       neg_inner_op (minus plus)
     (simplify
-     (outer_op (inner_op @0 CONSTANT_CLASS_P@1) CONSTANT_CLASS_P@2)
-     /* If the constant operation overflows we cannot do the transform
-       as we would introduce undefined overflow, for example
-       with (a - 1) + INT_MIN.  */
-     (with { tree cst = const_binop (outer_op == inner_op
-                                    ? PLUS_EXPR : MINUS_EXPR, type, @1, @2); }
-      (if (cst && !TREE_OVERFLOW (cst))
-       (inner_op @0 { cst; } ))))))
+     (outer_op (convert? (inner_op @0 CONSTANT_CLASS_P@1)) CONSTANT_CLASS_P@2)
+     (if (tree_nop_conversion_p (type, TREE_TYPE (@0)))
+      /* If one of the types wraps, use that one.  */
+      (if (!ANY_INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_WRAPS (type))
+       (if (outer_op == PLUS_EXPR)
+       (plus (convert @0) (inner_op @2 (convert @1)))
+       (minus (convert @0) (neg_inner_op @2 (convert @1))))
+       (if (!ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
+           || TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0)))
+       (if (outer_op == PLUS_EXPR)
+        (convert (plus @0 (inner_op (convert @2) @1)))
+        (convert (minus @0 (neg_inner_op (convert @2) @1))))
+       /* If the constant operation overflows we cannot do the transform
+          directly as we would introduce undefined overflow, for example
+          with (a - 1) + INT_MIN.  */
+       (if (types_match (type, @0))
+        (with { tree cst = const_binop (outer_op == inner_op
+                                        ? PLUS_EXPR : MINUS_EXPR,
+                                        type, @1, @2); }
+         (if (cst && !TREE_OVERFLOW (cst))
+          (inner_op @0 { cst; } )
+          /* X+INT_MAX+1 is X-INT_MIN.  */
+          (if (INTEGRAL_TYPE_P (type) && cst
+               && wi::eq_p (cst, wi::min_value (type)))
+           (neg_inner_op @0 { wide_int_to_tree (type, cst); })
+           /* Last resort, use some unsigned type.  */
+           (with { tree utype = unsigned_type_for (type); }
+            (convert (inner_op
+                      (convert:utype @0)
+                      (convert:utype
+                       { drop_tree_overflow (cst); }))))))))))))))
 
   /* (CST1 - A) +- CST2 -> CST3 - A  */
   (for outer_op (plus minus)
index 84026e31153439cc928631e4979b65fed81cfc81..efe1dcb14f84ebd531ebdd81718a1d22358887a3 100644 (file)
@@ -1,3 +1,7 @@
+2017-05-25  Marc Glisse  <marc.glisse@inria.fr>
+
+       * gcc.dg/tree-ssa/addadd.c: New file.
+
 2017-05-24  Nathan Sidwell  <nathan@acm.org>
 
        * g++.dg/lookup/friend12.C: Adjust diagnostics.
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/addadd.c b/gcc/testsuite/gcc.dg/tree-ssa/addadd.c
new file mode 100644 (file)
index 0000000..16474db
--- /dev/null
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-optimized" } */
+
+int f(unsigned x){
+  x += 123;
+  int y = x;
+  y -= 99;
+  return y;
+}
+unsigned g(int x){
+  x += 123;
+  unsigned y = x;
+  y -= 99;
+  return y;
+}
+int h(int x){
+  x += __INT_MAX__;
+  x += 1;
+  return x;
+}
+int i(int x){
+  x += __INT_MAX__;
+  x += __INT_MAX__;
+  return x;
+}
+typedef int S __attribute__((vector_size(16)));
+void j(S*x){
+  *x += __INT_MAX__;
+  *x += __INT_MAX__;
+}
+
+/* { dg-final { scan-tree-dump-times " \\+ 24;" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "\\(unsigned int\\)" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-not "2147483647" "optimized" } } */
index db31620736982f6b3c5f0884fc6ab9e9cec4cda9..a58f9aaa69ec4b0b5ad22d92a41935ceae36b1c4 100644 (file)
@@ -13138,6 +13138,25 @@ drop_tree_overflow (tree t)
      and drop the flag.  */
   t = copy_node (t);
   TREE_OVERFLOW (t) = 0;
+
+  /* For constants that contain nested constants, drop the flag
+     from those as well.  */
+  if (TREE_CODE (t) == COMPLEX_CST)
+    {
+      if (TREE_OVERFLOW (TREE_REALPART (t)))
+       TREE_REALPART (t) = drop_tree_overflow (TREE_REALPART (t));
+      if (TREE_OVERFLOW (TREE_IMAGPART (t)))
+       TREE_IMAGPART (t) = drop_tree_overflow (TREE_IMAGPART (t));
+    }
+  if (TREE_CODE (t) == VECTOR_CST)
+    {
+      for (unsigned i = 0; i < VECTOR_CST_NELTS (t); ++i)
+       {
+         tree& elt = VECTOR_CST_ELT (t, i);
+         if (TREE_OVERFLOW (elt))
+           elt = drop_tree_overflow (elt);
+       }
+    }
   return t;
 }