ipa-cp.c (ipcp_cloning_candidate_p): Use opt_for_fn.
[gcc.git] / gcc / tree-cfg.c
index 32110a7fafac268a5e69a015edb7c8785eadc601..9dd8961cb8f9421fe1ef7e4710835506c5c0cd55 100644 (file)
@@ -22,17 +22,27 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "hash-table.h"
+#include "hash-map.h"
 #include "tm.h"
 #include "tree.h"
 #include "trans-mem.h"
 #include "stor-layout.h"
 #include "print-tree.h"
 #include "tm_p.h"
+#include "predict.h"
+#include "vec.h"
+#include "hashtab.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "hard-reg-set.h"
+#include "input.h"
+#include "function.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfganal.h"
 #include "basic-block.h"
 #include "flags.h"
-#include "function.h"
 #include "gimple-pretty-print.h"
-#include "pointer-set.h"
 #include "tree-ssa-alias.h"
 #include "internal-fn.h"
 #include "gimple-fold.h"
@@ -44,6 +54,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimplify-me.h"
 #include "gimple-walk.h"
 #include "gimple-ssa.h"
+#include "plugin-api.h"
+#include "ipa-ref.h"
 #include "cgraph.h"
 #include "tree-cfg.h"
 #include "tree-phinodes.h"
@@ -68,6 +80,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa-live.h"
 #include "omp-low.h"
 #include "tree-cfgcleanup.h"
+#include "wide-int.h"
+#include "wide-int-print.h"
 
 /* This file contains functions for building the Control Flow Graph (CFG)
    for a function tree.  */
@@ -90,7 +104,7 @@ static const int initial_cfg_capacity = 20;
    more persistent.  The key is getting notification of changes to
    the CFG (particularly edge removal, creation and redirection).  */
 
-static struct pointer_map_t *edge_to_cases;
+static hash_map<edge, tree> *edge_to_cases;
 
 /* If we record edge_to_cases, this bitmap will hold indexes
    of basic blocks that end in a GIMPLE_SWITCH which we touched
@@ -106,9 +120,6 @@ struct cfg_stats_d
 
 static struct cfg_stats_d cfg_stats;
 
-/* Nonzero if we found a computed goto while building basic blocks.  */
-static bool found_computed_goto;
-
 /* Hash table to store last discriminator assigned for each locus.  */
 struct locus_discrim_map
 {
@@ -144,18 +155,17 @@ locus_discrim_hasher::equal (const value_type *a, const compare_type *b)
   return LOCATION_LINE (a->locus) == LOCATION_LINE (b->locus);
 }
 
-static hash_table <locus_discrim_hasher> discriminator_per_locus;
+static hash_table<locus_discrim_hasher> *discriminator_per_locus;
 
 /* Basic blocks and flowgraphs.  */
 static void make_blocks (gimple_seq);
-static void factor_computed_gotos (void);
 
 /* Edges.  */
 static void make_edges (void);
 static void assign_discriminators (void);
 static void make_cond_expr_edges (basic_block);
 static void make_gimple_switch_edges (basic_block);
-static void make_goto_expr_edges (basic_block);
+static bool make_goto_expr_edges (basic_block);
 static void make_gimple_asm_edges (basic_block);
 static edge gimple_redirect_edge_and_branch (edge, basic_block);
 static edge gimple_try_redirect_by_replacing_jump (edge, basic_block);
@@ -166,6 +176,7 @@ static int gimple_verify_flow_info (void);
 static void gimple_make_forwarder_block (edge);
 static gimple first_non_label_stmt (basic_block);
 static bool verify_gimple_transaction (gimple);
+static bool call_can_make_abnormal_goto (gimple);
 
 /* Flowgraph optimization and cleanup.  */
 static void gimple_merge_blocks (basic_block, basic_block);
@@ -225,17 +236,8 @@ build_gimple_cfg (gimple_seq seq)
 
   init_empty_tree_cfg ();
 
-  found_computed_goto = 0;
   make_blocks (seq);
 
-  /* Computed gotos are hell to deal with, especially if there are
-     lots of them with a large number of destinations.  So we factor
-     them to a common computed goto location before we build the
-     edge list.  After we convert back to normal form, we will un-factor
-     the computed gotos since factoring introduces an unwanted jump.  */
-  if (found_computed_goto)
-    factor_computed_gotos ();
-
   /* Make sure there is always at least one block, even if it's empty.  */
   if (n_basic_blocks_for_fn (cfun) == NUM_FIXED_BLOCKS)
     create_empty_bb (ENTRY_BLOCK_PTR_FOR_FN (cfun));
@@ -255,20 +257,64 @@ build_gimple_cfg (gimple_seq seq)
   group_case_labels ();
 
   /* Create the edges of the flowgraph.  */
-  discriminator_per_locus.create (13);
+  discriminator_per_locus = new hash_table<locus_discrim_hasher> (13);
   make_edges ();
   assign_discriminators ();
   cleanup_dead_labels ();
-  discriminator_per_locus.dispose ();
+  delete discriminator_per_locus;
+  discriminator_per_locus = NULL;
 }
 
+/* Look for ANNOTATE calls with loop annotation kind in BB; if found, remove
+   them and propagate the information to LOOP.  We assume that the annotations
+   come immediately before the condition in BB, if any.  */
+
+static void
+replace_loop_annotate_in_block (basic_block bb, struct loop *loop)
+{
+  gimple_stmt_iterator gsi = gsi_last_bb (bb);
+  gimple stmt = gsi_stmt (gsi);
+
+  if (!(stmt && gimple_code (stmt) == GIMPLE_COND))
+    return;
+
+  for (gsi_prev_nondebug (&gsi); !gsi_end_p (gsi); gsi_prev (&gsi))
+    {
+      stmt = gsi_stmt (gsi);
+      if (gimple_code (stmt) != GIMPLE_CALL)
+       break;
+      if (!gimple_call_internal_p (stmt)
+         || gimple_call_internal_fn (stmt) != IFN_ANNOTATE)
+       break;
+
+      switch ((annot_expr_kind) tree_to_shwi (gimple_call_arg (stmt, 1)))
+       {
+       case annot_expr_ivdep_kind:
+         loop->safelen = INT_MAX;
+         break;
+       case annot_expr_no_vector_kind:
+         loop->dont_vectorize = true;
+         break;
+       case annot_expr_vector_kind:
+         loop->force_vectorize = true;
+         cfun->has_force_vectorize_loops = true;
+         break;
+       default:
+         gcc_unreachable ();
+       }
+
+      stmt = gimple_build_assign (gimple_call_lhs (stmt),
+                                 gimple_call_arg (stmt, 0));
+      gsi_replace (&gsi, stmt, true);
+    }
+}
 
-/* Search for ANNOTATE call with annot_expr_ivdep_kind; if found, remove
-   it and set loop->safelen to INT_MAX.  We assume that the annotation
-   comes immediately before the condition.  */
+/* Look for ANNOTATE calls with loop annotation kind; if found, remove
+   them and propagate the information to the loop.  We assume that the
+   annotations come immediately before the condition of the loop.  */
 
 static void
-replace_loop_annotate ()
+replace_loop_annotate (void)
 {
   struct loop *loop;
   basic_block bb;
@@ -277,53 +323,42 @@ replace_loop_annotate ()
 
   FOR_EACH_LOOP (loop, 0)
     {
-      gsi = gsi_last_bb (loop->header);
-      stmt = gsi_stmt (gsi);
-      if (stmt && gimple_code (stmt) == GIMPLE_COND)
+      /* First look into the header.  */
+      replace_loop_annotate_in_block (loop->header, loop);
+
+      /* Then look into the latch, if any.  */
+      if (loop->latch)
+       replace_loop_annotate_in_block (loop->latch, loop);
+    }
+
+  /* Remove IFN_ANNOTATE.  Safeguard for the case loop->latch == NULL.  */
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi))
        {
-         gsi_prev_nondebug (&gsi);
-         if (gsi_end_p (gsi))
-           continue;
          stmt = gsi_stmt (gsi);
          if (gimple_code (stmt) != GIMPLE_CALL)
-               continue;
-         if (!gimple_call_internal_p (stmt)
-                 || gimple_call_internal_fn (stmt) != IFN_ANNOTATE)
            continue;
-         if ((annot_expr_kind) tree_to_shwi (gimple_call_arg (stmt, 1))
-             != annot_expr_ivdep_kind)
+         if (!gimple_call_internal_p (stmt)
+             || gimple_call_internal_fn (stmt) != IFN_ANNOTATE)
            continue;
+
+         switch ((annot_expr_kind) tree_to_shwi (gimple_call_arg (stmt, 1)))
+           {
+           case annot_expr_ivdep_kind:
+           case annot_expr_no_vector_kind:
+           case annot_expr_vector_kind:
+             break;
+           default:
+             gcc_unreachable ();
+           }
+
+         warning_at (gimple_location (stmt), 0, "ignoring loop annotation");
          stmt = gimple_build_assign (gimple_call_lhs (stmt),
                                      gimple_call_arg (stmt, 0));
          gsi_replace (&gsi, stmt, true);
-         loop->safelen = INT_MAX;
        }
     }
