Thanks for the review. I do not have GCC commit access. Could you
please push it for me?

Thanks a lot.
Yongqiang

On Sat, 24 Oct 2026 at 23:06, Richard Biener <[email protected]> wrote:
>
> On Thu, Oct 22, 2026 at 2:23 AM Yongqiang Tian <[email protected]> wrote:
> >
> > CRC verification treats every outside-loop use of an in-loop definition as
> > an observable use.  This includes debug binds, so adding debug information
> > can prevent an otherwise valid CRC loop from being recognized and replaced.
> >
> > Ignore debug statements when checking for outside-loop uses.  Ignoring them
> > alone is not sufficient, however: after the loop is replaced, an 
> > outside-loop
> > debug bind may still refer to an SSA value whose original final-iteration
> > value no longer exists.  Such a bind can make the debugger display an
> > incorrect value.
> >
> > Before replacing the loop, reset outside-loop debug binds that use values
> > defined inside it.  The vectorizer already performs the same reset before
> > peeling a loop, so factor that walk into reset_debug_uses_outside_loop and 
> > use
> > the common helper from both transformations.  Keep debug binds inside the 
> > loop
> > unchanged because the transformed loop body still executes once and those
> > binds may remain valid.
> >
> > Add a regression test that verifies both CRC recognition and that the
> > unrecoverable outside-loop value is marked unavailable.
> >
> > Bootstrapped and regression tested on x86_64-pc-linux-gnu.  The GCC, G++ and
> > libstdc++ testsuites showed no patch-induced regressions.  The new test and
> > the existing gcc.dg CRC tests pass.
>
> This is OK.
>
> Thanks,
> Richard.
>
> > Assisted-by: OpenAI Codex 5.6 Sol, co-reviewed by Claude and Yongqiang Tian.
> >
> >         PR tree-optimization/127716
> >
> > gcc/ChangeLog:
> >
> >         * crc-verification.cc
> >         (crc_symbolic_execution::is_used_outside_the_loop): Ignore debug
> >         statements when checking for outside-loop uses.
> >         * gimple-crc-optimization.cc
> >         (crc_optimization::optimize_crc_loop): Reset outside-loop debug 
> > binds
> >         before replacing the loop.
> >         * tree-ssa-loop-manip.cc (reset_debug_uses_outside_loop): New 
> > function,
> >         factored from vect_do_peeling.
> >         * tree-ssa-loop-manip.h (reset_debug_uses_outside_loop): Declare.
> >         * tree-vect-loop-manip.cc (vect_do_peeling): Use it.
> >
> > gcc/testsuite/ChangeLog:
> >
> >         * gcc.dg/pr127716.c: New test.
> >
> > Suggested-by: Richard Biener <[email protected]>
> > Signed-off-by: Yongqiang Tian <[email protected]>
> > ---
> > Thanks for the suggestion.  This version factors the existing vectorizer
> > logic into a common helper and reuses it for the CRC transformation.
> >
> > Changes in v2:
> >
> > - Factor the vectorizer's existing outside-loop debug-bind reset walk into
> >   reset_debug_uses_outside_loop in tree-ssa-loop-manip.{cc,h}, as suggested 
> > by
> >   Richard.
> > - Reuse the helper from both vect_do_peeling and the CRC transformation.
> > - Rerun the focused test, bootstrap, and full regression tests.
> >
> >  gcc/crc-verification.cc         |  4 +++
> >  gcc/gimple-crc-optimization.cc  |  5 ++++
> >  gcc/testsuite/gcc.dg/pr127716.c | 30 ++++++++++++++++++++++
> >  gcc/tree-ssa-loop-manip.cc      | 45 +++++++++++++++++++++++++++++++++
> >  gcc/tree-ssa-loop-manip.h       |  2 ++
> >  gcc/tree-vect-loop-manip.cc     | 37 ++-------------------------
> >  6 files changed, 88 insertions(+), 35 deletions(-)
> >  create mode 100644 gcc/testsuite/gcc.dg/pr127716.c
> >
> > diff --git a/gcc/crc-verification.cc b/gcc/crc-verification.cc
> > index ead4b8136..ffc93d0df 100644
> > --- a/gcc/crc-verification.cc
> > +++ b/gcc/crc-verification.cc
> > @@ -45,6 +45,10 @@ crc_symbolic_execution::is_used_outside_the_loop (tree 
> > def)
> >    gimple *use_stmt;
> >    FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter, def)
> >      {
> > +      /* Debug uses must not affect whether the loop is recognized.  Stale
> > +        outside-loop binds are reset if the loop is transformed.  */
> > +      if (is_gimple_debug (use_stmt))
> > +       continue;
> >        if (!flow_bb_inside_loop_p (m_crc_loop, use_stmt->bb))
> >         {
> >           if (is_a<gphi *> (use_stmt)
> > diff --git a/gcc/gimple-crc-optimization.cc b/gcc/gimple-crc-optimization.cc
> > index 81ea0a381..ec985148e 100644
> > --- a/gcc/gimple-crc-optimization.cc
> > +++ b/gcc/gimple-crc-optimization.cc
> > @@ -31,6 +31,7 @@ along with GCC; see the file COPYING3.  If not see
> >  #include "tree-cfg.h"
> >  #include "cfgloop.h"
> >  #include "tree-scalar-evolution.h"
> > +#include "tree-ssa-loop-manip.h"
> >  #include "crc-verification.h"
> >  #include "internal-fn.h"
> >  #include "predict.h"
> > @@ -1274,6 +1275,10 @@ crc_optimization::optimize_crc_loop (class loop 
> > *loop, gphi *output_crc)
> >         return false;
> >      }
> >
> > +  basic_block *bbs = get_loop_body (loop);
> > +  reset_debug_uses_outside_loop (loop, bbs, loop->num_nodes);
> > +  free (bbs);
> > +
> >    /* Add IFN call and write the return value in the phi_result.  */
> >    gcall *call = gimple_build_call_internal (ifn, 3, m_crc_arg, m_data_arg,
> >                                             polynomial_arg);
> > diff --git a/gcc/testsuite/gcc.dg/pr127716.c 
> > b/gcc/testsuite/gcc.dg/pr127716.c
> > new file mode 100644
> > index 000000000..c7d3de54c
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/pr127716.c
> > @@ -0,0 +1,30 @@
> > +/* PR tree-optimization/127716 */
> > +/* { dg-do compile } */
> > +/* { dg-options "-O2 -g -fcompare-debug -fdump-tree-crc-details" } */
> > +
> > +typedef unsigned short u16;
> > +
> > +#define POLY 0x1021
> > +
> > +u16
> > +crc16 (u16 data)
> > +{
> > +  int i = 0;
> > +  u16 sh;
> > +
> > +  do
> > +    {
> > +      sh = data << 1;
> > +      if (data & 0x8000)
> > +       data = sh ^ POLY;
> > +      else
> > +       data = sh;
> > +    }
> > +  while (++i < 16);
> > +
> > +  u16 last __attribute__ ((unused)) = sh;
> > +  return data;
> > +}
> > +
> > +/* { dg-final { scan-tree-dump "calculates CRC!" "crc" } } */
> > +/* { dg-final { scan-tree-dump "# DEBUG last => NULL" "crc" } } */
> > diff --git a/gcc/tree-ssa-loop-manip.cc b/gcc/tree-ssa-loop-manip.cc
> > index 7e1a183a1..f1e381e7d 100644
> > --- a/gcc/tree-ssa-loop-manip.cc
> > +++ b/gcc/tree-ssa-loop-manip.cc
> > @@ -47,6 +47,51 @@ along with GCC; see the file COPYING3.  If not see
> >     so that we can free them all at once.  */
> >  static bitmap_obstack loop_renamer_obstack;
> >
> > +/* Reset debug binds outside LOOP that use values defined in the NUM_NODES
> > +   basic blocks in BBS.  */
> > +
> > +void
> > +reset_debug_uses_outside_loop (class loop *loop, basic_block *bbs,
> > +                              unsigned num_nodes)
> > +{
> > +  for (unsigned i = 0; i < num_nodes; ++i)
> > +    {
> > +      basic_block bb = bbs[i];
> > +      imm_use_iterator ui;
> > +      gimple *use_stmt;
> > +      for (gphi_iterator gpi = gsi_start_phis (bb); !gsi_end_p (gpi);
> > +          gsi_next (&gpi))
> > +       {
> > +         FOR_EACH_IMM_USE_STMT (use_stmt, ui,
> > +                                gimple_phi_result (gpi.phi ()))
> > +           if (gimple_debug_bind_p (use_stmt)
> > +               && loop != gimple_bb (use_stmt)->loop_father
> > +               && !flow_loop_nested_p (loop,
> > +                                       gimple_bb (use_stmt)->loop_father))
> > +             {
> > +               gimple_debug_bind_reset_value (use_stmt);
> > +               update_stmt (use_stmt);
> > +             }
> > +       }
> > +      for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi);
> > +          gsi_next (&gsi))
> > +       {
> > +         ssa_op_iter op_iter;
> > +         def_operand_p def_p;
> > +         FOR_EACH_SSA_DEF_OPERAND (def_p, gsi_stmt (gsi), op_iter, 
> > SSA_OP_DEF)
> > +           FOR_EACH_IMM_USE_STMT (use_stmt, ui, DEF_FROM_PTR (def_p))
> > +             if (gimple_debug_bind_p (use_stmt)
> > +                 && loop != gimple_bb (use_stmt)->loop_father
> > +                 && !flow_loop_nested_p (loop,
> > +                                         gimple_bb 
> > (use_stmt)->loop_father))
> > +               {
> > +                 gimple_debug_bind_reset_value (use_stmt);
> > +                 update_stmt (use_stmt);
> > +               }
> > +       }
> > +    }
> > +}
> > +
> >  /* Insert IV increment statements STMTS before or after INCR_POS;
> >     AFTER selects which.  INCR_POS and AFTER can be computed using
> >     standard_iv_increment_position.  */
> > diff --git a/gcc/tree-ssa-loop-manip.h b/gcc/tree-ssa-loop-manip.h
> > index 521aac2db..aaa625e65 100644
> > --- a/gcc/tree-ssa-loop-manip.h
> > +++ b/gcc/tree-ssa-loop-manip.h
> > @@ -22,6 +22,8 @@ along with GCC; see the file COPYING3.  If not see
> >
> >  typedef void (*transform_callback)(class loop *, void *);
> >
> > +extern void reset_debug_uses_outside_loop (class loop *, basic_block *,
> > +                                          unsigned);
> >  extern void insert_iv_increment (gimple_stmt_iterator *, bool, gimple_seq);
> >  extern void create_iv (tree, tree_code, tree, tree, class loop *,
> >                        gimple_stmt_iterator *, bool, tree *, tree *,
> > diff --git a/gcc/tree-vect-loop-manip.cc b/gcc/tree-vect-loop-manip.cc
> > index 5e875d88f..a127fe4d1 100644
> > --- a/gcc/tree-vect-loop-manip.cc
> > +++ b/gcc/tree-vect-loop-manip.cc
> > @@ -3522,41 +3522,8 @@ vect_do_peeling (loop_vec_info loop_vinfo, tree 
> > niters, tree nitersm1,
> >    /* Before doing any peeling make sure to reset debug binds outside of
> >       the loop referring to defs not in LC SSA.  */
> >    class loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
> > -  for (unsigned i = 0; i < loop->num_nodes; ++i)
> > -    {
> > -      basic_block bb = LOOP_VINFO_BBS (loop_vinfo)[i];
> > -      imm_use_iterator ui;
> > -      gimple *use_stmt;
> > -      for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
> > -          gsi_next (&gsi))
> > -       {
> > -         FOR_EACH_IMM_USE_STMT (use_stmt, ui, gimple_phi_result (gsi.phi 
> > ()))
> > -           if (gimple_debug_bind_p (use_stmt)
> > -               && loop != gimple_bb (use_stmt)->loop_father
> > -               && !flow_loop_nested_p (loop,
> > -                                       gimple_bb (use_stmt)->loop_father))
> > -             {
> > -               gimple_debug_bind_reset_value (use_stmt);
> > -               update_stmt (use_stmt);
> > -             }
> > -       }
> > -      for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi);
> > -          gsi_next (&gsi))
> > -       {
> > -         ssa_op_iter op_iter;
> > -         def_operand_p def_p;
> > -         FOR_EACH_SSA_DEF_OPERAND (def_p, gsi_stmt (gsi), op_iter, 
> > SSA_OP_DEF)
> > -           FOR_EACH_IMM_USE_STMT (use_stmt, ui, DEF_FROM_PTR (def_p))
> > -             if (gimple_debug_bind_p (use_stmt)
> > -                 && loop != gimple_bb (use_stmt)->loop_father
> > -                 && !flow_loop_nested_p (loop,
> > -                                         gimple_bb 
> > (use_stmt)->loop_father))
> > -               {
> > -                 gimple_debug_bind_reset_value (use_stmt);
> > -                 update_stmt (use_stmt);
> > -               }
> > -       }
> > -    }
> > +  reset_debug_uses_outside_loop (loop, LOOP_VINFO_BBS (loop_vinfo),
> > +                                loop->num_nodes);
> >
> >    prob_vector = profile_probability::guessed_always ().apply_scale (9, 10);
> >    estimated_vf = vect_vf_for_cost (loop_vinfo);
> > --
> > 2.34.1
> >

Reply via email to