OSDN Git Service

2014-05-07 Richard Biener <rguenther@suse.de>
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-dce.c
index 00bf012..d99e771 100644 (file)
@@ -1,5 +1,5 @@
 /* Dead code elimination pass for the GNU compiler.
-   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
    Contributed by Ben Elliston <bje@redhat.com>
    and Andrew MacLeod <amacleod@redhat.com>
@@ -49,7 +49,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "tm.h"
 
 #include "tree.h"
-#include "diagnostic.h"
 #include "tree-pretty-print.h"
 #include "gimple-pretty-print.h"
 #include "basic-block.h"
@@ -78,8 +77,8 @@ static VEC(gimple,heap) *worklist;
    as necessary.  */
 static sbitmap processed;
 
-/* Vector indicating that last_stmt if a basic block has already been
-   marked as necessary.  */
+/* Vector indicating that the last statement of a basic block has already
+   been marked as necessary.  */
 static sbitmap last_stmt_necessary;
 
 /* Vector indicating that BB contains statements that are live.  */
@@ -198,6 +197,7 @@ find_all_control_dependences (struct edge_list *el)
 
 /* If STMT is not already marked necessary, mark it, and add it to the
    worklist if ADD_TO_WORKLIST is true.  */
+
 static inline void
 mark_stmt_necessary (gimple stmt, bool add_to_worklist)
 {
@@ -271,11 +271,9 @@ mark_operand_necessary (tree op)
 static void
 mark_stmt_if_obviously_necessary (gimple stmt, bool aggressive)
 {
-  tree lhs = NULL_TREE;
   /* With non-call exceptions, we have to assume that all statements could
      throw.  If a statement may throw, it is inherently necessary.  */
-  if (flag_non_call_exceptions
-      && stmt_could_throw_p (stmt))
+  if (cfun->can_throw_non_call_exceptions && stmt_could_throw_p (stmt))
     {
       mark_stmt_necessary (stmt, true);
       return;
@@ -301,30 +299,40 @@ mark_stmt_if_obviously_necessary (gimple stmt, bool aggressive)
       return;
 
     case GIMPLE_CALL:
-      /* Most, but not all function calls are required.  Function calls that
-        produce no result and have no side effects (i.e. const pure
-        functions) are unnecessary.  */
-      if (gimple_has_side_effects (stmt))
-       {
-         mark_stmt_necessary (stmt, true);
-         return;
-       }
-      if (!gimple_call_lhs (stmt))
-        return;
-      lhs = gimple_call_lhs (stmt);
-      /* Fall through */
+      {
+       tree callee = gimple_call_fndecl (stmt);
+       if (callee != NULL_TREE
+           && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL)
+         switch (DECL_FUNCTION_CODE (callee))
+           {
+           case BUILT_IN_MALLOC:
+           case BUILT_IN_CALLOC:
+           case BUILT_IN_ALLOCA:
+           case BUILT_IN_ALLOCA_WITH_ALIGN:
+             return;
 
-    case GIMPLE_ASSIGN:
-      if (!lhs)
-        lhs = gimple_assign_lhs (stmt);
-      break;
+           default:;
+           }
+       /* Most, but not all function calls are required.  Function calls that
+          produce no result and have no side effects (i.e. const pure
+          functions) are unnecessary.  */
+       if (gimple_has_side_effects (stmt))
+         {
+           mark_stmt_necessary (stmt, true);
+           return;
+         }
+       if (!gimple_call_lhs (stmt))
+         return;
+       break;
+      }
 
     case GIMPLE_DEBUG:
       /* Debug temps without a value are not useful.  ??? If we could
         easily locate the debug temp bind stmt for a use thereof,
         would could refrain from marking all debug temps here, and
         mark them only if they're used.  */
-      if (gimple_debug_bind_has_value_p (stmt)
+      if (!gimple_debug_bind_p (stmt)
+         || gimple_debug_bind_has_value_p (stmt)
          || TREE_CODE (gimple_debug_bind_get_var (stmt)) != DEBUG_EXPR_DECL)
        mark_stmt_necessary (stmt, false);
       return;
@@ -343,6 +351,12 @@ mark_stmt_if_obviously_necessary (gimple stmt, bool aggressive)
        mark_stmt_necessary (stmt, true);
       break;
 
+    case GIMPLE_ASSIGN:
+      if (TREE_CODE (gimple_assign_lhs (stmt)) == SSA_NAME
+         && TREE_CLOBBER_P (gimple_assign_rhs1 (stmt)))
+       return;
+      break;
+
     default:
       break;
     }
@@ -366,13 +380,30 @@ mark_stmt_if_obviously_necessary (gimple stmt, bool aggressive)
 }
 
 
-/* Make corresponding control dependent edges necessary.  We only
-   have to do this once for each basic block, so we clear the bitmap
-   after we're done.
+/* Mark the last statement of BB as necessary.  */
+
+static void
+mark_last_stmt_necessary (basic_block bb)
+{
+  gimple stmt = last_stmt (bb);
+
+  SET_BIT (last_stmt_necessary, bb->index);
+  SET_BIT (bb_contains_live_stmts, bb->index);
+
+  /* We actually mark the statement only if it is a control statement.  */
+  if (stmt && is_ctrl_stmt (stmt))
+    mark_stmt_necessary (stmt, true);
+}
+
+
+/* Mark control dependent edges of BB as necessary.  We have to do this only
+   once for each basic block so we set the appropriate bit after we're done.
+
+   When IGNORE_SELF is true, ignore BB in the list of control dependences.  */
 
-   When IGNORE_SELF it true, ignore BB from the list of control dependences.  */
 static void
-mark_control_dependent_edges_necessary (basic_block bb, struct edge_list *el, bool ignore_self)
+mark_control_dependent_edges_necessary (basic_block bb, struct edge_list *el,
+                                       bool ignore_self)
 {
   bitmap_iterator bi;
   unsigned edge_number;
@@ -385,7 +416,6 @@ mark_control_dependent_edges_necessary (basic_block bb, struct edge_list *el, bo
 
   EXECUTE_IF_CONTROL_DEPENDENT (bi, bb->index, edge_number)
     {
-      gimple stmt;
       basic_block cd_bb = INDEX_EDGE_PRED_BB (el, edge_number);
 
       if (ignore_self && cd_bb == bb)
@@ -394,15 +424,10 @@ mark_control_dependent_edges_necessary (basic_block bb, struct edge_list *el, bo
          continue;
        }
 
-      if (TEST_BIT (last_stmt_necessary, cd_bb->index))
-       continue;
-      SET_BIT (last_stmt_necessary, cd_bb->index);
-      SET_BIT (bb_contains_live_stmts, cd_bb->index);
-
-      stmt = last_stmt (cd_bb);
-      if (stmt && is_ctrl_stmt (stmt))
-       mark_stmt_necessary (stmt, true);
+      if (!TEST_BIT (last_stmt_necessary, cd_bb->index))
+       mark_last_stmt_necessary (cd_bb);
     }
+
   if (!skipped)
     SET_BIT (visited_control_parents, bb->index);
 }
@@ -422,6 +447,7 @@ find_obviously_necessary_stmts (struct edge_list *el)
   gimple_stmt_iterator gsi;
   edge e;
   gimple phi, stmt;
+  int flags;
 
   FOR_EACH_BB (bb)
     {
@@ -443,9 +469,8 @@ find_obviously_necessary_stmts (struct edge_list *el)
 
   /* Pure and const functions are finite and thus have no infinite loops in
      them.  */
-  if ((TREE_READONLY (current_function_decl)
-       || DECL_PURE_P (current_function_decl))
-      && !DECL_LOOPING_CONST_OR_PURE_P (current_function_decl))
+  flags = flags_from_decl_or_type (current_function_decl);
+  if ((flags & (ECF_CONST|ECF_PURE)) && !(flags & ECF_LOOPING_CONST_OR_PURE))
     return;
 
   /* Prevent the empty possibly infinite loops from being removed.  */
@@ -486,8 +511,12 @@ find_obviously_necessary_stmts (struct edge_list *el)
 static bool
 ref_may_be_aliased (tree ref)
 {
+  gcc_assert (TREE_CODE (ref) != WITH_SIZE_EXPR);
   while (handled_component_p (ref))
     ref = TREE_OPERAND (ref, 0);
+  if (TREE_CODE (ref) == MEM_REF
+      && TREE_CODE (TREE_OPERAND (ref, 0)) == ADDR_EXPR)
+    ref = TREE_OPERAND (TREE_OPERAND (ref, 0), 0);
   return !(DECL_P (ref)
           && !may_be_aliased (ref));
 }
@@ -515,7 +544,14 @@ mark_aliased_reaching_defs_necessary_1 (ao_ref *ref, tree vdef, void *data)
 
   /* If the stmt lhs kills ref, then we can stop walking.  */
   if (gimple_has_lhs (def_stmt)
-      && TREE_CODE (gimple_get_lhs (def_stmt)) != SSA_NAME)
+      && TREE_CODE (gimple_get_lhs (def_stmt)) != SSA_NAME
+      /* The assignment is not necessarily carried out if it can throw
+         and we can catch it in the current function where we could inspect
+        the previous value.
+         ???  We only need to care about the RHS throwing.  For aggregate
+        assignments or similar calls and non-call exceptions the LHS
+        might throw as well.  */
+      && !stmt_can_throw_internal (def_stmt))
     {
       tree base, lhs = gimple_get_lhs (def_stmt);
       HOST_WIDE_INT size, offset, max_size;
@@ -540,6 +576,11 @@ mark_aliased_reaching_defs_necessary_1 (ao_ref *ref, tree vdef, void *data)
                      in the references (gcc.c-torture/execute/pr42142.c).
                      The simplest way is to check if the kill dominates
                      the use.  */
+                  /* But when both are in the same block we cannot
+                     easily tell whether we came from a backedge
+                     unless we decide to compute stmt UIDs
+                     (see PR58246).  */
+                  && (basic_block) data != gimple_bb (def_stmt)
                   && dominated_by_p (CDI_DOMINATORS, (basic_block) data,
                                      gimple_bb (def_stmt))
                   && operand_equal_p (ref->ref, lhs, 0))
@@ -598,6 +639,26 @@ mark_all_reaching_defs_necessary_1 (ao_ref *ref ATTRIBUTE_UNUSED,
        return false;
     }
 
+  /* We want to skip statments that do not constitute stores but have
+     a virtual definition.  */
+  if (is_gimple_call (def_stmt))
+    {
+      tree callee = gimple_call_fndecl (def_stmt);
+      if (callee != NULL_TREE
+         && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL)
+       switch (DECL_FUNCTION_CODE (callee))
+         {
+         case BUILT_IN_MALLOC:
+         case BUILT_IN_CALLOC:
+         case BUILT_IN_ALLOCA:
+         case BUILT_IN_ALLOCA_WITH_ALIGN:
+         case BUILT_IN_FREE:
+           return false;
+
+         default:;
+         }
+    }
+
   mark_operand_necessary (vdef);
 
   return false;
@@ -653,12 +714,12 @@ propagate_necessity (struct edge_list *el)
 
       if (aggressive)
        {
-         /* Mark the last statements of the basic blocks that the block
-            containing STMT is control dependent on, but only if we haven't
+         /* Mark the last statement of the basic blocks on which the block
+            containing STMT is control dependent, but only if we haven't
             already done so.  */
          basic_block bb = gimple_bb (stmt);
          if (bb != ENTRY_BLOCK_PTR
-             && ! TEST_BIT (visited_control_parents, bb->index))
+             && !TEST_BIT (visited_control_parents, bb->index))
            mark_control_dependent_edges_necessary (bb, el, false);
        }
 
@@ -761,18 +822,11 @@ propagate_necessity (struct edge_list *el)
                      != get_immediate_dominator (CDI_POST_DOMINATORS, arg_bb))
                    {
                      if (!TEST_BIT (last_stmt_necessary, arg_bb->index))
-                       {
-                         gimple stmt2;
-                         SET_BIT (last_stmt_necessary, arg_bb->index);
-                         SET_BIT (bb_contains_live_stmts, arg_bb->index);
-
-                         stmt2 = last_stmt (arg_bb);
-                         if (stmt2 && is_ctrl_stmt (stmt2))
-                           mark_stmt_necessary (stmt2, true);
-                       }
+                       mark_last_stmt_necessary (arg_bb);
                    }
                  else if (arg_bb != ENTRY_BLOCK_PTR
-                          && ! TEST_BIT (visited_control_parents, arg_bb->index))
+                          && !TEST_BIT (visited_control_parents,
+                                        arg_bb->index))
                    mark_control_dependent_edges_necessary (arg_bb, el, true);
                }
            }