-
-  /* Remove IFN_ANNOTATE. Safeguard for the case loop->latch == NULL.  */
-  FOR_EACH_BB_FN (bb, cfun)
-    {
-      gsi = gsi_last_bb (bb);
-      stmt = gsi_stmt (gsi);
-      if (stmt && gimple_code (stmt) == GIMPLE_COND)
-       gsi_prev_nondebug (&gsi);
-      if (gsi_end_p (gsi))
-       continue;
-      stmt = gsi_stmt (gsi);
-      if (gimple_code (stmt) != GIMPLE_CALL)
-       continue;
-      if (!gimple_call_internal_p (stmt)
-         || gimple_call_internal_fn (stmt) != IFN_ANNOTATE)
-       continue;
-      if ((annot_expr_kind) tree_to_shwi (gimple_call_arg (stmt, 1))
-         != annot_expr_ivdep_kind)
-       continue;
-      warning_at (gimple_location (stmt), 0, "ignoring %<GCC ivdep%> "
-                 "annotation");
-      stmt = gimple_build_assign (gimple_call_lhs (stmt),
-                                 gimple_call_arg (stmt, 0));
-      gsi_replace (&gsi, stmt, true);
-    }
 }
 
 
@@ -352,14 +387,12 @@ const pass_data pass_data_build_cfg =
   GIMPLE_PASS, /* type */
   "cfg", /* name */
   OPTGROUP_NONE, /* optinfo_flags */
-  false, /* has_gate */
-  true, /* has_execute */
   TV_TREE_CFG, /* tv_id */
   PROP_gimple_leh, /* properties_required */
   ( PROP_cfg | PROP_loops ), /* properties_provided */
   0, /* properties_destroyed */
   0, /* todo_flags_start */
-  TODO_verify_stmts, /* todo_flags_finish */
+  0, /* todo_flags_finish */
 };
 
 class pass_build_cfg : public gimple_opt_pass
@@ -370,7 +403,7 @@ public:
   {}
 
   /* opt_pass methods: */
-  unsigned int execute () { return execute_build_cfg (); }
+  virtual unsigned int execute (function *) { return execute_build_cfg (); }
 
 }; // class pass_build_cfg
 
@@ -385,7 +418,7 @@ make_pass_build_cfg (gcc::context *ctxt)
 
 /* Return true if T is a computed goto.  */
 
