+static bool
+eliminate_unnecessary_stmts (void)
+{
+ bool something_changed = false;
+ basic_block bb;
+ gimple_stmt_iterator gsi, psi;
+ gimple stmt;
+ tree call;
+ VEC (basic_block, heap) *h;
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "\nEliminating unnecessary statements:\n");
+
+ clear_special_calls ();
+
+ /* Walking basic blocks and statements in reverse order avoids
+ releasing SSA names before any other DEFs that refer to them are
+ released. This helps avoid loss of debug information, as we get
+ a chance to propagate all RHSs of removed SSAs into debug uses,
+ rather than only the latest ones. E.g., consider:
+
+ x_3 = y_1 + z_2;
+ a_5 = x_3 - b_4;
+ # DEBUG a => a_5
+
+ If we were to release x_3 before a_5, when we reached a_5 and
+ tried to substitute it into the debug stmt, we'd see x_3 there,
+ but x_3's DEF, type, etc would have already been disconnected.
+ By going backwards, the debug stmt first changes to:
+
+ # DEBUG a => x_3 - b_4
+
+ and then to:
+
+ # DEBUG a => y_1 + z_2 - b_4
+
+ as desired. */
+ gcc_assert (dom_info_available_p (CDI_DOMINATORS));
+ h = get_all_dominated_blocks (CDI_DOMINATORS, single_succ (ENTRY_BLOCK_PTR));
+
+ while (VEC_length (basic_block, h))
+ {
+ bb = VEC_pop (basic_block, h);
+
+ /* Remove dead statements. */
+ for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi = psi)
+ {
+ stmt = gsi_stmt (gsi);
+
+ psi = gsi;
+ gsi_prev (&psi);
+
+ stats.total++;
+
+ /* If GSI is not necessary then remove it. */
+ if (!gimple_plf (stmt, STMT_NECESSARY))
+ {
+ if (!is_gimple_debug (stmt))
+ something_changed = true;
+ remove_dead_stmt (&gsi, bb);
+ }
+ else if (is_gimple_call (stmt))
+ {
+ call = gimple_call_fndecl (stmt);
+ if (call)
+ {
+ tree name;
+
+ /* When LHS of var = call (); is dead, simplify it into
+ call (); saving one operand. */
+ name = gimple_call_lhs (stmt);
+ if (name && TREE_CODE (name) == SSA_NAME
+ && !TEST_BIT (processed, SSA_NAME_VERSION (name)))
+ {
+ something_changed = true;
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Deleting LHS of call: ");
+ print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
+ fprintf (dump_file, "\n");
+ }
+
+ gimple_call_set_lhs (stmt, NULL_TREE);
+ maybe_clean_or_replace_eh_stmt (stmt, stmt);
+ update_stmt (stmt);
+ release_ssa_name (name);
+ }
+ notice_special_calls (stmt);
+ }
+ }
+ }