From: Alan Hayward Date: Fri, 13 Nov 2015 10:51:34 +0000 (+0000) Subject: Optimize condition reductions where the result is an integer induction variable X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=360e3406fb78ed13f168c25851b343ec6411aa12;p=gcc.git Optimize condition reductions where the result is an integer induction variable 2015-11-13 Alan Hayward gcc/ PR tree-optimization/66558 * tree-vect-loop.c (is_integer_induction):Add. (vectorizable_reduction): Add integer induction checks. gcc/testsuite/ PR tree-optimization/66558 * gcc.dg/vect/pr65947-1.c: Add checks. * gcc.dg/vect/pr65947-2.c: Add checks. * gcc.dg/vect/pr65947-3.c: Add checks. * gcc.dg/vect/pr65947-4.c: Add checks. * gcc.dg/vect/pr65947-5.c: Add checks. * gcc.dg/vect/pr65947-6.c: Add checks. * gcc.dg/vect/pr65947-10.c: Add checks. * gcc.dg/vect/pr65947-12.c: New test. * gcc.dg/vect/pr65947-13.c: New test. From-SVN: r230297 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8623e2198da..9d4758ba927 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2015-11-13 Alan Hayward + + PR tree-optimization/66558 + * tree-vect-loop.c (is_integer_induction):Add. + (vectorizable_reduction): Add integer induction checks. + 2015-11-13 Christophe Lyon Revert [ARM] Remove neon-testgen.ml and generated tests. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 5e8bdba99f0..66b3d181606 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,16 @@ +2015-11-13 Alan Hayward + + PR tree-optimization/66558 + * gcc.dg/vect/pr65947-1.c: Add checks. + * gcc.dg/vect/pr65947-2.c: Add checks. + * gcc.dg/vect/pr65947-3.c: Add checks. + * gcc.dg/vect/pr65947-4.c: Add checks. + * gcc.dg/vect/pr65947-5.c: Add checks. + * gcc.dg/vect/pr65947-6.c: Add checks. + * gcc.dg/vect/pr65947-10.c: Add checks. + * gcc.dg/vect/pr65947-12.c: New test. + * gcc.dg/vect/pr65947-13.c: New test. + 2015-11-13 Christophe Lyon Revert [ARM] Remove neon-testgen.ml and generated tests. diff --git a/gcc/testsuite/gcc.dg/vect/pr65947-1.c b/gcc/testsuite/gcc.dg/vect/pr65947-1.c index 7933f5c8612..1e7a05dc8cc 100644 --- a/gcc/testsuite/gcc.dg/vect/pr65947-1.c +++ b/gcc/testsuite/gcc.dg/vect/pr65947-1.c @@ -9,7 +9,7 @@ extern void abort (void) __attribute__ ((noreturn)); int condition_reduction (int *a, int min_v) { - int last = -1; + int last = 66; /* High start value. */ for (int i = 0; i < N; i++) if (a[i] < min_v) @@ -28,12 +28,13 @@ main (void) 31, 32 }; - int ret = condition_reduction (a, 16); + int ret = condition_reduction (a, 1); - if (ret != 19) + if (ret != 17) abort (); return 0; } /* { dg-final { scan-tree-dump-times "LOOP VECTORIZED" 2 "vect" { xfail { ! vect_max_reduc } } } } */ +/* { dg-final { scan-tree-dump-times "condition expression based on integer induction." 4 "vect" { xfail { ! vect_max_reduc } } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/pr65947-10.c b/gcc/testsuite/gcc.dg/vect/pr65947-10.c index 9a43a6059fa..b4c6659b77c 100644 --- a/gcc/testsuite/gcc.dg/vect/pr65947-10.c +++ b/gcc/testsuite/gcc.dg/vect/pr65947-10.c @@ -37,4 +37,5 @@ main (void) } /* { dg-final { scan-tree-dump-times "LOOP VECTORIZED" 2 "vect" { xfail { ! vect_max_reduc } } } } */ +/* { dg-final { scan-tree-dump-not "condition expression based on integer induction." "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/pr65947-12.c b/gcc/testsuite/gcc.dg/vect/pr65947-12.c new file mode 100644 index 00000000000..fb5ffd48c7b --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/pr65947-12.c @@ -0,0 +1,41 @@ +/* { dg-require-effective-target vect_condition } */ + +extern void abort (void) __attribute__ ((noreturn)); + +#define N 32 + +/* Simple condition reduction where the result is a negative of the induction. + Will fail to vectorize to a simple case. */ + +signed int +condition_reduction (signed int *a, signed int min_v) +{ + signed int last = -1; + + for (signed int i = 0; i < N; i++) + if (a[i] < min_v) + last = -i; + + return last; +} + +int +main (void) +{ + signed int a[N] = { + 11, -12, 13, 14, 15, 16, 17, 18, 19, 20, + 1, 2, -3, 4, 5, 6, 7, -8, 9, 10, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32 + }; + + signed int ret = condition_reduction (a, 16); + + if (ret != -19) + abort (); + + return 0; +} + +/* { dg-final { scan-tree-dump-times "LOOP VECTORIZED" 2 "vect" { xfail { ! vect_max_reduc } } } } */ +/* { dg-final { scan-tree-dump-not "condition expression based on integer induction." "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/pr65947-13.c b/gcc/testsuite/gcc.dg/vect/pr65947-13.c new file mode 100644 index 00000000000..8c6faddd189 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/pr65947-13.c @@ -0,0 +1,41 @@ +/* { dg-require-effective-target vect_condition } */ + +extern void abort (void) __attribute__ ((noreturn)); + +#define N 32 + +/* Simple condition reduction with a reversed loop. + Will fail to vectorize to a simple case. */ + +int +condition_reduction (int *a, int min_v) +{ + int last = -1; + + for (int i = N-1; i >=0; i--) + if (a[i] < min_v) + last = i; + + return last; +} + +int +main (void) +{ + int a[N] = { + 17, 28, 13, 14, 15, 16, 17, 18, 19, 20, + 1, 2, -3, 4, 5, 6, 7, -8, 9, 10, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32 + }; + + int ret = condition_reduction (a, 16); + + if (ret != 2) + abort (); + + return 0; +} + +/* { dg-final { scan-tree-dump-times "LOOP VECTORIZED" 2 "vect" { xfail { ! vect_max_reduc } } } } */ +/* { dg-final { scan-tree-dump-not "condition expression based on integer induction." "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/pr65947-2.c b/gcc/testsuite/gcc.dg/vect/pr65947-2.c index 9c627d9d7d5..9e9ff538286 100644 --- a/gcc/testsuite/gcc.dg/vect/pr65947-2.c +++ b/gcc/testsuite/gcc.dg/vect/pr65947-2.c @@ -38,3 +38,4 @@ main (void) } /* { dg-final { scan-tree-dump-times "LOOP VECTORIZED" 2 "vect" { xfail { ! vect_max_reduc } } } } */ +/* { dg-final { scan-tree-dump-not "condition expression based on integer induction." "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/pr65947-3.c b/gcc/testsuite/gcc.dg/vect/pr65947-3.c index e115de2a282..4b6aa9216b0 100644 --- a/gcc/testsuite/gcc.dg/vect/pr65947-3.c +++ b/gcc/testsuite/gcc.dg/vect/pr65947-3.c @@ -48,3 +48,4 @@ main (void) } /* { dg-final { scan-tree-dump-times "LOOP VECTORIZED" 2 "vect" { xfail { ! vect_max_reduc } } } } */ +/* { dg-final { scan-tree-dump-not "condition expression based on integer induction." "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/pr65947-4.c b/gcc/testsuite/gcc.dg/vect/pr65947-4.c index 76a0567aa54..f4e7fdc97c8 100644 --- a/gcc/testsuite/gcc.dg/vect/pr65947-4.c +++ b/gcc/testsuite/gcc.dg/vect/pr65947-4.c @@ -37,4 +37,5 @@ main (void) } /* { dg-final { scan-tree-dump-times "LOOP VECTORIZED" 2 "vect" { xfail { ! vect_max_reduc } } } } */ +/* { dg-final { scan-tree-dump-times "condition expression based on integer induction." 4 "vect" { xfail { ! vect_max_reduc } } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/pr65947-5.c b/gcc/testsuite/gcc.dg/vect/pr65947-5.c index 360e3b51ee1..21be8d0b749 100644 --- a/gcc/testsuite/gcc.dg/vect/pr65947-5.c +++ b/gcc/testsuite/gcc.dg/vect/pr65947-5.c @@ -39,3 +39,4 @@ main (void) /* { dg-final { scan-tree-dump-times "LOOP VECTORIZED" 1 "vect" { xfail { ! vect_max_reduc } } } } */ /* { dg-final { scan-tree-dump "loop size is greater than data size" "vect" { xfail { ! vect_max_reduc } } } } */ +/* { dg-final { scan-tree-dump-not "condition expression based on integer induction." "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/pr65947-6.c b/gcc/testsuite/gcc.dg/vect/pr65947-6.c index 4997ef79cae..e1432403b2d 100644 --- a/gcc/testsuite/gcc.dg/vect/pr65947-6.c +++ b/gcc/testsuite/gcc.dg/vect/pr65947-6.c @@ -37,3 +37,4 @@ main (void) } /* { dg-final { scan-tree-dump-times "LOOP VECTORIZED" 2 "vect" { xfail { ! vect_max_reduc } } } } */ +/* { dg-final { scan-tree-dump-not "condition expression based on integer induction." "vect" } } */ diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index b2fac611851..4630c86724e 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -4191,7 +4191,7 @@ vect_create_epilog_for_reduction (vec vect_defs, gimple *stmt, tree bitsize; tree adjustment_def = NULL; tree vec_initial_def = NULL; - tree reduction_op, expr, def; + tree reduction_op, expr, def, initial_def = NULL; tree orig_name, scalar_result; imm_use_iterator imm_iter, phi_imm_iter; use_operand_p use_p, phi_use_p; @@ -4252,9 +4252,10 @@ vect_create_epilog_for_reduction (vec vect_defs, gimple *stmt, /* Get at the scalar def before the loop, that defines the initial value of the reduction variable. */ gimple *def_stmt = SSA_NAME_DEF_STMT (reduction_op); - tree op = PHI_ARG_DEF_FROM_EDGE (def_stmt, loop_preheader_edge (loop)); + initial_def = PHI_ARG_DEF_FROM_EDGE (def_stmt, + loop_preheader_edge (loop)); vec_initial_defs.create (1); - vec_initial_def = get_initial_def_for_reduction (stmt, op, + vec_initial_def = get_initial_def_for_reduction (stmt, initial_def, &adjustment_def); vec_initial_defs.quick_push (vec_initial_def); } @@ -4270,9 +4271,25 @@ vect_create_epilog_for_reduction (vec vect_defs, gimple *stmt, def = vect_defs[i]; for (j = 0; j < ncopies; j++) { - /* Set the loop-entry arg of the reduction-phi. */ - add_phi_arg (as_a (phi), vec_init_def, - loop_preheader_edge (loop), UNKNOWN_LOCATION); + /* Set the loop-entry arg of the reduction-phi. */ + + if (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) + == INTEGER_INDUC_COND_REDUCTION) + { + /* Initialise the reduction phi to zero. This prevents initial + values of non-zero interferring with the reduction op. */ + gcc_assert (ncopies == 1); + gcc_assert (i == 0); + + tree vec_init_def_type = TREE_TYPE (vec_init_def); + tree zero_vec = build_zero_cst (vec_init_def_type); + + add_phi_arg (as_a (phi), zero_vec, + loop_preheader_edge (loop), UNKNOWN_LOCATION); + } + else + add_phi_arg (as_a (phi), vec_init_def, + loop_preheader_edge (loop), UNKNOWN_LOCATION); /* Set the loop-latch arg for the reduction-phi. */ if (j > 0) @@ -4614,10 +4631,28 @@ vect_create_epilog_for_reduction (vec vect_defs, gimple *stmt, } else tmp = build1 (reduc_code, scalar_type, new_phi_result); + epilog_stmt = gimple_build_assign (new_scalar_dest, tmp); new_temp = make_ssa_name (new_scalar_dest, epilog_stmt); gimple_assign_set_lhs (epilog_stmt, new_temp); gsi_insert_before (&exit_gsi, epilog_stmt, GSI_SAME_STMT); + + if (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) + == INTEGER_INDUC_COND_REDUCTION) + { + /* Earlier we set the initial value to be zero. Check the result + and if it is zero then replace with the original initial + value. */ + tree zero = build_zero_cst (scalar_type); + tree zcompare = build2 (EQ_EXPR, boolean_type_node, new_temp, zero); + + tmp = make_ssa_name (new_scalar_dest); + epilog_stmt = gimple_build_assign (tmp, COND_EXPR, zcompare, + initial_def, new_temp); + gsi_insert_before (&exit_gsi, epilog_stmt, GSI_SAME_STMT); + new_temp = tmp; + } + scalar_results.safe_push (new_temp); } else @@ -5094,6 +5129,52 @@ vect_finalize_reduction: } +/* Function is_nonwrapping_integer_induction. + + Check if STMT (which is part of loop LOOP) both increments and + does not cause overflow. */ + +static bool +is_nonwrapping_integer_induction (gimple *stmt, struct loop *loop) +{ + stmt_vec_info stmt_vinfo = vinfo_for_stmt (stmt); + tree base = PHI_ARG_DEF_FROM_EDGE (stmt, loop_preheader_edge (loop)); + tree step = STMT_VINFO_LOOP_PHI_EVOLUTION_PART (stmt_vinfo); + tree lhs_type = TREE_TYPE (gimple_phi_result (stmt)); + widest_int ni, max_loop_value, lhs_max; + bool overflow = false; + + /* Make sure the loop is integer based. */ + if (TREE_CODE (base) != INTEGER_CST + || TREE_CODE (step) != INTEGER_CST) + return false; + + /* Check that the induction increments. */ + if (tree_int_cst_sgn (step) == -1) + return false; + + /* Check that the max size of the loop will not wrap. */ + + if (TYPE_OVERFLOW_UNDEFINED (lhs_type)) + return true; + + if (! max_stmt_executions (loop, &ni)) + return false; + + max_loop_value = wi::mul (wi::to_widest (step), ni, TYPE_SIGN (lhs_type), + &overflow); + if (overflow) + return false; + + max_loop_value = wi::add (wi::to_widest (base), max_loop_value, + TYPE_SIGN (lhs_type), &overflow); + if (overflow) + return false; + + return (wi::min_precision (max_loop_value, TYPE_SIGN (lhs_type)) + <= TYPE_PRECISION (lhs_type)); +} + /* Function vectorizable_reduction. Check if STMT performs a reduction operation that can be vectorized. @@ -5192,6 +5273,7 @@ vectorizable_reduction (gimple *stmt, gimple_stmt_iterator *gsi, tree def0, def1, tem, op0, op1 = NULL_TREE; bool first_p = true; tree cr_index_scalar_type = NULL_TREE, cr_index_vector_type = NULL_TREE; + bool cond_expr_is_nonwrapping_integer_induction = false; /* In case of reduction chain we switch to the first stmt in the chain, but we don't update STMT_INFO, since only the last stmt is marked as reduction @@ -5335,6 +5417,16 @@ vectorizable_reduction (gimple *stmt, gimple_stmt_iterator *gsi, reduc_def_stmt = def_stmt; reduc_index = i; } + + if (i == 1 && code == COND_EXPR && dt == vect_induction_def + && is_nonwrapping_integer_induction (def_stmt, loop)) + { + if (dump_enabled_p ()) + dump_printf_loc (MSG_NOTE, vect_location, + "condition expression based on integer " + "induction.\n"); + cond_expr_is_nonwrapping_integer_induction = true; + } } is_simple_use = vect_is_simple_use (ops[i], loop_vinfo, &def_stmt, &dt, &tem); @@ -5364,6 +5456,11 @@ vectorizable_reduction (gimple *stmt, gimple_stmt_iterator *gsi, (loop_vinfo, reduc_def_stmt, !nested_cycle, &dummy, false, &STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info)); + + if (cond_expr_is_nonwrapping_integer_induction + && STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) == COND_REDUCTION) + STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) = INTEGER_INDUC_COND_REDUCTION; + if (orig_stmt) gcc_assert (tmp == orig_stmt || GROUP_FIRST_ELEMENT (vinfo_for_stmt (tmp)) == orig_stmt); @@ -5491,6 +5588,8 @@ vectorizable_reduction (gimple *stmt, gimple_stmt_iterator *gsi, { /* This is a reduction pattern: get the vectype from the type of the reduction variable, and get the tree-code from orig_stmt. */ + gcc_assert (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) + == TREE_CODE_REDUCTION); orig_code = gimple_assign_rhs_code (orig_stmt); gcc_assert (vectype_out); vec_mode = TYPE_MODE (vectype_out); @@ -5500,6 +5599,12 @@ vectorizable_reduction (gimple *stmt, gimple_stmt_iterator *gsi, /* Regular reduction: use the same vectype and tree-code as used for the vector code inside the loop can be used for the epilog code. */ orig_code = code; + + /* For simple condition reductions, replace with the actual expression + we want to base our reduction around. */ + if (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) + == INTEGER_INDUC_COND_REDUCTION) + orig_code = MAX_EXPR; } if (nested_cycle) @@ -5520,7 +5625,9 @@ vectorizable_reduction (gimple *stmt, gimple_stmt_iterator *gsi, epilog_reduc_code = ERROR_MARK; - if (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) == TREE_CODE_REDUCTION) + if (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) == TREE_CODE_REDUCTION + || STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) + == INTEGER_INDUC_COND_REDUCTION) { if (reduction_code_for_scalar_code (orig_code, &epilog_reduc_code)) { @@ -5546,6 +5653,19 @@ vectorizable_reduction (gimple *stmt, gimple_stmt_iterator *gsi, epilog_reduc_code = ERROR_MARK; } } + + /* When epilog_reduc_code is ERROR_MARK then a reduction will be + generated in the epilog using multiple expressions. This does not + work for condition reductions. */ + if (epilog_reduc_code == ERROR_MARK + && STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) + == INTEGER_INDUC_COND_REDUCTION) + { + if (dump_enabled_p ()) + dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, + "no reduc code for scalar code.\n"); + return false; + } } else { @@ -5580,7 +5700,9 @@ vectorizable_reduction (gimple *stmt, gimple_stmt_iterator *gsi, } if ((double_reduc - || STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) == COND_REDUCTION) + || STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) == COND_REDUCTION + || STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) + == INTEGER_INDUC_COND_REDUCTION) && ncopies > 1) { if (dump_enabled_p ()) diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h index 5a6a24073b3..1b5c95c10f4 100644 --- a/gcc/tree-vectorizer.h +++ b/gcc/tree-vectorizer.h @@ -64,7 +64,8 @@ enum vect_def_type { /* Define type of reduction. */ enum vect_reduction_type { TREE_CODE_REDUCTION, - COND_REDUCTION + COND_REDUCTION, + INTEGER_INDUC_COND_REDUCTION }; #define VECTORIZABLE_CYCLE_DEF(D) (((D) == vect_reduction_def) \