-static bool
+bool
 computed_goto_p (gimple t)
 {
   return (gimple_code (t) == GIMPLE_GOTO
@@ -423,9 +456,9 @@ assert_unreachable_fallthru_edge_p (edge e)
          if (gsi_end_p (gsi))
            return false;
          stmt = gsi_stmt (gsi);
-         if (is_gimple_debug (stmt))
+         while (is_gimple_debug (stmt) || gimple_clobber_p (stmt))
            {
-             gsi_next_nondebug (&gsi);
+             gsi_next (&gsi);
              if (gsi_end_p (gsi))
                return false;
              stmt = gsi_stmt (gsi);
@@ -437,79 +470,29 @@ assert_unreachable_fallthru_edge_p (edge e)
 }
 
 
-/* Search the CFG for any computed gotos.  If found, factor them to a
-   common computed goto site.  Also record the location of that site so
-   that we can un-factor the gotos after we have converted back to
-   normal form.  */
+/* Initialize GF_CALL_CTRL_ALTERING flag, which indicates the call
+   could alter control flow except via eh. We initialize the flag at
+   CFG build time and only ever clear it later.  */
 
 static void
-factor_computed_gotos (void)
-{
-  basic_block bb;
-  tree factored_label_decl = NULL;
-  tree var = NULL;
-  gimple factored_computed_goto_label = NULL;
-  gimple factored_computed_goto = NULL;
-
-  /* We know there are one or more computed gotos in this function.
-     Examine the last statement in each basic block to see if the block
-     ends with a computed goto.  */
-
-  FOR_EACH_BB_FN (bb, cfun)
-    {
-      gimple_stmt_iterator gsi = gsi_last_bb (bb);
-      gimple last;
-
-      if (gsi_end_p (gsi))
-       continue;
-
-      last = gsi_stmt (gsi);
-
-      /* Ignore the computed goto we create when we factor the original
-        computed gotos.  */
-      if (last == factored_computed_goto)
-       continue;
-
-      /* If the last statement is a computed goto, factor it.  */
-      if (computed_goto_p (last))
-       {
-         gimple assignment;
-
-         /* The first time we find a computed goto we need to create
-            the factored goto block and the variable each original
-            computed goto will use for their goto destination.  */
-         if (!factored_computed_goto)
-           {
-             basic_block new_bb = create_empty_bb (bb);
-             gimple_stmt_iterator new_gsi = gsi_start_bb (new_bb);
-
-             /* Create the destination of the factored goto.  Each original
-                computed goto will put its desired destination into this
-                variable and jump to the label we create immediately
-                below.  */
-             var = create_tmp_var (ptr_type_node, "gotovar");
-
-             /* Build a label for the new block which will contain the
-                factored computed goto.  */
-             factored_label_decl = create_artificial_label (UNKNOWN_LOCATION);
-             factored_computed_goto_label
-               = gimple_build_label (factored_label_decl);
-             gsi_insert_after (&new_gsi, factored_computed_goto_label,
-                               GSI_NEW_STMT);
-
-             /* Build our new computed goto.  */
-             factored_computed_goto = gimple_build_goto (var);
-             gsi_insert_after (&new_gsi, factored_computed_goto, GSI_NEW_STMT);
-           }
-
-         /* Copy the original computed goto's destination into VAR.  */
-         assignment = gimple_build_assign (var, gimple_goto_dest (last));
-         gsi_insert_before (&gsi, assignment, GSI_SAME_STMT);
-
-         /* And re-vector the computed goto to the new destination.  */
-         gimple_goto_set_dest (last, factored_label_decl);
-       }
-    }
+gimple_call_initialize_ctrl_altering (gimple stmt)
+{
+  int flags = gimple_call_flags (stmt);
+
+  /* A call alters control flow if it can make an abnormal goto.  */
+  if (call_can_make_abnormal_goto (stmt)
+      /* A call also alters control flow if it does not return.  */
+      || flags & ECF_NORETURN
+      /* TM ending statements have backedges out of the transaction.
+        Return true so we split the basic block containing them.
+        Note that the TM_BUILTIN test is merely an optimization.  */
+      || ((flags & ECF_TM_BUILTIN)
+         && is_tm_ending_fndecl (gimple_call_fndecl (stmt)))
+      /* BUILT_IN_RETURN call is same as return statement.  */
+      || gimple_call_builtin_p (stmt, BUILT_IN_RETURN))
+    gimple_call_set_ctrl_altering (stmt, true);
+  else
+    gimple_call_set_ctrl_altering (stmt, false);
 }
 
 
@@ -531,6 +514,9 @@ make_blocks (gimple_seq seq)
       prev_stmt = stmt;
       stmt = gsi_stmt (i);
 
+      if (stmt && is_gimple_call (stmt))
+       gimple_call_initialize_ctrl_altering (stmt);
+
       /* If the statement starts a new basic block or if we have determined
         in a previous pass that we need to create a new block for STMT, do
         so now.  */
@@ -546,9 +532,6 @@ make_blocks (gimple_seq seq)
         codes.  */
       gimple_set_bb (stmt, bb);
 
-      if (computed_goto_p (stmt))
-       found_computed_goto = true;
-
       /* If STMT is a basic block terminator, set START_NEW_BLOCK for the
         next iteration.  */
       if (stmt_ends_bb_p (stmt))
@@ -666,6 +649,144 @@ fold_cond_expr_cond (void)
     }
 }
 
+/* If basic block BB has an abnormal edge to a basic block
+   containing IFN_ABNORMAL_DISPATCHER internal call, return
+   that the dispatcher's basic block, otherwise return NULL.  */
+
+basic_block
+get_abnormal_succ_dispatcher (basic_block bb)
+{
+  edge e;
+  edge_iterator ei;
+
+  FOR_EACH_EDGE (e, ei, bb->succs)
+    if ((e->flags & (EDGE_ABNORMAL | EDGE_EH)) == EDGE_ABNORMAL)
+      {
+       gimple_stmt_iterator gsi
+         = gsi_start_nondebug_after_labels_bb (e->dest);
+       gimple g = gsi_stmt (gsi);
+       if (g
+           && is_gimple_call (g)
+           && gimple_call_internal_p (g)
+           && gimple_call_internal_fn (g) == IFN_ABNORMAL_DISPATCHER)
+         return e->dest;
+      }
+  return NULL;
+}
+
+/* Helper function for make_edges.  Create a basic block with
+   with ABNORMAL_DISPATCHER internal call in it if needed, and
+   create abnormal edges from BBS to it and from it to FOR_BB
+   if COMPUTED_GOTO is false, otherwise factor the computed gotos.  */
+
+static void
+handle_abnormal_edges (basic_block *dispatcher_bbs,
+                      basic_block for_bb, int *bb_to_omp_idx,
+                      auto_vec<basic_block> *bbs, bool computed_goto)
+{
+  basic_block *dispatcher = dispatcher_bbs + (computed_goto ? 1 : 0);
+  unsigned int idx = 0;
+  basic_block bb;
+  bool inner = false;
+
+  if (bb_to_omp_idx)
+    {
+      dispatcher = dispatcher_bbs + 2 * bb_to_omp_idx[for_bb->index];
+      if (bb_to_omp_idx[for_bb->index] != 0)
+       inner = true;
+    }
+
+  /* If the dispatcher has been created already, then there are basic
+     blocks with abnormal edges to it, so just make a new edge to
+     for_bb.  */
+  if (*dispatcher == NULL)
+    {
+      /* Check if there are any basic blocks that need to have
+        abnormal edges to this dispatcher.  If there are none, return
+        early.  */
+      if (bb_to_omp_idx == NULL)
+       {
+         if (bbs->is_empty ())
+           return;
+       }
+      else
+       {
+         FOR_EACH_VEC_ELT (*bbs, idx, bb)
+           if (bb_to_omp_idx[bb->index] == bb_to_omp_idx[for_bb->index])
+             break;
+         if (bb == NULL)
+           return;
+       }
+
+      /* Create the dispatcher bb.  */
+      *dispatcher = create_basic_block (NULL, NULL, for_bb);
+      if (computed_goto)
+       {
+         /* Factor computed gotos into a common computed goto site.  Also
+            record the location of that site so that we can un-factor the
+            gotos after we have converted back to normal form.  */
+         gimple_stmt_iterator gsi = gsi_start_bb (*dispatcher);
+
+         /* Create the destination of the factored goto.  Each original
+            computed goto will put its desired destination into this
+            variable and jump to the label we create immediately below.  */
+         tree var = create_tmp_var (ptr_type_node, "gotovar");
+
+         /* Build a label for the new block which will contain the
+            factored computed goto.  */
+         tree factored_label_decl
+           = create_artificial_label (UNKNOWN_LOCATION);
+         gimple factored_computed_goto_label
+           = gimple_build_label (factored_label_decl);
+         gsi_insert_after (&gsi, factored_computed_goto_label, GSI_NEW_STMT);
+
+         /* Build our new computed goto.  */
+         gimple factored_computed_goto = gimple_build_goto (var);
+         gsi_insert_after (&gsi, factored_computed_goto, GSI_NEW_STMT);
+
+         FOR_EACH_VEC_ELT (*bbs, idx, bb)
+           {
+             if (bb_to_omp_idx
+                 && bb_to_omp_idx[bb->index] != bb_to_omp_idx[for_bb->index])
+               continue;
+
+             gsi = gsi_last_bb (bb);
+             gimple last = gsi_stmt (gsi);
+
+             gcc_assert (computed_goto_p (last));
+
+             /* Copy the original computed goto's destination into VAR.  */
+             gimple assignment
+               = gimple_build_assign (var, gimple_goto_dest (last));
+             gsi_insert_before (&gsi, assignment, GSI_SAME_STMT);
+
+             edge e = make_edge (bb, *dispatcher, EDGE_FALLTHRU);
+             e->goto_locus = gimple_location (last);
+             gsi_remove (&gsi, true);
+           }
+       }
+      else
+       {
+         tree arg = inner ? boolean_true_node : boolean_false_node;
+         gimple g = gimple_build_call_internal (IFN_ABNORMAL_DISPATCHER,
+                                                1, arg);
+         gimple_stmt_iterator gsi = gsi_after_labels (*dispatcher);
+         gsi_insert_after (&gsi, g, GSI_NEW_STMT);
+
+         /* Create predecessor edges of the dispatcher.  */
+         FOR_EACH_VEC_ELT (*bbs, idx, bb)
+           {
+             if (bb_to_omp_idx
+                 && bb_to_omp_idx[bb->index] != bb_to_omp_idx[for_bb->index])
+               continue;
+             make_edge (bb, *dispatcher, EDGE_ABNORMAL);
+           }
+       }
+    }
+
+  make_edge (*dispatcher, for_bb, EDGE_ABNORMAL);
+}
+
 /* Join all the blocks in the flowgraph.  */
 
 static void
@@ -673,6 +794,10 @@ make_edges (void)
 {
   basic_block bb;
   struct omp_region *cur_region = NULL;
+  auto_vec<basic_block> ab_edge_goto;
+  auto_vec<basic_block> ab_edge_call;
+  int *bb_to_omp_idx = NULL;
+  int cur_omp_region_idx = 0;
 
   /* Create an edge from entry to the first block with executable
      statements in it.  */
@@ -686,18 +811,25 @@ make_edges (void)
       gimple last = last_stmt (bb);
       bool fallthru;
 
+      if (bb_to_omp_idx)
+       bb_to_omp_idx[bb->index] = cur_omp_region_idx;
+
       if (last)
        {
          enum gimple_code code = gimple_code (last);
          switch (code)
            {
            case GIMPLE_GOTO:
-             make_goto_expr_edges (bb);
+             if (make_goto_expr_edges (bb))
+               ab_edge_goto.safe_push (bb);
              fallthru = false;
              break;
            case GIMPLE_RETURN:
-             make_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
-             fallthru = false;
+             {
+               edge e = make_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
+               e->goto_locus = gimple_location (last);
+               fallthru = false;
+             }
              break;
            case GIMPLE_COND:
              make_cond_expr_edges (bb);
@@ -720,7 +852,7 @@ make_edges (void)
                 make edges from this call site to all the nonlocal goto
                 handlers.  */
              if (stmt_can_make_abnormal_goto (last))
-               make_abnormal_goto_edges (bb, true);
+               ab_edge_call.safe_push (bb);
 
              /* If this statement has reachable exception handlers, then
                 create abnormal edges to them.  */
@@ -728,8 +860,10 @@ make_edges (void)
 
              /* BUILTIN_RETURN is really a return statement.  */
              if (gimple_call_builtin_p (last, BUILT_IN_RETURN))
-               make_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0), fallthru =
-            false;
+               {
+                 make_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
+                 fallthru = false;
+               }
              /* Some calls are known not to return.  */
              else
                fallthru = !(gimple_call_flags (last) & ECF_NORETURN);
@@ -749,7 +883,10 @@ make_edges (void)
              break;
 
            CASE_GIMPLE_OMP:
-             fallthru = make_gimple_omp_edges (bb, &cur_region);
+             fallthru = make_gimple_omp_edges (bb, &cur_region,
+                                               &cur_omp_region_idx);
+             if (cur_region && bb_to_omp_idx == NULL)
+               bb_to_omp_idx = XCNEWVEC (int, n_basic_blocks_for_fn (cfun));
              break;
 
            case GIMPLE_TRANSACTION:
@@ -773,6 +910,77 @@ make_edges (void)
        make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
     }
 
+  /* Computed gotos are hell to deal with, especially if there are
+     lots of them with a large number of destinations.  So we factor
+     them to a common computed goto location before we build the
+     edge list.  After we convert back to normal form, we will un-factor
+     the computed gotos since factoring introduces an unwanted jump.
+     For non-local gotos and abnormal edges from calls to calls that return
+     twice or forced labels, factor the abnormal edges too, by having all
+     abnormal edges from the calls go to a common artificial basic block
+     with ABNORMAL_DISPATCHER internal call and abnormal edges from that
+     basic block to all forced labels and calls returning twice.
+     We do this per-OpenMP structured block, because those regions
+     are guaranteed to be single entry single exit by the standard,
+     so it is not allowed to enter or exit such regions abnormally this way,
+     thus all computed gotos, non-local gotos and setjmp/longjmp calls
+     must not transfer control across SESE region boundaries.  */
+  if (!ab_edge_goto.is_empty () || !ab_edge_call.is_empty ())
+    {
+      gimple_stmt_iterator gsi;
+      basic_block dispatcher_bb_array[2] = { NULL, NULL };
+      basic_block *dispatcher_bbs = dispatcher_bb_array;
+      int count = n_basic_blocks_for_fn (cfun);
+
+      if (bb_to_omp_idx)
+       dispatcher_bbs = XCNEWVEC (basic_block, 2 * count);
+
+      FOR_EACH_BB_FN (bb, cfun)
+       {
+         for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+           {
+             gimple label_stmt = gsi_stmt (gsi);
+             tree target;
+
+             if (gimple_code (label_stmt) != GIMPLE_LABEL)
+               break;
+
+             target = gimple_label_label (label_stmt);
+
+             /* Make an edge to every label block that has been marked as a
+                potential target for a computed goto or a non-local goto.  */
+             if (FORCED_LABEL (target))
+               handle_abnormal_edges (dispatcher_bbs, bb, bb_to_omp_idx,
+                                      &ab_edge_goto, true);
+             if (DECL_NONLOCAL (target))
+               {
+                 handle_abnormal_edges (dispatcher_bbs, bb, bb_to_omp_idx,
+                                        &ab_edge_call, false);
+                 break;
+               }
+           }
+
+         if (!gsi_end_p (gsi) && is_gimple_debug (gsi_stmt (gsi)))
+           gsi_next_nondebug (&gsi);
+         if (!gsi_end_p (gsi))
+           {
+             /* Make an edge to every setjmp-like call.  */
+             gimple call_stmt = gsi_stmt (gsi);
+             if (is_gimple_call (call_stmt)
+                 && ((gimple_call_flags (call_stmt) & ECF_RETURNS_TWICE)
+                     || gimple_call_builtin_p (call_stmt,
+                                               BUILT_IN_SETJMP_RECEIVER)))
+               handle_abnormal_edges (dispatcher_bbs, bb, bb_to_omp_idx,
+                                      &ab_edge_call, false);
+           }
+       }
+
+      if (bb_to_omp_idx)
+       XDELETE (dispatcher_bbs);
+    }
+
+  XDELETE (bb_to_omp_idx);
+
   free_omp_regions ();
 
   /* Fold COND_EXPR_COND of each COND_EXPR.  */
@@ -792,7 +1000,7 @@ next_discriminator_for_locus (location_t locus)
 
   item.locus = locus;
   item.discriminator = 0;
-  slot = discriminator_per_locus.find_slot_with_hash (
+  slot = discriminator_per_locus->find_slot_with_hash (
       &item, LOCATION_LINE (locus), INSERT);
   gcc_assert (slot);
   if (*slot == HTAB_EMPTY_ENTRY)
@@ -902,19 +1110,17 @@ make_cond_expr_edges (basic_block bb)
    SWITCH_EXPRs and structure sharing rules, then free the hash table
    element.  */
 
-static bool
-edge_to_cases_cleanup (const void *key ATTRIBUTE_UNUSED, void **value,
-                      void *data ATTRIBUTE_UNUSED)
+bool
+edge_to_cases_cleanup (edge const &, tree const &value, void *)
 {
   tree t, next;
 
-  for (t = (tree) *value; t; t = next)
+  for (t = value; t; t = next)
     {
       next = CASE_CHAIN (t);
       CASE_CHAIN (t) = NULL;
     }
 
-  *value = NULL;
   return true;
 }
 
@@ -924,7 +1130,7 @@ void
 start_recording_case_labels (void)
 {
   gcc_assert (edge_to_cases == NULL);
-  edge_to_cases = pointer_map_create ();
+  edge_to_cases = new hash_map<edge, tree>;
   touched_switch_bbs = BITMAP_ALLOC (NULL);
 }
 
@@ -943,8 +1149,8 @@ end_recording_case_labels (void)
 {
   bitmap_iterator bi;
   unsigned i;
-  pointer_map_traverse (edge_to_cases, edge_to_cases_cleanup, NULL);
-  pointer_map_destroy (edge_to_cases);
+  edge_to_cases->traverse<void *, edge_to_cases_cleanup> (NULL);
+  delete edge_to_cases;
   edge_to_cases = NULL;
   EXECUTE_IF_SET_IN_BITMAP (touched_switch_bbs, 0, i, bi)
     {
@@ -967,7 +1173,7 @@ end_recording_case_labels (void)
 static tree
 get_cases_for_edge (edge e, gimple t)
 {
-  void **slot;
+  tree *slot;
   size_t i, n;
 
   /* If we are not recording cases, then we do not have CASE_LABEL_EXPR
@@ -975,9 +1181,9 @@ get_cases_for_edge (edge e, gimple t)
   if (!recording_case_labels_p ())
     return NULL;
 
-  slot = pointer_map_contains (edge_to_cases, e);
+  slot = edge_to_cases->get (e);
   if (slot)
-    return (tree) *slot;
+    return *slot;
 
   /* If we did not find E in the hash table, then this must be the first
      time we have been queried for information about E & T.  Add all the
@@ -993,12 +1199,12 @@ get_cases_for_edge (edge e, gimple t)
 
       /* Add it to the chain of CASE_LABEL_EXPRs referencing E, or create
         a new chain.  */
-      slot = pointer_map_insert (edge_to_cases, this_edge);
-      CASE_CHAIN (elt) = (tree) *slot;
-      *slot = elt;
+      tree &s = edge_to_cases->get_or_insert (this_edge);
+      CASE_CHAIN (elt) = s;
+      s = elt;
     }
 
-  return (tree) *pointer_map_contains (edge_to_cases, e);
+  return *edge_to_cases->get (e);
 }
 
 /* Create the edges for a GIMPLE_SWITCH starting at block BB.  */
@@ -1045,53 +1251,10 @@ label_to_block_fn (struct function *ifun, tree dest)
   return (*ifun->cfg->x_label_to_block_map)[uid];
 }
 
-/* Create edges for an abnormal goto statement at block BB.  If FOR_CALL
-   is true, the source statement is a CALL_EXPR instead of a GOTO_EXPR.  */
-
-void
-make_abnormal_goto_edges (basic_block bb, bool for_call)
-{
-  basic_block target_bb;
-  gimple_stmt_iterator gsi;
-
-  FOR_EACH_BB_FN (target_bb, cfun)
-    {
-      for (gsi = gsi_start_bb (target_bb); !gsi_end_p (gsi); gsi_next (&gsi))
-       {
-         gimple label_stmt = gsi_stmt (gsi);
-         tree target;
-
-         if (gimple_code (label_stmt) != GIMPLE_LABEL)
-           break;
-
-         target = gimple_label_label (label_stmt);
+/* Create edges for a goto statement at block BB.  Returns true
+   if abnormal edges should be created.  */
 
-         /* Make an edge to every label block that has been marked as a
-            potential target for a computed goto or a non-local goto.  */
-         if ((FORCED_LABEL (target) && !for_call)
-             || (DECL_NONLOCAL (target) && for_call))
-           {
-             make_edge (bb, target_bb, EDGE_ABNORMAL);
-             break;
-           }
-       }
-      if (!gsi_end_p (gsi)
-         && is_gimple_debug (gsi_stmt (gsi)))
-       gsi_next_nondebug (&gsi);
-      if (!gsi_end_p (gsi))
-       {
-         /* Make an edge to every setjmp-like call.  */
-         gimple call_stmt = gsi_stmt (gsi);
-         if (is_gimple_call (call_stmt)
-             && (gimple_call_flags (call_stmt) & ECF_RETURNS_TWICE))
-           make_edge (bb, target_bb, EDGE_ABNORMAL);
-       }
-    }
-}
-
-/* Create edges for a goto statement at block BB.  */
-
-static void
+static bool
 make_goto_expr_edges (basic_block bb)
 {
   gimple_stmt_iterator last = gsi_last_bb (bb);
@@ -1105,11 +1268,11 @@ make_goto_expr_edges (basic_block bb)
       edge e = make_edge (bb, label_bb, EDGE_FALLTHRU);
       e->goto_locus = gimple_location (goto_t);
       gsi_remove (&last, true);
-      return;
+      return false;
     }
 
   /* A computed GOTO creates abnormal edges.  */
-  make_abnormal_goto_edges (bb, false);
+  return true;
 }
 
 /* Create edges for an asm statement with labels at block BB.  */
@@ -1444,12 +1607,12 @@ group_case_labels_stmt (gimple stmt)
        {
          tree merge_case = gimple_switch_label (stmt, i);
          basic_block merge_bb = label_to_block (CASE_LABEL (merge_case));
-         double_int bhp1 = tree_to_double_int (base_high) + double_int_one;
+         wide_int bhp1 = wi::add (base_high, 1);
 
          /* Merge the cases if they jump to the same place,
             and their ranges are consecutive.  */
          if (merge_bb == base_bb
-             && tree_to_double_int (CASE_LOW (merge_case)) == bhp1)
+             && wi::eq_p (CASE_LOW (merge_case), bhp1))
            {
              base_high = CASE_HIGH (merge_case) ?
                  CASE_HIGH (merge_case) : CASE_LOW (merge_case);
@@ -1543,8 +1706,12 @@ gimple_can_merge_blocks_p (basic_block a, basic_block b)
        return false;
     }
 
-  /* Protect the loop latches.  */
-  if (current_loops && b->loop_father->latch == b)
+  /* Protect simple loop latches.  We only want to avoid merging
+     the latch with the loop header in this case.  */
+  if (current_loops
+      && b->loop_father->latch == b
+      && loops_state_satisfies_p (LOOPS_HAVE_SIMPLE_LATCHES)
+      && b->loop_father->header == a)
     return false;
 
   /* It must be possible to eliminate all phi nodes in B.  If ssa form
@@ -1590,6 +1757,11 @@ replace_uses_by (tree name, tree val)
 
   FOR_EACH_IMM_USE_STMT (stmt, imm_iter, name)
     {
+      /* Mark the block if we change the last stmt in it.  */
+      if (cfgcleanup_altered_bbs
+         && stmt_ends_bb_p (stmt))
+       bitmap_set_bit (cfgcleanup_altered_bbs, gimple_bb (stmt)->index);
+
       FOR_EACH_IMM_USE_ON_STMT (use, imm_iter)
         {
          replace_exp (use, val);
@@ -1614,11 +1786,6 @@ replace_uses_by (tree name, tree val)
          gimple orig_stmt = stmt;
          size_t i;
 
-         /* Mark the block if we changed the last stmt in it.  */
-         if (cfgcleanup_altered_bbs
-             && stmt_ends_bb_p (stmt))
-           bitmap_set_bit (cfgcleanup_altered_bbs, gimple_bb (stmt)->index);
-
          /* FIXME.  It shouldn't be required to keep TREE_CONSTANT
             on ADDR_EXPRs up-to-date on GIMPLE.  Propagation will
             only change sth from non-invariant to invariant, and only
@@ -1777,6 +1944,15 @@ gimple_merge_blocks (basic_block a, basic_block b)
        }
     }
 
+  /* When merging two BBs, if their counts are different, the larger count
+     is selected as the new bb count. This is to handle inconsistent
+     profiles.  */
+  if (a->loop_father == b->loop_father)
+    {
+      a->count = MAX (a->count, b->count);
+      a->frequency = MAX (a->frequency, b->frequency);
+    }
+
   /* Merge the sequences.  */
   last = gsi_last_bb (a);
   gsi_insert_seq_after (&last, bb_seq (b), GSI_NEW_STMT);
@@ -1860,7 +2036,7 @@ remove_bb (basic_block bb)
       fprintf (dump_file, "Removing basic block %d\n", bb->index);
       if (dump_flags & TDF_DETAILS)
        {
-         dump_bb (dump_file, bb, 0, dump_flags);
+         dump_bb (dump_file, bb, 0, TDF_BLOCKS);
          fprintf (dump_file, "\n");
        }
     }
@@ -2262,28 +2438,10 @@ is_ctrl_altering_stmt (gimple t)
   switch (gimple_code (t))
     {
     case GIMPLE_CALL:
-      {
-       int flags = gimple_call_flags (t);
-
-       /* A call alters control flow if it can make an abnormal goto.  */
-       if (call_can_make_abnormal_goto (t))
-         return true;
-
-       /* A call also alters control flow if it does not return.  */
-       if (flags & ECF_NORETURN)
-         return true;
-
-       /* TM ending statements have backedges out of the transaction.
-          Return true so we split the basic block containing them.
-          Note that the TM_BUILTIN test is merely an optimization.  */
-       if ((flags & ECF_TM_BUILTIN)
-           && is_tm_ending_fndecl (gimple_call_fndecl (t)))
-         return true;
-
-       /* BUILT_IN_RETURN call is same as return statement.  */
-       if (gimple_call_builtin_p (t, BUILT_IN_RETURN))
-         return true;
-      }
+      /* Per stmt call flag indicates whether the call could alter
+        controlflow.  */
+      if (gimple_call_ctrl_altering_p (t))
+       return true;
       break;
 
     case GIMPLE_EH_DISPATCH:
@@ -2465,12 +2623,11 @@ last_and_only_stmt (basic_block bb)
 static void
 reinstall_phi_args (edge new_edge, edge old_edge)
 {
-  edge_var_map_vector *v;
   edge_var_map *vm;
   int i;
   gimple_stmt_iterator phis;
 
-  v = redirect_edge_var_map_vector (old_edge);
+  vec<edge_var_map> *v = redirect_edge_var_map_vector (old_edge);
   if (!v)
     return;
 
@@ -3418,12 +3575,21 @@ verify_gimple_assign_unary (gimple stmt)
 
         return false;
       }
-
-    case VEC_UNPACK_HI_EXPR:
-    case VEC_UNPACK_LO_EXPR:
     case REDUC_MAX_EXPR:
     case REDUC_MIN_EXPR:
     case REDUC_PLUS_EXPR:
+      if (!VECTOR_TYPE_P (rhs1_type)
+         || !useless_type_conversion_p (lhs_type, TREE_TYPE (rhs1_type)))
+        {
+         error ("reduction should convert from vector to element type");
+         debug_generic_expr (lhs_type);
+         debug_generic_expr (rhs1_type);
+         return true;
+       }
+      return false;
+
+    case VEC_UNPACK_HI_EXPR:
+    case VEC_UNPACK_LO_EXPR:
     case VEC_UNPACK_FLOAT_HI_EXPR:
     case VEC_UNPACK_FLOAT_LO_EXPR:
       /* FIXME.  */
@@ -3433,7 +3599,6 @@ verify_gimple_assign_unary (gimple stmt)
     case ABS_EXPR:
     case BIT_NOT_EXPR:
     case PAREN_EXPR:
-    case NON_LVALUE_EXPR:
     case CONJ_EXPR:
       break;
 
@@ -3530,39 +3695,6 @@ verify_gimple_assign_binary (gimple stmt)
        return false;
       }
 
-    case VEC_LSHIFT_EXPR:
-    case VEC_RSHIFT_EXPR:
-      {
-       if (TREE_CODE (rhs1_type) != VECTOR_TYPE
-           || !(INTEGRAL_TYPE_P (TREE_TYPE (rhs1_type))
-                || POINTER_TYPE_P (TREE_TYPE (rhs1_type))
-                || FIXED_POINT_TYPE_P (TREE_TYPE (rhs1_type))
-                || SCALAR_FLOAT_TYPE_P (TREE_TYPE (rhs1_type)))
-           || (!INTEGRAL_TYPE_P (rhs2_type)
-               && (TREE_CODE (rhs2_type) != VECTOR_TYPE
-                   || !INTEGRAL_TYPE_P (TREE_TYPE (rhs2_type))))
-           || !useless_type_conversion_p (lhs_type, rhs1_type))
-         {
-           error ("type mismatch in vector shift expression");
-           debug_generic_expr (lhs_type);
-           debug_generic_expr (rhs1_type);
-           debug_generic_expr (rhs2_type);
-           return true;
-         }
-       /* For shifting a vector of non-integral components we
-          only allow shifting by a constant multiple of the element size.  */
-       if (!INTEGRAL_TYPE_P (TREE_TYPE (rhs1_type))
-           && (TREE_CODE (rhs2) != INTEGER_CST
-               || !div_if_zero_remainder (EXACT_DIV_EXPR, rhs2,
-                                          TYPE_SIZE (TREE_TYPE (rhs1_type)))))
-         {
-           error ("non-element sized vector shift of floating point vector");
-           return true;
-         }
-
-       return false;
-      }
-
     case WIDEN_LSHIFT_EXPR:
       {
         if (!INTEGRAL_TYPE_P (lhs_type)
@@ -3859,6 +3991,36 @@ verify_gimple_assign_ternary (gimple stmt)
 
       return false;
 
+    case SAD_EXPR:
+      if (!useless_type_conversion_p (rhs1_type, rhs2_type)
+         || !useless_type_conversion_p (lhs_type, rhs3_type)
+         || 2 * GET_MODE_BITSIZE (GET_MODE_INNER
+                                    (TYPE_MODE (TREE_TYPE (rhs1_type))))
+              > GET_MODE_BITSIZE (GET_MODE_INNER
+                                    (TYPE_MODE (TREE_TYPE (lhs_type)))))
+       {
+         error ("type mismatch in sad expression");
+         debug_generic_expr (lhs_type);
+         debug_generic_expr (rhs1_type);
+         debug_generic_expr (rhs2_type);
+         debug_generic_expr (rhs3_type);
+         return true;
+       }
+
+      if (TREE_CODE (rhs1_type) != VECTOR_TYPE
+         || TREE_CODE (rhs2_type) != VECTOR_TYPE
+         || TREE_CODE (rhs3_type) != VECTOR_TYPE)
+       {
+         error ("vector types expected in sad expression");
+         debug_generic_expr (lhs_type);
+         debug_generic_expr (rhs1_type);
+         debug_generic_expr (rhs2_type);
+         debug_generic_expr (rhs3_type);
+         return true;
+       }
+
+      return false;
+
     case DOT_PROD_EXPR:
     case REALIGN_LOAD_EXPR:
       /* FIXME.  */
@@ -3899,7 +4061,9 @@ verify_gimple_assign_single (gimple stmt)
       return true;
     }
 
-  if (handled_component_p (lhs))
+  if (handled_component_p (lhs)
+      || TREE_CODE (lhs) == MEM_REF
+      || TREE_CODE (lhs) == TARGET_MEM_REF)
     res |= verify_types_in_gimple_reference (lhs, true);
 
   /* Special codes we cannot handle via their class.  */
@@ -4055,8 +4219,20 @@ verify_gimple_assign_single (gimple stmt)
                  debug_generic_stmt (rhs1);
                  return true;
                }
+             if (!is_gimple_val (elt_v))
+               {
+                 error ("vector CONSTRUCTOR element is not a GIMPLE value");
+                 debug_generic_stmt (rhs1);
+                 return true;
+               }
            }
        }
