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
>