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 >
