re PR target/88152 (optimize SSE & AVX char compares with subsequent movmskb)
authorJakub Jelinek <jakub@redhat.com>
Thu, 29 Nov 2018 14:32:00 +0000 (15:32 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Thu, 29 Nov 2018 14:32:00 +0000 (15:32 +0100)
PR target/88152
* tree.h (build_uniform_cst, uniform_integer_cst_p): Declare.
* tree.c (build_uniform_cst, uniform_integer_cst_p): New functions.
* match.pd (define_predicates): Add uniform_integer_cst_p.
(cmp @0 INTEGER_CST@1, cmp (convert?@2 @0) INTEGER_CST@1): Adjust
so that it works also for vector comparisons with uniform constants
with INTEGER_CST element.

* g++.dg/tree-ssa/pr88152-1.C: New test.
* g++.dg/tree-ssa/pr88152-2.C: New test.

From-SVN: r266620

gcc/ChangeLog
gcc/match.pd
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/tree-ssa/pr88152-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tree-ssa/pr88152-2.C [new file with mode: 0644]
gcc/tree.c
gcc/tree.h

index 5fe36e07b9cd6707091c749c17de9ea01e6ff115..fcf4cf7a19c22682a06c1e762159ba5316d878fb 100644 (file)
@@ -1,5 +1,13 @@
 2018-11-29  Jakub Jelinek  <jakub@redhat.com>
 
+       PR target/88152
+       * tree.h (build_uniform_cst, uniform_integer_cst_p): Declare.
+       * tree.c (build_uniform_cst, uniform_integer_cst_p): New functions.
+       * match.pd (define_predicates): Add uniform_integer_cst_p.
+       (cmp @0 INTEGER_CST@1, cmp (convert?@2 @0) INTEGER_CST@1): Adjust
+       so that it works also for vector comparisons with uniform constants
+       with INTEGER_CST element.
+
        PR target/88234
        * config/rs6000/rs6000.c (rs6000_gimple_fold_builtin): For
        vec_add and vec_sub builtins, perform PLUS_EXPR or MINUS_EXPR
index e9f9e0c08f7e25022ca7f5dd94f78c4bc0ba9e1e..6c267510adff3c582949611c5490470a8cf4c99c 100644 (file)
@@ -34,6 +34,7 @@ along with GCC; see the file COPYING3.  If not see
    tree_expr_nonzero_p
    integer_valued_real_p
    integer_pow2p
+   uniform_integer_cst_p
    HONOR_NANS)
 
 /* Operator lists.  */
