]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/tree-ssa-dce.c
Use function_arg_info for TARGET_MUST_PASS_IN_STACK
[thirdparty/gcc.git] / gcc / tree-ssa-dce.c
index 8db149e0a6cc4dc4447b4f87f79b119f995628b5..80d5f5c30f7f4bbe209db5357414ff443ee88b5f 100644 (file)
@@ -1,5 +1,5 @@
 /* Dead code elimination pass for the GNU compiler.
-   Copyright (C) 2002-2014 Free Software Foundation, Inc.
+   Copyright (C) 2002-2019 Free Software Foundation, Inc.
    Contributed by Ben Elliston <bje@redhat.com>
    and Andrew MacLeod <amacleod@redhat.com>
    Adapted to use control dependence by Steven Bosscher, SUSE Labs.
@@ -45,34 +45,28 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
-
+#include "backend.h"
+#include "rtl.h"
 #include "tree.h"
-#include "calls.h"
+#include "gimple.h"
+#include "cfghooks.h"
+#include "tree-pass.h"
+#include "ssa.h"
 #include "gimple-pretty-print.h"
-#include "basic-block.h"
-#include "tree-ssa-alias.h"
-#include "internal-fn.h"
+#include "fold-const.h"
+#include "calls.h"
+#include "cfganal.h"
 #include "tree-eh.h"
-#include "gimple-expr.h"
-#include "is-a.h"
-#include "gimple.h"
 #include "gimplify.h"
 #include "gimple-iterator.h"
-#include "gimple-ssa.h"
 #include "tree-cfg.h"
-#include "tree-phinodes.h"
-#include "ssa-iterators.h"
-#include "stringpool.h"
-#include "tree-ssanames.h"
 #include "tree-ssa-loop-niter.h"
 #include "tree-into-ssa.h"
-#include "expr.h"
 #include "tree-dfa.h"
-#include "tree-pass.h"
-#include "flags.h"
 #include "cfgloop.h"
 #include "tree-scalar-evolution.h"
+#include "tree-ssa-propagate.h"
+#include "gimple-fold.h"
 
 static struct stmt_stats
 {
@@ -84,7 +78,7 @@ static struct stmt_stats
 
 #define STMT_NECESSARY GF_PLF_1
 
-static vec<gimple> worklist;
+static vec<gimple *> worklist;
 
 /* Vector indicating an SSA name has already been processed and marked
    as necessary.  */
@@ -117,12 +111,23 @@ static sbitmap visited_control_parents;
    to be recomputed.  */
 static bool cfg_altered;
 
+/* When non-NULL holds map from basic block index into the postorder.  */
+static int *bb_postorder;
+
+
+/* True if we should treat any stmt with a vdef as necessary.  */
+
+static inline bool
+keep_all_vdefs_p ()
+{
+  return optimize_debug;
+}
 
 /* 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)
+mark_stmt_necessary (gimple *stmt, bool add_to_worklist)
 {
   gcc_assert (stmt);
 
@@ -139,7 +144,7 @@ mark_stmt_necessary (gimple stmt, bool add_to_worklist)
   gimple_set_plf (stmt, STMT_NECESSARY, true);
   if (add_to_worklist)
     worklist.safe_push (stmt);
-  if (bb_contains_live_stmts && !is_gimple_debug (stmt))
+  if (add_to_worklist && bb_contains_live_stmts && !is_gimple_debug (stmt))
     bitmap_set_bit (bb_contains_live_stmts, gimple_bb (stmt)->index);
 }
 
@@ -149,7 +154,7 @@ mark_stmt_necessary (gimple stmt, bool add_to_worklist)
 static inline void
 mark_operand_necessary (tree op)
 {
-  gimple stmt;
+  gimple *stmt;
   int ver;
 
   gcc_assert (op);
@@ -173,9 +178,9 @@ mark_operand_necessary (tree op)
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
       fprintf (dump_file, "marking necessary through ");
-      print_generic_expr (dump_file, op, 0);
+      print_generic_expr (dump_file, op);
       fprintf (dump_file, " stmt ");
-      print_gimple_stmt (dump_file, stmt, 0, 0);
+      print_gimple_stmt (dump_file, stmt, 0);
     }
 
   gimple_set_plf (stmt, STMT_NECESSARY, true);
@@ -192,13 +197,13 @@ mark_operand_necessary (tree op)
    necessary.  */
 
 static void
-mark_stmt_if_obviously_necessary (gimple stmt, bool aggressive)
+mark_stmt_if_obviously_necessary (gimple *stmt, bool aggressive)
 {
   /* With non-call exceptions, we have to assume that all statements could
      throw.  If a statement could throw, it can be deemed necessary.  */
   if (cfun->can_throw_non_call_exceptions
       && !cfun->can_delete_dead_exceptions
-      && stmt_could_throw_p (stmt))
+      && stmt_could_throw_p (cfun, stmt))
     {
       mark_stmt_necessary (stmt, true);
       return;
@@ -227,17 +232,25 @@ mark_stmt_if_obviously_necessary (gimple stmt, bool aggressive)
       {
        tree callee = gimple_call_fndecl (stmt);
        if (callee != NULL_TREE
-           && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL)
+           && fndecl_built_in_p (callee, BUILT_IN_NORMAL))
          switch (DECL_FUNCTION_CODE (callee))
            {
            case BUILT_IN_MALLOC:
+           case BUILT_IN_ALIGNED_ALLOC:
            case BUILT_IN_CALLOC:
-           case BUILT_IN_ALLOCA:
-           case BUILT_IN_ALLOCA_WITH_ALIGN:
+           CASE_BUILT_IN_ALLOCA:
+           case BUILT_IN_STRDUP:
+           case BUILT_IN_STRNDUP:
              return;
 
            default:;
            }
+
+       if (callee != NULL_TREE
+           && flag_allocation_dce
+           && DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee))
+         return;
+
        /* 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.  */
@@ -246,6 +259,17 @@ mark_stmt_if_obviously_necessary (gimple stmt, bool aggressive)
            mark_stmt_necessary (stmt, true);
            return;
          }
