On Mon, Dec 2, 2024 at 10:52 PM Andrew Pinski <quic_apin...@quicinc.com> wrote:
>
> After r12-5300-gf98f373dd822b3, phiopt could get the following bb structure:
>       |
>     middle-bb -----|
>       |            |
>       |   |----|   |
>     phi<1, 2>  |   |
>     cond       |   |
>       |        |   |
>       |--------+---|
>
> Which was considered 2 loops. The inner loop had esimtate of upper_bound to 
> be 8,
> due to the original `for (b = 0; b <= 7; b++)`. The outer loop was already an
> infinite one.
> So phiopt would come along and change the condition to be unconditionally true
> and cleanup cfg would remove the condition and remove the outer loop but not
> update the inner one becoming an infinite loop.
> I decided it was easier to avoid this inside phiopt rather than figuring out 
> how
> to fix up cleanup cfg.
>
> This patch avoids the issue by rejecting edges back to the condition bb before
> loop optmiizations have been run.
>
> Bootstrapped and tested on x86_64-linux-gnu.
>
> Note since the testcases depend on the loop being infinite, I used the alarm 
> signal trick.
>
>         PR tree-optimization/117243
>         PR tree-optimization/116749
>
> gcc/ChangeLog:
>
>         * tree-ssa-phiopt.cc (execute_over_cond_phis): Reject edges back
>         to the conditional bb before loop optimizers have been run.
>
> gcc/testsuite/ChangeLog:
>
>         * gcc.dg/torture/pr117243-1.c: New test.
>         * gcc.dg/torture/pr117243-2.c: New test.
>
> Signed-off-by: Andrew Pinski <quic_apin...@quicinc.com>
> ---
>  gcc/testsuite/gcc.dg/torture/pr117243-1.c | 44 ++++++++++++++++++
>  gcc/testsuite/gcc.dg/torture/pr117243-2.c | 54 +++++++++++++++++++++++
>  gcc/tree-ssa-phiopt.cc                    |  7 +++
>  3 files changed, 105 insertions(+)
>  create mode 100644 gcc/testsuite/gcc.dg/torture/pr117243-1.c
>  create mode 100644 gcc/testsuite/gcc.dg/torture/pr117243-2.c
>
> diff --git a/gcc/testsuite/gcc.dg/torture/pr117243-1.c 
> b/gcc/testsuite/gcc.dg/torture/pr117243-1.c
> new file mode 100644
> index 00000000000..46723132553
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/torture/pr117243-1.c
> @@ -0,0 +1,44 @@
> +/* { dg-do run } */
> +/* { dg-require-effective-target signal } */
> +
> +/* PR tree-optimization/117243 */
> +#include <unistd.h>
> +#include <signal.h>
> +#include <stdlib.h>
> +
> +void do_exit (int i)
> +{
> +  exit (0);
> +}
> +
> +/* foo should be an infinite but sometimes it gets optimized incorrectly into
> +   an __builtin_unreachable(); which is not valid.  */
> +void
> +foo (unsigned int a, unsigned char b)
> +{
> +  lbl:
> +  for (b = 0; b <= 7; b++)
> +    {
> +      unsigned char c[1][1];
> +      int i, j;
> +      for (i = 0; i < 1; i++)
> +        for (j = 0; j < 1; j++)
> +          c[i][j] = 1;
> +      if (b)
> +       goto lbl;
> +    }
> +}
> +
> +int
> +main ()
> +{
> +  struct sigaction s;
> +  sigemptyset (&s.sa_mask);
> +  s.sa_handler = do_exit;
> +  s.sa_flags = 0;
> +  sigaction (SIGALRM, &s, NULL);
> +  alarm (1);
> +
> +  foo (1, 2);
> +}
> +
> diff --git a/gcc/testsuite/gcc.dg/torture/pr117243-2.c 
> b/gcc/testsuite/gcc.dg/torture/pr117243-2.c
> new file mode 100644
> index 00000000000..5cb864b467d
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/torture/pr117243-2.c
> @@ -0,0 +1,54 @@
> +/* { dg-do run } */
> +/* { dg-additional-options "-fno-tree-ch" } */
> +/* { dg-require-effective-target signal } */
> +
> +/* PR tree-optimization/117243 */
> +/* PR tree-optimization/116749 */
> +#include <unistd.h>
> +#include <signal.h>
> +#include <stdlib.h>
> +
> +void do_exit (int i)
> +{
> +  exit (0);
> +}
> +
> +/* main1 should be an infinite but sometimes it gets optimized incorrectly 
> into
> +   an __builtin_unreachable(); which is not valid.  */
> +int main1 (void)
> +{
> +    int g=0;
> +    int l1[1];
> +    int *l2 = &g;
> +    int i;
> +    for (i=0; i<1; i++)
> +        l1[i] = (1);
> +    for (g=0; g; ++g)
> +    {
> +        int *l3[1] = {&l1[0]};
> +    }
> +    *l2 = *l1;
> +b:
> +    for (i=0; i<2; ++i)
> +    {
> +        if (i)
> +            goto b;
> +        if (g)
> +            continue;
> +    }
> +    return 0;
> +}
> +
> +int
> +main (void)
> +{
> +  struct sigaction s;
> +  sigemptyset (&s.sa_mask);
> +  s.sa_handler = do_exit;
> +  s.sa_flags = 0;
> +  sigaction (SIGALRM, &s, NULL);
> +  alarm (1);
> +
> +  main1 ();
> +}
> +
> diff --git a/gcc/tree-ssa-phiopt.cc b/gcc/tree-ssa-phiopt.cc
> index 15651809d71..a2649590d29 100644
> --- a/gcc/tree-ssa-phiopt.cc
> +++ b/gcc/tree-ssa-phiopt.cc
> @@ -4178,6 +4178,13 @@ execute_over_cond_phis (func_type func)
>        e2 = EDGE_SUCC (bb, 1);
>        bb2 = e2->dest;
>
> +      /* If loop opts are not done, then don't handle a loop back to itself.
> +         The loop estimates sometimes are not updated correctly when changing
> +        a loop into an infinite loop.  */
> +      if (!(cfun->curr_properties & PROP_loop_opts_done)
> +         && (bb1 == bb || bb2 == bb))
> +       continue;

It seems incomplete if you think of a forwarder between e1/2->dest and BB.
I'd say you'd want to disallow dominated_by_p (CDI_DOMINATORS, bb, bb1/2),
aka backedges.  And why only when !PROP_loop_opts_done?

Indeed CFG cleanup is supposed to handle all sorts of required loop updates here
but for the case in question phiopt changes the exit condition of a
loop and thus
phiopt is responsible for clearing loop estimates.  So another fix
would be to simply
never process loop exit conditions (loop_exits_from_bb_p (bb->loop_father, bb)),
or if such a condition is altered, call free_numbers_of_iterations_estimates
on the loop and reset ->any_upper_bound and ->any_likely_upper_bound.

Richard.

> +
>        /* We cannot do the optimization on abnormal edges.  */
>        if ((e1->flags & EDGE_ABNORMAL) != 0
>           || (e2->flags & EDGE_ABNORMAL) != 0)
> --
> 2.43.0
>

Reply via email to