@@ -3107,16 +3108,22 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 (for cmp  (le gt)
      acmp (lt ge)
  (simplify
-  (cmp @0 INTEGER_CST@1)
-  (if (tree_int_cst_sgn (@1) == -1)
-   (acmp @0 { wide_int_to_tree (TREE_TYPE (@1), wi::to_wide (@1) + 1); }))))
+  (cmp @0 uniform_integer_cst_p@1)
+  (with { tree cst = uniform_integer_cst_p (@1); }
+   (if (tree_int_cst_sgn (cst) == -1)
+     (acmp @0 { build_uniform_cst (TREE_TYPE (@1),
+                                  wide_int_to_tree (TREE_TYPE (cst),
+                                                    wi::to_wide (cst)
+                                                    + 1)); })))))
 (for cmp  (ge lt)
      acmp (gt le)
  (simplify
-  (cmp @0 INTEGER_CST@1)
-  (if (tree_int_cst_sgn (@1) == 1)
-   (acmp @0 { wide_int_to_tree (TREE_TYPE (@1), wi::to_wide (@1) - 1); }))))
-
+  (cmp @0 uniform_integer_cst_p@1)
+  (with { tree cst = uniform_integer_cst_p (@1); }
+   (if (tree_int_cst_sgn (cst) == 1)
+    (acmp @0 { build_uniform_cst (TREE_TYPE (@1),
+                                 wide_int_to_tree (TREE_TYPE (cst),
+                                 wi::to_wide (cst) - 1)); })))))
 
 /* We can simplify a logical negation of a comparison to the
    inverted comparison.  As we cannot compute an expression
@@ -3934,19 +3941,22 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
  /* Comparisons with the highest or lowest possible integer of
     the specified precision will have known values.  */
  (simplify
-  (cmp (convert?@2 @0) INTEGER_CST@1)
-  (if ((INTEGRAL_TYPE_P (TREE_TYPE (@1)) || POINTER_TYPE_P (TREE_TYPE (@1)))
+  (cmp (convert?@2 @0) uniform_integer_cst_p@1)
+  (if ((INTEGRAL_TYPE_P (TREE_TYPE (@1))
+       || POINTER_TYPE_P (TREE_TYPE (@1))
+       || VECTOR_INTEGER_TYPE_P (TREE_TYPE (@1)))
        && tree_nop_conversion_p (TREE_TYPE (@2), TREE_TYPE (@0)))
    (with
     {
-      tree arg1_type = TREE_TYPE (@1);
+      tree cst = uniform_integer_cst_p (@1);
+      tree arg1_type = TREE_TYPE (cst);
       unsigned int prec = TYPE_PRECISION (arg1_type);
       wide_int max = wi::max_value (arg1_type);
       wide_int signed_max = wi::max_value (prec, SIGNED);
       wide_int min = wi::min_value (arg1_type);
     }
     (switch
-     (if (wi::to_wide (@1) == max)
+     (if (wi::to_wide (cst) == max)
       (switch
        (if (cmp == GT_EXPR)
        { constant_boolean_node (false, type); })
@@ -3956,7 +3966,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
        { constant_boolean_node (true, type); })
        (if (cmp == LT_EXPR)
        (ne @2 @1))))
-     (if (wi::to_wide (@1) == min)
+     (if (wi::to_wide (cst) == min)
       (switch
        (if (cmp == LT_EXPR)
         { constant_boolean_node (false, type); })
@@ -3966,19 +3976,31 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
         { constant_boolean_node (true, type); })
        (if (cmp == GT_EXPR)
         (ne @2 @1))))
-     (if (wi::to_wide (@1) == max - 1)
+     (if (wi::to_wide (cst) == max - 1)
       (switch
        (if (cmp == GT_EXPR)
-       (eq @2 { wide_int_to_tree (TREE_TYPE (@1), wi::to_wide (@1) + 1); }))
+       (eq @2 { build_uniform_cst (TREE_TYPE (@1),
+                                   wide_int_to_tree (TREE_TYPE (cst),
+                                                     wi::to_wide (cst)
+                                                     + 1)); }))
        (if (cmp == LE_EXPR)
-       (ne @2 { wide_int_to_tree (TREE_TYPE (@1), wi::to_wide (@1) + 1); }))))
-     (if (wi::to_wide (@1) == min + 1)
+       (ne @2 { build_uniform_cst (TREE_TYPE (@1),
+                                   wide_int_to_tree (TREE_TYPE (cst),
+                                                     wi::to_wide (cst)
+                                                     + 1)); }))))
+     (if (wi::to_wide (cst) == min + 1)
       (switch
        (if (cmp == GE_EXPR)
-        (ne @2 { wide_int_to_tree (TREE_TYPE (@1), wi::to_wide (@1) - 1); }))
+        (ne @2 { build_uniform_cst (TREE_TYPE (@1),
+                                   wide_int_to_tree (TREE_TYPE (cst),
+                                                     wi::to_wide (cst)
+                                                     - 1)); }))
        (if (cmp == LT_EXPR)
-        (eq @2 { wide_int_to_tree (TREE_TYPE (@1), wi::to_wide (@1) - 1); }))))
-     (if (wi::to_wide (@1) == signed_max
+        (eq @2 { build_uniform_cst (TREE_TYPE (@1),
+                                   wide_int_to_tree (TREE_TYPE (cst),
+                                                     wi::to_wide (cst)
+                                                     - 1)); }))))
+     (if (wi::to_wide (cst) == signed_max
          && TYPE_UNSIGNED (arg1_type)
          /* We will flip the signedness of the comparison operator
             associated with the mode of @1, so the sign bit is
@@ -3990,10 +4012,16 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
       /* The following case also applies to X < signed_max+1
         and X >= signed_max+1 because previous transformations.  */
       (if (cmp == LE_EXPR || cmp == GT_EXPR)
-       (with { tree st = signed_type_for (arg1_type); }
-        (if (cmp == LE_EXPR)
-        (ge (convert:st @0) { build_zero_cst (st); })
-        (lt (convert:st @0) { build_zero_cst (st); }))))))))))
+       (with { tree st = signed_type_for (TREE_TYPE (@1)); }
+               (switch
+        (if (cst == @1 && cmp == LE_EXPR)
+         (ge (convert:st @0) { build_zero_cst (st); }))
+        (if (cst == @1 && cmp == GT_EXPR)
+         (lt (convert:st @0) { build_zero_cst (st); }))
+        (if (cmp == LE_EXPR)
+         (ge (view_convert:st @0) { build_zero_cst (st); }))
+        (if (cmp == GT_EXPR)
+         (lt (view_convert:st @0) { build_zero_cst (st); })))))))))))
 
 (for cmp (unordered ordered unlt unle ungt unge uneq ltgt)
  /* If the second operand is NaN, the result is constant.  */
index 0e908be06d14cd8edd301d01fd9139c11e71995f..b75b80d9c82d76faf681114b1fd9d4681e52b640 100644 (file)
@@ -1,5 +1,9 @@
 2018-11-29  Jakub Jelinek  <jakub@redhat.com>
 
+       PR target/88152
+       * g++.dg/tree-ssa/pr88152-1.C: New test.
+       * g++.dg/tree-ssa/pr88152-2.C: New test.
+
        PR target/88234
        * gcc.dg/ubsan/pr88234.c: New test.
 
diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr88152-1.C b/gcc/testsuite/g++.dg/tree-ssa/pr88152-1.C
new file mode 100644 (file)
index 0000000..423ec89
--- /dev/null
@@ -0,0 +1,55 @@
+// PR target/88152
+// { dg-do compile }
+// { dg-options "-O2 -std=c++14 -fdump-tree-forwprop1" }
+// { dg-final { scan-tree-dump-times " (?:<|>=) \{ 0\[, ]" 120 "forwprop1" } }
+
+template <typename T, int N>
+using V [[gnu::vector_size (sizeof (T) * N)]] = T;
+
+void *foo ();
+
+template <typename T, int N, T max, T maxp1>
+__attribute__((noipa)) void
+test_uns ()
+{
+  V<T, N> *x = (V<T, N> *) foo ();
+  x[1] = x[0] > max;
+  x[3] = x[2] >= maxp1;
+  x[5] = x[4] <= max;
+  x[7] = x[6] < maxp1;
+}
+
+template <typename T, int N>
+__attribute__((noipa)) void
+test ()
+{
+  V<T, N> *x = (V<T, N> *) foo ();
+  x[1] = x[0] >= 0;
+  x[3] = x[2] > -1;
+  x[5] = x[4] < 0;
+  x[7] = x[6] <= -1;
+}
+
+template <int N>
+__attribute__((noipa)) void
+tests ()
+{
+  test_uns<unsigned char, N, __SCHAR_MAX__, 1U + __SCHAR_MAX__> ();
+  test<signed char, N> ();
+  test_uns<unsigned short int, N, __SHRT_MAX__, 1U + __SHRT_MAX__> ();
+  test<short int, N> ();
+  test_uns<unsigned int, N, __INT_MAX__, 1U + __INT_MAX__> ();
+  test<int, N> ();
+  test_uns<unsigned long int, N, __LONG_MAX__, 1UL + __LONG_MAX__> ();
+  test<long int, N> ();
+  test_uns<unsigned long long int, N, __LONG_LONG_MAX__, 1ULL + __LONG_LONG_MAX__> ();
+  test<long long int, N> ();
+}
+
+void
+all_tests ()
+{
+  tests<1> ();
+  tests<2> ();
+  tests<8> ();
+}
diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr88152-2.C b/gcc/testsuite/g++.dg/tree-ssa/pr88152-2.C
new file mode 100644 (file)
index 0000000..69118b4
--- /dev/null
@@ -0,0 +1,85 @@
+// PR target/88152
+// { dg-do compile { target int32 } }
+// { dg-options "-O2 -Wno-psabi -fdump-tree-forwprop1" }
+// { dg-final { scan-tree-dump-not " (?:>|>=|<|<=) \{ 214748364\[67]" "forwprop1" } }
+// { dg-final { scan-tree-dump-not " (?:>|>=|<|<=) \{ -214748364\[78]" "forwprop1" } }
+// { dg-final { scan-tree-dump-times "(?:return| =) \{ 0, 0, 0, 0 \}" 2 "forwprop1" } }
+// { dg-final { scan-tree-dump-times "(?:return| =) \{ -1, -1, -1, -1 \}" 2 "forwprop1" } }
+// { dg-final { scan-tree-dump-times " == \{ 2147483647, 2147483647, 2147483647, 2147483647 \}" 2 "forwprop1" } }
+// { dg-final { scan-tree-dump-times " != \{ 2147483647, 2147483647, 2147483647, 2147483647 \}" 2 "forwprop1" } }
+// { dg-final { scan-tree-dump-times " == \{ -2147483648, -2147483648, -2147483648, -2147483648 \}" 2 "forwprop1" } }
+// { dg-final { scan-tree-dump-times " != \{ -2147483648, -2147483648, -2147483648, -2147483648 \}" 2 "forwprop1" } }
+
+typedef int V __attribute__((vector_size (16)));
+
+V
+f1 (V a)
+{
+  return a > __INT_MAX__;
+}
+
+V
+f2 (V a)
+{
+  return a >= __INT_MAX__;
+}
+
+V
+f3 (V a)
+{
+  return a < __INT_MAX__;
+}
+
+V
+f4 (V a)
+{
+  return a <= __INT_MAX__;
+}
+
+V
+f5 (V a)
+{
+  return a > -__INT_MAX__ - 1;
+}
+
+V
+f6 (V a)
+{
+  return a >= -__INT_MAX__ - 1;
+}
+
+V
+f7 (V a)
+{
+  return a < -__INT_MAX__ - 1;
+}
+
+V
+f8 (V a)
+{
+  return a <= -__INT_MAX__ - 1;
+}
+
+V
+f9 (V a)
+{
+  return a > __INT_MAX__ - 1;
+}
+
+V
+f10 (V a)
+{
+  return a <= __INT_MAX__ - 1;
+}
+
+V
+f11 (V a)
+{
+  return a >= -__INT_MAX__;
+}
+
+V
+f12 (V a)
+{
+  return a < -__INT_MAX__;
+}
index 1e19a0bbdaccb16648ca6751b3b6f24bfcfe6d36..170ef1300ed240fb6a4bd51bdaf94991e46f1f55 100644 (file)
@@ -1906,6 +1906,18 @@ build_vector_from_val (tree vectype, tree sc)
     }
 }
 
