https://gcc.gnu.org/g:40df8ff06970e783b424299be509115b574d9f13

commit r17-5579-g40df8ff06970e783b424299be509115b574d9f13
Author: Yongqiang Tian <[email protected]>
Date:   Thu Oct 22 11:22:36 2026 +1100

    tree-optimization: Preserve debug correctness in CRC loop replacement 
[PR127716]
    
    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.
    
    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]>

Diff:
---
 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(-)

diff --git a/gcc/crc-verification.cc b/gcc/crc-verification.cc
index ead4b81365cc..ffc93d0df463 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 81ea0a381190..ec985148e08a 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 000000000000..c7d3de54c686
--- /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 7e1a183a1785..f1e381e7d174 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 521aac2dbac1..aaa625e6550e 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 4dfef69de876..56b2a557cde7 100644
--- a/gcc/tree-vect-loop-manip.cc
+++ b/gcc/tree-vect-loop-manip.cc
@@ -3513,41 +3513,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);

Reply via email to