> 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);