+       /* IFN_GOACC_LOOP calls are necessary in that they are used to
+          represent parameter (i.e. step, bound) of a lowered OpenACC
+          partitioned loop.  But this kind of partitioned loop might not
+          survive from aggressive loop removal for it has loop exit and
+          is assumed to be finite.  Therefore, we need to explicitly mark
+          these calls. (An example is libgomp.oacc-c-c++-common/pr84955.c) */
+       if (gimple_call_internal_p (stmt, IFN_GOACC_LOOP))
+         {
+           mark_stmt_necessary (stmt, true);
+           return;
+         }
        if (!gimple_call_lhs (stmt))
          return;
        break;
@@ -256,7 +280,8 @@ mark_stmt_if_obviously_necessary (gimple stmt, bool aggressive)
         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_p (stmt)
+      if (gimple_debug_nonbind_marker_p (stmt)
+         || !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);
@@ -277,8 +302,7 @@ mark_stmt_if_obviously_necessary (gimple stmt, bool aggressive)
       break;
 
     case GIMPLE_ASSIGN:
-      if (TREE_CODE (gimple_assign_lhs (stmt)) == SSA_NAME
-         && TREE_CLOBBER_P (gimple_assign_rhs1 (stmt)))
+      if (gimple_clobber_p (stmt))
        return;
       break;
 
@@ -301,6 +325,12 @@ mark_stmt_if_obviously_necessary (gimple stmt, bool aggressive)
       return;
     }
 
+  if (gimple_vdef (stmt) && keep_all_vdefs_p ())
+    {
+      mark_stmt_necessary (stmt, true);
+      return;
+    }
+
   return;
 }
 
