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 |
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 > >
--- 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__; +}