+/* If TYPE is not a vector type, just return SC, otherwise return
+   build_vector_from_val (TYPE, SC).  */
+
+tree
+build_uniform_cst (tree type, tree sc)
+{
+  if (!VECTOR_TYPE_P (type))
+    return sc;
+
+  return build_vector_from_val (type, sc);
+}
+
 /* Build a vector series of type TYPE in which element I has the value
    BASE + I * STEP.  The result is a constant if BASE and STEP are constant
    and a VEC_SERIES_EXPR otherwise.  */
@@ -11212,6 +11224,26 @@ uniform_vector_p (const_tree vec)
   return NULL_TREE;
 }
 
+/* If the argument is INTEGER_CST, return it.  If the argument is vector
+   with all elements the same INTEGER_CST, return that INTEGER_CST.  Otherwise
+   return NULL_TREE.  */
+
+tree
+uniform_integer_cst_p (tree t)
+{
+  if (TREE_CODE (t) == INTEGER_CST)
+    return t;
+
+  if (VECTOR_TYPE_P (TREE_TYPE (t)))
+    {
+      t = uniform_vector_p (t);
+      if (t && TREE_CODE (t) == INTEGER_CST)
+       return t;
+    }
+
+  return NULL_TREE;
+}
+
 /* Build an empty statement at location LOC.  */
 
 tree