@@ -310,7 +340,7 @@ mark_stmt_if_obviously_necessary (gimple stmt, bool aggressive)
 static void
 mark_last_stmt_necessary (basic_block bb)
 {
-  gimple stmt = last_stmt (bb);
+  gimple *stmt = last_stmt (bb);
 
   bitmap_set_bit (last_stmt_necessary, bb->index);
   bitmap_set_bit (bb_contains_live_stmts, bb->index);
@@ -341,7 +371,7 @@ mark_control_dependent_edges_necessary (basic_block bb, bool ignore_self)
   EXECUTE_IF_SET_IN_BITMAP (cd->get_edges_dependent_on (bb->index),
                            0, edge_number, bi)
     {
-      basic_block cd_bb = cd->get_edge (edge_number)->src;
+      basic_block cd_bb = cd->get_edge_src (edge_number);
 
       if (ignore_self && cd_bb == bb)
        {
@@ -371,7 +401,7 @@ find_obviously_necessary_stmts (bool aggressive)
   basic_block bb;
   gimple_stmt_iterator gsi;
   edge e;
-  gimple phi, stmt;
+  gimple *phi, *stmt;
   int flags;
 
   FOR_EACH_BB_FN (bb, cfun)
@@ -401,8 +431,7 @@ find_obviously_necessary_stmts (bool aggressive)
   /* Prevent the empty possibly infinite loops from being removed.  */
   if (aggressive)
     {
-      struct loop *loop;
-      scev_initialize ();
+      class loop *loop;
       if (mark_irreducible_loops ())
        FOR_EACH_BB_FN (bb, cfun)
          {
@@ -422,10 +451,9 @@ find_obviously_necessary_stmts (bool aggressive)
        if (!finite_loop_p (loop))
          {
            if (dump_file)
-             fprintf (dump_file, "can not prove finiteness of loop %i\n", loop->num);
+             fprintf (dump_file, "cannot prove finiteness of loop %i\n", loop->num);
            mark_control_dependent_edges_necessary (loop->latch, false);
          }
-      scev_finalize ();
     }
 }
 
@@ -461,10 +489,11 @@ static bool chain_ovfl = false;
 static bool
 mark_aliased_reaching_defs_necessary_1 (ao_ref *ref, tree vdef, void *data)
 {
-  gimple def_stmt = SSA_NAME_DEF_STMT (vdef);
+  gimple *def_stmt = SSA_NAME_DEF_STMT (vdef);
 
   /* All stmts we visit are necessary.  */
-  mark_operand_necessary (vdef);
+  if (! gimple_clobber_p (def_stmt))
+    mark_operand_necessary (vdef);
 
   /* If the stmt lhs kills ref, then we can stop walking.  */
   if (gimple_has_lhs (def_stmt)
@@ -475,25 +504,23 @@ mark_aliased_reaching_defs_necessary_1 (ao_ref *ref, tree vdef, void *data)
          ???  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))
+      && !stmt_can_throw_internal (cfun, def_stmt))
     {
       tree base, lhs = gimple_get_lhs (def_stmt);
-      HOST_WIDE_INT size, offset, max_size;
+      poly_int64 size, offset, max_size;
+      bool reverse;
       ao_ref_base (ref);
-      base = get_ref_base_and_extent (lhs, &offset, &size, &max_size);
+      base
+       = get_ref_base_and_extent (lhs, &offset, &size, &max_size, &reverse);
       /* We can get MEM[symbol: sZ, index: D.8862_1] here,
         so base == refd->base does not always hold.  */
       if (base == ref->base)
        {
          /* For a must-alias check we need to be able to constrain
             the accesses properly.  */
-         if (size != -1 && size == max_size
-             && ref->max_size != -1)
-           {
-             if (offset <= ref->offset
-                 && offset + size >= ref->offset + ref->max_size)
-               return true;
-           }
+         if (known_eq (size, max_size)
+             && known_subrange_p (ref->offset, ref->max_size, offset, size))
+           return true;
          /* Or they need to be exactly the same.  */
          else if (ref->ref
                   /* Make sure there is no induction variable involved
@@ -517,8 +544,11 @@ mark_aliased_reaching_defs_necessary_1 (ao_ref *ref, tree vdef, void *data)
 }
 
 static void
-mark_aliased_reaching_defs_necessary (gimple stmt, tree ref)
+mark_aliased_reaching_defs_necessary (gimple *stmt, tree ref)
 {
+  /* Should have been caught before calling this function.  */
+  gcc_checking_assert (!keep_all_vdefs_p ());
+
   unsigned int chain;
   ao_ref refd;
   gcc_assert (!chain_ovfl);
@@ -542,7 +572,7 @@ static bool
 mark_all_reaching_defs_necessary_1 (ao_ref *ref ATTRIBUTE_UNUSED,
                                    tree vdef, void *data ATTRIBUTE_UNUSED)
 {
-  gimple def_stmt = SSA_NAME_DEF_STMT (vdef);
+  gimple *def_stmt = SSA_NAME_DEF_STMT (vdef);
 
   /* We have to skip already visited (and thus necessary) statements
      to make the chaining work after we dropped back to simple mode.  */
@@ -569,28 +599,36 @@ mark_all_reaching_defs_necessary_1 (ao_ref *ref ATTRIBUTE_UNUSED,
     {
       tree callee = gimple_call_fndecl (def_stmt);
       if (callee != NULL_TREE
-         && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL)
+         && fndecl_built_in_p (callee, BUILT_IN_NORMAL))
        switch (DECL_FUNCTION_CODE (callee))
          {
          case BUILT_IN_MALLOC:
+         case BUILT_IN_ALIGNED_ALLOC:
          case BUILT_IN_CALLOC:
-         case BUILT_IN_ALLOCA:
-         case BUILT_IN_ALLOCA_WITH_ALIGN:
+         CASE_BUILT_IN_ALLOCA:
          case BUILT_IN_FREE:
            return false;
 
          default:;
          }
+
+      if (callee != NULL_TREE
+         && (DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee)
+             || DECL_IS_OPERATOR_DELETE_P (callee)))
+       return false;
     }
 
-  mark_operand_necessary (vdef);
+  if (! gimple_clobber_p (def_stmt))
+    mark_operand_necessary (vdef);
 
   return false;
 }
 
 static void
-mark_all_reaching_defs_necessary (gimple stmt)
+mark_all_reaching_defs_necessary (gimple *stmt)
 {
+  /* Should have been caught before calling this function.  */
+  gcc_checking_assert (!keep_all_vdefs_p ());
   walk_aliased_vdefs (NULL, gimple_vuse (stmt),
                      mark_all_reaching_defs_necessary_1, NULL, &visited);
 }
@@ -598,7 +636,7 @@ mark_all_reaching_defs_necessary (gimple stmt)
 /* Return true for PHI nodes with one or identical arguments
    can be removed.  */
 static bool
-degenerate_phi_p (gimple phi)
+degenerate_phi_p (gimple *phi)
 {
   unsigned int i;
   tree op = gimple_phi_arg_def (phi, 0);
@@ -618,7 +656,7 @@ degenerate_phi_p (gimple phi)
 static void
 propagate_necessity (bool aggressive)
 {
-  gimple stmt;
+  gimple *stmt;
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     fprintf (dump_file, "\nProcessing worklist:\n");
@@ -657,6 +695,7 @@ propagate_necessity (bool aggressive)
             we also consider the control dependent edges leading to the
             predecessor block associated with each PHI alternative as
             necessary.  */
+         gphi *phi = as_a <gphi *> (stmt);
          size_t k;
 
          for (k = 0; k < gimple_phi_num_args (stmt); k++)
@@ -739,7 +778,7 @@ propagate_necessity (bool aggressive)
            {
              for (k = 0; k < gimple_phi_num_args (stmt); k++)
                {
-                 basic_block arg_bb = gimple_phi_arg_edge (stmt, k)->src;
+                 basic_block arg_bb = gimple_phi_arg_edge (phi, k)->src;
 
                  if (gimple_bb (stmt)
                      != get_immediate_dominator (CDI_POST_DOMINATORS, arg_bb))
@@ -765,20 +804,39 @@ propagate_necessity (bool aggressive)
          /* 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))
+         bool is_delete_operator
+           = (is_gimple_call (stmt)
+              && gimple_call_operator_delete_p (as_a <gcall *> (stmt)));
+         if (is_delete_operator
+             || gimple_call_builtin_p (stmt, BUILT_IN_FREE))
            {
              tree ptr = gimple_call_arg (stmt, 0);
-             gimple def_stmt;
+             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;
+                 && ((DECL_BUILT_IN_CLASS (def_callee) == BUILT_IN_NORMAL
+                      && (DECL_FUNCTION_CODE (def_callee) == BUILT_IN_ALIGNED_ALLOC
+                          || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_MALLOC
+                          || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_CALLOC))
+                     || DECL_IS_REPLACEABLE_OPERATOR_NEW_P (def_callee)))
+               {
+                 /* Delete operators can have alignment and (or) size as next
+                    arguments.  When being a SSA_NAME, they must be marked
+                    as necessary.  */
+                 if (is_delete_operator && gimple_call_num_args (stmt) >= 2)
+                   for (unsigned i = 1; i < gimple_call_num_args (stmt); i++)
+                     {
+                       tree arg = gimple_call_arg (stmt, i);
+                       if (TREE_CODE (arg) == SSA_NAME)
+                         mark_operand_necessary (arg);
+                     }
+
+                 continue;
+               }
            }
 
          FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
@@ -788,6 +846,10 @@ propagate_necessity (bool aggressive)
          if (!use)
            continue;
 
+         /* No need to search for vdefs if we intrinsicly keep them all.  */
+         if (keep_all_vdefs_p ())
+           continue;
+
          /* If we dropped to simple mode make all immediately
             reachable definitions necessary.  */
          if (chain_ovfl)
@@ -822,17 +884,21 @@ propagate_necessity (bool aggressive)
                  && (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_ALIGNED_ALLOC
                      || 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)
+                     || ALLOCA_FUNCTION_CODE_P (DECL_FUNCTION_CODE (callee))
                      || 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;
 
+             if (callee != NULL_TREE
+                 && (DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee)
+                     || DECL_IS_OPERATOR_DELETE_P (callee)))
+               continue;
+
              /* Calls implicitly load from memory, their arguments
                 in addition may explicitly perform memory loads.  */
              mark_all_reaching_defs_necessary (stmt);
@@ -863,9 +929,9 @@ propagate_necessity (bool aggressive)
                    mark_all_reaching_defs_necessary (stmt);
                }
            }
-         else if (gimple_code (stmt) == GIMPLE_RETURN)
+         else if (greturn *return_stmt = dyn_cast <greturn *> (stmt))
            {
-             tree rhs = gimple_return_retval (stmt);
+             tree rhs = gimple_return_retval (return_stmt);
              /* A return statement may perform a load.  */
              if (rhs
                  && TREE_CODE (rhs) != SSA_NAME
@@ -878,14 +944,14 @@ propagate_necessity (bool aggressive)
                    mark_all_reaching_defs_necessary (stmt);
                }
            }
-         else if (gimple_code (stmt) == GIMPLE_ASM)
+         else if (gasm *asm_stmt = dyn_cast <gasm *> (stmt))
            {
              unsigned i;
              mark_all_reaching_defs_necessary (stmt);
              /* Inputs may perform loads.  */
-             for (i = 0; i < gimple_asm_ninputs (stmt); ++i)
+             for (i = 0; i < gimple_asm_ninputs (asm_stmt); ++i)
                {
-                 tree op = TREE_VALUE (gimple_asm_input_op (stmt, i));
+                 tree op = TREE_VALUE (gimple_asm_input_op (asm_stmt, i));
                  if (TREE_CODE (op) != SSA_NAME
                      && !is_gimple_min_invariant (op)
                      && TREE_CODE (op) != CONSTRUCTOR
@@ -929,13 +995,13 @@ static bool
 remove_dead_phis (basic_block bb)
 {
   bool something_changed = false;
-  gimple phi;
-  gimple_stmt_iterator gsi;
+  gphi *phi;
+  gphi_iterator gsi;
 
   for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi);)
     {
       stats.total_phis++;
-      phi = gsi_stmt (gsi);
+      phi = gsi.phi ();
 
       /* We do not track necessity of virtual PHI nodes.  Instead do
          very simple dead PHI removal here.  */
@@ -950,7 +1016,7 @@ remove_dead_phis (basic_block bb)
 
              use_operand_p use_p;
              imm_use_iterator iter;
-             gimple use_stmt;
+             gimple *use_stmt;
              FOR_EACH_IMM_USE_STMT (use_stmt, iter, vdef)
                FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
                  SET_USE (use_p, vuse);
@@ -982,73 +1048,15 @@ remove_dead_phis (basic_block bb)
   return something_changed;
 }
 
-/* Forward edge E to respective POST_DOM_BB and update PHIs.  */
-
-static edge
-forward_edge_to_pdom (edge e, basic_block post_dom_bb)
-{
-  gimple_stmt_iterator gsi;
-  edge e2 = NULL;
-  edge_iterator ei;
-
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    fprintf (dump_file, "Redirecting edge %i->%i to %i\n", e->src->index,
-            e->dest->index, post_dom_bb->index);
-
-  e2 = redirect_edge_and_branch (e, post_dom_bb);
-  cfg_altered = true;
-
-  /* If edge was already around, no updating is necessary.  */
-  if (e2 != e)
-    return e2;
-
-  if (!gimple_seq_empty_p (phi_nodes (post_dom_bb)))
-    {
-      /* We are sure that for every live PHI we are seeing control dependent BB.
-         This means that we can pick any edge to duplicate PHI args from.  */
-      FOR_EACH_EDGE (e2, ei, post_dom_bb->preds)
-       if (e2 != e)
-         break;
-      for (gsi = gsi_start_phis (post_dom_bb); !gsi_end_p (gsi);)
-       {
-         gimple phi = gsi_stmt (gsi);
-         tree op;
-         source_location locus;
-
-         /* PHIs for virtuals have no control dependency relation on them.
-            We are lost here and must force renaming of the symbol.  */
-         if (virtual_operand_p (gimple_phi_result (phi)))
-           {
-             mark_virtual_phi_result_for_renaming (phi);
-             remove_phi_node (&gsi, true);
-             continue;
-           }
-
-         /* Dead PHI do not imply control dependency.  */
-          if (!gimple_plf (phi, STMT_NECESSARY))
-           {
-             gsi_next (&gsi);
-             continue;
-           }
-
-         op = gimple_phi_arg_def (phi, e2->dest_idx);
-         locus = gimple_phi_arg_location (phi, e2->dest_idx);
-         add_phi_arg (phi, op, e, locus);
-         /* The resulting PHI if not dead can only be degenerate.  */
-         gcc_assert (degenerate_phi_p (phi));
-         gsi_next (&gsi);
-       }
-    }
-  return e;
-}
 
 /* Remove dead statement pointed to by iterator I.  Receives the basic block BB
    containing I so that we don't have to look it up.  */
 
 static void
-remove_dead_stmt (gimple_stmt_iterator *i, basic_block bb)
+remove_dead_stmt (gimple_stmt_iterator *i, basic_block bb,
+                 vec<edge> &to_remove_edges)
 {
-  gimple stmt = gsi_stmt (*i);
+  gimple *stmt = gsi_stmt (*i);
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
@@ -1060,68 +1068,80 @@ remove_dead_stmt (gimple_stmt_iterator *i, basic_block bb)
   stats.removed++;
 
   /* If we have determined that a conditional branch statement contributes
-     nothing to the program, then we not only remove it, but we also change
-     the flow graph so that the current block will simply fall-thru to its
-     immediate post-dominator.  The blocks we are circumventing will be
-     removed by cleanup_tree_cfg if this change in the flow graph makes them
-     unreachable.  */
+     nothing to the program, then we not only remove it, but we need to update
+     the CFG.  We can chose any of edges out of BB as long as we are sure to not
+     close infinite loops.  This is done by always choosing the edge closer to
+     exit in inverted_post_order_compute order.  */
   if (is_ctrl_stmt (stmt))
     {
-      basic_block post_dom_bb;
-      edge e, e2;
       edge_iterator ei;
-
-      post_dom_bb = get_immediate_dominator (CDI_POST_DOMINATORS, bb);
-
-      e = find_edge (bb, post_dom_bb);
-
-      /* If edge is already there, try to use it.  This avoids need to update
-         PHI nodes.  Also watch for cases where post dominator does not exists
-        or is exit block.  These can happen for infinite loops as we create
-        fake edges in the dominator tree.  */
-      if (e)
-        ;
-      else if (! post_dom_bb || post_dom_bb == EXIT_BLOCK_PTR_FOR_FN (cfun))
-       e = EDGE_SUCC (bb, 0);
-      else
-        e = forward_edge_to_pdom (EDGE_SUCC (bb, 0), post_dom_bb);
+      edge e = NULL, e2;
+
+      /* See if there is only one non-abnormal edge.  */
+      if (single_succ_p (bb))
+        e = single_succ_edge (bb);
+      /* Otherwise chose one that is closer to bb with live statement in it.
+         To be able to chose one, we compute inverted post order starting from
+        all BBs with live statements.  */
+      if (!e)
+       {
+         if (!bb_postorder)
+           {
+             auto_vec<int, 20> postorder;
+                inverted_post_order_compute (&postorder,
+                                             &bb_contains_live_stmts);
+             bb_postorder = XNEWVEC (int, last_basic_block_for_fn (cfun));
+             for (unsigned int i = 0; i < postorder.length (); ++i)
+                bb_postorder[postorder[i]] = i;
+           }
+          FOR_EACH_EDGE (e2, ei, bb->succs)
+           if (!e || e2->dest == EXIT_BLOCK_PTR_FOR_FN (cfun)
+               || bb_postorder [e->dest->index]
+                  < bb_postorder [e2->dest->index])
+             e = e2;
+       }
       gcc_assert (e);
-      e->probability = REG_BR_PROB_BASE;
-      e->count = bb->count;
+      e->probability = profile_probability::always ();
 
       /* The edge is no longer associated with a conditional, so it does
-        not have TRUE/FALSE flags.  */
-      e->flags &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
+        not have TRUE/FALSE flags.
+        We are also safe to drop EH/ABNORMAL flags and turn them into
+        normal control flow, because we know that all the destinations (including
+        those odd edges) are equivalent for program execution.  */
+      e->flags &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE | EDGE_EH | EDGE_ABNORMAL);
 
       /* The lone outgoing edge from BB will be a fallthru edge.  */
       e->flags |= EDGE_FALLTHRU;
 
       /* Remove the remaining outgoing edges.  */
-      for (ei = ei_start (bb->succs); (e2 = ei_safe_edge (ei)); )
+      FOR_EACH_EDGE (e2, ei, bb->succs)
        if (e != e2)
          {
-           cfg_altered = true;
-            remove_edge (e2);
+           /* If we made a BB unconditionally exit a loop or removed
+              an entry into an irreducible region, then this transform
+              alters the set of BBs in the loop.  Schedule a fixup.  */
+           if (loop_exit_edge_p (bb->loop_father, e)
+               || (e2->dest->flags & BB_IRREDUCIBLE_LOOP))
+             loops_state_set (LOOPS_NEED_FIXUP);
+           to_remove_edges.safe_push (e2);
          }
-       else
-         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
+  if (MAY_HAVE_DEBUG_BIND_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)
+      if ((VAR_P (lhs) || 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
+         gdebug *note
            = gimple_build_debug_bind (lhs, unshare_expr (rhs), stmt);
          gsi_insert_after (i, note, GSI_SAME_STMT);
        }
@@ -1132,6 +1152,109 @@ remove_dead_stmt (gimple_stmt_iterator *i, basic_block bb)
   release_defs (stmt);
 }
 
+/* Helper for maybe_optimize_arith_overflow.  Find in *TP if there are any
+   uses of data (SSA_NAME) other than REALPART_EXPR referencing it.  */
+
+static tree
+find_non_realpart_uses (tree *tp, int *walk_subtrees, void *data)
+{
+  if (TYPE_P (*tp) || TREE_CODE (*tp) == REALPART_EXPR)
+    *walk_subtrees = 0;
+  if (*tp == (tree) data)
+    return *tp;
+  return NULL_TREE;
+}
+
+/* If the IMAGPART_EXPR of the {ADD,SUB,MUL}_OVERFLOW result is never used,
+   but REALPART_EXPR is, optimize the {ADD,SUB,MUL}_OVERFLOW internal calls
+   into plain unsigned {PLUS,MINUS,MULT}_EXPR, and if needed reset debug
+   uses.  */
+
+static void
+maybe_optimize_arith_overflow (gimple_stmt_iterator *gsi,
+                              enum tree_code subcode)
+{
+  gimple *stmt = gsi_stmt (*gsi);
+  tree lhs = gimple_call_lhs (stmt);
+
+  if (lhs == NULL || TREE_CODE (lhs) != SSA_NAME)
+    return;
+
+  imm_use_iterator imm_iter;
+  use_operand_p use_p;
+  bool has_debug_uses = false;
+  bool has_realpart_uses = false;
+  bool has_other_uses = false;
+  FOR_EACH_IMM_USE_FAST (use_p, imm_iter, lhs)
+    {
+      gimple *use_stmt = USE_STMT (use_p);
+      if (is_gimple_debug (use_stmt))
+       has_debug_uses = true;
+      else if (is_gimple_assign (use_stmt)
+              && gimple_assign_rhs_code (use_stmt) == REALPART_EXPR
+              && TREE_OPERAND (gimple_assign_rhs1 (use_stmt), 0) == lhs)
+       has_realpart_uses = true;
+      else
+       {
+         has_other_uses = true;
+         break;
+       }
+    }
+
+  if (!has_realpart_uses || has_other_uses)
+    return;
+
+  tree arg0 = gimple_call_arg (stmt, 0);
+  tree arg1 = gimple_call_arg (stmt, 1);
+  location_t loc = gimple_location (stmt);
+  tree type = TREE_TYPE (TREE_TYPE (lhs));
+  tree utype = type;
+  if (!TYPE_UNSIGNED (type))
+    utype = build_nonstandard_integer_type (TYPE_PRECISION (type), 1);
+  tree result = fold_build2_loc (loc, subcode, utype,
+                                fold_convert_loc (loc, utype, arg0),
+                                fold_convert_loc (loc, utype, arg1));
+  result = fold_convert_loc (loc, type, result);
+
+  if (has_debug_uses)
+    {
+      gimple *use_stmt;
+      FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter, lhs)
+       {
+         if (!gimple_debug_bind_p (use_stmt))
+           continue;
+         tree v = gimple_debug_bind_get_value (use_stmt);
+         if (walk_tree (&v, find_non_realpart_uses, lhs, NULL))
+           {
+             gimple_debug_bind_reset_value (use_stmt);
+             update_stmt (use_stmt);
+           }
+       }
+    }
+
+  if (TREE_CODE (result) == INTEGER_CST && TREE_OVERFLOW (result))
+    result = drop_tree_overflow (result);
+  tree overflow = build_zero_cst (type);
+  tree ctype = build_complex_type (type);
+  if (TREE_CODE (result) == INTEGER_CST)
+    result = build_complex (ctype, result, overflow);
+  else
+    result = build2_loc (gimple_location (stmt), COMPLEX_EXPR,
+                        ctype, result, overflow);
+
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "Transforming call: ");
+      print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
+      fprintf (dump_file, "because the overflow result is never used into: ");
+      print_generic_stmt (dump_file, result, TDF_SLIM);
+      fprintf (dump_file, "\n");
+    }
+
+  if (!update_call_from_tree (gsi, result))
+    gimplify_and_update_call_from_tree (gsi, result);
+}
+
 /* Eliminate unnecessary statements. Any instruction not marked as necessary
    contributes nothing to the program, and can be deleted.  */
 
@@ -1141,9 +1264,10 @@ eliminate_unnecessary_stmts (void)
   bool something_changed = false;
   basic_block bb;
   gimple_stmt_iterator gsi, psi;
-  gimple stmt;
+  gimple *stmt;
   tree call;
   vec<basic_block> h;
+  auto_vec<edge> to_remove_edges;
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     fprintf (dump_file, "\nEliminating unnecessary statements:\n");
@@ -1181,6 +1305,7 @@ eliminate_unnecessary_stmts (void)
       bb = h.pop ();
 
       /* Remove dead statements.  */
+      auto_bitmap debug_seen;
       for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi = psi)
        {
          stmt = gsi_stmt (gsi);
@@ -1194,12 +1319,14 @@ eliminate_unnecessary_stmts (void)
             defining statement of its argument is not necessary
             (and thus is getting removed).  */
          if (gimple_plf (stmt, STMT_NECESSARY)
-             && gimple_call_builtin_p (stmt, BUILT_IN_FREE))
+             && (gimple_call_builtin_p (stmt, BUILT_IN_FREE)
+                 || (is_gimple_call (stmt)
+                     && gimple_call_operator_delete_p (as_a <gcall *> (stmt)))))
            {
              tree ptr = gimple_call_arg (stmt, 0);
              if (TREE_CODE (ptr) == SSA_NAME)
                {
-                 gimple def_stmt = SSA_NAME_DEF_STMT (ptr);
+                 gimple *def_stmt = SSA_NAME_DEF_STMT (ptr);
                  if (!gimple_nop_p (def_stmt)
                      && !gimple_plf (def_stmt, STMT_NECESSARY))
                    gimple_set_plf (stmt, STMT_NECESSARY, false);
@@ -1209,15 +1336,38 @@ eliminate_unnecessary_stmts (void)
          /* If GSI is not necessary then remove it.  */
          if (!gimple_plf (stmt, STMT_NECESSARY))
            {
+             /* Keep clobbers that we can keep live live.  */
+             if (gimple_clobber_p (stmt))
+               {
+                 ssa_op_iter iter;
+                 use_operand_p use_p;
+                 bool dead = false;
+                 FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE)
+                   {
+                     tree name = USE_FROM_PTR (use_p);
+                     if (!SSA_NAME_IS_DEFAULT_DEF (name)
+                         && !bitmap_bit_p (processed, SSA_NAME_VERSION (name)))
+                       {
+                         dead = true;
+                         break;
+                       }
+                   }
+                 if (!dead)
+                   {
+                     bitmap_clear (debug_seen);
+                     continue;
+                   }
+               }
              if (!is_gimple_debug (stmt))
                something_changed = true;
-             remove_dead_stmt (&gsi, bb);
+             remove_dead_stmt (&gsi, bb, to_remove_edges);
+             continue;
            }
          else if (is_gimple_call (stmt))
            {
              tree name = gimple_call_lhs (stmt);
 
-             notice_special_calls (stmt);
+             notice_special_calls (as_a <gcall *> (stmt));
 
              /* When LHS of var = call (); is dead, simplify it into
                 call (); saving one operand.  */
@@ -1228,12 +1378,13 @@ eliminate_unnecessary_stmts (void)
                     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))))