@@ -785,6 +839,25 @@ propagate_necessity (struct edge_list *el)
          ssa_op_iter iter;
          tree use;
 
+         /* If this is a call to free which is directly fed by an
+            allocation function do not mark that necessary through
+            processing the argument.  */
+         if (gimple_call_builtin_p (stmt, BUILT_IN_FREE))
+           {
+             tree ptr = gimple_call_arg (stmt, 0);
+             gimple def_stmt;
+             tree def_callee;
+             /* If the pointer we free is defined by an allocation
+                function do not add the call to the worklist.  */
+             if (TREE_CODE (ptr) == SSA_NAME
+                 && is_gimple_call (def_stmt = SSA_NAME_DEF_STMT (ptr))
+                 && (def_callee = gimple_call_fndecl (def_stmt))
+                 && DECL_BUILT_IN_CLASS (def_callee) == BUILT_IN_NORMAL
+                 && (DECL_FUNCTION_CODE (def_callee) == BUILT_IN_MALLOC
+                     || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_CALLOC))
+               continue;
+           }
+
          FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
            mark_operand_necessary (use);
 
@@ -824,8 +897,17 @@ propagate_necessity (struct edge_list *el)
              if (callee != NULL_TREE
                  && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL
                  && (DECL_FUNCTION_CODE (callee) == BUILT_IN_MEMSET
+                     || DECL_FUNCTION_CODE (callee) == BUILT_IN_MEMSET_CHK
                      || DECL_FUNCTION_CODE (callee) == BUILT_IN_MALLOC
-                     || DECL_FUNCTION_CODE (callee) == BUILT_IN_FREE))
+                     || DECL_FUNCTION_CODE (callee) == BUILT_IN_CALLOC
+                     || DECL_FUNCTION_CODE (callee) == BUILT_IN_FREE
+                     || DECL_FUNCTION_CODE (callee) == BUILT_IN_VA_END
+                     || DECL_FUNCTION_CODE (callee) == BUILT_IN_ALLOCA
+                     || (DECL_FUNCTION_CODE (callee)
+                         == BUILT_IN_ALLOCA_WITH_ALIGN)
+                     || DECL_FUNCTION_CODE (callee) == BUILT_IN_STACK_SAVE
+                     || DECL_FUNCTION_CODE (callee) == BUILT_IN_STACK_RESTORE
+                     || DECL_FUNCTION_CODE (callee) == BUILT_IN_ASSUME_ALIGNED))
                continue;
 
              /* Calls implicitly load from memory, their arguments
@@ -837,6 +919,8 @@ propagate_necessity (struct edge_list *el)
                  if (TREE_CODE (arg) == SSA_NAME
                      || is_gimple_min_invariant (arg))
                    continue;
+                 if (TREE_CODE (arg) == WITH_SIZE_EXPR)
+                   arg = TREE_OPERAND (arg, 0);
                  if (!ref_may_be_aliased (arg))
                    mark_aliased_reaching_defs_necessary (stmt, arg);
                }
@@ -844,26 +928,26 @@ propagate_necessity (struct edge_list *el)
          else if (gimple_assign_single_p (stmt))
            {
              tree rhs;
-             bool rhs_aliased = false;
              /* If this is a load mark things necessary.  */
              rhs = gimple_assign_rhs1 (stmt);
              if (TREE_CODE (rhs) != SSA_NAME
-                 && !is_gimple_min_invariant (rhs))
+                 && !is_gimple_min_invariant (rhs)
+                 && TREE_CODE (rhs) != CONSTRUCTOR)
                {
                  if (!ref_may_be_aliased (rhs))
                    mark_aliased_reaching_defs_necessary (stmt, rhs);
                  else
-                   rhs_aliased = true;
+                   mark_all_reaching_defs_necessary (stmt);
                }
