From 286cda3461d6f5ce7d911d3f26bd4975ea7ea11d Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Mon, 1 Jul 2024 10:06:55 +0200 Subject: [PATCH] tree-optimization/115723 - ICE with .COND_ADD reduction The following fixes an ICE with a .COND_ADD discovered as reduction even though its else value isn't the reduction chain link but a constant. This would be wrong-code with --disable-checking I think. PR tree-optimization/115723 * tree-vect-loop.cc (check_reduction_path): For a .COND_ADD verify the else value also refers to the reduction chain op. * gcc.dg/vect/pr115723.c: New testcase. --- gcc/testsuite/gcc.dg/vect/pr115723.c | 25 +++++++++++++++++++++++++ gcc/tree-vect-loop.cc | 12 ++++++++---- 2 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/vect/pr115723.c diff --git a/gcc/testsuite/gcc.dg/vect/pr115723.c b/gcc/testsuite/gcc.dg/vect/pr115723.c new file mode 100644 index 00000000000..b98b29d4870 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/pr115723.c @@ -0,0 +1,25 @@ +/* { dg-additional-options "-ffast-math -fno-unsafe-math-optimizations" } */ + +#include "tree-vect.h" + +double __attribute__((noipa)) +foo (double *x, double *y, int n) +{ + double res = 0.; + for (int i = 0; i < n; ++i) + if (y[i] > 0.) + res += x[i]; + else + res = 64.; + return res; +} + +double y[16] = { 1., 1., 1., 1., 0., 1., 1., 1., + 1., 1., 1., 1., 1., 1., 1., 1. }; +int main () +{ + check_vect (); + if (foo (y, y, 16) != 64. + 11.) + abort (); + return 0; +} diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc index 3095ff5ab6b..a64b5082bd1 100644 --- a/gcc/tree-vect-loop.cc +++ b/gcc/tree-vect-loop.cc @@ -4163,15 +4163,19 @@ pop: FOR_EACH_IMM_USE_STMT (op_use_stmt, imm_iter, op.ops[opi]) { - /* In case of a COND_OP (mask, op1, op2, op1) reduction we might have - op1 twice (once as definition, once as else) in the same operation. - Allow this. */ + /* In case of a COND_OP (mask, op1, op2, op1) reduction we should + have op1 twice (once as definition, once as else) in the same + operation. Enforce this. */ if (cond_fn_p && op_use_stmt == use_stmt) { gcall *call = as_a (use_stmt); unsigned else_pos = internal_fn_else_index (internal_fn (op.code)); - + if (gimple_call_arg (call, else_pos) != op.ops[opi]) + { + fail = true; + break; + } for (unsigned int j = 0; j < gimple_call_num_args (call); ++j) { if (j == else_pos)