index 0767ee80ad369f27a6f2087a2152cb4473806a6b..960526d48a8dbea38dc74bfc171162ccdf238d90 100644 (file)
@@ -4182,6 +4182,7 @@ extern tree build_int_cst_type (tree, poly_int64);
 extern tree make_vector (unsigned, unsigned CXX_MEM_STAT_INFO);
 extern tree build_vector_from_ctor (tree, vec<constructor_elt, va_gc> *);
 extern tree build_vector_from_val (tree, tree);
+extern tree build_uniform_cst (tree, tree);
 extern tree build_vec_series (tree, tree, tree);
 extern tree build_index_vector (tree, poly_uint64, poly_uint64);
 extern void recompute_constructor_flags (tree);
@@ -4492,6 +4493,12 @@ extern tree vector_cst_elt (const_tree, unsigned int);
 
 extern tree uniform_vector_p (const_tree);
 
+/* If the argument is INTEGER_CST, return it.  If the argument is vector
+   with all elements the same INTEGER_CST, return that INTEGER_CST.  Otherwise
+   return NULL_TREE.  */
+
+extern tree uniform_integer_cst_p (tree);
+
 /* Given a CONSTRUCTOR CTOR, return the element values as a vector.  */
 
 extern vec<tree, va_gc> *ctor_to_vec (tree);