-             if (rhs_aliased)
-               mark_all_reaching_defs_necessary (stmt);
            }
          else if (gimple_code (stmt) == GIMPLE_RETURN)
            {
              tree rhs = gimple_return_retval (stmt);
              /* A return statement may perform a load.  */
-             if (TREE_CODE (rhs) != SSA_NAME
-                 && !is_gimple_min_invariant (rhs))
+             if (rhs
+                 && TREE_CODE (rhs) != SSA_NAME
+                 && !is_gimple_min_invariant (rhs)
+                 && TREE_CODE (rhs) != CONSTRUCTOR)
                {
                  if (!ref_may_be_aliased (rhs))
                    mark_aliased_reaching_defs_necessary (stmt, rhs);
@@ -881,10 +965,18 @@ propagate_necessity (struct edge_list *el)
                  tree op = TREE_VALUE (gimple_asm_input_op (stmt, i));
                  if (TREE_CODE (op) != SSA_NAME
                      && !is_gimple_min_invariant (op)
+                     && TREE_CODE (op) != CONSTRUCTOR
                      && !ref_may_be_aliased (op))
                    mark_aliased_reaching_defs_necessary (stmt, op);
                }
            }
+         else if (gimple_code (stmt) == GIMPLE_TRANSACTION)
+           {
+             /* The beginning of a transaction is a memory barrier.  */
+             /* ??? If we were really cool, we'd only be a barrier
+                for the memories touched within the transaction.  */
+             mark_all_reaching_defs_necessary (stmt);
+           }
          else
            gcc_unreachable ();
 
