On Thu, Nov 20, 2025 at 5:17 PM Andrew Pinski
<[email protected]> wrote:
>
> Thinking about unreachable vs all noreturn calls,
> ch should support all noreturn calls similarly. This
> allows the testcase be optimized to memset as expected.
> This should also improve code generation of GCC code itself.
> Since there are a lot of `if(a)assert_failed();` calls.
> Also we don't want to treat `if(static)abort();` that way as that
> will most likely be the induction variable comparison.
> We do want to stop looking for noreturn if the first bb was not
> a noreturn and not an invariant comparison.
>
> 20030711-1.c needed to be updated since we copy the "full" loop header
> which included the `if(a) abort();`. Which it was before 
> r9-68-g2925cd9d1c9d9e .

I'll note we handle a { printf("oops"); abort (); } exit differently
as we only match
the first stmt on the exit.  I'll also note that not all noreturns
might be exceptional
if you consider exit(0); or a function call wrapping lots of work and
an exit(0);,

While I agree that __builtin_trap() or unreachable_trap () should behave the
same I'm not sure those are really the same as a general noreturn call.
Heuristically it might work out, of course (you could also argue about a
std::throw () on loop exit?).

Thanks,
Richard.

>         PR tree-optimization/122734
>
> gcc/ChangeLog:
>
>         * tree-ssa-loop-ch.cc (should_duplicate_loop_header_p):
>         s/canbe_unreachable/canbe_noreturn/. Instead of checking for
>         __builtin_unreachable just allow for the first stmt being a
>         noreturn call.
>         (ch_base::copy_headers): s/canbe_unreachable/canbe_noreturn/.
>
> gcc/testsuite/ChangeLog:
>
>         * gcc.dg/tree-ssa/copy-headers-11.c: New test.
>         * gcc.dg/tree-ssa/20030711-1.c: Update.
>
> Signed-off-by: Andrew Pinski <[email protected]>
> ---
>  gcc/testsuite/gcc.dg/tree-ssa/20030711-1.c    |  8 +++---
>  .../gcc.dg/tree-ssa/copy-headers-11.c         | 25 +++++++++++++++++++
>  gcc/tree-ssa-loop-ch.cc                       | 19 +++++++-------
>  3 files changed, 39 insertions(+), 13 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/copy-headers-11.c
>
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030711-1.c 
> b/gcc/testsuite/gcc.dg/tree-ssa/20030711-1.c
> index c3f75eff29e..29e1df7a707 100644
> --- a/gcc/testsuite/gcc.dg/tree-ssa/20030711-1.c
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030711-1.c
> @@ -44,12 +44,12 @@ record_component_aliases (type)
>  /* The call to blah can not be eliminated.  */
>  /* { dg-final { scan-tree-dump-times "blah \\(\\)" 1 "dom2" } } */
>
> -/* There should be three IF conditionals.  */
> -/* { dg-final { scan-tree-dump-times "if " 3 "dom2"} } */
> +/* There should be four IF conditionals.  */
> +/* { dg-final { scan-tree-dump-times "if " 4 "dom2"} } */
>
>  /* There should be two loads of type.binfo.  */
>  /* { dg-final { scan-tree-dump-times "type\\.binfo" 2 "dom2"} } */
>
> -/* There should be three loads of vec.length.  */
> -/* { dg-final { scan-tree-dump-times "vec.length" 3 "dom2"} } */
> +/* There should be four loads of vec.length.  */
> +/* { dg-final { scan-tree-dump-times "vec.length" 4 "dom2"} } */
>
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/copy-headers-11.c 
> b/gcc/testsuite/gcc.dg/tree-ssa/copy-headers-11.c
> new file mode 100644
> index 00000000000..2223a72f023
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/copy-headers-11.c
> @@ -0,0 +1,25 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O3 -fdump-tree-ch-details -fdump-tree-ldist-details" } */
> +
> +/* PR tree-optimization/122734 */
> +/* We want to duplicate the block after the one containing the condition 
> going to unreachable.
> +   Since later on we will be removing the condition going to unreachable 
> anyways. */
> +/* So in the end ldist can generate a memset. */
> +
> +static inline int size(int *a)
> +{
> +  int t = *a;
> +  if (t < 0)  __builtin_trap();
> +  return t;
> +}
> +
> +void f(int *l, short *d)
> +{
> +  for(int i = 0; i < size(l); i++)
> +    d[i] = 0;
> +}
> +
> +/* { dg-final { scan-tree-dump-times "Duplicating bb . is a win" 1 "ch2" } } 
> */
> +/* { dg-final { scan-tree-dump-times "Will duplicate bb" 2 "ch2" } } */
> +/* { dg-final { scan-tree-dump "is now do-while loop" "ch2" } } */
> +/* { dg-final { scan-tree-dump "generated memset zero" "ldist" } } */
> diff --git a/gcc/tree-ssa-loop-ch.cc b/gcc/tree-ssa-loop-ch.cc
> index 56b60022360..51ba8971be3 100644
> --- a/gcc/tree-ssa-loop-ch.cc
> +++ b/gcc/tree-ssa-loop-ch.cc
> @@ -190,7 +190,7 @@ enum ch_decision
>
>  /* Check whether we should duplicate HEADER of LOOP.  At most *LIMIT
>     instructions should be duplicated, limit is decreased by the actual
> -   amount.  In the case of *CANBE_UNREACHBABLE, if there is a exit edge of 
> the HEADER, that goes directly to unreachable, then consider that as 
> invariant and continue. Set *CANBE_UNREACHBABLE to false otherwise.  */
> +   amount.  In the case of *CANBE_NORETURN, if there is a exit edge of the 
> HEADER, that goes directly to unreachable, then consider that as invariant 
> and continue. Set *CANBE_NORETURN to false otherwise.  */
>
>  static ch_decision
>  should_duplicate_loop_header_p (basic_block header, class loop *loop,
> @@ -198,7 +198,7 @@ should_duplicate_loop_header_p (basic_block header, class 
> loop *loop,
>                                 int *limit,
>                                 hash_set <edge> *invariant_exits,
>                                 hash_set <edge> *static_exits,
> -                               bool *canbe_unreachable)
> +                               bool *canbe_noreturn)
>  {
>    gimple_stmt_iterator bsi;
>
> @@ -461,9 +461,9 @@ should_duplicate_loop_header_p (basic_block header, class 
> loop *loop,
>         }
>        return ch_win_invariant_exit;
>      }
> -  if (*canbe_unreachable)
> +  if (!static_exit && *canbe_noreturn)
>      {
> -      /* See if one of the edges are an edge to __builtin_unreachable().
> +      /* See if one of the edges are an edge to noreturn function call.
>          If so treat it as invariant exit win.  */
>        edge e;
>        edge_iterator ei;
> @@ -473,19 +473,20 @@ should_duplicate_loop_header_p (basic_block header, 
> class loop *loop,
>           {
>             auto gsi = gsi_start_nondebug_after_labels_bb (e->dest);
>             if (!gsi_end_p (gsi)
> -               && gimple_call_builtin_p (*gsi, BUILT_IN_UNREACHABLE))
> +               && is_a<gcall*>(*gsi)
> +               && gimple_call_noreturn_p (*gsi))
>              {
>                 hasone = true;
>                 if (dump_file && (dump_flags & TDF_DETAILS))
>                   fprintf (dump_file,
> -                          "    `unreachable` exit %i->%i\n",
> +                          "    `noreturn` exit %i->%i\n",
>                            e->src->index, e->dest->index);
>              }
>           }
>        if (hasone)
>         return ch_win_invariant_exit;
> -      *canbe_unreachable = false;
>      }
> +  *canbe_noreturn = false;
>
>    /* If the static exit fully optimize out, it is win to "duplicate"
>       it.
> @@ -872,12 +873,12 @@ ch_base::copy_headers (function *fun)
>        auto_vec <ch_decision, 32> decision;
>        hash_set <edge> *invariant_exits = new hash_set <edge>;
>        hash_set <edge> *static_exits = new hash_set <edge>;
> -      bool canbe_unreachable = true;
> +      bool canbe_noreturn = true;
>        while ((ret = should_duplicate_loop_header_p (header, loop, ranger,
>                                                     &remaining_limit,
>                                                     invariant_exits,
>                                                     static_exits,
> -                                                   &canbe_unreachable))
> +                                                   &canbe_noreturn))
>              != ch_impossible)
>         {
>           nheaders++;
> --
> 2.43.0
>

Reply via email to