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