re PR target/88152 (optimize SSE & AVX char compares with subsequent movmskb)
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
This commit is contained in:
parent
b076fecbc2
commit
f06e47d7b6
|
@ -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
|
||||
|
|
74
gcc/match.pd
74
gcc/match.pd
|
@ -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. */
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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> ();
|
||||
}
|
|
@ -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__;
|
||||
}
|
32
gcc/tree.c
32
gcc/tree.c
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue