From a3931eed1328a15f9839ccfe5965429c2506491f Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Mon, 30 Mar 2026 15:38:13 -0400
Subject: [PATCH 33/98] FIXME: more on dataflow events

---
 gcc/analyzer/call-info.cc                     |  10 --
 gcc/analyzer/common.h                         |   9 +-
 gcc/analyzer/diagnostic-manager.cc            |  54 ++++++---
 gcc/analyzer/engine.cc                        |  32 +++++
 gcc/analyzer/exploded-graph.h                 |   3 +
 gcc/analyzer/ops.cc                           | 114 ++++++++----------
 gcc/analyzer/ops.h                            |  73 +++++------
 .../c-c++-common/analyzer/divide-by-zero-1.c  |   2 +-
 .../c-c++-common/analyzer/divide-by-zero-2.c  |   3 +-
 .../c-c++-common/analyzer/divide-by-zero-3.c  |   6 +-
 .../c-c++-common/analyzer/divide-by-zero-4.c  |   2 +-
 11 files changed, 167 insertions(+), 141 deletions(-)

diff --git a/gcc/analyzer/call-info.cc b/gcc/analyzer/call-info.cc
index b5d2ddbcb9c4..10022b43f343 100644
--- a/gcc/analyzer/call-info.cc
+++ b/gcc/analyzer/call-info.cc
@@ -78,16 +78,6 @@ custom_edge_info::create_enode (exploded_graph &eg,
   return eg.get_or_create_node (point, state, enode_for_diag);
 }
 
-eedge_annotation
-custom_edge_info::update_annotation_backwards (rewind_context &ctxt,
-					       const eedge_annotation &ann,
-					       logger *) const
-{
-  // FIXME:
-  // gcc_unreachable (); // FIXME
-  return ann;
-}
-
 /* class call_info : public custom_edge_info.  */
 
 /* Implementation of custom_edge_info::print vfunc for call_info.  */
diff --git a/gcc/analyzer/common.h b/gcc/analyzer/common.h
index 2a2a2784e90f..a5e81bd2d31a 100644
--- a/gcc/analyzer/common.h
+++ b/gcc/analyzer/common.h
@@ -443,10 +443,11 @@ public:
 				       exploded_node *enode_for_diag,
 				       region_model_context *ctxt) const;
 