+                     || ((DECL_BUILT_IN_CLASS (call) != BUILT_IN_NORMAL
+                          || (DECL_FUNCTION_CODE (call) != BUILT_IN_ALIGNED_ALLOC
+                              && DECL_FUNCTION_CODE (call) != BUILT_IN_MALLOC
+                              && DECL_FUNCTION_CODE (call) != BUILT_IN_CALLOC
+                              && !ALLOCA_FUNCTION_CODE_P
+                              (DECL_FUNCTION_CODE (call))))
+                         && !DECL_IS_REPLACEABLE_OPERATOR_NEW_P (call))))
                {
                  something_changed = true;
                  if (dump_file && (dump_flags & TDF_DETAILS))
@@ -1247,9 +1398,56 @@ eliminate_unnecessary_stmts (void)
                  maybe_clean_or_replace_eh_stmt (stmt, stmt);
                  update_stmt (stmt);
                  release_ssa_name (name);
+
+                 /* GOMP_SIMD_LANE (unless three argument) or ASAN_POISON
+                    without lhs is not needed.  */
+                 if (gimple_call_internal_p (stmt))
+                   switch (gimple_call_internal_fn (stmt))
+                     {
+                     case IFN_GOMP_SIMD_LANE:
+                       if (gimple_call_num_args (stmt) >= 3
+                           && !integer_nonzerop (gimple_call_arg (stmt, 2)))
+                         break;
+                       /* FALLTHRU */
+                     case IFN_ASAN_POISON:
+                       remove_dead_stmt (&gsi, bb, to_remove_edges);
+                       break;
+                     default:
+                       break;
+                     }
                }