+      else if (CONSTRUCTOR_NELTS (rhs1) != 0)
+       {
+         error ("non-vector CONSTRUCTOR with elements");
+         debug_generic_stmt (rhs1);
+         return true;
+       }
       return res;
     case OBJ_TYPE_REF:
     case ASSERT_EXPR:
@@ -4547,7 +4723,7 @@ tree_node_can_be_shared (tree t)
 static tree
 verify_node_sharing_1 (tree *tp, int *walk_subtrees, void *data)
 {
-  struct pointer_set_t *visited = (struct pointer_set_t *) data;
+  hash_set<void *> *visited = (hash_set<void *> *) data;
 
   if (tree_node_can_be_shared (*tp))
     {
@@ -4555,7 +4731,7 @@ verify_node_sharing_1 (tree *tp, int *walk_subtrees, void *data)
       return NULL;
     }
 
-  if (pointer_set_insert (visited, *tp))
+  if (visited->add (*tp))
     return *tp;
 
   return NULL;
@@ -4571,29 +4747,27 @@ verify_node_sharing (tree *tp, int *walk_subtrees, void *data)
 }
 
 static bool eh_error_found;
-static int
-verify_eh_throw_stmt_node (void **slot, void *data)
+bool
+verify_eh_throw_stmt_node (const gimple &stmt, const int &,
+                          hash_set<gimple> *visited)
 {
-  struct throw_stmt_node *node = (struct throw_stmt_node *)*slot;
-  struct pointer_set_t *visited = (struct pointer_set_t *) data;
-
-  if (!pointer_set_contains (visited, node->stmt))
+  if (!visited->contains (stmt))
     {
       error ("dead STMT in EH table");
-      debug_gimple_stmt (node->stmt);
+      debug_gimple_stmt (stmt);
       eh_error_found = true;
     }
-  return 1;
+  return true;
 }
 
 /* Verify if the location LOCs block is in BLOCKS.  */
 
 static bool