-  virtual eedge_annotation
-  update_annotation_backwards (rewind_context &ctxt,
-			       const eedge_annotation &ann,
-			       logger *) const;
+  virtual bool
+  try_to_rewind_data_flow (rewind_context &) const
+  {
+    return false;
+  }
 };
 
 /* Abstract base class for splitting state.
diff --git a/gcc/analyzer/diagnostic-manager.cc b/gcc/analyzer/diagnostic-manager.cc
index c4825ff9826e..33517581fdaf 100644
--- a/gcc/analyzer/diagnostic-manager.cc
+++ b/gcc/analyzer/diagnostic-manager.cc
@@ -1649,8 +1649,8 @@ void
 diagnostic_manager::annotate_exploded_path (const path_builder &pb,
 					    exploded_path &epath) const
 {
-  // FIXME:
-  LOG_SCOPE (get_logger ());
+  auto logger = get_logger ();
+  LOG_SCOPE (logger);
 
   // FIXME: consolidate this with build_emission_path?
   interesting_t interest;
@@ -1667,25 +1667,51 @@ diagnostic_manager::annotate_exploded_path (const path_builder &pb,
   for (int idx = epath.m_elements.length () - 1; idx > 0; --idx)
     {
       exploded_path::element_t &iter_element = epath.m_elements[idx];
+      if (logger)
+	{
+	  logger->log ("edge[%i]: considering rewinding EN %i -> EN %i",
+		       idx,
+		       iter_element.m_eedge->m_src->m_index,
+		       iter_element.m_eedge->m_dest->m_index);
+	  logger->start_log_line ();
+	  logger->log_partial ("curr_annotation: ");
+	  curr_annotation.dump_to_pp (logger->get_printer ());
+	  logger->end_log_line ();
+	}
       iter_element.m_annotation_at_dst = curr_annotation;
-      eedge_annotation &annotation_at_src = iter_element.m_annotation_at_src;
       const exploded_edge *eedge = iter_element.m_eedge;
       gcc_assert (eedge);
 
-      rewind_context ctxt (*eedge);
+      rewind_context ctxt (*eedge, logger, curr_annotation);
       if (eedge->m_custom_info)
-	annotation_at_src
-	  = eedge->m_custom_info->update_annotation_backwards (ctxt,
-							       curr_annotation,
-							       get_logger ());
+	{
+	  if (!eedge->m_custom_info->try_to_rewind_data_flow (ctxt))
+	    {
+	      if (logger)
+		logger->log ("could not rewind custom info");
+	      return;
+	    }
+	}
       else if (const operation *op = eedge->maybe_get_op ())
-	annotation_at_src = op->update_annotation_backwards (ctxt,
-							     curr_annotation,
-							     get_logger ());
-      else
-	annotation_at_src = curr_annotation;
+	{
+	  if (!op->try_to_rewind_data_flow (ctxt))
+	    {
+	      if (logger)
+		logger->log ("could not rewind op");
+	      return;
+	    }
+	}
 
-      curr_annotation = annotation_at_src;
+      iter_element.m_annotation_at_src = ctxt.m_output;
+      curr_annotation = ctxt.m_output;
+      if (logger)
+	{
+	  logger->log ("rewound");
+	  logger->start_log_line ();
+	  logger->log_partial ("curr_annotation: ");
+	  curr_annotation.dump_to_pp (logger->get_printer ());
+	  logger->end_log_line ();
+	}
     }
 }
 
diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc
index f7bd822064fc..181798973e04 100644
--- a/gcc/analyzer/engine.cc
+++ b/gcc/analyzer/engine.cc
@@ -1724,6 +1724,38 @@ interprocedural_return::add_events_to_path (checker_path *emission_path,
 			dst_point.get_stack_depth ())));
 }
 
+bool
+interprocedural_return::try_to_rewind_data_flow (rewind_context &ctxt) const
+{
+  auto logger = ctxt.m_logger;
+
+  tree lhs = gimple_call_lhs (&m_call_stmt);
+  if (!lhs)
+    return true;
+
+  const region_model *dst_enode_model
+    = ctxt.m_eedge.m_dest->get_state ().m_region_model;
+  const region *dst_reg_in_dst_enode
+    = dst_enode_model->get_lvalue (lhs, nullptr);
+
+  if (ctxt.m_input.m_region_holding_value == dst_reg_in_dst_enode)
+    {
+      if (logger)
+	logger->log ("updating m_region_holding_value for interprocedural return");
+
+      const region_model *src_enode_model
+	= ctxt.m_eedge.m_src->get_state ().m_region_model;
+      tree fndecl = src_enode_model->get_current_function ()->decl;
+      tree fn_result = DECL_RESULT (fndecl);
+
+      const region *src_reg_in_src_enode
+	= src_enode_model->get_lvalue (fn_result, nullptr);
+      ctxt.m_output.m_region_holding_value = src_reg_in_src_enode;
+    }
+
+  return true;
+}
+
 /* class exploded_edge : public dedge<eg_traits>.  */
 
 /* exploded_edge's ctor.  */
diff --git a/gcc/analyzer/exploded-graph.h b/gcc/analyzer/exploded-graph.h
index c5d87d135260..47b4fcb025ef 100644
--- a/gcc/analyzer/exploded-graph.h
+++ b/gcc/analyzer/exploded-graph.h
@@ -436,6 +436,9 @@ public:
 			   const exploded_edge &eedge,
 			   pending_diagnostic &pd) const final override;
 
+  bool
+  try_to_rewind_data_flow (rewind_context &) const final override;
+
 private:
   const gcall &m_call_stmt;
 };
