]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
SSA immediate use iterator checking
authorRichard Biener <rguenther@suse.de>
Mon, 3 Nov 2025 13:04:55 +0000 (14:04 +0100)
committerRichard Biener <rguenth@gcc.gnu.org>
Thu, 6 Nov 2025 13:56:13 +0000 (14:56 +0100)
The following implements additional checking around
SSA immediate use iteration.  Specifically this prevents

 - any nesting of FOR_EACH_IMM_USE_STMT inside another iteration
   via FOR_EACH_IMM_USE_STMT or FOR_EACH_IMM_USE_FAST when iterating
   on the same SSA name

 - modification (for now unlinking of immediate uses) of a SSA
   immediate use list when a fast iteration of the immediate uses
   of the SSA name is active

 - modification (for now unlinking of immediate uses) of the immediate
   use list outside of the block of uses for the currently active stmt
   of an ongoing FOR_EACH_IMM_USE_STMT of the SSA name

To implement this additional bookkeeping members are put into the
SSA name structure when ENABLE_GIMPLE_CHECKING is active.  I have
kept the existing consistency checking of the fast iterator.

* ssa-iterators.h (imm_use_iterator::name): Add.
(delink_imm_use): When in a FOR_EACH_IMM_USE_STMT iteration
enforce we only remove uses from the current stmt.
(end_imm_use_stmt_traverse): Reset current stmt.
(first_imm_use_stmt): Assert no FOR_EACH_IMM_USE_STMT on
var is in progress.  Set the current stmt.
(next_imm_use_stmt): Set the current stmt.
(auto_end_imm_use_fast_traverse): New, lower iteration
depth upon destruction.
(first_readonly_imm_use): Bump the iteration depth.
* tree-core.h (tree_ssa_name::active_iterated_stmt,
tree_ssa_name::fast_iteration_depth): New members when
ENABLE_GIMPLE_CHECKING.
* tree-ssanames.cc (make_ssa_name_fn): Initialize
immediate use verifier bookkeeping members.

gcc/ssa-iterators.h
gcc/tree-core.h
gcc/tree-ssanames.cc

index 8fcc9b8a55f6ba2d764b2ba345d50aeb6d339e03..24cf6bfd63b83f0ba0acc112eea270b4dca92e7f 100644 (file)
@@ -59,16 +59,40 @@ struct imm_use_iterator
   /* This is the next ssa_name to visit.  IMM_USE may get removed before
      the next one is traversed to, so it must be cached early.  */
   ssa_use_operand_t *next_imm_name;
+  /* This is the SSA name iterated over.  */
+  tree name;
 };
 
 
 /* Use this iterator when simply looking at stmts.  Adding, deleting or
    modifying stmts will cause this iterator to malfunction.  */
 
+#if ! defined ENABLE_GIMPLE_CHECKING
 #define FOR_EACH_IMM_USE_FAST(DEST, ITER, SSAVAR)              \
   for ((DEST) = first_readonly_imm_use (&(ITER), (SSAVAR));    \
        !end_readonly_imm_use_p (&(ITER));                      \
        (void) ((DEST) = next_readonly_imm_use (&(ITER))))
+#else
+
+/* arrange to automatically call, upon descruction, with a given pointer
+   to imm_use_iterator.  */
+struct auto_end_imm_use_fast_traverse
+{
+  imm_use_iterator *imm;
+  auto_end_imm_use_fast_traverse (imm_use_iterator *imm)
+  : imm (imm) {}
+  ~auto_end_imm_use_fast_traverse ()
+  { imm->name->ssa_name.fast_iteration_depth--; }
+};
+
+#define FOR_EACH_IMM_USE_FAST(DEST, ITER, SSAVAR)              \
+  for (struct auto_end_imm_use_fast_traverse                   \
+        auto_end_imm_use_fast_traverse                         \
+          ((((DEST) = first_readonly_imm_use (&(ITER), (SSAVAR))), \
+           &(ITER)));                                          \
+       !end_readonly_imm_use_p (&(ITER));                      \
+       (void) ((DEST) = next_readonly_imm_use (&(ITER))))
+#endif
 
 /* Forward declare for use in the class below.  */
 inline void end_imm_use_stmt_traverse (imm_use_iterator *);
@@ -251,6 +275,20 @@ delink_imm_use (ssa_use_operand_t *linknode)
   if (linknode->prev == NULL)
     return;
 
+#if defined ENABLE_GIMPLE_CHECKING
+  if (linknode->loc.stmt
+      /* update_stmt on constant/removed uses.  */
+      && USE_FROM_PTR (linknode)
+      && TREE_CODE (USE_FROM_PTR (linknode)) == SSA_NAME)
+    {
+      tree var = USE_FROM_PTR (linknode);
+      gcc_assert (var->ssa_name.fast_iteration_depth == 0
+                 && (var->ssa_name.active_iterated_stmt == NULL
+                     || (var->ssa_name.active_iterated_stmt
+                         == linknode->loc.stmt)));
+    }
+#endif
+
   linknode->prev->next = linknode->next;
   linknode->next->prev = linknode->prev;
   linknode->prev = NULL;
