aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRichard Biener <rguenther@suse.de>2022-09-07 12:50:40 +0200
committerRichard Biener <rguenther@suse.de>2022-09-07 13:51:19 +0200
commita262f969d6fd936f4fb5d9e1d5756b0dcbc925b2 (patch)
tree3d107e3e9889c1f142b00d5d509deee804858243 /gcc
parent04bb15e48ef8dd3d6a5ff30723c603cef3e0a3c6 (diff)
downloadgcc-a262f969d6fd936f4fb5d9e1d5756b0dcbc925b2.zip
gcc-a262f969d6fd936f4fb5d9e1d5756b0dcbc925b2.tar.gz
gcc-a262f969d6fd936f4fb5d9e1d5756b0dcbc925b2.tar.bz2
tree-optimization/106866 - avoid dead abnormal edges from DCE
When DCE clears cfun->calls_setjmp then suddenly we don't need any abnormal call edges anymore. The following makes sure to prune them which otherwise can confuse other passes. PR tree-optimization/106866 * tree-ssa-dce.cc (eliminate_unnecessary_stmts): When we changed cfun->calls_setjmp make sure to purge all abnormal call edges. * gcc.dg/uninit-pr106866.c: New testcase.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/testsuite/gcc.dg/uninit-pr106866.c38
-rw-r--r--gcc/tree-ssa-dce.cc48
2 files changed, 79 insertions, 7 deletions
diff --git a/gcc/testsuite/gcc.dg/uninit-pr106866.c b/gcc/testsuite/gcc.dg/uninit-pr106866.c
new file mode 100644
index 0000000..530e274
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/uninit-pr106866.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fno-ipa-pure-const -Wuninitialized" } */
+
+int n;
+
+void
+empty (int)
+{
+}
+
+int
+bar (int x)
+{
+ return n + x + 1;
+}
+
+__attribute__ ((pure, returns_twice)) int
+foo (void)
+{
+ int uninitialized;
+
+ if (n)
+ {
+ if (bar (0))
+ return 0;
+
+ __builtin_unreachable ();
+ }
+
+ while (uninitialized < 1) /* { dg-warning "uninitialized" } */
+ {
+ foo ();
+ empty (bar (0) == foo ());
+ ++uninitialized;
+ }
+
+ return 0;
+}
diff --git a/gcc/tree-ssa-dce.cc b/gcc/tree-ssa-dce.cc
index daf0782..54e5d8c 100644
--- a/gcc/tree-ssa-dce.cc
+++ b/gcc/tree-ssa-dce.cc
@@ -1313,6 +1313,7 @@ eliminate_unnecessary_stmts (bool aggressive)
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\nEliminating unnecessary statements:\n");
+ bool had_setjmp = cfun->calls_setjmp;
clear_special_calls ();
/* Walking basic blocks and statements in reverse order avoids
@@ -1496,19 +1497,48 @@ eliminate_unnecessary_stmts (bool aggressive)
something_changed |= remove_dead_phis (bb);
}
-
- /* Since we don't track liveness of virtual PHI nodes, it is possible that we
- rendered some PHI nodes unreachable while they are still in use.
- Mark them for renaming. */
+ /* First remove queued edges. */
if (!to_remove_edges.is_empty ())
{
- basic_block prev_bb;
-
/* Remove edges. We've delayed this to not get bogus debug stmts
during PHI node removal. */
for (unsigned i = 0; i < to_remove_edges.length (); ++i)
remove_edge (to_remove_edges[i]);
cfg_altered = true;
+ }
+ /* When we cleared calls_setjmp we can purge all abnormal edges. Do so. */
+ if (cfun->calls_setjmp != had_setjmp)
+ {
+ gcc_assert (!cfun->calls_setjmp);
+ /* Make sure we only remove the edges, not dominated blocks. Using
+ gimple_purge_dead_abnormal_call_edges would do that and we
+ cannot free dominators yet. */
+ FOR_EACH_BB_FN (bb, cfun)
+ if (gcall *stmt = safe_dyn_cast <gcall *> (last_stmt (bb)))
+ if (!stmt_can_make_abnormal_goto (stmt))
+ {
+ edge_iterator ei;
+ edge e;
+ for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
+ {
+ if (e->flags & EDGE_ABNORMAL)
+ {
+ if (e->flags & EDGE_FALLTHRU)
+ e->flags &= ~EDGE_ABNORMAL;
+ else
+ remove_edge (e);
+ cfg_altered = true;
+ }
+ else
+ ei_next (&ei);
+ }
+ }
+ }
+
+ /* Now remove the unreachable blocks. */
+ if (cfg_altered)
+ {
+ basic_block prev_bb;
find_unreachable_blocks ();
@@ -1518,9 +1548,13 @@ eliminate_unnecessary_stmts (bool aggressive)
{
prev_bb = bb->prev_bb;
- if (!bitmap_bit_p (bb_contains_live_stmts, bb->index)
+ if ((bb_contains_live_stmts
+ && !bitmap_bit_p (bb_contains_live_stmts, bb->index))
|| !(bb->flags & BB_REACHABLE))
{
+ /* Since we don't track liveness of virtual PHI nodes, it is
+ possible that we rendered some PHI nodes unreachable while
+ they are still in use. Mark them for renaming. */
for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
gsi_next (&gsi))
if (virtual_operand_p (gimple_phi_result (gsi.phi ())))