This fixes an ordering problem with verifying that no intermediate computations in a reduction path are used outside of the chain. The check was disabled for value-preserving conversions at the tail but whether a stmt was a conversion or not was only computed after the first use. The following fixes this by re-ordering things accordingly.
Bootstrapped and tested on x86_64-unknown-linux-gnu, pushed. 2021-02-25 Richard Biener <rguent...@suse.de> PR tree-optimization/99253 * tree-vect-loop.c (check_reduction_path): First compute code, then verify out-of-loop uses. * gcc.dg/vect/pr99253.c: New testcase. --- gcc/testsuite/gcc.dg/vect/pr99253.c | 22 ++++++++++++ gcc/tree-vect-loop.c | 56 ++++++++++++++--------------- 2 files changed, 50 insertions(+), 28 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/vect/pr99253.c diff --git a/gcc/testsuite/gcc.dg/vect/pr99253.c b/gcc/testsuite/gcc.dg/vect/pr99253.c new file mode 100644 index 00000000000..9e3345025ba --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/pr99253.c @@ -0,0 +1,22 @@ +/* { dg-do run } */ + +#include "tree-vect.h" + +int a = 0; +static int b = 0; +long c = 0; + +int +main() +{ + check_vect (); + for (int d = 0; d < 8; d++) + { + a ^= c; + b = a; + a ^= 1; + } + if (a != 0 || b != 1) + __builtin_abort(); + return 0; +} diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index 27845c01430..3e973e774af 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -3432,34 +3432,6 @@ pop: fail = true; break; } - /* Check there's only a single stmt the op is used on. For the - not value-changing tail and the last stmt allow out-of-loop uses. - ??? We could relax this and handle arbitrary live stmts by - forcing a scalar epilogue for example. */ - imm_use_iterator imm_iter; - gimple *op_use_stmt; - unsigned cnt = 0; - FOR_EACH_IMM_USE_STMT (op_use_stmt, imm_iter, op) - if (!is_gimple_debug (op_use_stmt) - && (*code != ERROR_MARK - || flow_bb_inside_loop_p (loop, gimple_bb (op_use_stmt)))) - { - /* We want to allow x + x but not x < 1 ? x : 2. */ - if (is_gimple_assign (op_use_stmt) - && gimple_assign_rhs_code (op_use_stmt) == COND_EXPR) - { - use_operand_p use_p; - FOR_EACH_IMM_USE_ON_STMT (use_p, imm_iter) - cnt++; - } - else - cnt++; - } - if (cnt != 1) - { - fail = true; - break; - } tree_code use_code = gimple_assign_rhs_code (use_stmt); if (use_code == MINUS_EXPR) { @@ -3489,6 +3461,34 @@ pop: fail = true; break; } + /* Check there's only a single stmt the op is used on. For the + not value-changing tail and the last stmt allow out-of-loop uses. + ??? We could relax this and handle arbitrary live stmts by + forcing a scalar epilogue for example. */ + imm_use_iterator imm_iter; + gimple *op_use_stmt; + unsigned cnt = 0; + FOR_EACH_IMM_USE_STMT (op_use_stmt, imm_iter, op) + if (!is_gimple_debug (op_use_stmt) + && (*code != ERROR_MARK + || flow_bb_inside_loop_p (loop, gimple_bb (op_use_stmt)))) + { + /* We want to allow x + x but not x < 1 ? x : 2. */ + if (is_gimple_assign (op_use_stmt) + && gimple_assign_rhs_code (op_use_stmt) == COND_EXPR) + { + use_operand_p use_p; + FOR_EACH_IMM_USE_ON_STMT (use_p, imm_iter) + cnt++; + } + else + cnt++; + } + if (cnt != 1) + { + fail = true; + break; + } } return ! fail && ! neg && *code != ERROR_MARK; } -- 2.26.2