+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);
+ }
+ }
+ }
+ }
+
+ VEC_free (basic_block, heap, h);
+
+ /* 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. */
+ if (cfg_altered)
+ {
+ basic_block prev_bb;
+
+ find_unreachable_blocks ();
+
+ /* Delete all unreachable basic blocks in reverse dominator order. */
+ for (bb = EXIT_BLOCK_PTR->prev_bb; bb != ENTRY_BLOCK_PTR; bb = prev_bb)
+ {
+ prev_bb = bb->prev_bb;
+
+ if (!TEST_BIT (bb_contains_live_stmts, bb->index)
+ || !(bb->flags & BB_REACHABLE))
+ {
+ for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+ if (!is_gimple_reg (gimple_phi_result (gsi_stmt (gsi))))
+ {
+ bool found = false;
+ imm_use_iterator iter;
+
+ FOR_EACH_IMM_USE_STMT (stmt, iter, gimple_phi_result (gsi_stmt (gsi)))
+ {
+ if (!(gimple_bb (stmt)->flags & BB_REACHABLE))
+ continue;
+ if (gimple_code (stmt) == GIMPLE_PHI
+ || gimple_plf (stmt, STMT_NECESSARY))
+ {
+ found = true;
+ BREAK_FROM_IMM_USE_STMT (iter);
+ }
+ }
+ if (found)
+ mark_virtual_phi_result_for_renaming (gsi_stmt (gsi));
+ }
+
+ if (!(bb->flags & BB_REACHABLE))
+ {
+ /* Speed up the removal of blocks that don't
+ dominate others. Walking backwards, this should
+ be the common case. ??? Do we need to recompute
+ dominators because of cfg_altered? */
+ if (!MAY_HAVE_DEBUG_STMTS
+ || !first_dom_son (CDI_DOMINATORS, bb))
+ delete_basic_block (bb);
+ else
+ {
+ h = get_all_dominated_blocks (CDI_DOMINATORS, bb);
+
+ while (VEC_length (basic_block, h))
+ {
+ bb = VEC_pop (basic_block, h);
+ prev_bb = bb->prev_bb;
+ /* Rearrangements to the CFG may have failed
+ to update the dominators tree, so that
+ formerly-dominated blocks are now
+ otherwise reachable. */
+ if (!!(bb->flags & BB_REACHABLE))
+ continue;
+ delete_basic_block (bb);
+ }
+
+ VEC_free (basic_block, heap, h);
+ }
+ }
+ }
+ }