On Fri, Nov 21, 2025 at 5:04 AM Richard Biener <[email protected]> wrote: > > On Wed, Nov 19, 2025 at 10:39 PM Andrew Pinski > <[email protected]> wrote: > > > > With the addition of some `if (a) __builtin_unreachable();` in libstdc++, > > the loop ch might not be copying the full header and only copy the bb > > which contains the condition that leads to the `__builtin_unreachable()`. > > We want to continue if there is such a condition on to the next bb and copy > > that too. There is code already to do the copying, just the costing part > > needs to be improved. > > > > In the C testcase we have: > > ``` > > <bb2>: > > goto <bb4>; > > > > <bb3>: > > .... > > > > `````` > > <bb 4> [local count: 1073741824]: > > # i_4 = PHI <0(2), i_11(3)> > > t_8 = *l_7(D); > > if (t_8 < 0) > > goto <bb 5>; [0.04%] > > else > > goto <bb 6>; [99.96%] > > > > <bb 5> [local count: 429496]: > > __builtin_unreachable (); > > > > <bb 6> [local count: 1073312328]: > > if (i_4 < t_8) > > goto <bb 3>; [94.50%] > > else > > goto <bb 7>; [5.50%] > > > > So we want to duplicate bb 4 and bb 6 here and nothing else. Before this > > we would duplicate only bb 4 which caused problems later on for other loop > > optimizations. We remove the unreachable before the loop optimizations but > > don't > > have another ch until right before vect so LIM, ldist and others mess up. > > Hmm, I wonder if, instead of matching unreachable() or sth else, we should > instead see if the branch is predicted to never execute the edge? > (probably_never_executed_edge_p) This would mean we'll at least have > a fallthru series of well-predicted branches.
Let me try that. I see single_likely_exit is exactly what we are trying to get to really. That is those exits are not likely. Thanks, Andrew > > Richard. > > > Bootstrapped and tested on x86_64-linux-gnu. > > > > PR tree-optimization/122734 > > gcc/ChangeLog: > > > > * tree-ssa-loop-ch.cc (should_duplicate_loop_header_p): New argument > > canbe_unreachable. Test canbe_unreachable and treat a conditional > > which > > is leading to a __builtin_unreachable as being an "invariant" one. > > (ch_base::copy_headers): Update call to > > should_duplicate_loop_header_p. > > > > gcc/testsuite/ChangeLog: > > > > * gcc.dg/tree-ssa/copy-headers-10.c: New test. > > > > Signed-off-by: Andrew Pinski <[email protected]> > > --- > > .../gcc.dg/tree-ssa/copy-headers-10.c | 25 ++++++++++++++ > > gcc/tree-ssa-loop-ch.cc | 34 +++++++++++++++++-- > > 2 files changed, 56 insertions(+), 3 deletions(-) > > create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/copy-headers-10.c > > > > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/copy-headers-10.c > > b/gcc/testsuite/gcc.dg/tree-ssa/copy-headers-10.c > > new file mode 100644 > > index 00000000000..5641a9a1d3a > > --- /dev/null > > +++ b/gcc/testsuite/gcc.dg/tree-ssa/copy-headers-10.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_unreachable(); > > + 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 91a61dd4e80..1b38dcf8189 100644 > > --- a/gcc/tree-ssa-loop-ch.cc > > +++ b/gcc/tree-ssa-loop-ch.cc > > @@ -190,14 +190,15 @@ 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. */ > > + 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. */ > > > > static ch_decision > > should_duplicate_loop_header_p (basic_block header, class loop *loop, > > gimple_ranger *ranger, > > int *limit, > > hash_set <edge> *invariant_exits, > > - hash_set <edge> *static_exits) > > + hash_set <edge> *static_exits, > > + bool *canbe_unreachable) > > { > > gimple_stmt_iterator bsi; > > > > @@ -460,6 +461,31 @@ should_duplicate_loop_header_p (basic_block header, > > class loop *loop, > > } > > return ch_win_invariant_exit; > > } > > + if (*canbe_unreachable) > > + { > > + /* See if one of the edges are an edge to __builtin_unreachable(). > > + If so treat it as invariant exit win. */ > > + edge e; > > + edge_iterator ei; > > + bool hasone = false; > > + FOR_EACH_EDGE (e, ei, header->succs) > > + if (loop_exit_edge_p (loop, e)) > > + { > > + auto gsi = gsi_start_nondebug_after_labels_bb (e->dest); > > + if (!gsi_end_p (gsi) > > + && gimple_call_builtin_p (*gsi, BUILT_IN_UNREACHABLE)) > > + { > > + hasone = true; > > + if (dump_file && (dump_flags & TDF_DETAILS)) > > + fprintf (dump_file, > > + " `unreachable` exit %i->%i\n", > > + e->src->index, e->dest->index); > > + } > > + } > > + if (hasone) > > + return ch_win_invariant_exit; > > + *canbe_unreachable = false; > > + } > > > > /* If the static exit fully optimize out, it is win to "duplicate" > > it. > > @@ -846,10 +872,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; > > while ((ret = should_duplicate_loop_header_p (header, loop, ranger, > > &remaining_limit, > > invariant_exits, > > - static_exits)) > > + static_exits, > > + &canbe_unreachable)) > > != ch_impossible) > > { > > nheaders++; > > -- > > 2.43.0 > >
