Message ID | patch-18248-tamar@arm.com |
---|---|
State | New |
Headers | show |
Series | middle-end: fix ICE when destination BB for stores starts with a label [PR113750] | expand |
On Mon, 5 Feb 2024, Tamar Christina wrote: > Hi All, > > The report shows that if the FE leaves a label as the first thing in the dest > BB then we ICE because we move the stores before the label. > > This is easy to fix if we know that there's still only one way into the BB. > We would have already rejected the loop if there was multiple paths into the BB > however I added an additional check just for early break in case the other > constraints are relaxed later with an explanation. > > After that we fix the issue just by getting the GSI after the labels and I add > a bunch of testcases for different positions the label can be added. Only the > vect-early-break_112-pr113750.c one results in the label being kept. > > Bootstrapped Regtested on aarch64-none-linux-gnu and no issues. > > Ok for master? OK. I'll note the extra check is likely redundant with the one for in-loop diamonds. Thanks, Richard. > Thanks, > Tamar > > gcc/ChangeLog: > > PR tree-optimization/113750 > * tree-vect-data-refs.cc (vect_analyze_early_break_dependences): Check > for single predecessor when doing early break vect. > * tree-vect-loop.cc (move_early_exit_stmts): Get gsi at the start but > after labels. > > gcc/testsuite/ChangeLog: > > PR tree-optimization/113750 > * gcc.dg/vect/vect-early-break_112-pr113750.c: New test. > * gcc.dg/vect/vect-early-break_113-pr113750.c: New test. > * gcc.dg/vect/vect-early-break_114-pr113750.c: New test. > * gcc.dg/vect/vect-early-break_115-pr113750.c: New test. > * gcc.dg/vect/vect-early-break_116-pr113750.c: New test. > > --- inline copy of patch -- > diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_112-pr113750.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_112-pr113750.c > new file mode 100644 > index 0000000000000000000000000000000000000000..559ebd84d5c39881e694e7c8c31be29d846866ed > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_112-pr113750.c > @@ -0,0 +1,26 @@ > +/* { dg-do compile } */ > +/* { dg-add-options vect_early_break } */ > +/* { dg-require-effective-target vect_early_break } */ > +/* { dg-require-effective-target vect_int } */ > + > +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */ > + > +#ifndef N > +#define N 800 > +#endif > +unsigned vect_a[N]; > +unsigned vect_b[N]; > + > +unsigned test4(unsigned x) > +{ > + unsigned ret = 0; > + for (int i = 0; i < N; i++) > + { > + vect_b[i] = x + i; > + if (vect_a[i] != x) > + break; > +foo: > + vect_a[i] = x; > + } > + return ret; > +} > diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_113-pr113750.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_113-pr113750.c > new file mode 100644 > index 0000000000000000000000000000000000000000..ba85780a46b1378aaec238ff9eb5f906be9a44dd > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_113-pr113750.c > @@ -0,0 +1,26 @@ > +/* { dg-do compile } */ > +/* { dg-add-options vect_early_break } */ > +/* { dg-require-effective-target vect_early_break } */ > +/* { dg-require-effective-target vect_int } */ > + > +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */ > + > +#ifndef N > +#define N 800 > +#endif > +unsigned vect_a[N]; > +unsigned vect_b[N]; > + > +unsigned test4(unsigned x) > +{ > + unsigned ret = 0; > + for (int i = 0; i < N; i++) > + { > + vect_b[i] = x + i; > + if (vect_a[i] != x) > + break; > + vect_a[i] = x; > +foo: > + } > + return ret; > +} > diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_114-pr113750.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_114-pr113750.c > new file mode 100644 > index 0000000000000000000000000000000000000000..37af2998688f5d60e2cdb372ab43afcaa52a3146 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_114-pr113750.c > @@ -0,0 +1,26 @@ > +/* { dg-do compile } */ > +/* { dg-add-options vect_early_break } */ > +/* { dg-require-effective-target vect_early_break } */ > +/* { dg-require-effective-target vect_int } */ > + > +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */ > + > +#ifndef N > +#define N 800 > +#endif > +unsigned vect_a[N]; > +unsigned vect_b[N]; > + > +unsigned test4(unsigned x) > +{ > + unsigned ret = 0; > + for (int i = 0; i < N; i++) > + { > + vect_b[i] = x + i; > +foo: > + if (vect_a[i] != x) > + break; > + vect_a[i] = x; > + } > + return ret; > +} > diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_115-pr113750.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_115-pr113750.c > new file mode 100644 > index 0000000000000000000000000000000000000000..502686d308e298cd84e9e3b74d7b4ad1979602a9 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_115-pr113750.c > @@ -0,0 +1,26 @@ > +/* { dg-do compile } */ > +/* { dg-add-options vect_early_break } */ > +/* { dg-require-effective-target vect_early_break } */ > +/* { dg-require-effective-target vect_int } */ > + > +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */ > + > +#ifndef N > +#define N 800 > +#endif > +unsigned vect_a[N]; > +unsigned vect_b[N]; > + > +unsigned test4(unsigned x) > +{ > + unsigned ret = 0; > + for (int i = 0; i < N; i++) > + { > +foo: > + vect_b[i] = x + i; > + if (vect_a[i] != x) > + break; > + vect_a[i] = x; > + } > + return ret; > +} > diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_116-pr113750.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_116-pr113750.c > new file mode 100644 > index 0000000000000000000000000000000000000000..4e02158aa351c8e1a5edf6cc7bcab0b5eaa06795 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_116-pr113750.c > @@ -0,0 +1,26 @@ > +/* { dg-do compile } */ > +/* { dg-add-options vect_early_break } */ > +/* { dg-require-effective-target vect_early_break } */ > +/* { dg-require-effective-target vect_int } */ > + > +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */ > + > +#ifndef N > +#define N 800 > +#endif > +unsigned vect_a[N]; > +unsigned vect_b[N]; > + > +unsigned test4(unsigned x) > +{ > + unsigned ret = 0; > + for (int i = 0; i < N; i++) > + { > + vect_b[i] = x + i; > + if (vect_a[i] != x) > +foo: > + break; > + vect_a[i] = x; > + } > + return ret; > +} > diff --git a/gcc/tree-vect-data-refs.cc b/gcc/tree-vect-data-refs.cc > index 53fdfc25d7dc2deb7788176252697d2e455555fc..109d4ce5192f304d31f36fd6dfe32dd1f4bcbe82 100644 > --- a/gcc/tree-vect-data-refs.cc > +++ b/gcc/tree-vect-data-refs.cc > @@ -819,6 +819,18 @@ vect_analyze_early_break_dependences (loop_vec_info loop_vinfo) > trapped already during loop form analysis. */ > gcc_assert (dest_bb->loop_father == loop); > > + /* Check that the destination block we picked has only one pred. To relax this we > + have to take special care when moving the statements. We don't currently support > + such control flow however this check is there to simplify how we handle > + labels that may be present anywhere in the IL. This check is to ensure that the > + labels aren't significant for the CFG. */ > + if (!single_pred (dest_bb)) > + return opt_result::failure_at (vect_location, > + "chosen loop exit block (BB %d) does not have a " > + "single predecessor which is currently not " > + "supported for early break vectorization.\n", > + dest_bb->index); > + > LOOP_VINFO_EARLY_BRK_DEST_BB (loop_vinfo) = dest_bb; > > if (!LOOP_VINFO_EARLY_BRK_VUSES (loop_vinfo).is_empty ()) > diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc > index e2587315020a35a7d4ebd3e7a9842caa36bb5d3c..e85b1fd20eda815d5615c1934c2ac5afcaf53f67 100644 > --- a/gcc/tree-vect-loop.cc > +++ b/gcc/tree-vect-loop.cc > @@ -11786,7 +11786,7 @@ move_early_exit_stmts (loop_vec_info loop_vinfo) > > /* Move all stmts that need moving. */ > basic_block dest_bb = LOOP_VINFO_EARLY_BRK_DEST_BB (loop_vinfo); > - gimple_stmt_iterator dest_gsi = gsi_start_bb (dest_bb); > + gimple_stmt_iterator dest_gsi = gsi_after_labels (dest_bb); > > for (gimple *stmt : LOOP_VINFO_EARLY_BRK_STORES (loop_vinfo)) > { > > > > >
--- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_112-pr113750.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-add-options vect_early_break } */ +/* { dg-require-effective-target vect_early_break } */ +/* { dg-require-effective-target vect_int } */ + +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */ + +#ifndef N +#define N 800 +#endif +unsigned vect_a[N]; +unsigned vect_b[N]; + +unsigned test4(unsigned x) +{ + unsigned ret = 0; + for (int i = 0; i < N; i++) + { + vect_b[i] = x + i; + if (vect_a[i] != x) + break; +foo: + vect_a[i] = x; + } + return ret; +} diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_113-pr113750.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_113-pr113750.c new file mode 100644 index 0000000000000000000000000000000000000000..ba85780a46b1378aaec238ff9eb5f906be9a44dd --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_113-pr113750.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-add-options vect_early_break } */ +/* { dg-require-effective-target vect_early_break } */ +/* { dg-require-effective-target vect_int } */ + +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */ + +#ifndef N +#define N 800 +#endif +unsigned vect_a[N]; +unsigned vect_b[N]; + +unsigned test4(unsigned x) +{ + unsigned ret = 0; + for (int i = 0; i < N; i++) + { + vect_b[i] = x + i; + if (vect_a[i] != x) + break; + vect_a[i] = x; +foo: + } + return ret; +} diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_114-pr113750.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_114-pr113750.c new file mode 100644 index 0000000000000000000000000000000000000000..37af2998688f5d60e2cdb372ab43afcaa52a3146 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_114-pr113750.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-add-options vect_early_break } */ +/* { dg-require-effective-target vect_early_break } */ +/* { dg-require-effective-target vect_int } */ + +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */ + +#ifndef N +#define N 800 +#endif +unsigned vect_a[N]; +unsigned vect_b[N]; + +unsigned test4(unsigned x) +{ + unsigned ret = 0; + for (int i = 0; i < N; i++) + { + vect_b[i] = x + i; +foo: + if (vect_a[i] != x) + break; + vect_a[i] = x; + } + return ret; +} diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_115-pr113750.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_115-pr113750.c new file mode 100644 index 0000000000000000000000000000000000000000..502686d308e298cd84e9e3b74d7b4ad1979602a9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_115-pr113750.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-add-options vect_early_break } */ +/* { dg-require-effective-target vect_early_break } */ +/* { dg-require-effective-target vect_int } */ + +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */ + +#ifndef N +#define N 800 +#endif +unsigned vect_a[N]; +unsigned vect_b[N]; + +unsigned test4(unsigned x) +{ + unsigned ret = 0; + for (int i = 0; i < N; i++) + { +foo: + vect_b[i] = x + i; + if (vect_a[i] != x) + break; + vect_a[i] = x; + } + return ret; +} diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_116-pr113750.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_116-pr113750.c new file mode 100644 index 0000000000000000000000000000000000000000..4e02158aa351c8e1a5edf6cc7bcab0b5eaa06795 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_116-pr113750.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-add-options vect_early_break } */ +/* { dg-require-effective-target vect_early_break } */ +/* { dg-require-effective-target vect_int } */ + +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */ + +#ifndef N +#define N 800 +#endif +unsigned vect_a[N]; +unsigned vect_b[N]; + +unsigned test4(unsigned x) +{ + unsigned ret = 0; + for (int i = 0; i < N; i++) + { + vect_b[i] = x + i; + if (vect_a[i] != x) +foo: + break; + vect_a[i] = x; + } + return ret; +} diff --git a/gcc/tree-vect-data-refs.cc b/gcc/tree-vect-data-refs.cc index 53fdfc25d7dc2deb7788176252697d2e455555fc..109d4ce5192f304d31f36fd6dfe32dd1f4bcbe82 100644 --- a/gcc/tree-vect-data-refs.cc +++ b/gcc/tree-vect-data-refs.cc @@ -819,6 +819,18 @@ vect_analyze_early_break_dependences (loop_vec_info loop_vinfo) trapped already during loop form analysis. */ gcc_assert (dest_bb->loop_father == loop); + /* Check that the destination block we picked has only one pred. To relax this we + have to take special care when moving the statements. We don't currently support + such control flow however this check is there to simplify how we handle + labels that may be present anywhere in the IL. This check is to ensure that the + labels aren't significant for the CFG. */ + if (!single_pred (dest_bb)) + return opt_result::failure_at (vect_location, + "chosen loop exit block (BB %d) does not have a " + "single predecessor which is currently not " + "supported for early break vectorization.\n", + dest_bb->index); + LOOP_VINFO_EARLY_BRK_DEST_BB (loop_vinfo) = dest_bb; if (!LOOP_VINFO_EARLY_BRK_VUSES (loop_vinfo).is_empty ()) diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc index e2587315020a35a7d4ebd3e7a9842caa36bb5d3c..e85b1fd20eda815d5615c1934c2ac5afcaf53f67 100644 --- a/gcc/tree-vect-loop.cc +++ b/gcc/tree-vect-loop.cc @@ -11786,7 +11786,7 @@ move_early_exit_stmts (loop_vec_info loop_vinfo) /* Move all stmts that need moving. */ basic_block dest_bb = LOOP_VINFO_EARLY_BRK_DEST_BB (loop_vinfo); - gimple_stmt_iterator dest_gsi = gsi_start_bb (dest_bb); + gimple_stmt_iterator dest_gsi = gsi_after_labels (dest_bb); for (gimple *stmt : LOOP_VINFO_EARLY_BRK_STORES (loop_vinfo)) {