-verify_location (pointer_set_t *blocks, location_t loc)
+verify_location (hash_set<tree> *blocks, location_t loc)
 {
   tree block = LOCATION_BLOCK (loc);
   if (block != NULL_TREE
-      && !pointer_set_contains (blocks, block))
+      && !blocks->contains (block))
     {
       error ("location references block not in block tree");
       return true;
@@ -4626,7 +4800,7 @@ verify_expr_no_block (tree *tp, int *walk_subtrees, void *)
 static tree
 verify_expr_location_1 (tree *tp, int *walk_subtrees, void *data)
 {
-  struct pointer_set_t *blocks = (struct pointer_set_t *) data;
+  hash_set<tree> *blocks = (hash_set<tree> *) data;
 
   if (TREE_CODE (*tp) == VAR_DECL
       && DECL_HAS_DEBUG_EXPR_P (*tp))
@@ -4672,12 +4846,12 @@ verify_expr_location (tree *tp, int *walk_subtrees, void *data)
 /* Insert all subblocks of BLOCK into BLOCKS and recurse.  */
 
 static void
-collect_subblocks (pointer_set_t *blocks, tree block)
+collect_subblocks (hash_set<tree> *blocks, tree block)
 {
   tree t;
   for (t = BLOCK_SUBBLOCKS (block); t; t = BLOCK_CHAIN (t))
     {
-      pointer_set_insert (blocks, t);
+      blocks->add (t);
       collect_subblocks (blocks, t);
     }
 }
@@ -4685,22 +4859,21 @@ collect_subblocks (pointer_set_t *blocks, tree block)
 /* Verify the GIMPLE statements in the CFG of FN.  */
 
 DEBUG_FUNCTION void
-verify_gimple_in_cfg (struct function *fn)
+verify_gimple_in_cfg (struct function *fn, bool verify_nothrow)
 {
   basic_block bb;
   bool err = false;
-  struct pointer_set_t *visited, *visited_stmts, *blocks;
 
   timevar_push (TV_TREE_STMT_VERIFY);
-  visited = pointer_set_create ();
-  visited_stmts = pointer_set_create ();
+  hash_set<void *> visited;
+  hash_set<gimple> visited_stmts;
 
   /* Collect all BLOCKs referenced by the BLOCK tree of FN.  */
-  blocks = pointer_set_create ();
+  hash_set<tree> blocks;
   if (DECL_INITIAL (fn->decl))
     {
-      pointer_set_insert (blocks, DECL_INITIAL (fn->decl));
-      collect_subblocks (blocks, DECL_INITIAL (fn->decl));
+      blocks.add (DECL_INITIAL (fn->decl));
+      collect_subblocks (&blocks, DECL_INITIAL (fn->decl));
     }
 
   FOR_EACH_BB_FN (bb, fn)
@@ -4713,7 +4886,7 @@ verify_gimple_in_cfg (struct function *fn)
          bool err2 = false;
          unsigned i;
 
-         pointer_set_insert (visited_stmts, phi);
+         visited_stmts.add (phi);
 
          if (gimple_bb (phi) != bb)
            {
@@ -4734,7 +4907,7 @@ verify_gimple_in_cfg (struct function *fn)
            {
              tree arg = gimple_phi_arg_def (phi, i);
              tree addr = walk_tree (&arg, verify_node_sharing_1,
-                                    visited, NULL);
+                                    &visited, NULL);
              if (addr)
                {
                  error ("incorrect sharing of tree nodes");
@@ -4748,13 +4921,13 @@ verify_gimple_in_cfg (struct function *fn)
                  error ("virtual PHI with argument locations");
                  err2 = true;
                }
-             addr = walk_tree (&arg, verify_expr_location_1, blocks, NULL);
+             addr = walk_tree (&arg, verify_expr_location_1, &blocks, NULL);
              if (addr)
                {
                  debug_generic_expr (addr);
                  err2 = true;
                }
-             err2 |= verify_location (blocks, loc);
+             err2 |= verify_location (&blocks, loc);
            }
 
          if (err2)
@@ -4770,7 +4943,7 @@ verify_gimple_in_cfg (struct function *fn)
          tree addr;
          int lp_nr;
 
-         pointer_set_insert (visited_stmts, stmt);
+         visited_stmts.add (stmt);
 
          if (gimple_bb (stmt) != bb)
            {
@@ -4779,10 +4952,10 @@ verify_gimple_in_cfg (struct function *fn)
            }
 
          err2 |= verify_gimple_stmt (stmt);
-         err2 |= verify_location (blocks, gimple_location (stmt));
+         err2 |= verify_location (&blocks, gimple_location (stmt));
 
          memset (&wi, 0, sizeof (wi));
-         wi.info = (void *) visited;
+         wi.info = (void *) &visited;
          addr = walk_gimple_op (stmt, verify_node_sharing, &wi);
          if (addr)
            {
@@ -4792,7 +4965,7 @@ verify_gimple_in_cfg (struct function *fn)
            }
 
          memset (&wi, 0, sizeof (wi));
-         wi.info = (void *) blocks;
+         wi.info = (void *) &blocks;
          addr = walk_gimple_op (stmt, verify_expr_location, &wi);
          if (addr)
            {
@@ -4821,16 +4994,17 @@ verify_gimple_in_cfg (struct function *fn)
             that they cannot throw, that we update other data structures
             to match.  */
          lp_nr = lookup_stmt_eh_lp (stmt);
-         if (lp_nr != 0)
+         if (lp_nr > 0)
            {
              if (!stmt_could_throw_p (stmt))
                {
-                 error ("statement marked for throw, but doesn%'t");
-                 err2 |= true;
+                 if (verify_nothrow)
+                   {
+                     error ("statement marked for throw, but doesn%'t");
+                     err2 |= true;
+                   }
                }
-             else if (lp_nr > 0
-                      && !gsi_one_before_end_p (gsi)
-                      && stmt_can_throw_internal (stmt))
+             else if (!gsi_one_before_end_p (gsi))
                {
                  error ("statement marked for throw in middle of block");
                  err2 |= true;
@@ -4844,17 +5018,14 @@ verify_gimple_in_cfg (struct function *fn)
     }
 
   eh_error_found = false;
-  if (get_eh_throw_stmt_table (cfun))
-    htab_traverse (get_eh_throw_stmt_table (cfun),
-                  verify_eh_throw_stmt_node,
-                  visited_stmts);
+  hash_map<gimple, int> *eh_table = get_eh_throw_stmt_table (cfun);
+  if (eh_table)
+    eh_table->traverse<hash_set<gimple> *, verify_eh_throw_stmt_node>
+      (&visited_stmts);
 
   if (err || eh_error_found)
     internal_error ("verify_gimple failed");
 
-  pointer_set_destroy (visited);
-  pointer_set_destroy (visited_stmts);
-  pointer_set_destroy (blocks);
   verify_histograms ();
   timevar_pop (TV_TREE_STMT_VERIFY);
 }
@@ -5792,14 +5963,11 @@ gimple_duplicate_sese_region (edge entry, edge exit,
        return false;
     }
 
-  set_loop_copy (loop, loop);
-
   /* In case the function is used for loop header copying (which is the primary
      use), ensure that EXIT and its copy will be new latch and entry edges.  */
   if (loop->header == entry->dest)
     {
       copying_header = true;
-      set_loop_copy (loop, loop_outer (loop));
 
       if (!dominated_by_p (CDI_DOMINATORS, loop->latch, exit->src))
        return false;
@@ -5810,14 +5978,19 @@ gimple_duplicate_sese_region (edge entry, edge exit,
          return false;
     }
 
+  initialize_original_copy_tables ();
+
+  if (copying_header)
+    set_loop_copy (loop, loop_outer (loop));
+  else
+    set_loop_copy (loop, loop);
+
   if (!region_copy)
     {
       region_copy = XNEWVEC (basic_block, n_region);
       free_region_copy = true;
     }
 
-  initialize_original_copy_tables ();
-
   /* Record blocks outside the region that are dominated by something
      inside.  */
   if (update_dominance)
@@ -6125,22 +6298,20 @@ gather_blocks_in_sese_region (basic_block entry, basic_block exit,
    The duplicates are recorded in VARS_MAP.  */
 
 static void
-replace_by_duplicate_decl (tree *tp, struct pointer_map_t *vars_map,
+replace_by_duplicate_decl (tree *tp, hash_map<tree, tree> *vars_map,
                           tree to_context)
 {
   tree t = *tp, new_t;
   struct function *f = DECL_STRUCT_FUNCTION (to_context);
-  void **loc;
 
   if (DECL_CONTEXT (t) == to_context)
     return;
 
-  loc = pointer_map_contains (vars_map, t);
+  bool existed;
+  tree &loc = vars_map->get_or_insert (t, &existed);
 
-  if (!loc)
+  if (!existed)
     {
-      loc = pointer_map_insert (vars_map, t);
-
       if (SSA_VAR_P (t))
        {
          new_t = copy_var_decl (t, DECL_NAME (t), TREE_TYPE (t));
@@ -6153,10 +6324,10 @@ replace_by_duplicate_decl (tree *tp, struct pointer_map_t *vars_map,
        }
       DECL_CONTEXT (new_t) = to_context;
 
-      *loc = new_t;
+      loc = new_t;
     }
   else
-    new_t = (tree) *loc;
+    new_t = loc;
 
   *tp = new_t;
 }
@@ -6166,15 +6337,14 @@ replace_by_duplicate_decl (tree *tp, struct pointer_map_t *vars_map,
    VARS_MAP maps old ssa names and var_decls to the new ones.  */
 
 static tree
-replace_ssa_name (tree name, struct pointer_map_t *vars_map,
+replace_ssa_name (tree name, hash_map<tree, tree> *vars_map,
                  tree to_context)
 {
-  void **loc;
   tree new_name;
 
   gcc_assert (!virtual_operand_p (name));
 
-  loc = pointer_map_contains (vars_map, name);
+  tree *loc = vars_map->get (name);
 
   if (!loc)
     {
@@ -6192,11 +6362,10 @@ replace_ssa_name (tree name, struct pointer_map_t *vars_map,
        new_name = copy_ssa_name_fn (DECL_STRUCT_FUNCTION (to_context),
                                     name, SSA_NAME_DEF_STMT (name));
 
-      loc = pointer_map_insert (vars_map, name);
-      *loc = new_name;
+      vars_map->put (name, new_name);
     }
   else
-    new_name = (tree) *loc;
+    new_name = *loc;
 
   return new_name;
 }
@@ -6207,9 +6376,9 @@ struct move_stmt_d
   tree new_block;
   tree from_context;
   tree to_context;
-  struct pointer_map_t *vars_map;
+  hash_map<tree, tree> *vars_map;
   htab_t new_label_map;
-  struct pointer_map_t *eh_map;
+  hash_map<void *, void *> *eh_map;
   bool remap_decls_p;
 };
 
@@ -6286,11 +6455,9 @@ static int
 move_stmt_eh_region_nr (int old_nr, struct move_stmt_d *p)
 {
   eh_region old_r, new_r;
-  void **slot;
 
   old_r = get_eh_region_from_number (old_nr);
-  slot = pointer_map_contains (p->eh_map, old_r);
-  new_r = (eh_region) *slot;
+  new_r = static_cast<eh_region> (*p->eh_map->get (old_r));
 
   return new_r->index;
 }
@@ -6624,7 +6791,7 @@ new_label_mapper (tree decl, void *data)
    subblocks.  */
 
 static void
-replace_block_vars_by_duplicates (tree block, struct pointer_map_t *vars_map,
+replace_block_vars_by_duplicates (tree block, hash_map<tree, tree> *vars_map,
                                  tree to_context)
 {
   tree *tp, t;
@@ -6702,7 +6869,7 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
   edge e;
   edge_iterator ei;
   htab_t new_label_map;
-  struct pointer_map_t *vars_map, *eh_map;
+  hash_map<void *, void *> *eh_map;
   struct loop *loop = entry_bb->loop_father;
   struct loop *loop0 = get_loop (saved_cfun, 0);
   struct move_stmt_d d;
@@ -6791,7 +6958,7 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
     }
 
   /* Initialize an empty loop tree.  */
-  struct loops *loops = ggc_alloc_cleared_loops ();
+  struct loops *loops = ggc_cleared_alloc<struct loops> ();
   init_loops_structure (dest_cfun, loops, 1);
   loops->state = LOOPS_MAY_HAVE_MULTIPLE_LATCHES;
   set_loops_for_fn (dest_cfun, loops);
@@ -6825,11 +6992,12 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
       if (loops_for_fn (saved_cfun)->exits)
        FOR_EACH_EDGE (e, ei, bb->succs)
          {
-           void **slot = htab_find_slot_with_hash
-               (loops_for_fn (saved_cfun)->exits, e,
-                htab_hash_pointer (e), NO_INSERT);
+           struct loops *l = loops_for_fn (saved_cfun);
+           loop_exit **slot
+             = l->exits->find_slot_with_hash (e, htab_hash_pointer (e),
+                                              NO_INSERT);
            if (slot)
-             htab_clear_slot (loops_for_fn (saved_cfun)->exits, slot);
+             l->exits->clear_slot (slot);
          }
     }
 
@@ -6846,14 +7014,14 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
   /* Move blocks from BBS into DEST_CFUN.  */
   gcc_assert (bbs.length () >= 2);
   after = dest_cfun->cfg->x_entry_block_ptr;
-  vars_map = pointer_map_create ();
+  hash_map<tree, tree> vars_map;
 
   memset (&d, 0, sizeof (d));
   d.orig_block = orig_block;
   d.new_block = DECL_INITIAL (dest_cfun->decl);
   d.from_context = cfun->decl;
   d.to_context = dest_cfun->decl;
-  d.vars_map = vars_map;
+  d.vars_map = &vars_map;
   d.new_label_map = new_label_map;
   d.eh_map = eh_map;
   d.remap_decls_p = true;
@@ -6876,7 +7044,7 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
     outer->num_nodes -= num_nodes;
   loop0->num_nodes -= bbs.length () - num_nodes;
 
-  if (saved_cfun->has_simduid_loops || saved_cfun->has_force_vect_loops)
+  if (saved_cfun->has_simduid_loops || saved_cfun->has_force_vectorize_loops)
     {
       struct loop *aloop;
       for (i = 0; vec_safe_iterate (loops->larray, i, &aloop); i++)
@@ -6888,8 +7056,8 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
                                           d.to_context);
                dest_cfun->has_simduid_loops = true;
              }
-           if (aloop->force_vect)
-             dest_cfun->has_force_vect_loops = true;
+           if (aloop->force_vectorize)
+             dest_cfun->has_force_vectorize_loops = true;
          }
     }
 
@@ -6908,13 +7076,12 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
     }
 
   replace_block_vars_by_duplicates (DECL_INITIAL (dest_cfun->decl),
-                                   vars_map, dest_cfun->decl);
+                                   &vars_map, dest_cfun->decl);
 
   if (new_label_map)
     htab_delete (new_label_map);
   if (eh_map)
-    pointer_map_destroy (eh_map);
-  pointer_map_destroy (vars_map);
+    delete eh_map;
 
   /* Rewire the entry and exit blocks.  The successor to the entry
      block turns into the successor of DEST_FN's ENTRY_BLOCK_PTR in
@@ -7226,13 +7393,13 @@ print_loop (FILE *file, struct loop *loop, int indent, int verbosity)
   if (loop->any_upper_bound)
     {
       fprintf (file, ", upper_bound = ");
-      dump_double_int (file, loop->nb_iterations_upper_bound, true);
+      print_decu (loop->nb_iterations_upper_bound, file);
     }
 
   if (loop->any_estimate)
     {
       fprintf (file, ", estimate = ");
-      dump_double_int (file, loop->nb_iterations_estimate, true);
+      print_decu (loop->nb_iterations_estimate, file);
     }
   fprintf (file, ")\n");
 
@@ -7981,14 +8148,12 @@ const pass_data pass_data_split_crit_edges =
   GIMPLE_PASS, /* type */
   "crited", /* name */
   OPTGROUP_NONE, /* optinfo_flags */
-  false, /* has_gate */
-  true, /* has_execute */
   TV_TREE_SPLIT_EDGES, /* tv_id */
   PROP_cfg, /* properties_required */
   PROP_no_crit_edges, /* properties_provided */
   0, /* properties_destroyed */
   0, /* todo_flags_start */
-  TODO_verify_flow, /* todo_flags_finish */
+  0, /* todo_flags_finish */
 };
 
 class pass_split_crit_edges : public gimple_opt_pass
@@ -7999,7 +8164,7 @@ public:
   {}
 
   /* opt_pass methods: */
-  unsigned int execute () { return split_critical_edges (); }
+  virtual unsigned int execute (function *) { return split_critical_edges (); }
 
   opt_pass * clone () { return new pass_split_crit_edges (m_ctxt); }
 }; // class pass_split_crit_edges
@@ -8013,6 +8178,46 @@ make_pass_split_crit_edges (gcc::context *ctxt)
 }
 
 
+/* Insert COND expression which is GIMPLE_COND after STMT
+   in basic block BB with appropriate basic block split
+   and creation of a new conditionally executed basic block.
+   Return created basic block.  */
+basic_block
+insert_cond_bb (basic_block bb, gimple stmt, gimple cond)
+{
+  edge fall = split_block (bb, stmt);
+  gimple_stmt_iterator iter = gsi_last_bb (bb);
+  basic_block new_bb;
+
+  /* Insert cond statement.  */
+  gcc_assert (gimple_code (cond) == GIMPLE_COND);
+  if (gsi_end_p (iter))
+    gsi_insert_before (&iter, cond, GSI_CONTINUE_LINKING);
+  else
+    gsi_insert_after (&iter, cond, GSI_CONTINUE_LINKING);
+
+  /* Create conditionally executed block.  */
+  new_bb = create_empty_bb (bb);
+  make_edge (bb, new_bb, EDGE_TRUE_VALUE);
+  make_single_succ_edge (new_bb, fall->dest, EDGE_FALLTHRU);
+
+  /* Fix edge for split bb.  */
+  fall->flags = EDGE_FALSE_VALUE;
+
+  /* Update dominance info.  */
+  if (dom_info_available_p (CDI_DOMINATORS))
+    {
+      set_immediate_dominator (CDI_DOMINATORS, new_bb, bb);
+      set_immediate_dominator (CDI_DOMINATORS, fall->dest, bb);
+    }
+
+  /* Update loop info.  */
+  if (current_loops)
+    add_bb_to_loop (new_bb, bb->loop_father);
+
+  return new_bb;
+}
+
 /* Build a ternary operation and gimplify it.  Emit code before GSI.
    Return the gimple_val holding the result.  */
 
@@ -8064,64 +8269,6 @@ gimplify_build1 (gimple_stmt_iterator *gsi, enum tree_code code, tree type,
 
 
 \f
-/* Emit return warnings.  */
-
-static unsigned int
-execute_warn_function_return (void)
-{
-  source_location location;
-  gimple last;
-  edge e;
-  edge_iterator ei;
-
-  if (!targetm.warn_func_return (cfun->decl))
-    return 0;
-
-  /* If we have a path to EXIT, then we do return.  */
-  if (TREE_THIS_VOLATILE (cfun->decl)
-      && EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds) > 0)
-    {
-      location = UNKNOWN_LOCATION;
-      FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
-       {
-         last = last_stmt (e->src);
-         if ((gimple_code (last) == GIMPLE_RETURN
-              || gimple_call_builtin_p (last, BUILT_IN_RETURN))
-             && (location = gimple_location (last)) != UNKNOWN_LOCATION)
-           break;
-       }
-      if (location == UNKNOWN_LOCATION)
-       location = cfun->function_end_locus;
-      warning_at (location, 0, "%<noreturn%> function does return");
-    }
-
-  /* If we see "return;" in some basic block, then we do reach the end
-     without returning a value.  */
-  else if (warn_return_type
-          && !TREE_NO_WARNING (cfun->decl)
-          && EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds) > 0
-          && !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (cfun->decl))))
-    {
-      FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
-       {
-         gimple last = last_stmt (e->src);
-         if (gimple_code (last) == GIMPLE_RETURN
-             && gimple_return_retval (last) == NULL
-             && !gimple_no_warning_p (last))
-           {
-             location = gimple_location (last);
-             if (location == UNKNOWN_LOCATION)
-                 location = cfun->function_end_locus;
-             warning_at (location, OPT_Wreturn_type, "control reaches end of non-void function");
-             TREE_NO_WARNING (cfun->decl) = 1;
-             break;
-           }
-       }
-    }
-  return 0;
-}
-
-
 /* Given a basic block B which ends with a conditional and has
    precisely two successors, determine which of the edges is taken if
    the conditional is true and which is taken if the conditional is
@@ -8146,6 +8293,8 @@ extract_true_false_edges_from_block (basic_block b,
     }
 }
 
+/* Emit return warnings.  */
+
 namespace {
 
 const pass_data pass_data_warn_function_return =
@@ -8153,8 +8302,6 @@ const pass_data pass_data_warn_function_return =
   GIMPLE_PASS, /* type */
   "*warn_function_return", /* name */
   OPTGROUP_NONE, /* optinfo_flags */
-  false, /* has_gate */
-  true, /* has_execute */
   TV_NONE, /* tv_id */
   PROP_cfg, /* properties_required */
   0, /* properties_provided */
@@ -8171,10 +8318,65 @@ public:
   {}
 
   /* opt_pass methods: */
-  unsigned int execute () { return execute_warn_function_return (); }
+  virtual unsigned int execute (function *);
 
 }; // class pass_warn_function_return
 