+             else if (gimple_call_internal_p (stmt))
+               switch (gimple_call_internal_fn (stmt))
+                 {
+                 case IFN_ADD_OVERFLOW:
+                   maybe_optimize_arith_overflow (&gsi, PLUS_EXPR);
+                   break;
+                 case IFN_SUB_OVERFLOW:
+                   maybe_optimize_arith_overflow (&gsi, MINUS_EXPR);
+                   break;
+                 case IFN_MUL_OVERFLOW:
+                   maybe_optimize_arith_overflow (&gsi, MULT_EXPR);
+                   break;
+                 default:
+                   break;
+                 }
            }
+         else if (gimple_debug_bind_p (stmt))
+           {
+             /* We are only keeping the last debug-bind of a
+                non-DEBUG_EXPR_DECL variable in a series of
+                debug-bind stmts.  */
+             tree var = gimple_debug_bind_get_var (stmt);
+             if (TREE_CODE (var) != DEBUG_EXPR_DECL
+                 && !bitmap_set_bit (debug_seen, DECL_UID (var)))
+               remove_dead_stmt (&gsi, bb, to_remove_edges);
+             continue;
+           }
+         bitmap_clear (debug_seen);
        }
+
+      /* Remove dead PHI nodes.  */
+      something_changed |= remove_dead_phis (bb);
     }
 
   h.release ();