diff --git a/gcc/analyzer/ops.cc b/gcc/analyzer/ops.cc
index 1975ea6dd6d3..0c163f5a985c 100644
--- a/gcc/analyzer/ops.cc
+++ b/gcc/analyzer/ops.cc
@@ -665,22 +665,12 @@ gimple_stmt_op::add_any_events_for_eedge (const exploded_edge &eedge,
 
 // class gasm_op : public gimple_stmt_op
 
-eedge_annotation
-gasm_op::update_annotation_backwards (rewind_context &ctxt,
-				      const eedge_annotation &ann,
-				      logger *logger) const
-{
-  LOG_SCOPE (logger);
-  gcc_unreachable (); // FIXME
-}
-
 // class gassign_op : public gimple_stmt_op
 
-eedge_annotation
-gassign_op::update_annotation_backwards (rewind_context &ctxt,
-					 const eedge_annotation &ann,
-					 logger *logger) const
+bool
+gassign_op::try_to_rewind_data_flow (rewind_context &ctxt) const
 {
+  auto logger = ctxt.m_logger;
   LOG_SCOPE (logger);
   if (logger)
     {
@@ -695,12 +685,10 @@ gassign_op::update_annotation_backwards (rewind_context &ctxt,
   tree rhs1 = gimple_assign_rhs1 (&assign);
   enum tree_code op = gimple_assign_rhs_code (&assign);
 
-  eedge_annotation result (ann);
-
   switch (op)
     {
     default:
-      gcc_unreachable (); // FIXME
+      return false;
 
     case SSA_NAME:
     case VAR_DECL:
@@ -710,14 +698,14 @@ gassign_op::update_annotation_backwards (rewind_context &ctxt,
 	const region *dst_reg_in_dst_enode
 	  = ctxt.m_eedge.m_dest->get_state ().m_region_model->get_lvalue
 	      (lhs, nullptr);
-	if (ann.m_region_holding_value == dst_reg_in_dst_enode)
+	if (ctxt.m_input.m_region_holding_value == dst_reg_in_dst_enode)
 	  {
 	    if (logger)
 	      logger->log ("updating m_region_holding_value for assign");
 	    const region *src_reg_in_src_enode
 	      = ctxt.m_eedge.m_src->get_state ().m_region_model->get_lvalue
 		  (rhs1, nullptr);
-	    result.m_region_holding_value = src_reg_in_src_enode;
+	    ctxt.m_output.m_region_holding_value = src_reg_in_src_enode;
 	  }
       }
       break;
@@ -726,24 +714,15 @@ gassign_op::update_annotation_backwards (rewind_context &ctxt,
     case REAL_CST:
       if (logger)
 	logger->log ("value comes from here");
-      result.m_region_holding_value = nullptr;
+      ctxt.m_output.m_region_holding_value = nullptr;
       break;
     }
 
-  return result;
+  return true;
 }
 
 // class predict_op : public gimple_stmt_op
 
-eedge_annotation
-predict_op::update_annotation_backwards (rewind_context &ctxt,
-					 const eedge_annotation &ann,
-					 logger *logger) const
-{
-  LOG_SCOPE (logger);
-  gcc_unreachable (); // FIXME
-}
-
 // class greturn_op : public gimple_stmt_op
 
 void
@@ -813,14 +792,37 @@ greturn_op::add_any_events_for_eedge (const exploded_edge &,
   // No-op.
 }
 
-eedge_annotation
-greturn_op::update_annotation_backwards (rewind_context &ctxt,
-					 const eedge_annotation &ann,
-					 logger *logger) const
+
+bool
+greturn_op::try_to_rewind_data_flow (rewind_context &ctxt) const
 {
+  auto logger = ctxt.m_logger;
   LOG_SCOPE (logger);
-  //gcc_unreachable (); // FIXME
-  return ann;
+
+  const region_model *dst_enode_model
+    = ctxt.m_eedge.m_dest->get_state ().m_region_model;
+  const region_model *src_enode_model
+    = ctxt.m_eedge.m_src->get_state ().m_region_model;
+
+  tree fndecl = src_enode_model->get_current_function ()->decl;
+  tree lhs = DECL_RESULT (fndecl);
+
+    const region *dst_reg_in_dst_enode
+    = dst_enode_model->get_lvalue (lhs, nullptr);
+
+  if (ctxt.m_input.m_region_holding_value == dst_reg_in_dst_enode)
+    {
+      if (logger)
+	logger->log ("updating m_region_holding_value for greturn_op");
+
+      const region_model *src_enode_model
+	= ctxt.m_eedge.m_src->get_state ().m_region_model;
+      const region *src_reg_in_src_enode
+	= src_enode_model->get_lvalue (get_retval (), nullptr);
+      ctxt.m_output.m_region_holding_value = src_reg_in_src_enode;
+    }
+
+  return true;
 }
 
 // class call_and_return_op : public gimple_stmt_op
@@ -1112,14 +1114,12 @@ replay_call_summaries (operation_context &op_ctxt,
     }
 }
 
-eedge_annotation
-call_and_return_op::update_annotation_backwards (rewind_context &ctxt,
-						 const eedge_annotation &ann,
-						 logger *logger) const
+bool
+call_and_return_op::try_to_rewind_data_flow (rewind_context &ctxt) const
 {
-  LOG_SCOPE (logger);
+  LOG_SCOPE (ctxt.m_logger);
   // gcc_unreachable (); // FIXME
-  return ann; // FIXME
+  return true;
 }
 
 /* A concrete call_info subclass representing a replay of a call summary.  */
@@ -1413,15 +1413,6 @@ execute_for_feasibility (const exploded_edge &eedge,
 			    out_rc);
 }
 
-eedge_annotation
-control_flow_op::update_annotation_backwards (rewind_context &ctxt,
-					      const eedge_annotation &ann,
-					      logger *logger) const
-{
-  LOG_SCOPE (logger);
-  return ann;
-}
-
 // class gcond_edge_op : public control_flow_op
 
 gcond_edge_op::gcond_edge_op (::edge cfg_edge,
@@ -2458,29 +2449,27 @@ phis_for_edge_op::add_any_events_for_eedge (const exploded_edge &,
   // No-op
 }
 
-eedge_annotation
-phis_for_edge_op::update_annotation_backwards (rewind_context &ctxt,
-					       const eedge_annotation &ann,
-					       logger *logger) const
+bool
+phis_for_edge_op::try_to_rewind_data_flow (rewind_context &ctxt) const
 {
+  auto logger = ctxt.m_logger;
   LOG_SCOPE (logger);
-  eedge_annotation result (ann);
   for (auto iter : m_pairs)
     {
       const region *dst_reg_in_dst_enode
 	= ctxt.m_eedge.m_dest->get_state ().m_region_model->get_lvalue
 	    (iter.m_dst, nullptr);
-      if (ann.m_region_holding_value == dst_reg_in_dst_enode)
+      if (ctxt.m_input.m_region_holding_value == dst_reg_in_dst_enode)
 	{
 	  if (logger)
 	    logger->log ("updating m_region_holding_value_at_dst for phi");
 	  const region *src_reg_in_src_enode
 	    = ctxt.m_eedge.m_src->get_state ().m_region_model->get_lvalue
 	    (iter.m_src, nullptr);
-	  result.m_region_holding_value = src_reg_in_src_enode;
+	  ctxt.m_output.m_region_holding_value = src_reg_in_src_enode;
 	}
     }
-  return result;
+  return true;
 }
 
 // class resx_op : public gimple_stmt_op
@@ -2521,15 +2510,6 @@ resx_op::add_any_events_for_eedge (const exploded_edge &,
 {
 }
 
-eedge_annotation
-resx_op::update_annotation_backwards (rewind_context &ctxt,
-				      const eedge_annotation &ann,
-				      logger *logger) const
-{
-  LOG_SCOPE (logger);
-  gcc_unreachable (); // FIXME
-}
-
 } // namespace ana
 
 #endif /* #if ENABLE_ANALYZER */
diff --git a/gcc/analyzer/ops.h b/gcc/analyzer/ops.h
index 1a901b0c6957..ebb747549f6c 100644
--- a/gcc/analyzer/ops.h
+++ b/gcc/analyzer/ops.h
@@ -76,12 +76,20 @@ struct operation_context
 
 struct rewind_context
 {
-  rewind_context (const exploded_edge &eedge)
-  : m_eedge (eedge)
+  rewind_context (const exploded_edge &eedge,
+		  logger *logger,
+		  eedge_annotation input_ann)
+  : m_eedge (eedge),
+    m_logger (logger),
+    m_input (input_ann),
+    m_output (input_ann)
   {
   }
 
   const exploded_edge &m_eedge;
+  logger *m_logger;
+  eedge_annotation m_input;
+  eedge_annotation m_output;
 };
 
 /* Abstract base class for an operation along a superedge.  */
@@ -173,10 +181,11 @@ class operation
 
   enum kind get_kind () const { return m_kind; }
 
-  virtual eedge_annotation
-  update_annotation_backwards (rewind_context &ctxt,
-			       const eedge_annotation &ann,
-			       logger *) const = 0;
+  virtual bool
+  try_to_rewind_data_flow (rewind_context &) const
+  {
+    return false;
+  }
 
 protected:
   operation (enum kind kind_)
@@ -272,11 +281,6 @@ public:
   {
     return *as_a <const gasm *> (&get_stmt ());
   }
-
-  eedge_annotation
-  update_annotation_backwards (rewind_context &ctxt,
-			       const eedge_annotation &ann,
-			       logger *) const final override;
 };
 
 /* An operation subclass representing the effect of a GIMPLE_ASSIGN stmt.  */
@@ -300,10 +304,8 @@ public:
     return *as_a <const gassign *> (&get_stmt ());
   }
 
-  eedge_annotation
-  update_annotation_backwards (rewind_context &ctxt,
-			       const eedge_annotation &ann,
-			       logger *) const final override;
+  bool
+  try_to_rewind_data_flow (rewind_context &ctxt) const final override;
 };
 
 /* An operation subclass for a GIMPLE_PREDICT stmt.
@@ -326,10 +328,11 @@ public:
     return std::make_unique<predict_op> (get_stmt ());
   }
 
-  eedge_annotation
-  update_annotation_backwards (rewind_context &ctxt,
-			       const eedge_annotation &ann,
-			       logger *) const final override;
+  bool
+  try_to_rewind_data_flow (rewind_context &) const final override
+  {
+    return true;
+  }
 };
 
 /* An operation subclass representing both:
@@ -381,10 +384,8 @@ public:
     return gimple_return_retval (&get_greturn ());
   }
 
-  eedge_annotation
-  update_annotation_backwards (rewind_context &ctxt,
-			       const eedge_annotation &ann,
-			       logger *) const final override;
+  bool
+  try_to_rewind_data_flow (rewind_context &ctxt) const final override;
 };
 
 /* A concrete operation subclass representing the effect of a GIMPLE_CALL stmt.
@@ -463,10 +464,8 @@ public:
   const known_function *
   maybe_get_known_function (const call_details &cd) const;
 
-  eedge_annotation
-  update_annotation_backwards (rewind_context &ctxt,
-			       const eedge_annotation &ann,
-			       logger *) const final override;
+  bool
+  try_to_rewind_data_flow (rewind_context &ctxt) const final override;
 
 private:
   cgraph_edge *
@@ -620,11 +619,6 @@ public:
   void
   add_any_events_for_eedge (const exploded_edge &eedge,
 			    checker_path &out_path) const final override;
-
-  eedge_annotation
-  update_annotation_backwards (rewind_context &ctxt,
-			       const eedge_annotation &ann,
-			       logger *) const final override;
 };
 
 /* An abstract subclass of operation representing the filtering effect on
@@ -683,10 +677,11 @@ public:
 
   const gimple &get_ctrlflow_stmt () const { return m_ctrlflow_stmt; }
 
-  eedge_annotation
-  update_annotation_backwards (rewind_context &ctxt,
-			       const eedge_annotation &ann,
-			       logger *) const final override;
+  bool
+  try_to_rewind_data_flow (rewind_context &) const final override
+  {
+    return true;
+  }
 
 protected:
   control_flow_op (enum kind kind_,
@@ -1033,10 +1028,8 @@ public:
   add_any_events_for_eedge (const exploded_edge &eedge,
 			    checker_path &out_path) const final override;
 
-  eedge_annotation
-  update_annotation_backwards (rewind_context &ctxt,
-			       const eedge_annotation &ann,
-			       logger *) const final override;
+  bool
+  try_to_rewind_data_flow (rewind_context &ctxt) const final override;
 
   const std::vector<pair> &get_pairs () const { return m_pairs; }
 
diff --git a/gcc/testsuite/c-c++-common/analyzer/divide-by-zero-1.c b/gcc/testsuite/c-c++-common/analyzer/divide-by-zero-1.c
index 0d0b8e01157c..ff4f788f8d71 100644
--- a/gcc/testsuite/c-c++-common/analyzer/divide-by-zero-1.c
+++ b/gcc/testsuite/c-c++-common/analyzer/divide-by-zero-1.c
@@ -3,7 +3,7 @@
 static int __attribute__((noipa))
 return_zero (void)
 {
-  return 0;
+  return 0; /* { dg-message "value originates here" } */
 }
 
 void
