https://gcc.gnu.org/g:4fb2541debcca1d1bd7b71b32cee39755f067640

commit r17-1237-g4fb2541debcca1d1bd7b71b32cee39755f067640
Author: Richard Sandiford <[email protected]>
Date:   Tue Jun 2 20:50:27 2026 +0100

    Relax gsi_replace requirement
    
    gsi_replace requires the new statement to have the same lhs as
    the old one, if both statements have lhses.  This requirement was
    added by r0-96285-g0ca5af51abe63d as part of the DEBUG_EXPR_DECL
    work.  And it makes sense in that context.  If gsi_replace nixes
    the definition of an SSA name that is still referenced by debug
    statements then things are going to go wrong.
    
    But if that's the "only" reason, we should be able to relax the
    condition to say that, if the new statement has a different lhs,
    the caller must ensure that it has updated all debug uses before
    calling gsi_replace.
    
    The patch adds a completely_unused helper to test that.  The helper
    has a sharp edge and is not widely useful, so I've kept it local
    to gimple-iterators.cc for now.
    
    It's arguable that the old code was too forgiving with its
    !gimple_has_lhs (stmt) escape hatch.  A tighter condition would be
    the one tested by:
    
      tree old_lhs = gimple_get_lhs (orig_stmt);
      return (!old_lhs
              || gimple_get_lhs (stmt) == old_lhs
              || completely_unused (old_lhs));
    
    gcc/
            * gimple-iterator.cc (completely_unused): New function.
            (gsi_replace): Allow changes in lhs if the caller has updated
            all uses of the old name, including all debug uses.
            * gimple-fold.cc (gsi_replace_with_seq_vops): Likewise.

Diff:
---
 gcc/gimple-fold.cc     | 10 ++++++++--
 gcc/gimple-iterator.cc | 20 ++++++++++++++++----
 2 files changed, 24 insertions(+), 6 deletions(-)

diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
index 1ceb5aa5fba7..fab4886b0f2e 100644
--- a/gcc/gimple-fold.cc
+++ b/gcc/gimple-fold.cc
@@ -581,8 +581,14 @@ fold_gimple_assign (gimple_stmt_iterator *si)
 
 /* Replace a statement at *SI_P with a sequence of statements in STMTS,
    adjusting the replacement stmts location and virtual operands.
-   If the statement has a lhs the last stmt in the sequence is expected
-   to assign to that lhs.  */
+
+   If the statements has an lhs, either:
+
+   - the last statement of the new sequence must assign to the same lhs or
+
+   - the caller must ensure that all uses of the old lhs have been
+     removed before calling this function.  This includes removing
+     all debug uses.  */
 
 void
 gsi_replace_with_seq_vops (gimple_stmt_iterator *si_p, gimple_seq stmts)
diff --git a/gcc/gimple-iterator.cc b/gcc/gimple-iterator.cc
index 2b6133ec8c02..b6cf30aea6ac 100644
--- a/gcc/gimple-iterator.cc
+++ b/gcc/gimple-iterator.cc
@@ -34,6 +34,14 @@ along with GCC; see the file COPYING3.  If not see
 #include "value-prof.h"
 #include "gimplify.h"
 
+/* Return true if VAR has no uses at all, including no debug uses.  */
+
+static inline bool
+completely_unused (const_tree var)
+{
+  auto *head = &SSA_NAME_IMM_USE_NODE (var);
+  return head->next == head;
+}
 
 /* Mark the statement STMT as modified, and update it.  */
 
@@ -422,9 +430,12 @@ gsi_split_seq_before (gimple_stmt_iterator *i, gimple_seq 
*pnew_seq)
 
 /* Replace the statement pointed-to by GSI to STMT.  If UPDATE_EH_INFO
    is true, the exception handling information of the original
-   statement is moved to the new statement.  Assignments must only be
-   replaced with assignments to the same LHS.  Returns whether EH edge
-   cleanup is required.  */
+   statement is moved to the new statement.  Returns whether EH edge
+   cleanup is required.
+
+   If the two statements assign to different SSA names, the caller must
+   ensure that all uses of the old SSA name have been removed before
+   calling this function.  This includes removing all debug uses.  */
 
 bool
 gsi_replace (gimple_stmt_iterator *gsi, gimple *stmt, bool update_eh_info)
@@ -436,7 +447,8 @@ gsi_replace (gimple_stmt_iterator *gsi, gimple *stmt, bool 
update_eh_info)
     return false;
 
   gcc_assert (!gimple_has_lhs (orig_stmt) || !gimple_has_lhs (stmt)
-             || gimple_get_lhs (orig_stmt) == gimple_get_lhs (stmt));
+             || gimple_get_lhs (orig_stmt) == gimple_get_lhs (stmt)
+             || completely_unused (gimple_get_lhs (orig_stmt)));
 
   gimple_set_location (stmt, gimple_location (orig_stmt));
   gimple_set_bb (stmt, gsi_bb (*gsi));

Reply via email to