> probably also helps PR109612 and the other similar PR referenced therein.

Here's a more aggressive patch in this area, but it regresses guality tests, 
for example:

+FAIL: gcc.dg/guality/ipa-sra-1.c   -O2  -DPREVENT_OPTIMIZATION  line 27 k == 
3
+FAIL: gcc.dg/guality/ipa-sra-1.c   -O3 -g  -DPREVENT_OPTIMIZATION  line 27 k 
== 3
+FAIL: gcc.dg/guality/ipa-sra-1.c   -Os  -DPREVENT_OPTIMIZATION  line 27 k == 
3

eric@fomalhaut:~/build/gcc/native> diff -u ipa-sra-1.c.254t.optimized.0 ipa-
sra-1.c.254t.optimized
--- ipa-sra-1.c.254t.optimized.0        2023-04-26 11:12:07.806357325 +0200
+++ ipa-sra-1.c.254t.optimized  2023-04-26 11:24:08.632874257 +0200
@@ -101,7 +101,6 @@
   # DEBUG k => k_5
   # DEBUG BEGIN_STMT
   _1 = get_val1 ();
-  # DEBUG D#6 => k_5
   r_8 = foo.isra (_1);
   # DEBUG r => r_8
   # DEBUG BEGIN_STMT

and I don't understand why yet.


        * tree-ssa-dce.cc (find_debug_expr_decl): New callback.
        (mark_stmt_if_obviously_necessary): Add DECLS parameters.
        <GIMPLE_DEBUG>: Call find_debug_expr_decl on the value of
        DEBUG_BIND statements and record the results in DECLS.
        (find_obviously_necessary_stmts): If DEBUG_BIND statements may be
        present, get rid of those setting an unnecessary DEBUG_EXPR_DECL.

-- 
Eric Botcazou
diff --git a/gcc/tree-ssa-dce.cc b/gcc/tree-ssa-dce.cc
index 08876bfc1c7..09bbfaca22e 100644
--- a/gcc/tree-ssa-dce.cc
+++ b/gcc/tree-ssa-dce.cc
@@ -191,14 +191,35 @@ mark_operand_necessary (tree op)
 }
 
 
+/* Called via walk_tree, look for DEBUG_EXPR_DECLs and mark them in DATA.  */
+
+static tree
+find_debug_expr_decl (tree *tp, int *walk_subtrees, void *data)
+{
+  auto_bitmap *decls = (auto_bitmap *) data;
+
+  if (TREE_CODE (*tp) == SSA_NAME || IS_TYPE_OR_DECL_P (*tp))
+    {
+      if (TREE_CODE (*tp) == DEBUG_EXPR_DECL)
+	bitmap_set_bit (*decls, DECL_UID (*tp));
+
+      *walk_subtrees = 0;
+    }
+
+  return NULL_TREE;
+}
+
 /* Mark STMT as necessary if it obviously is.  Add it to the worklist if
    it can make other statements necessary.
 
+   If STMT is a DEBUG_BIND, mark the necessary DEBUG_EXPR_DECLs in DECLS.
+
    If AGGRESSIVE is false, control statements are conservatively marked as
    necessary.  */
 
 static void
-mark_stmt_if_obviously_necessary (gimple *stmt, bool aggressive)
+mark_stmt_if_obviously_necessary (gimple *stmt, auto_bitmap *decls,
+				  bool aggressive)
 {
   /* Statements that are implicitly live.  Most function calls, asm
      and return statements are required.  Labels and GIMPLE_BIND nodes
@@ -258,14 +279,28 @@ mark_stmt_if_obviously_necessary (gimple *stmt, bool aggressive)
       }
 
     case GIMPLE_DEBUG:
-      /* Debug temps without a value are not useful.  ??? If we could
-	 easily locate the debug temp bind stmt for a use thereof,
-	 would could refrain from marking all debug temps here, and
-	 mark them only if they're used.  */
-      if (gimple_debug_nonbind_marker_p (stmt)
-	  || !gimple_debug_bind_p (stmt)
-	  || gimple_debug_bind_has_value_p (stmt)
-	  || TREE_CODE (gimple_debug_bind_get_var (stmt)) != DEBUG_EXPR_DECL)
+      if (gimple_debug_bind_p (stmt))
+	{
+	  tree var = gimple_debug_bind_get_var (stmt);
+	  tree val = gimple_debug_bind_get_value (stmt);
+	  bool necessary = false;
+
+	  /* A bind statement for a real variable is always necessary.  */
+	  if (TREE_CODE (var) != DEBUG_EXPR_DECL)
+	    necessary = true;
+
+	  /* A bind statement with a value is necessary for now and we look
+	     into the value to find out necessary DEBUG_EXPR_DECLs.  */
+	  if (val)
+	    {
+	      walk_tree (&val, find_debug_expr_decl, decls, NULL);
+	      necessary = true;
+	    }
+
+	  if (necessary )
+	    mark_stmt_necessary (stmt, false);
+	}
+      else
 	mark_stmt_necessary (stmt, false);
       return;
 
@@ -398,6 +433,7 @@ find_obviously_necessary_stmts (bool aggressive)
   gimple_stmt_iterator gsi;
   edge e;
   gimple *phi, *stmt;
+  auto_bitmap necessary_decls;
   int flags;
 
   FOR_EACH_BB_FN (bb, cfun)
@@ -414,10 +450,35 @@ find_obviously_necessary_stmts (bool aggressive)
 	{
 	  stmt = gsi_stmt (gsi);
 	  gimple_set_plf (stmt, STMT_NECESSARY, false);
-	  mark_stmt_if_obviously_necessary (stmt, aggressive);
+	  mark_stmt_if_obviously_necessary (stmt, &necessary_decls, aggressive);
 	}
     }
 
+  /* Check all debug bind statements again in the basic blocks and find out
+     those which set an unnecessary DEBUG_EXPR_DECL to a value.  */
+  if (MAY_HAVE_DEBUG_BIND_STMTS)
+    FOR_EACH_BB_FN (bb, cfun)
+      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+	{
+	  stmt = gsi_stmt (gsi);
+	  if (gimple_debug_bind_p (stmt)
+	      && gimple_debug_bind_has_value_p (stmt))
+	    {
+	      tree var = gimple_debug_bind_get_var (stmt);
+	      if (TREE_CODE (var) == DEBUG_EXPR_DECL
+		  && !bitmap_bit_p (necessary_decls, DECL_UID (var)))
+		{
+		  gimple_set_plf (stmt, STMT_NECESSARY, false);
+		  if (dump_file && (dump_flags & TDF_DETAILS))
+		    {
+		      fprintf (dump_file, "Unmarking useful stmt: ");
+		      print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
+		      fprintf (dump_file, "\n");
+		    }
+		}
+	      }
+	  }
+
   /* Pure and const functions are finite and thus have no infinite loops in
      them.  */
   flags = flags_from_decl_or_type (current_function_decl);

Reply via email to