diff --git a/gcc/testsuite/c-c++-common/analyzer/divide-by-zero-2.c b/gcc/testsuite/c-c++-common/analyzer/divide-by-zero-2.c
index c6bc16c0e912..880a50c69e93 100644
--- a/gcc/testsuite/c-c++-common/analyzer/divide-by-zero-2.c
+++ b/gcc/testsuite/c-c++-common/analyzer/divide-by-zero-2.c
@@ -7,8 +7,9 @@ int
 test (int flag)
 {
   int x = 42;
-  int y = 0;
+  int y = 0; /* { dg-message "value originates here" } */
   if (flag)
     y = get_value ();
   return x / y; /* { dg-warning "division by zero" } */
+  /* { dg-message "value of 'y' unchanged here" "unchanged msg" { target *-*-* } .-1 } */
 }
diff --git a/gcc/testsuite/c-c++-common/analyzer/divide-by-zero-3.c b/gcc/testsuite/c-c++-common/analyzer/divide-by-zero-3.c
index 6be3e763f55f..ecbef9311114 100644
--- a/gcc/testsuite/c-c++-common/analyzer/divide-by-zero-3.c
+++ b/gcc/testsuite/c-c++-common/analyzer/divide-by-zero-3.c
@@ -6,9 +6,9 @@ get_value (void);
 int
 test (int flag, int flag_2, int flag_3)
 {
-  int x = 42;
-  int y = 10;
-  int z = 0;
+  int x = 42; /* { dg-bogus "value originates here" } */
+  int y = 10; /* { dg-bogus "value originates here" } */
+  int z = 0; /* { dg-message "value originates here" } */
   if (flag)
     y = get_value ();
   if (flag_2)
diff --git a/gcc/testsuite/c-c++-common/analyzer/divide-by-zero-4.c b/gcc/testsuite/c-c++-common/analyzer/divide-by-zero-4.c
index 139dbf535e36..50aff0e5f069 100644
--- a/gcc/testsuite/c-c++-common/analyzer/divide-by-zero-4.c
+++ b/gcc/testsuite/c-c++-common/analyzer/divide-by-zero-4.c
@@ -18,7 +18,7 @@ init_foo (struct foo *f, int x, int y)
 int
 do_divide (struct foo *f)
 {
-  return f->x / f->y;
+  return f->x / f->y; /* { dg-warning "division by zero" } */
 }
 
 int
-- 
2.49.0