@@ -908,18 +1000,36 @@ propagate_necessity (struct edge_list *el)
     }
 }
 
-/* Replace all uses of result of PHI by underlying variable and mark it
+/* Replace all uses of NAME by underlying variable and mark it
    for renaming.  */
 
 void
-mark_virtual_phi_result_for_renaming (gimple phi)
+mark_virtual_operand_for_renaming (tree name)
 {
   bool used = false;
   imm_use_iterator iter;
   use_operand_p use_p;
   gimple stmt;
-  tree result_ssa, result_var;
+  tree name_var;
 
+  name_var = SSA_NAME_VAR (name);
+  FOR_EACH_IMM_USE_STMT (stmt, iter, name)
+    {
+      FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
+        SET_USE (use_p, name_var);
+      update_stmt (stmt);
+      used = true;
+    }
+  if (used)
+    mark_sym_for_renaming (name_var);
+}
+
+/* Replace all uses of result of PHI by underlying variable and mark it
+   for renaming.  */
+
+void
+mark_virtual_phi_result_for_renaming (gimple phi)
+{
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
       fprintf (dump_file, "Marking result for renaming : ");
@@ -927,19 +1037,10 @@ mark_virtual_phi_result_for_renaming (gimple phi)
       fprintf (dump_file, "\n");
     }
 
