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
> >

Reply via email to