+unsigned int
+pass_warn_function_return::execute (function *fun)
+{
+  source_location location;
+  gimple last;
+  edge e;
+  edge_iterator ei;
+
+  if (!targetm.warn_func_return (fun->decl))
+    return 0;
+
+  /* If we have a path to EXIT, then we do return.  */
+  if (TREE_THIS_VOLATILE (fun->decl)
+      && EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (fun)->preds) > 0)
+    {
+      location = UNKNOWN_LOCATION;
+      FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (fun)->preds)
+       {
+         last = last_stmt (e->src);
+         if ((gimple_code (last) == GIMPLE_RETURN
+              || gimple_call_builtin_p (last, BUILT_IN_RETURN))
+             && (location = gimple_location (last)) != UNKNOWN_LOCATION)
+           break;
+       }
+      if (location == UNKNOWN_LOCATION)
+       location = cfun->function_end_locus;
+      warning_at (location, 0, "%<noreturn%> function does return");
+    }
+
+  /* If we see "return;" in some basic block, then we do reach the end
+     without returning a value.  */
+  else if (warn_return_type
+          && !TREE_NO_WARNING (fun->decl)
+          && EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (fun)->preds) > 0
+          && !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (fun->decl))))
+    {
+      FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (fun)->preds)
+       {
+         gimple last = last_stmt (e->src);
+         if (gimple_code (last) == GIMPLE_RETURN
+             && gimple_return_retval (last) == NULL
+             && !gimple_no_warning_p (last))
+           {
+             location = gimple_location (last);
+             if (location == UNKNOWN_LOCATION)
+               location = fun->function_end_locus;
+             warning_at (location, OPT_Wreturn_type, "control reaches end of non-void function");
+             TREE_NO_WARNING (fun->decl) = 1;
+             break;
+           }
+       }
+    }
+  return 0;
+}
+
 } // anon namespace
 
 gimple_opt_pass *