@@ -1257,10 +1455,16 @@ eliminate_unnecessary_stmts (void)
   /* 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)
+  if (!to_remove_edges.is_empty ())
     {
       basic_block prev_bb;
 
+      /* Remove edges.  We've delayed this to not get bogus debug stmts
+         during PHI node removal.  */
+      for (unsigned i = 0; i < to_remove_edges.length (); ++i)
+       remove_edge (to_remove_edges[i]);
+      cfg_altered = true;
+
       find_unreachable_blocks ();
 
       /* Delete all unreachable basic blocks in reverse dominator order.  */
@@ -1272,13 +1476,15 @@ eliminate_unnecessary_stmts (void)
          if (!bitmap_bit_p (bb_contains_live_stmts, bb->index)
              || !(bb->flags & BB_REACHABLE))
            {
-             for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
-               if (virtual_operand_p (gimple_phi_result (gsi_stmt (gsi))))
+             for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
+                  gsi_next (&gsi))
+               if (virtual_operand_p (gimple_phi_result (gsi.phi ())))
                  {
                    bool found = false;
                    imm_use_iterator iter;
 
-                   FOR_EACH_IMM_USE_STMT (stmt, iter, gimple_phi_result (gsi_stmt (gsi)))
+                   FOR_EACH_IMM_USE_STMT (stmt, iter,
+                                          gimple_phi_result (gsi.phi ()))
                      {
                        if (!(gimple_bb (stmt)->flags & BB_REACHABLE))
                          continue;
@@ -1290,7 +1496,7 @@ eliminate_unnecessary_stmts (void)
                          }
                      }
                    if (found)
