diff options
-rw-r--r-- | gcc/testsuite/g++.dg/torture/pr96881-1.C | 37 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/torture/pr96881-2.C | 37 | ||||
-rw-r--r-- | gcc/tree-ssa-dce.cc | 39 |
3 files changed, 109 insertions, 4 deletions
diff --git a/gcc/testsuite/g++.dg/torture/pr96881-1.C b/gcc/testsuite/g++.dg/torture/pr96881-1.C new file mode 100644 index 0000000..1c182e6 --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/pr96881-1.C @@ -0,0 +1,37 @@ +/* { dg-do run } */ + +struct S { int s; ~S () {} } s; + +void __attribute__((noipa)) +foo (struct S *s, int flag) +{ + s->s = 1; + // We have to makes sure to not make the inlined CLOBBER + // unconditional but we have to remove it to be able + // to elide the branch + if (!flag) + return; + s->~S(); +} + +void __attribute__((noipa)) +bar (struct S *s, int flag) +{ + s->s = 1; + // CD-DCE chooses an arbitrary path, try to present it + // with all variants + if (flag) + s->~S(); +} + +int +main () +{ + foo (&s, 0); + if (s.s != 1) + __builtin_abort (); + bar (&s, 0); + if (s.s != 1) + __builtin_abort (); + return 0; +} diff --git a/gcc/testsuite/g++.dg/torture/pr96881-2.C b/gcc/testsuite/g++.dg/torture/pr96881-2.C new file mode 100644 index 0000000..35c7887 --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/pr96881-2.C @@ -0,0 +1,37 @@ +/* { dg-do run } */ + +struct S { int s; ~S () {} } s; + +void __attribute__((noipa)) +foo (int flag) +{ + s.s = 1; + // We have to makes sure to not make the inlined CLOBBER + // unconditional but we have to remove it to be able + // to elide the branch + if (!flag) + return; + s.~S(); +} + +void __attribute__((noipa)) +bar (int flag) +{ + s.s = 1; + // CD-DCE chooses an arbitrary path, try to present it + // with all variants + if (flag) + s.~S(); +} + +int +main () +{ + foo (0); + if (s.s != 1) + __builtin_abort (); + bar (0); + if (s.s != 1) + __builtin_abort (); + return 0; +} diff --git a/gcc/tree-ssa-dce.cc b/gcc/tree-ssa-dce.cc index f103487..2a13ea3 100644 --- a/gcc/tree-ssa-dce.cc +++ b/gcc/tree-ssa-dce.cc @@ -284,7 +284,10 @@ mark_stmt_if_obviously_necessary (gimple *stmt, bool aggressive) break; case GIMPLE_ASSIGN: - if (gimple_clobber_p (stmt)) + /* Mark indirect CLOBBERs to be lazily removed if their SSA operands + do not prevail. That also makes control flow leading to them + not necessary in aggressive mode. */ + if (gimple_clobber_p (stmt) && !zero_ssa_operands (stmt, SSA_OP_USE)) return; break; @@ -1268,11 +1271,36 @@ maybe_optimize_arith_overflow (gimple_stmt_iterator *gsi, gimplify_and_update_call_from_tree (gsi, result); } +/* Returns whether the control parents of BB are preserved. */ + +static bool +control_parents_preserved_p (basic_block bb) +{ + /* If we marked the control parents from BB they are preserved. */ + if (bitmap_bit_p (visited_control_parents, bb->index)) + return true; + + /* But they can also end up being marked from elsewhere. */ + bitmap_iterator bi; + unsigned edge_number; + EXECUTE_IF_SET_IN_BITMAP (cd->get_edges_dependent_on (bb->index), + 0, edge_number, bi) + { + basic_block cd_bb = cd->get_edge_src (edge_number); + if (cd_bb != bb + && !bitmap_bit_p (last_stmt_necessary, cd_bb->index)) + return false; + } + /* And cache the result. */ + bitmap_set_bit (visited_control_parents, bb->index); + return true; +} + /* Eliminate unnecessary statements. Any instruction not marked as necessary contributes nothing to the program, and can be deleted. */ static bool -eliminate_unnecessary_stmts (void) +eliminate_unnecessary_stmts (bool aggressive) { bool something_changed = false; basic_block bb; @@ -1366,7 +1394,10 @@ eliminate_unnecessary_stmts (void) break; } } - if (!dead) + if (!dead + /* When doing CD-DCE we have to ensure all controls + of the stmt are still live. */ + && (!aggressive || control_parents_preserved_p (bb))) { bitmap_clear (debug_seen); continue; @@ -1876,7 +1907,7 @@ perform_tree_ssa_dce (bool aggressive) propagate_necessity (aggressive); BITMAP_FREE (visited); - something_changed |= eliminate_unnecessary_stmts (); + something_changed |= eliminate_unnecessary_stmts (aggressive); something_changed |= cfg_altered; /* We do not update postdominators, so free them unconditionally. */ |