new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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;
+}
@@ -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,34 @@ 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;
+ }
+ 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 +1392,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 +1905,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. */