-                     mark_virtual_phi_result_for_renaming (gsi_stmt (gsi));
+                     mark_virtual_phi_result_for_renaming (gsi.phi ());
                  }
 
              if (!(bb->flags & BB_REACHABLE))
@@ -1299,8 +1505,7 @@ eliminate_unnecessary_stmts (void)
                     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))
+                 if (!first_dom_son (CDI_DOMINATORS, bb))
                    delete_basic_block (bb);
                  else
                    {
@@ -1325,11 +1530,10 @@ eliminate_unnecessary_stmts (void)
            }
        }
     }
-  FOR_EACH_BB_FN (bb, cfun)
-    {
-      /* Remove dead PHI nodes.  */
-      something_changed |= remove_dead_phis (bb);
-    }
+
+  if (bb_postorder)
+    free (bb_postorder);
+  bb_postorder = NULL;
 
   return something_changed;
 }
@@ -1420,9 +1624,13 @@ perform_tree_ssa_dce (bool aggressive)
   /* 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  */
-  if (aggressive)
-    loop_optimizer_init (LOOPS_NORMAL
-                        | LOOPS_HAVE_RECORDED_EXITS);
+  bool in_loop_pipeline = scev_initialized_p ();
+  if (aggressive && ! in_loop_pipeline)
+    {
+      scev_initialize ();
+      loop_optimizer_init (LOOPS_NORMAL
+                          | LOOPS_HAVE_RECORDED_EXITS);
+    }
 
   tree_dce_init (aggressive);
 
@@ -1430,7 +1638,7 @@ perform_tree_ssa_dce (bool aggressive)
     {
       /* Compute control dependence.  */
       calculate_dominance_info (CDI_POST_DOMINATORS);
-      cd = new control_dependences (create_edge_list ());
+      cd = new control_dependences ();
 
       visited_control_parents =
        sbitmap_alloc (last_basic_block_for_fn (cfun));
@@ -1441,8 +1649,11 @@ perform_tree_ssa_dce (bool aggressive)
 
   find_obviously_necessary_stmts (aggressive);
 
-  if (aggressive)
-    loop_optimizer_finalize ();
+  if (aggressive && ! in_loop_pipeline)
+    {
+      loop_optimizer_finalize ();
+      scev_finalize ();
+    }
 
   longest_chain = 0;
   total_chain = 0;
@@ -1474,7 +1685,12 @@ perform_tree_ssa_dce (bool aggressive)
   tree_dce_done (aggressive);
 
   if (something_changed)
-    return TODO_update_ssa | TODO_cleanup_cfg;
+    {
+      free_numbers_of_iterations_estimates (cfun);
+      if (in_loop_pipeline)
+       scev_reset ();
+      return TODO_update_ssa | TODO_cleanup_cfg;
+    }
   return 0;
 }
 
@@ -1485,31 +1701,12 @@ tree_ssa_dce (void)
   return perform_tree_ssa_dce (/*aggressive=*/false);
 }
 
