tree-optimization/99253 - fix reduction path check

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.

2021-02-25  Richard Biener  <rguenther@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.
This commit is contained in:
Richard Biener 2021-02-25 09:36:33 +01:00
parent 880682e7b2
commit 1193d05465
2 changed files with 50 additions and 28 deletions

View File

@ -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;
}

View File

@ -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;
}