@@ -8248,19 +8450,6 @@ do_warn_unused_result (gimple_seq seq)
     }
 }
 
-static unsigned int
-run_warn_unused_result (void)
-{
-  do_warn_unused_result (gimple_body (current_function_decl));
-  return 0;
-}
-
-static bool
-gate_warn_unused_result (void)
-{
-  return flag_warn_unused_result;
-}
-
 namespace {
 
 const pass_data pass_data_warn_unused_result =
@@ -8268,8 +8457,6 @@ const pass_data pass_data_warn_unused_result =
   GIMPLE_PASS, /* type */
   "*warn_unused_result", /* name */
   OPTGROUP_NONE, /* optinfo_flags */
-  true, /* has_gate */
-  true, /* has_execute */
   TV_NONE, /* tv_id */
   PROP_gimple_any, /* properties_required */
   0, /* properties_provided */
@@ -8286,8 +8473,12 @@ public:
   {}
 
   /* opt_pass methods: */
-  bool gate () { return gate_warn_unused_result (); }
-  unsigned int execute () { return run_warn_unused_result (); }
+  virtual bool gate (function *) { return flag_warn_unused_result; }
+  virtual unsigned int execute (function *)
+    {
+      do_warn_unused_result (gimple_body (current_function_decl));
+      return 0;
+    }
 
 }; // class pass_warn_unused_result
 