-static unsigned int
-tree_ssa_dce_loop (void)
-{
-  unsigned int todo;
-  todo = perform_tree_ssa_dce (/*aggressive=*/false);
-  if (todo)
-    {
-      free_numbers_of_iterations_estimates ();
-      scev_reset ();
-    }
-  return todo;
-}
-
 static unsigned int
 tree_ssa_cd_dce (void)
 {
   return perform_tree_ssa_dce (/*aggressive=*/optimize >= 2);
 }
 
-static bool
-gate_dce (void)
-{
-  return flag_tree_dce != 0;
-}
-
 namespace {
 
 const pass_data pass_data_dce =
@@ -1517,13 +1714,12 @@ const pass_data pass_data_dce =
   GIMPLE_PASS, /* type */
   "dce", /* name */
   OPTGROUP_NONE, /* optinfo_flags */
-  true, /* has_execute */
   TV_TREE_DCE, /* tv_id */
   ( PROP_cfg | PROP_ssa ), /* properties_required */
   0, /* properties_provided */
   0, /* properties_destroyed */
   0, /* todo_flags_start */
-  TODO_verify_ssa, /* todo_flags_finish */
+  0, /* todo_flags_finish */
 };
 
 class pass_dce : public gimple_opt_pass
@@ -1535,8 +1731,8 @@ public:
 
   /* opt_pass methods: */
   opt_pass * clone () { return new pass_dce (m_ctxt); }
-  bool gate () { return gate_dce (); }
-  unsigned int execute () { return tree_ssa_dce (); }
+  virtual bool gate (function *) { return flag_tree_dce != 0; }
+  virtual unsigned int execute (function *) { return tree_ssa_dce (); }
 
 }; // class pass_dce
 
@@ -1550,56 +1746,17 @@ make_pass_dce (gcc::context *ctxt)
 
 namespace {
 
-const pass_data pass_data_dce_loop =
-{
-  GIMPLE_PASS, /* type */
-  "dceloop", /* name */
-  OPTGROUP_NONE, /* optinfo_flags */
-  true, /* has_execute */
-  TV_TREE_DCE, /* tv_id */
-  ( PROP_cfg | PROP_ssa ), /* properties_required */
-  0, /* properties_provided */
-  0, /* properties_destroyed */
-  0, /* todo_flags_start */
-  TODO_verify_ssa, /* todo_flags_finish */
-};
-
-class pass_dce_loop : public gimple_opt_pass
-{
-public:
-  pass_dce_loop (gcc::context *ctxt)
-    : gimple_opt_pass (pass_data_dce_loop, ctxt)
-  {}
-
-  /* opt_pass methods: */
-  opt_pass * clone () { return new pass_dce_loop (m_ctxt); }
-  bool gate () { return gate_dce (); }
-  unsigned int execute () { return tree_ssa_dce_loop (); }
-
-}; // class pass_dce_loop
-
-} // anon namespace
-
-gimple_opt_pass *
-make_pass_dce_loop (gcc::context *ctxt)
-{
-  return new pass_dce_loop (ctxt);
-}
-
-namespace {
-
 const pass_data pass_data_cd_dce =
 {
   GIMPLE_PASS, /* type */
   "cddce", /* name */
   OPTGROUP_NONE, /* optinfo_flags */
-  true, /* has_execute */
   TV_TREE_CD_DCE, /* tv_id */
   ( PROP_cfg | PROP_ssa ), /* properties_required */
   0, /* properties_provided */
   0, /* properties_destroyed */
   0, /* todo_flags_start */
-  ( TODO_verify_ssa | TODO_verify_flow ), /* todo_flags_finish */
+  0, /* todo_flags_finish */
 };
 
 class pass_cd_dce : public gimple_opt_pass
@@ -1611,8 +1768,8 @@ public:
 
   /* opt_pass methods: */
   opt_pass * clone () { return new pass_cd_dce (m_ctxt); }
-  bool gate () { return gate_dce (); }
-  unsigned int execute () { return tree_ssa_cd_dce (); }
+  virtual bool gate (function *) { return flag_tree_dce != 0; }
+  virtual unsigned int execute (function *) { return tree_ssa_cd_dce (); }
 
 }; // class pass_cd_dce
 
@@ -1623,3 +1780,55 @@ make_pass_cd_dce (gcc::context *ctxt)
 {
   return new pass_cd_dce (ctxt);
 }
+
+
+/* A cheap DCE interface.  WORKLIST is a list of possibly dead stmts and
+   is consumed by this function.  The function has linear complexity in
+   the number of dead stmts with a constant factor like the average SSA
+   use operands number.  */
+
+void
+simple_dce_from_worklist (bitmap worklist)
+{
+  while (! bitmap_empty_p (worklist))
+    {
+      /* Pop item.  */
+      unsigned i = bitmap_first_set_bit (worklist);
+      bitmap_clear_bit (worklist, i);
+
+      tree def = ssa_name (i);
+      /* Removed by somebody else or still in use.  */
+      if (! def || ! has_zero_uses (def))
+       continue;
+
+      gimple *t = SSA_NAME_DEF_STMT (def);
+      if (gimple_has_side_effects (t))
+       continue;
+
+      /* Add uses to the worklist.  */
+      ssa_op_iter iter;
+      use_operand_p use_p;
+      FOR_EACH_PHI_OR_STMT_USE (use_p, t, iter, SSA_OP_USE)
+       {
+         tree use = USE_FROM_PTR (use_p);
+         if (TREE_CODE (use) == SSA_NAME
+             && ! SSA_NAME_IS_DEFAULT_DEF (use))
+           bitmap_set_bit (worklist, SSA_NAME_VERSION (use));
+       }
+
+      /* Remove stmt.  */
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       {
+         fprintf (dump_file, "Removing dead stmt:");
+         print_gimple_stmt (dump_file, t, 0);
+       }
+      gimple_stmt_iterator gsi = gsi_for_stmt (t);
+      if (gimple_code (t) == GIMPLE_PHI)
+       remove_phi_node (&gsi, true);
+      else
+       {
+         gsi_remove (&gsi, true);
+         release_defs (t);
+       }
+    }
+}