Allow non-overflow ops in vect_is_simple_reduction_1
2015-07-28 Tom de Vries <tom@codesourcery.com>
* tree.c (operation_overflows_and_traps, operation_no_overflow_or_wraps)
(operation_overflows_and_undefined): New function.
* tree.h (operation_overflows_and_traps, operation_no_overflow_or_wraps)
(operation_overflows_and_undefined): Declare.
* tree-vect-loop.c (vect_is_simple_reduction_1): Use
operation_overflows_and_traps and operation_overflows_and_wraps.
* graphite-sese-to-poly.c (is_reduction_operation_p): Same.
* gcc.dg/autopar/reduc-2char.c (init_arrays): Mark with attribute
optimize ("-ftree-parallelize-loops=0").
Add successful scans for 2 detected reductions. Add xfail scans for 3
detected reductions.
* gcc.dg/autopar/reduc-2short.c: Same.
* gcc.dg/autopar/reduc-8.c (init_arrays): Mark with attribute
optimize ("-ftree-parallelize-loops=0"). Add successful scans for 2
detected reductions.
* gcc.dg/vect/trapv-vect-reduc-4.c: Update scan to match vectorized min
and max reductions.
---
gcc/graphite-sese-to-poly.c | 6 +-
gcc/testsuite/gcc.dg/autopar/reduc-2char.c | 10 +-
gcc/testsuite/gcc.dg/autopar/reduc-2short.c | 10 +-
gcc/testsuite/gcc.dg/autopar/reduc-8.c | 7 +-
gcc/testsuite/gcc.dg/vect/trapv-vect-reduc-4.c | 2 +-
gcc/tree-vect-loop.c | 5 +-
gcc/tree.c | 125 +++++++++++++++++++++++++
gcc/tree.h | 3 +
8 files changed, 153 insertions(+), 15 deletions(-)
@@ -2614,8 +2614,10 @@ is_reduction_operation_p (gimple stmt)
if (FLOAT_TYPE_P (type))
return flag_associative_math;
- return (INTEGRAL_TYPE_P (type)
- && TYPE_OVERFLOW_WRAPS (type));
+ if (ANY_INTEGRAL_TYPE_P (type))
+ return operation_no_overflow_or_wraps (type, code);
+
+ return false;
}
/* Returns true when PHI contains an argument ARG. */
@@ -39,8 +39,9 @@ void main1 (signed char x, signed char max_result, signed char min_result)
abort ();
}
- __attribute__((noinline))
- void init_arrays ()
+void __attribute__((noinline))
+ __attribute__((optimize ("-ftree-parallelize-loops=0")))
+init_arrays ()
{
int i;
@@ -60,7 +61,10 @@ int main (void)
}
-/* { dg-final { scan-tree-dump-times "Detected reduction" 2 "parloops" { xfail *-*-* } } } */
+/* { dg-final { scan-tree-dump-times "Detected reduction" 2 "parloops" } } */
+/* { dg-final { scan-tree-dump-times "Detected reduction" 3 "parloops" { xfail *-*-* } } } */
+
+/* { dg-final { scan-tree-dump-times "SUCCESS: may be parallelized" 2 "parloops" } } */
/* { dg-final { scan-tree-dump-times "SUCCESS: may be parallelized" 3 "parloops" { xfail *-*-* } } } */
@@ -38,8 +38,9 @@ void main1 (short x, short max_result, short min_result)
abort ();
}
- __attribute__((noinline))
- void init_arrays ()
+void __attribute__((noinline))
+ __attribute__((optimize ("-ftree-parallelize-loops=0")))
+init_arrays ()
{
int i;
@@ -58,7 +59,8 @@ int main (void)
return 0;
}
+/* { dg-final { scan-tree-dump-times "Detected reduction" 2 "parloops" } } */
+/* { dg-final { scan-tree-dump-times "Detected reduction" 3 "parloops" { xfail *-*-* } } } */
-/* { dg-final { scan-tree-dump-times "Detected reduction" 2 "parloops" { xfail *-*-* } } } */
+/* { dg-final { scan-tree-dump-times "SUCCESS: may be parallelized" 2 "parloops" } } */
/* { dg-final { scan-tree-dump-times "SUCCESS: may be parallelized" 3 "parloops" { xfail *-*-* } } } */
-
@@ -40,7 +40,8 @@ testmin (const T *c, T init, T result)
abort ();
}
-int main (void)
+int __attribute__((optimize ("-ftree-parallelize-loops=0")))
+main (void)
{
static signed char A[N] = {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
@@ -84,5 +85,5 @@ int main (void)
}
-/* { dg-final { scan-tree-dump-times "Detected reduction" 2 "parloops" { xfail *-*-* } } } */
-/* { dg-final { scan-tree-dump-times "SUCCESS: may be parallelized" 3 "parloops" { xfail *-*-* } } } */
+/* { dg-final { scan-tree-dump-times "Detected reduction" 2 "parloops" } } */
+/* { dg-final { scan-tree-dump-times "SUCCESS: may be parallelized" 2 "parloops" } } */
@@ -46,4 +46,4 @@ int main (void)
return 0;
}
-/* { dg-final { scan-tree-dump-times "vectorized 0 loops" 1 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 2 loops" 1 "vect" } } */
@@ -2615,7 +2615,7 @@ vect_is_simple_reduction_1 (loop_vec_info loop_info, gimple phi,
}
else if (INTEGRAL_TYPE_P (type) && check_reduction)
{
- if (TYPE_OVERFLOW_TRAPS (type))
+ if (operation_overflows_and_traps (type, code))
{
/* Changing the order of operations changes the semantics. */
if (dump_enabled_p ())
@@ -2624,7 +2624,8 @@ vect_is_simple_reduction_1 (loop_vec_info loop_info, gimple phi,
" (overflow traps): ");
return NULL;
}
- if (need_wrapping_integral_overflow && !TYPE_OVERFLOW_WRAPS (type))
+ if (need_wrapping_integral_overflow
+ && !operation_no_overflow_or_wraps (type, code))
{
/* Changing the order of operations changes the semantics. */
if (dump_enabled_p ())
@@ -7597,6 +7597,131 @@ commutative_ternary_tree_code (enum tree_code code)
return false;
}
+/* Returns true if CODE operating on operands of type TYPE can overflow, and
+ fwrapv generates trapping insns for CODE. */
+
+bool
+operation_overflows_and_traps (tree type, enum tree_code code)
+{
+ gcc_checking_assert (ANY_INTEGRAL_TYPE_P (type));
+
+ /* We don't take advantage of integral type overflow behaviour for complex and
+ vector types. */
+ if (!INTEGRAL_TYPE_P (type))
+ return true;
+
+ if (!TYPE_OVERFLOW_TRAPS (type))
+ return false;
+
+ switch (code)
+ {
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ case MULT_EXPR:
+ case LSHIFT_EXPR:
+ /* Can overflow in various ways. */
+ return true;
+ case TRUNC_DIV_EXPR:
+ case EXACT_DIV_EXPR:
+ case FLOOR_DIV_EXPR:
+ case CEIL_DIV_EXPR:
+ /* These operators can overflow, but -fwrapv only generates trapping code
+ for addition, subtraction and multiplication operations. */
+ return false;
+ case NEGATE_EXPR:
+ case ABS_EXPR:
+ /* For -INT_MIN. */
+ return true;
+ default:
+ return false;
+ }
+}
+
+/* Returns true if CODE operating on operands of type TYPE cannot overflow, or
+ wraps on overflow. */
+
+bool
+operation_no_overflow_or_wraps (tree type, enum tree_code code)
+{
+ gcc_checking_assert (ANY_INTEGRAL_TYPE_P (type));
+
+ /* We don't take advantage of integral type overflow behaviour for complex and
+ vector types. */
+ if (!INTEGRAL_TYPE_P (type))
+ return false;
+
+ if (TYPE_OVERFLOW_WRAPS (type))
+ return true;
+
+ switch (code)
+ {
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ case MULT_EXPR:
+ case LSHIFT_EXPR:
+ /* Can overflow in various ways. */
+ return false;
+ case TRUNC_DIV_EXPR:
+ case EXACT_DIV_EXPR:
+ case FLOOR_DIV_EXPR:
+ case CEIL_DIV_EXPR:
+ /* For INT_MIN / -1. */
+ return false;
+ case NEGATE_EXPR:
+ case ABS_EXPR:
+ /* For -INT_MIN. */
+ return false;
+ default:
+ return true;
+ }
+}
+
+/* Returns true if CODE operating on operands of type TYPE can overflow, and
+ overflow is undefined. */
+
+bool
+operation_overflow_and_undefined (tree type, enum tree_code code)
+{
+ gcc_checking_assert (ANY_INTEGRAL_TYPE_P (type));
+
+ /* We don't take advantage of integral type overflow behaviour for complex and
+ vector types. */
+ if (!INTEGRAL_TYPE_P (type))
+ return false;
+
+ if (!TYPE_OVERFLOW_UNDEFINED (type))
+ return false;
+
+ switch (code)
+ {
+ case LSHIFT_EXPR:
+ /* LSHIFT_EXPR can overflow, but we don't take advantage of that:
+ GCC manual, C Implementation-defined behavior, Integers implementation:
+ GCC does not use the latitude given in C99 and C11 only to treat
+ certain aspects of signed << as undefined, but this is subject to
+ change. */
+ return false;
+ case TRUNC_DIV_EXPR:
+ case EXACT_DIV_EXPR:
+ case FLOOR_DIV_EXPR:
+ case CEIL_DIV_EXPR:
+ /* These operators can overflow, but we don't take advantage of that.
+ FIXME: where has this been documented? */
+ return false;
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ case MULT_EXPR:
+ /* Can overflow in various ways. */
+ return true;
+ case NEGATE_EXPR:
+ case ABS_EXPR:
+ /* For -INT_MIN. */
+ return true;
+ default:
+ return false;
+ }
+}
+
namespace inchash
{
@@ -4369,6 +4369,9 @@ extern int type_num_arguments (const_tree);
extern bool associative_tree_code (enum tree_code);
extern bool commutative_tree_code (enum tree_code);
extern bool commutative_ternary_tree_code (enum tree_code);
+extern bool operation_overflows_and_traps (tree, enum tree_code);
+extern bool operation_no_overflow_or_wraps (tree, enum tree_code);
+extern bool operation_overflows_and_undefined (tree, enum tree_code);
extern tree upper_bound_in_type (tree, tree);
extern tree lower_bound_in_type (tree, tree);
extern int operand_equal_for_phi_arg_p (const_tree, const_tree);
--
1.9.1