@@ -8312,17 +8503,17 @@ execute_fixup_cfg (void)
 {
   basic_block bb;
   gimple_stmt_iterator gsi;
-  int todo = gimple_in_ssa_p (cfun) ? TODO_verify_ssa : 0;
+  int todo = 0;
   gcov_type count_scale;
   edge e;
   edge_iterator ei;
 
   count_scale
-      = GCOV_COMPUTE_SCALE (cgraph_get_node (current_function_decl)->count,
+      = GCOV_COMPUTE_SCALE (cgraph_node::get (current_function_decl)->count,
                            ENTRY_BLOCK_PTR_FOR_FN (cfun)->count);
 
   ENTRY_BLOCK_PTR_FOR_FN (cfun)->count =
-                           cgraph_get_node (current_function_decl)->count;
+                           cgraph_node::get (current_function_decl)->count;
   EXIT_BLOCK_PTR_FOR_FN (cfun)->count =
                            apply_scale (EXIT_BLOCK_PTR_FOR_FN (cfun)->count,
                                        count_scale);
@@ -8333,7 +8524,7 @@ execute_fixup_cfg (void)
   FOR_EACH_BB_FN (bb, cfun)
     {
       bb->count = apply_scale (bb->count, count_scale);
-      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);)
        {
          gimple stmt = gsi_stmt (gsi);
          tree decl = is_gimple_call (stmt)
@@ -8359,9 +8550,46 @@ execute_fixup_cfg (void)
                todo |= TODO_cleanup_cfg;
             }
 
+         /* Remove stores to variables we marked write-only.
+            Keep access when store has side effect, i.e. in case when source
+            is volatile.  */
+         if (gimple_store_p (stmt)
+             && !gimple_has_side_effects (stmt))
+           {
+             tree lhs = get_base_address (gimple_get_lhs (stmt));
+
+             if (TREE_CODE (lhs) == VAR_DECL
+                 && (TREE_STATIC (lhs) || DECL_EXTERNAL (lhs))
+                 && varpool_node::get (lhs)->writeonly)
+               {
+                 unlink_stmt_vdef (stmt);
+                 gsi_remove (&gsi, true);
+                 release_defs (stmt);
+                 todo |= TODO_update_ssa | TODO_cleanup_cfg;
+                 continue;
+               }
+           }
+         /* For calls we can simply remove LHS when it is known
+            to be write-only.  */
+         if (is_gimple_call (stmt)
+             && gimple_get_lhs (stmt))
+           {
+             tree lhs = get_base_address (gimple_get_lhs (stmt));
+
+             if (TREE_CODE (lhs) == VAR_DECL
+                 && (TREE_STATIC (lhs) || DECL_EXTERNAL (lhs))
+                 && varpool_node::get (lhs)->writeonly)
+               {
+                 gimple_call_set_lhs (stmt, NULL);
+                 update_stmt (stmt);
+                 todo |= TODO_update_ssa | TODO_cleanup_cfg;
+               }
+           }
+
          if (maybe_clean_eh_stmt (stmt)
              && gimple_purge_dead_eh_edges (bb))
            todo |= TODO_cleanup_cfg;
+         gsi_next (&gsi);
        }
 
       FOR_EACH_EDGE (e, ei, bb->succs)
@@ -8379,6 +8607,8 @@ execute_fixup_cfg (void)
                  && (!is_gimple_call (stmt)
                      || (gimple_call_flags (stmt) & ECF_NORETURN) == 0)))
            {
+             if (stmt && is_gimple_call (stmt))
+               gimple_call_set_ctrl_altering (stmt, false);
              stmt = gimple_build_call
                  (builtin_decl_implicit (BUILT_IN_UNREACHABLE), 0);
              gimple_stmt_iterator gsi = gsi_last_bb (bb);
@@ -8389,10 +8619,6 @@ execute_fixup_cfg (void)
   if (count_scale != REG_BR_PROB_BASE)
     compute_function_frequency ();
 
-  /* We just processed all calls.  */
-  if (cfun->gimple_df)
-    vec_free (MODIFIED_NORETURN_CALLS (cfun));
-
   /* Dump a textual representation of the flowgraph.  */
   if (dump_file)
     gimple_dump_cfg (dump_file, dump_flags);
@@ -8411,8 +8637,6 @@ const pass_data pass_data_fixup_cfg =
   GIMPLE_PASS, /* type */
   "*free_cfg_annotations", /* name */
   OPTGROUP_NONE, /* optinfo_flags */
-  false, /* has_gate */
-  true, /* has_execute */
   TV_NONE, /* tv_id */
   PROP_cfg, /* properties_required */
   0, /* properties_provided */
@@ -8430,7 +8654,7 @@ public:
 
   /* opt_pass methods: */
   opt_pass * clone () { return new pass_fixup_cfg (m_ctxt); }
-  unsigned int execute () { return execute_fixup_cfg (); }
+  virtual unsigned int execute (function *) { return execute_fixup_cfg (); }
 
 }; // class pass_fixup_cfg
 
@@ -8449,6 +8673,13 @@ extern void gt_ggc_mx (gimple&);
 extern void gt_ggc_mx (rtx&);
 extern void gt_ggc_mx (basic_block&);
 
+static void
+gt_ggc_mx (rtx_insn *& x)
+{
+  if (x)
+    gt_ggc_mx_rtx_def ((void *) x);
+}
+
 void
 gt_ggc_mx (edge_def *e)
 {
@@ -8469,6 +8700,13 @@ extern void gt_pch_nx (gimple&);
 extern void gt_pch_nx (rtx&);
 extern void gt_pch_nx (basic_block&);
 
+static void
+gt_pch_nx (rtx_insn *& x)
+{
+  if (x)
+    gt_pch_nx_rtx_def ((void *) x);
+}
+
 void
 gt_pch_nx (edge_def *e)
 {