@@ -349,9 +387,13 @@ end_readonly_imm_use_p (const imm_use_iterator *imm)
 inline use_operand_p
 first_readonly_imm_use (imm_use_iterator *imm, tree var)
 {
+#if defined ENABLE_GIMPLE_CHECKING
+  var->ssa_name.fast_iteration_depth++;
+#endif
   imm->end_p = &(SSA_NAME_IMM_USE_NODE (var));
   imm->imm_use = imm->end_p->next;
   imm->next_stmt_use = imm->imm_use->next;
+  imm->name = var;
   if (end_readonly_imm_use_p (imm))
     return NULL_USE_OPERAND_P;
   return imm->imm_use;
@@ -846,8 +888,11 @@ end_imm_use_stmt_p (const imm_use_iterator *imm)
    placeholder node from the list.  */
 
 inline void
-end_imm_use_stmt_traverse (imm_use_iterator *)
+end_imm_use_stmt_traverse (imm_use_iterator * ARG_UNUSED (imm))
 {
+#if defined ENABLE_GIMPLE_CHECKING
+  imm->name->ssa_name.active_iterated_stmt = NULL;
+#endif
 }
 
 /* Immediate use traversal of uses within a stmt require that all the
@@ -923,6 +968,10 @@ link_use_stmts_after (use_operand_p head, imm_use_iterator *)
 inline gimple *
 first_imm_use_stmt (imm_use_iterator *imm, tree var)
 {
+#if defined ENABLE_GIMPLE_CHECKING
+  gcc_assert (var->ssa_name.active_iterated_stmt == NULL
+             && var->ssa_name.fast_iteration_depth == 0);
+#endif
   imm->end_p = &(SSA_NAME_IMM_USE_NODE (var));
   imm->imm_use = imm->end_p->next;
   imm->next_imm_name = NULL_USE_OPERAND_P;
@@ -930,12 +979,16 @@ first_imm_use_stmt (imm_use_iterator *imm, tree var)
   /* next_stmt_use is used to point to the immediate use node after
      the set of uses for the current stmt.  */
   imm->next_stmt_use = NULL_USE_OPERAND_P;
+  imm->name = var;
 
   if (end_imm_use_stmt_p (imm))
     return NULL;
 
   imm->next_stmt_use = link_use_stmts_after (imm->imm_use, imm)->next;
 
+#if defined ENABLE_GIMPLE_CHECKING
+  var->ssa_name.active_iterated_stmt = USE_STMT (imm->imm_use);
+#endif
   return USE_STMT (imm->imm_use);
 }
 
@@ -948,6 +1001,9 @@ next_imm_use_stmt (imm_use_iterator *imm)
   if (end_imm_use_stmt_p (imm))
     return NULL;
 
+#if defined ENABLE_GIMPLE_CHECKING
+  imm->name->ssa_name.active_iterated_stmt = USE_STMT (imm->imm_use);
+#endif
   imm->next_stmt_use = link_use_stmts_after (imm->imm_use, imm)->next;
   return USE_STMT (imm->imm_use);
 }
index 145e758600e8db14a8bfb330901097ee0ca3ed02..a6e40c7497f4f1d79f25c8afe4cd1fd39110c623 100644 (file)
@@ -1717,6 +1717,10 @@ struct GTY(()) tree_ssa_name {
                "!POINTER_TYPE_P (TREE_TYPE ((tree)&%1)) : 2"))) info;
   /* Immediate uses list for this SSA_NAME.  */
   struct ssa_use_operand_t imm_uses;
+#if defined ENABLE_GIMPLE_CHECKING
+  gimple *active_iterated_stmt;
+  unsigned fast_iteration_depth;
+#endif
 };
 
 struct GTY(()) phi_arg_d {
index dcf8da56272d800df6810fbb72da7e223c3038a5..3d915738c987b4e9bf194ec76af37a844887472e 100644 (file)
@@ -406,6 +406,10 @@ make_ssa_name_fn (struct function *fn, tree var, gimple *stmt,
   SSA_NAME_IN_FREE_LIST (t) = 0;
   SSA_NAME_IS_DEFAULT_DEF (t) = 0;
   init_ssa_name_imm_use (t);
+#if defined ENABLE_GIMPLE_CHECKING
+  t->ssa_name.active_iterated_stmt = NULL;
+  t->ssa_name.fast_iteration_depth = 0;
+#endif
 
   return t;
 }