-  result_ssa = gimple_phi_result (phi);
-  result_var = SSA_NAME_VAR (result_ssa);
-  FOR_EACH_IMM_USE_STMT (stmt, iter, result_ssa)
-    {
-      FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
-        SET_USE (use_p, result_var);
-      update_stmt (stmt);
-      used = true;
-    }
-  if (used)
-    mark_sym_for_renaming (result_var);
+  mark_virtual_operand_for_renaming (gimple_phi_result (phi));
 }
 
+
 /* Remove dead PHI nodes from block BB.  */
 
 static bool
@@ -1126,6 +1227,26 @@ remove_dead_stmt (gimple_stmt_iterator *i, basic_block bb)
          ei_next (&ei);
     }
 
+  /* If this is a store into a variable that is being optimized away,
+     add a debug bind stmt if possible.  */
+  if (MAY_HAVE_DEBUG_STMTS
+      && gimple_assign_single_p (stmt)
+      && is_gimple_val (gimple_assign_rhs1 (stmt)))
+    {
+      tree lhs = gimple_assign_lhs (stmt);
+      if ((TREE_CODE (lhs) == VAR_DECL || TREE_CODE (lhs) == PARM_DECL)
+         && !DECL_IGNORED_P (lhs)
+         && is_gimple_reg_type (TREE_TYPE (lhs))
+         && !is_global_var (lhs)
+         && !DECL_HAS_VALUE_EXPR_P (lhs))
+       {
+         tree rhs = gimple_assign_rhs1 (stmt);
+         gimple note
+           = gimple_build_debug_bind (lhs, unshare_expr (rhs), stmt);
+         gsi_insert_after (i, note, GSI_SAME_STMT);
+       }
+    }
+
   unlink_stmt_vdef (stmt);
   gsi_remove (i, true);
   release_defs (stmt);
