On Wed, 10 Jan 2024, Tamar Christina wrote:
> Hi All,
>
> The vectorizer needs to know during early break vectorization whether the edge
> that will be taken if the condition is true stays or leaves the loop.
>
> This is because the code assumes that if you take the true branch you exit the
> loop. If you don't exit the loop it has to generate a different condition.
>
> Basically it uses this information to decide whether it's generating a
> "any element" or an "all element" check.
>
> Bootstrapped Regtested on aarch64-none-linux-gnu, x86_64-pc-linux-gnu
> and no issues with --enable-lto --with-build-config=bootstrap-O3
> --enable-checking=release,yes,rtl,extra.
>
> Ok for master?
OK.
Richard.
> Thanks,
> Tamar
>
> gcc/ChangeLog:
>
> PR tree-optimization/113287
> * tree-vect-stmts.cc (vectorizable_early_exit): Check the flags on edge
> instead of using BRANCH_EDGE to determine true edge.
>
> gcc/testsuite/ChangeLog:
>
> PR tree-optimization/113287
> * gcc.dg/vect/vect-early-break_100-pr113287.c: New test.
> * gcc.dg/vect/vect-early-break_99-pr113287.c: New test.
>
> --- inline copy of patch --
> diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_100-pr113287.c
> b/gcc/testsuite/gcc.dg/vect/vect-early-break_100-pr113287.c
> new file mode 100644
> index
> ..f908e5bc60779c148dc95bda3e200383d12b9e1e
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_100-pr113287.c
> @@ -0,0 +1,35 @@
> +/* { dg-add-options vect_early_break } */
> +/* { dg-require-effective-target vect_early_break } */
> +/* { dg-require-effective-target vect_int } */
> +/* { dg-require-effective-target bitint } */
> +
> +__attribute__((noipa)) void
> +bar (unsigned long *p)
> +{
> + __builtin_memset (p, 0, 142 * sizeof (unsigned long));
> + p[17] = 0x500UL;
> +}
> +
> +__attribute__((noipa)) int
> +foo (void)
> +{
> + unsigned long r[142];
> + bar (r);
> + unsigned long v = ((long) r[0] >> 31);
> + if (v + 1 > 1)
> +return 1;
> + for (unsigned long i = 1; i <= 140; ++i)
> +if (r[i] != v)
> + return 1;
> + unsigned long w = r[141];
> + if ((unsigned long) (((long) (w << 60)) >> 60) != v)
> +return 1;
> + return 0;
> +}
> +
> +int
> +main ()
> +{
> + if (foo () != 1)
> +__builtin_abort ();
> +}
> diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_99-pr113287.c
> b/gcc/testsuite/gcc.dg/vect/vect-early-break_99-pr113287.c
> new file mode 100644
> index
> ..b92a8a268d803ab1656b4716b1a319ed4edc87a3
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_99-pr113287.c
> @@ -0,0 +1,32 @@
> +/* { dg-add-options vect_early_break } */
> +/* { dg-require-effective-target vect_early_break } */
> +/* { dg-require-effective-target vect_int } */
> +/* { dg-require-effective-target bitint } */
> +
> +_BitInt(998) b;
> +char c;
> +char d;
> +char e;
> +char f;
> +char g;
> +char h;
> +char i;
> +char j;
> +
> +void
> +foo(char y, _BitInt(9020) a, char *r)
> +{
> + char x = __builtin_mul_overflow_p(a << sizeof(a), y, 0);
> + x += c + d + e + f + g + h + i + j + b;
> + *r = x;
> +}
> +
> +int
> +main(void)
> +{
> + char x;
> + foo(5, 5, &x);
> + if (x != 1)
> +__builtin_abort();
> + return 0;
> +}
> diff --git a/gcc/tree-vect-stmts.cc b/gcc/tree-vect-stmts.cc
> index
> 1333d8934783acdb5277e3a03c2b4021fec4777b..da004b0e9e2696cd2ce358d3b221851c7b60b448
> 100644
> --- a/gcc/tree-vect-stmts.cc
> +++ b/gcc/tree-vect-stmts.cc
> @@ -12870,13 +12870,18 @@ vectorizable_early_exit (vec_info *vinfo,
> stmt_vec_info stmt_info,
> rewrite conditions to always be a comparison against 0. To do this it
> sometimes flips the edges. This is fine for scalar, but for vector we
> then have to flip the test, as we're still assuming that if you take the
> - branch edge that we found the exit condition. */
> + branch edge that we found the exit condition. i.e. we need to know
> whether
> + we are generating a `forall` or an `exist` condition. */
>auto new_code = NE_EXPR;
>auto reduc_optab = ior_optab;
>auto reduc_op = BIT_IOR_EXPR;
>tree cst = build_zero_cst (vectype);
> + edge exit_true_edge = EDGE_SUCC (gimple_bb (cond_stmt), 0);
> + if (exit_true_edge->flags & EDGE_FALSE_VALUE)
> +exit_true_edge = EDGE_SUCC (gimple_bb (cond_stmt), 1);
> + gcc_assert (exit_true_edge->flags & EDGE_TRUE_VALUE);
>if (flow_bb_inside_loop_p (LOOP_VINFO_LOOP (loop_vinfo),
> - BRANCH_EDGE (gimple_bb (cond_stmt))->dest))
> + exit_true_edge->dest))
> {
>new_code = EQ_EXPR;
>reduc_optab = and_optab;
>
>
>
>
>
--
Richard Biener
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)