diff mbox series

Adapt a couple of scalar comparison match.pd optimizations for vector comparisons against uniform vectors (PR target/88152, take 2)

Message ID 20181129102041.GH12380@tucnak
State New
Headers show
Series Adapt a couple of scalar comparison match.pd optimizations for vector comparisons against uniform vectors (PR target/88152, take 2) | expand

Commit Message

Jakub Jelinek Nov. 29, 2018, 10:20 a.m. UTC
On Thu, Nov 29, 2018 at 10:31:06AM +0100, Jakub Jelinek wrote:
> On Thu, Nov 29, 2018 at 10:22:15AM +0100, Richard Biener wrote:
> > OK.  I didn't spent a lot of time trying to see if we can merge the
> > scalar and vector variants but I trust you did ;)
> 
> Yeah, sadly it is too different, even if we were to introduce a predicate
> whether a tree is either INTEGER_CST, or VECTOR_CST where uniform_vector_p
> is non-NULL and INTEGER_CST, e.g. because we need to use build_vector_from_val
> and take care of the sometimes vector, sometimes element types.

Actually, it isn't that bad.
So, would you prefer something like this instead (untested so far)?
Any better suggestions for the 2 new functions?  Just don't want to make
them much longer as that causes formatting issues.

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.

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



	Jakub

Comments

Richard Biener Nov. 29, 2018, 10:27 a.m. UTC | #1
On Thu, 29 Nov 2018, Jakub Jelinek wrote:

> On Thu, Nov 29, 2018 at 10:31:06AM +0100, Jakub Jelinek wrote:
> > On Thu, Nov 29, 2018 at 10:22:15AM +0100, Richard Biener wrote:
> > > OK.  I didn't spent a lot of time trying to see if we can merge the
> > > scalar and vector variants but I trust you did ;)
> > 
> > Yeah, sadly it is too different, even if we were to introduce a predicate
> > whether a tree is either INTEGER_CST, or VECTOR_CST where uniform_vector_p
> > is non-NULL and INTEGER_CST, e.g. because we need to use build_vector_from_val
> > and take care of the sometimes vector, sometimes element types.
> 
> Actually, it isn't that bad.
> So, would you prefer something like this instead (untested so far)?

Yes.

> Any better suggestions for the 2 new functions?  Just don't want to make
> them much longer as that causes formatting issues.

They look good as-is.

Richard.

> 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.
> 
> 	* g++.dg/tree-ssa/pr88152-1.C: New test.
> 	* g++.dg/tree-ssa/pr88152-2.C: New test.
> 
> --- gcc/tree.h.jj	2018-11-23 20:00:29.591224109 +0100
> +++ gcc/tree.h	2018-11-29 11:06:41.258362258 +0100
> @@ -4182,6 +4182,7 @@ extern tree build_int_cst_type (tree, po
>  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,
>  
>  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);
> --- gcc/tree.c.jj	2018-11-23 20:00:29.590224125 +0100
> +++ gcc/tree.c	2018-11-29 11:07:12.569839152 +0100
> @@ -1906,6 +1906,18 @@ build_vector_from_val (tree vectype, tre
>      }
>  }
>  
> +/* 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.  */
> @@ -11210,6 +11222,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.  */
> --- gcc/match.pd.jj	2018-11-29 08:41:21.229948339 +0100
> +++ gcc/match.pd	2018-11-29 11:04:56.325115332 +0100
> @@ -34,6 +34,7 @@ (define_predicates
>     tree_expr_nonzero_p
>     integer_valued_real_p
>     integer_pow2p
> +   uniform_integer_cst_p
>     HONOR_NANS)
>  
>  /* Operator lists.  */
> @@ -3107,16 +3108,22 @@ (define_operator_list COND_TERNARY
>  (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_operator_list COND_TERNARY
>   /* 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_operator_list COND_TERNARY
>  	{ 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_operator_list COND_TERNARY
>          { 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_operator_list COND_TERNARY
>        /* 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.  */
> --- gcc/testsuite/g++.dg/tree-ssa/pr88152-1.C.jj	2018-11-29 08:54:30.535773479 +0100
> +++ gcc/testsuite/g++.dg/tree-ssa/pr88152-1.C	2018-11-29 11:15:17.206742541 +0100
> @@ -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> ();
> +}
> --- gcc/testsuite/g++.dg/tree-ssa/pr88152-2.C.jj	2018-11-29 11:04:08.741910282 +0100
> +++ gcc/testsuite/g++.dg/tree-ssa/pr88152-2.C	2018-11-29 09:20:51.844365763 +0100
> @@ -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__;
> +}
> 
> 
> 	Jakub
> 
>
diff mbox series

Patch

--- gcc/tree.h.jj	2018-11-23 20:00:29.591224109 +0100
+++ gcc/tree.h	2018-11-29 11:06:41.258362258 +0100
@@ -4182,6 +4182,7 @@  extern tree build_int_cst_type (tree, po
 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,
 
 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);
--- gcc/tree.c.jj	2018-11-23 20:00:29.590224125 +0100
+++ gcc/tree.c	2018-11-29 11:07:12.569839152 +0100
@@ -1906,6 +1906,18 @@  build_vector_from_val (tree vectype, tre
     }
 }
 
+/* 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.  */
@@ -11210,6 +11222,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.  */
--- gcc/match.pd.jj	2018-11-29 08:41:21.229948339 +0100
+++ gcc/match.pd	2018-11-29 11:04:56.325115332 +0100
@@ -34,6 +34,7 @@  (define_predicates
    tree_expr_nonzero_p
    integer_valued_real_p
    integer_pow2p
+   uniform_integer_cst_p
    HONOR_NANS)
 
 /* Operator lists.  */
@@ -3107,16 +3108,22 @@  (define_operator_list COND_TERNARY
 (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_operator_list COND_TERNARY
  /* 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_operator_list COND_TERNARY
 	{ 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_operator_list COND_TERNARY
         { 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_operator_list COND_TERNARY
       /* 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.  */
--- gcc/testsuite/g++.dg/tree-ssa/pr88152-1.C.jj	2018-11-29 08:54:30.535773479 +0100
+++ gcc/testsuite/g++.dg/tree-ssa/pr88152-1.C	2018-11-29 11:15:17.206742541 +0100
@@ -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> ();
+}
--- gcc/testsuite/g++.dg/tree-ssa/pr88152-2.C.jj	2018-11-29 11:04:08.741910282 +0100
+++ gcc/testsuite/g++.dg/tree-ssa/pr88152-2.C	2018-11-29 09:20:51.844365763 +0100
@@ -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__;
+}