@@ -1188,6 +1309,29 @@ eliminate_unnecessary_stmts (void)
 
          stats.total++;
 
+         /* We can mark a call to free as not necessary if the
+            defining statement of its argument is an allocation
+            function and that is not necessary itself.  */
+         if (gimple_call_builtin_p (stmt, BUILT_IN_FREE))
+           {
+             tree ptr = gimple_call_arg (stmt, 0);
+             tree callee2;
+             gimple def_stmt;
+             if (TREE_CODE (ptr) != SSA_NAME)
+               continue;
+             def_stmt = SSA_NAME_DEF_STMT (ptr);
+             if (!is_gimple_call (def_stmt)
+                 || gimple_plf (def_stmt, STMT_NECESSARY))
+               continue;
+             callee2 = gimple_call_fndecl (def_stmt);
+             if (callee2 == NULL_TREE
+                 || DECL_BUILT_IN_CLASS (callee2) != BUILT_IN_NORMAL
+                 || (DECL_FUNCTION_CODE (callee2) != BUILT_IN_MALLOC
+                     && DECL_FUNCTION_CODE (callee2) != BUILT_IN_CALLOC))
+               continue;
+             gimple_set_plf (stmt, STMT_NECESSARY, false);
+           }
+
          /* If GSI is not necessary then remove it.  */
          if (!gimple_plf (stmt, STMT_NECESSARY))
            {
@@ -1197,31 +1341,38 @@ eliminate_unnecessary_stmts (void)
            }
          else if (is_gimple_call (stmt))
            {
-             call = gimple_call_fndecl (stmt);
-             if (call)
+             tree name = gimple_call_lhs (stmt);
+
+             notice_special_calls (stmt);
+
+             /* When LHS of var = call (); is dead, simplify it into
+                call (); saving one operand.  */
+             if (name
+                 && TREE_CODE (name) == SSA_NAME
+                 && !TEST_BIT (processed, SSA_NAME_VERSION (name))
+                 /* Avoid doing so for allocation calls which we
+                    did not mark as necessary, it will confuse the
+                    special logic we apply to malloc/free pair removal.  */
+                 && (!(call = gimple_call_fndecl (stmt))
+                     || DECL_BUILT_IN_CLASS (call) != BUILT_IN_NORMAL
+                     || (DECL_FUNCTION_CODE (call) != BUILT_IN_MALLOC
+                         && DECL_FUNCTION_CODE (call) != BUILT_IN_CALLOC
+                         && DECL_FUNCTION_CODE (call) != BUILT_IN_ALLOCA
+                         && (DECL_FUNCTION_CODE (call)
+                             != BUILT_IN_ALLOCA_WITH_ALIGN))))
                {
-                 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))
                    {
-                     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);
+                     fprintf (dump_file, "Deleting LHS of call: ");
+                     print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
+                     fprintf (dump_file, "\n");
                    }
-                 notice_special_calls (stmt);
+
+                 gimple_call_set_lhs (stmt, NULL_TREE);
+                 maybe_clean_or_replace_eh_stmt (stmt, stmt);
+                 update_stmt (stmt);
+                 release_ssa_name (name);
                }
            }
        }
@@ -1401,6 +1552,8 @@ perform_tree_ssa_dce (bool aggressive)
   struct edge_list *el = NULL;
   bool something_changed = 0;
 
+  calculate_dominance_info (CDI_DOMINATORS);
+
   /* Preheaders are needed for SCEV to work.
      Simple lateches and recorded exits improve chances that loop will
      proved to be finite in testcases such as in loop-15.c and loop-24.c  */
@@ -1515,7 +1668,7 @@ struct gimple_opt_pass pass_dce =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func | TODO_verify_ssa     /* todo_flags_finish */
+  TODO_verify_ssa                      /* todo_flags_finish */
  }
 };
 
@@ -1534,7 +1687,7 @@ struct gimple_opt_pass pass_dce_loop =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func | TODO_verify_ssa     /* todo_flags_finish */
+  TODO_verify_ssa                      /* todo_flags_finish */
  }
 };
 
@@ -1553,7 +1706,7 @@ struct gimple_opt_pass pass_cd_dce =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func | TODO_verify_ssa
+  TODO_verify_ssa
   | TODO_verify_flow                   /* todo_flags_finish */
  }
 };